Просмотр исходного кода

Merge branch 'master' into frodo-aes

tags/v0.0.1
Douglas Stebila 5 лет назад
Родитель
Сommit
a2c2521e81
80 измененных файлов: 3328 добавлений и 2616 удалений
  1. +1
    -3
      .github/pull_request_template.md
  2. +2
    -1
      README.md
  3. +24
    -0
      crypto_kem/frodokem1344shake/META.yml
  4. +21
    -0
      crypto_kem/frodokem1344shake/clean/LICENSE
  5. +3
    -3
      crypto_kem/frodokem1344shake/clean/Makefile
  6. +19
    -0
      crypto_kem/frodokem1344shake/clean/Makefile.Microsoft_nmake
  7. +20
    -0
      crypto_kem/frodokem1344shake/clean/api.h
  8. +19
    -0
      crypto_kem/frodokem1344shake/clean/common.h
  9. +238
    -0
      crypto_kem/frodokem1344shake/clean/kem.c
  10. +79
    -0
      crypto_kem/frodokem1344shake/clean/matrix_shake.c
  11. +33
    -0
      crypto_kem/frodokem1344shake/clean/noise.c
  12. +27
    -0
      crypto_kem/frodokem1344shake/clean/params.h
  13. +234
    -0
      crypto_kem/frodokem1344shake/clean/util.c
  14. +15
    -15
      crypto_kem/frodokem640shake/META.yml
  15. +24
    -0
      crypto_kem/frodokem976shake/META.yml
  16. +21
    -0
      crypto_kem/frodokem976shake/clean/LICENSE
  17. +19
    -0
      crypto_kem/frodokem976shake/clean/Makefile
  18. +19
    -0
      crypto_kem/frodokem976shake/clean/Makefile.Microsoft_nmake
  19. +20
    -0
      crypto_kem/frodokem976shake/clean/api.h
  20. +19
    -0
      crypto_kem/frodokem976shake/clean/common.h
  21. +238
    -0
      crypto_kem/frodokem976shake/clean/kem.c
  22. +79
    -0
      crypto_kem/frodokem976shake/clean/matrix_shake.c
  23. +33
    -0
      crypto_kem/frodokem976shake/clean/noise.c
  24. +27
    -0
      crypto_kem/frodokem976shake/clean/params.h
  25. +234
    -0
      crypto_kem/frodokem976shake/clean/util.c
  26. +2
    -2
      crypto_kem/kyber768/META.yml
  27. +4
    -6
      crypto_kem/kyber768/clean/api.h
  28. +0
    -54
      crypto_kem/kyber768/clean/cbd.c
  29. +0
    -18
      crypto_sign/dilithium-iii/META.yml
  30. +0
    -1
      crypto_sign/dilithium-iii/clean/LICENSE
  31. +0
    -30
      crypto_sign/dilithium-iii/clean/api.h
  32. +0
    -139
      crypto_sign/dilithium-iii/clean/ntt.c
  33. +0
    -10
      crypto_sign/dilithium-iii/clean/ntt.h
  34. +0
    -301
      crypto_sign/dilithium-iii/clean/packing.c
  35. +0
    -30
      crypto_sign/dilithium-iii/clean/packing.h
  36. +0
    -68
      crypto_sign/dilithium-iii/clean/params.h
  37. +0
    -777
      crypto_sign/dilithium-iii/clean/poly.c
  38. +0
    -53
      crypto_sign/dilithium-iii/clean/poly.h
  39. +0
    -367
      crypto_sign/dilithium-iii/clean/polyvec.c
  40. +0
    -54
      crypto_sign/dilithium-iii/clean/polyvec.h
  41. +0
    -74
      crypto_sign/dilithium-iii/clean/reduce.c
  42. +0
    -21
      crypto_sign/dilithium-iii/clean/reduce.h
  43. +0
    -119
      crypto_sign/dilithium-iii/clean/rounding.c
  44. +0
    -11
      crypto_sign/dilithium-iii/clean/rounding.h
  45. +0
    -402
      crypto_sign/dilithium-iii/clean/sign.c
  46. +0
    -30
      crypto_sign/dilithium-iii/clean/sign.h
  47. +27
    -0
      crypto_sign/sphincs-shake256-128f-simple/META.yml
  48. +116
    -0
      crypto_sign/sphincs-shake256-128f-simple/clean/LICENSE
  49. +20
    -0
      crypto_sign/sphincs-shake256-128f-simple/clean/Makefile
  50. +3
    -3
      crypto_sign/sphincs-shake256-128f-simple/clean/Makefile.Microsoft_nmake
  51. +77
    -0
      crypto_sign/sphincs-shake256-128f-simple/clean/address.c
  52. +50
    -0
      crypto_sign/sphincs-shake256-128f-simple/clean/address.h
  53. +78
    -0
      crypto_sign/sphincs-shake256-128f-simple/clean/api.h
  54. +164
    -0
      crypto_sign/sphincs-shake256-128f-simple/clean/fors.c
  55. +30
    -0
      crypto_sign/sphincs-shake256-128f-simple/clean/fors.h
  56. +22
    -0
      crypto_sign/sphincs-shake256-128f-simple/clean/hash.h
  57. +86
    -0
      crypto_sign/sphincs-shake256-128f-simple/clean/hash_shake256.c
  58. +53
    -0
      crypto_sign/sphincs-shake256-128f-simple/clean/params.h
  59. +344
    -0
      crypto_sign/sphincs-shake256-128f-simple/clean/sign.c
  60. +22
    -0
      crypto_sign/sphincs-shake256-128f-simple/clean/thash.h
  61. +61
    -0
      crypto_sign/sphincs-shake256-128f-simple/clean/thash_shake256_simple.c
  62. +192
    -0
      crypto_sign/sphincs-shake256-128f-simple/clean/utils.c
  63. +60
    -0
      crypto_sign/sphincs-shake256-128f-simple/clean/utils.h
  64. +159
    -0
      crypto_sign/sphincs-shake256-128f-simple/clean/wots.c
  65. +38
    -0
      crypto_sign/sphincs-shake256-128f-simple/clean/wots.h
  66. +4
    -1
      test/Makefile
  67. +2
    -2
      test/Makefile.Microsoft_nmake
  68. +3
    -3
      test/crypto_kem/functest.c
  69. +1
    -1
      test/crypto_kem/testvectors.c
  70. +72
    -1
      test/crypto_sign/functest.c
  71. +9
    -2
      test/crypto_sign/testvectors.c
  72. +9
    -0
      test/duplicate_consistency/frodokem1344shake_clean.yml
  73. +9
    -0
      test/duplicate_consistency/frodokem976shake_clean.yml
  74. +17
    -8
      test/pqclean.py
  75. +32
    -0
      test/test_api_h.py
  76. +4
    -0
      test/test_char.py
  77. +42
    -0
      test/test_duplicate_consistency.py
  78. +8
    -5
      test/test_metadata.py
  79. +3
    -1
      test/test_metadata_sizes.py
  80. +37
    -0
      test/test_preprocessor.py

+ 1
- 3
.github/pull_request_template.md Просмотреть файл

@@ -3,11 +3,9 @@
<!-- Type some lines about your submission -->


## Manually checked properties
#### Manually checked properties
<!-- These checkboxes serve for the maintainers of PQClean to verify your submission. Please do not check them yourself. -->

* [ ] `#ifdef`s only for header encapsulation
* [ ] `api.h` does not include other files
* [ ] No stringification macros
* [ ] Output-parameter pointers in functions are on the left
* [ ] Negative return values on failure of API functions (within restrictions of FO transform).


+ 2
- 1
README.md Просмотреть файл

@@ -34,7 +34,9 @@ _The checking of items on this list is still being developed. Checked items shou
* [x] Code is valid C99
* [x] Passes functional tests
* [x] API functions do not write outside provided buffers
* [x] `api.h` cannot include external files
* [x] Compiles with `-Wall -Wextra -Wpedantic -Werror` with `gcc` and `clang`
* [x] `#if`/`#ifdef`s only for header encapsulation
* [x] Consistent test vectors across runs
* [x] Consistent test vectors on big-endian and little-endian machines
* [x] Consistent test vectors on 32-bit and 64-bit machines
@@ -65,7 +67,6 @@ _The checking of items on this list is still being developed. Checked items shou
## Requirements on C implementations that are manually checked

* Minimalist Makefiles
* `#ifdef`s only for header encapsulation
* No stringification macros
* Output-parameter pointers in functions are on the left
* `const` arguments are labeled as `const`


+ 24
- 0
crypto_kem/frodokem1344shake/META.yml Просмотреть файл

@@ -0,0 +1,24 @@
name: FrodoKEM-1344-SHAKE
type: kem
claimed-nist-level: 5
length-public-key: 21520
length-ciphertext: 21632
length-shared-secret: 32
testvectors-sha256: 8b62fc01fc1e4b4e336776b09b37aaf55d161b7c815b3298f39d4444b011e10c
principal-submitter: Douglas Stebila, University of Waterloo
auxiliary-submitters:
- Erdem Alkim
- Joppe W. Bos, NXP Semiconductors
- Léo Ducas, CWI
- Patrick Longa, Microsoft Research
- Ilya Mironov, Google
- Michael Naehrig, Microsoft Research
- Valeria Nikolaenko
- Chris Peikert, University of Michigan
- Ananth Raghunathan, Google
- Karen Easterbrook, Microsoft Research
- Brian LaMacchia, Microsoft Research
implementations:
- name: clean
version: https://github.com/Microsoft/PQCrypto-LWEKE/commit/437e228fca580a82435cab09f30ae14b03183119
length-secret-key: 43088

+ 21
- 0
crypto_kem/frodokem1344shake/clean/LICENSE Просмотреть файл

@@ -0,0 +1,21 @@
MIT License

Copyright (c) Microsoft Corporation. All rights reserved.

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE

crypto_sign/dilithium-iii/clean/Makefile → crypto_kem/frodokem1344shake/clean/Makefile Просмотреть файл

@@ -1,8 +1,8 @@
# This Makefile can be used with GNU Make or BSD Make

LIB=libdilithium-iii_clean.a
HEADERS=api.h ntt.h packing.h params.h poly.h polyvec.h reduce.h rounding.h sign.h
OBJECTS=ntt.o packing.o poly.o polyvec.o reduce.o rounding.o sign.o
LIB=libfrodokem1344shake_clean.a
HEADERS=api.h params.h common.h
OBJECTS=kem.o matrix_shake.o noise.o util.o

CFLAGS=-Wall -Wextra -Wpedantic -Werror -std=c99 -I../../../common $(EXTRAFLAGS)


+ 19
- 0
crypto_kem/frodokem1344shake/clean/Makefile.Microsoft_nmake Просмотреть файл

@@ -0,0 +1,19 @@
# This Makefile can be used with Microsoft Visual Studio's nmake using the command:
# nmake /f Makefile.Microsoft_nmake

LIBRARY=libfrodokem1344shake_clean.lib
OBJECTS=kem.obj matrix_shake.obj noise.obj util.obj

CFLAGS=/nologo /I ..\..\..\common /W4 /WX

all: $(LIBRARY)

# Make sure objects are recompiled if headers change.
$(OBJECTS): *.h

$(LIBRARY): $(OBJECTS)
LIB.EXE /NOLOGO /WX /OUT:$@ $**

clean:
-DEL $(OBJECTS)
-DEL $(LIBRARY)

+ 20
- 0
crypto_kem/frodokem1344shake/clean/api.h Просмотреть файл

@@ -0,0 +1,20 @@
#ifndef PQCLEAN_FRODOKEM1344SHAKE_CLEAN_API_H
#define PQCLEAN_FRODOKEM1344SHAKE_CLEAN_API_H

#include <stddef.h>
#include <stdint.h>

#define PQCLEAN_FRODOKEM1344SHAKE_CLEAN_CRYPTO_SECRETKEYBYTES 43088 // sizeof(s) + CRYPTO_PUBLICKEYBYTES + 2*PARAMS_N*PARAMS_NBAR + BYTES_PKHASH
#define PQCLEAN_FRODOKEM1344SHAKE_CLEAN_CRYPTO_PUBLICKEYBYTES 21520 // sizeof(seed_A) + (PARAMS_LOGQ*PARAMS_N*PARAMS_NBAR)/8
#define PQCLEAN_FRODOKEM1344SHAKE_CLEAN_CRYPTO_BYTES 32
#define PQCLEAN_FRODOKEM1344SHAKE_CLEAN_CRYPTO_CIPHERTEXTBYTES 21632 // (PARAMS_LOGQ*PARAMS_N*PARAMS_NBAR)/8 + (PARAMS_LOGQ*PARAMS_NBAR*PARAMS_NBAR)/8

#define PQCLEAN_FRODOKEM1344SHAKE_CLEAN_CRYPTO_ALGNAME "FrodoKEM-1344-SHAKE"

int PQCLEAN_FRODOKEM1344SHAKE_CLEAN_crypto_kem_keypair(uint8_t *pk, uint8_t *sk);

int PQCLEAN_FRODOKEM1344SHAKE_CLEAN_crypto_kem_enc(uint8_t *ct, uint8_t *ss, const uint8_t *pk);

int PQCLEAN_FRODOKEM1344SHAKE_CLEAN_crypto_kem_dec(uint8_t *ss, const uint8_t *ct, const uint8_t *sk);

#endif

+ 19
- 0
crypto_kem/frodokem1344shake/clean/common.h Просмотреть файл

@@ -0,0 +1,19 @@
#ifndef COMMON_H
#define COMMON_H

int PQCLEAN_FRODOKEM1344SHAKE_CLEAN_mul_add_as_plus_e(uint16_t *out, const uint16_t *s, const uint16_t *e, const uint8_t *seed_A);
int PQCLEAN_FRODOKEM1344SHAKE_CLEAN_mul_add_sa_plus_e(uint16_t *out, const uint16_t *s, const uint16_t *e, const uint8_t *seed_A);
void PQCLEAN_FRODOKEM1344SHAKE_CLEAN_sample_n(uint16_t *s, size_t n);
void PQCLEAN_FRODOKEM1344SHAKE_CLEAN_mul_bs(uint16_t *out, const uint16_t *b, const uint16_t *s);
void PQCLEAN_FRODOKEM1344SHAKE_CLEAN_mul_add_sb_plus_e(uint16_t *out, const uint16_t *b, const uint16_t *s, const uint16_t *e);
void PQCLEAN_FRODOKEM1344SHAKE_CLEAN_add(uint16_t *out, const uint16_t *a, const uint16_t *b);
void PQCLEAN_FRODOKEM1344SHAKE_CLEAN_sub(uint16_t *out, const uint16_t *a, const uint16_t *b);
void PQCLEAN_FRODOKEM1344SHAKE_CLEAN_key_encode(uint16_t *out, const uint16_t *in);
void PQCLEAN_FRODOKEM1344SHAKE_CLEAN_key_decode(uint16_t *out, const uint16_t *in);
void PQCLEAN_FRODOKEM1344SHAKE_CLEAN_pack(uint8_t *out, size_t outlen, const uint16_t *in, size_t inlen, uint8_t lsb);
void PQCLEAN_FRODOKEM1344SHAKE_CLEAN_unpack(uint16_t *out, size_t outlen, const uint8_t *in, size_t inlen, uint8_t lsb);
void PQCLEAN_FRODOKEM1344SHAKE_CLEAN_clear_bytes(uint8_t *mem, size_t n);
uint16_t PQCLEAN_FRODOKEM1344SHAKE_CLEAN_LE_TO_UINT16(uint16_t n);
uint16_t PQCLEAN_FRODOKEM1344SHAKE_CLEAN_UINT16_TO_LE(uint16_t n);

#endif

+ 238
- 0
crypto_kem/frodokem1344shake/clean/kem.c Просмотреть файл

@@ -0,0 +1,238 @@
/********************************************************************************************
* FrodoKEM: Learning with Errors Key Encapsulation
*
* Abstract: Key Encapsulation Mechanism (KEM) based on Frodo
*********************************************************************************************/

#include <stdint.h>
#include <string.h>

#include "fips202.h"
#include "randombytes.h"

#include "api.h"
#include "common.h"
#include "params.h"

int PQCLEAN_FRODOKEM1344SHAKE_CLEAN_crypto_kem_keypair(uint8_t *pk, uint8_t *sk) {
// FrodoKEM's key generation
// Outputs: public key pk ( BYTES_SEED_A + (PARAMS_LOGQ*PARAMS_N*PARAMS_NBAR)/8 bytes)
// secret key sk (CRYPTO_BYTES + BYTES_SEED_A + (PARAMS_LOGQ*PARAMS_N*PARAMS_NBAR)/8 + 2*PARAMS_N*PARAMS_NBAR + BYTES_PKHASH bytes)
uint8_t *pk_seedA = &pk[0];
uint8_t *pk_b = &pk[BYTES_SEED_A];
uint8_t *sk_s = &sk[0];
uint8_t *sk_pk = &sk[CRYPTO_BYTES];
uint8_t *sk_S = &sk[CRYPTO_BYTES + CRYPTO_PUBLICKEYBYTES];
uint8_t *sk_pkh = &sk[CRYPTO_BYTES + CRYPTO_PUBLICKEYBYTES + 2 * PARAMS_N * PARAMS_NBAR];
uint16_t B[PARAMS_N * PARAMS_NBAR] = {0};
uint16_t S[2 * PARAMS_N * PARAMS_NBAR] = {0}; // contains secret data
uint16_t *E = &S[PARAMS_N * PARAMS_NBAR]; // contains secret data
uint8_t randomness[2 * CRYPTO_BYTES + BYTES_SEED_A]; // contains secret data via randomness_s and randomness_seedSE
uint8_t *randomness_s = &randomness[0]; // contains secret data
uint8_t *randomness_seedSE = &randomness[CRYPTO_BYTES]; // contains secret data
uint8_t *randomness_z = &randomness[2 * CRYPTO_BYTES];
uint8_t shake_input_seedSE[1 + CRYPTO_BYTES]; // contains secret data

// Generate the secret value s, the seed for S and E, and the seed for the seed for A. Add seed_A to the public key
randombytes(randomness, CRYPTO_BYTES + CRYPTO_BYTES + BYTES_SEED_A);
shake(pk_seedA, BYTES_SEED_A, randomness_z, BYTES_SEED_A);

// Generate S and E, and compute B = A*S + E. Generate A on-the-fly
shake_input_seedSE[0] = 0x5F;
memcpy(&shake_input_seedSE[1], randomness_seedSE, CRYPTO_BYTES);
shake((uint8_t *)S, 2 * PARAMS_N * PARAMS_NBAR * sizeof(uint16_t), shake_input_seedSE, 1 + CRYPTO_BYTES);
for (size_t i = 0; i < 2 * PARAMS_N * PARAMS_NBAR; i++) {
S[i] = PQCLEAN_FRODOKEM1344SHAKE_CLEAN_LE_TO_UINT16(S[i]);
}
PQCLEAN_FRODOKEM1344SHAKE_CLEAN_sample_n(S, PARAMS_N * PARAMS_NBAR);
PQCLEAN_FRODOKEM1344SHAKE_CLEAN_sample_n(E, PARAMS_N * PARAMS_NBAR);
PQCLEAN_FRODOKEM1344SHAKE_CLEAN_mul_add_as_plus_e(B, S, E, pk);

// Encode the second part of the public key
PQCLEAN_FRODOKEM1344SHAKE_CLEAN_pack(pk_b, CRYPTO_PUBLICKEYBYTES - BYTES_SEED_A, B, PARAMS_N * PARAMS_NBAR, PARAMS_LOGQ);

// Add s, pk and S to the secret key
memcpy(sk_s, randomness_s, CRYPTO_BYTES);
memcpy(sk_pk, pk, CRYPTO_PUBLICKEYBYTES);
for (size_t i = 0; i < PARAMS_N * PARAMS_NBAR; i++) {
S[i] = PQCLEAN_FRODOKEM1344SHAKE_CLEAN_UINT16_TO_LE(S[i]);
}
memcpy(sk_S, S, 2 * PARAMS_N * PARAMS_NBAR);

// Add H(pk) to the secret key
shake(sk_pkh, BYTES_PKHASH, pk, CRYPTO_PUBLICKEYBYTES);

// Cleanup:
PQCLEAN_FRODOKEM1344SHAKE_CLEAN_clear_bytes((uint8_t *)S, PARAMS_N * PARAMS_NBAR * sizeof(uint16_t));
PQCLEAN_FRODOKEM1344SHAKE_CLEAN_clear_bytes((uint8_t *)E, PARAMS_N * PARAMS_NBAR * sizeof(uint16_t));
PQCLEAN_FRODOKEM1344SHAKE_CLEAN_clear_bytes(randomness, 2 * CRYPTO_BYTES);
PQCLEAN_FRODOKEM1344SHAKE_CLEAN_clear_bytes(shake_input_seedSE, 1 + CRYPTO_BYTES);
return 0;
}


int PQCLEAN_FRODOKEM1344SHAKE_CLEAN_crypto_kem_enc(uint8_t *ct, uint8_t *ss, const uint8_t *pk) {
// FrodoKEM's key encapsulation
const uint8_t *pk_seedA = &pk[0];
const uint8_t *pk_b = &pk[BYTES_SEED_A];
uint8_t *ct_c1 = &ct[0];
uint8_t *ct_c2 = &ct[(PARAMS_LOGQ * PARAMS_N * PARAMS_NBAR) / 8];
uint16_t B[PARAMS_N * PARAMS_NBAR] = {0};
uint16_t V[PARAMS_NBAR * PARAMS_NBAR] = {0}; // contains secret data
uint16_t C[PARAMS_NBAR * PARAMS_NBAR] = {0};
uint16_t Bp[PARAMS_N * PARAMS_NBAR] = {0};
uint16_t Sp[(2 * PARAMS_N + PARAMS_NBAR)*PARAMS_NBAR] = {0}; // contains secret data
uint16_t *Ep = &Sp[PARAMS_N * PARAMS_NBAR]; // contains secret data
uint16_t *Epp = &Sp[2 * PARAMS_N * PARAMS_NBAR]; // contains secret data
uint8_t G2in[BYTES_PKHASH + BYTES_MU]; // contains secret data via mu
uint8_t *pkh = &G2in[0];
uint8_t *mu = &G2in[BYTES_PKHASH]; // contains secret data
uint8_t G2out[2 * CRYPTO_BYTES]; // contains secret data
uint8_t *seedSE = &G2out[0]; // contains secret data
uint8_t *k = &G2out[CRYPTO_BYTES]; // contains secret data
uint8_t Fin[CRYPTO_CIPHERTEXTBYTES + CRYPTO_BYTES]; // contains secret data via Fin_k
uint8_t *Fin_ct = &Fin[0];
uint8_t *Fin_k = &Fin[CRYPTO_CIPHERTEXTBYTES]; // contains secret data
uint8_t shake_input_seedSE[1 + CRYPTO_BYTES]; // contains secret data

// pkh <- G_1(pk), generate random mu, compute (seedSE || k) = G_2(pkh || mu)
shake(pkh, BYTES_PKHASH, pk, CRYPTO_PUBLICKEYBYTES);
randombytes(mu, BYTES_MU);
shake(G2out, CRYPTO_BYTES + CRYPTO_BYTES, G2in, BYTES_PKHASH + BYTES_MU);

// Generate Sp and Ep, and compute Bp = Sp*A + Ep. Generate A on-the-fly
shake_input_seedSE[0] = 0x96;
memcpy(&shake_input_seedSE[1], seedSE, CRYPTO_BYTES);
shake((uint8_t *)Sp, (2 * PARAMS_N + PARAMS_NBAR) * PARAMS_NBAR * sizeof(uint16_t), shake_input_seedSE, 1 + CRYPTO_BYTES);
for (size_t i = 0; i < (2 * PARAMS_N + PARAMS_NBAR) * PARAMS_NBAR; i++) {
Sp[i] = PQCLEAN_FRODOKEM1344SHAKE_CLEAN_LE_TO_UINT16(Sp[i]);
}
PQCLEAN_FRODOKEM1344SHAKE_CLEAN_sample_n(Sp, PARAMS_N * PARAMS_NBAR);
PQCLEAN_FRODOKEM1344SHAKE_CLEAN_sample_n(Ep, PARAMS_N * PARAMS_NBAR);
PQCLEAN_FRODOKEM1344SHAKE_CLEAN_mul_add_sa_plus_e(Bp, Sp, Ep, pk_seedA);
PQCLEAN_FRODOKEM1344SHAKE_CLEAN_pack(ct_c1, (PARAMS_LOGQ * PARAMS_N * PARAMS_NBAR) / 8, Bp, PARAMS_N * PARAMS_NBAR, PARAMS_LOGQ);

// Generate Epp, and compute V = Sp*B + Epp
PQCLEAN_FRODOKEM1344SHAKE_CLEAN_sample_n(Epp, PARAMS_NBAR * PARAMS_NBAR);
PQCLEAN_FRODOKEM1344SHAKE_CLEAN_unpack(B, PARAMS_N * PARAMS_NBAR, pk_b, CRYPTO_PUBLICKEYBYTES - BYTES_SEED_A, PARAMS_LOGQ);
PQCLEAN_FRODOKEM1344SHAKE_CLEAN_mul_add_sb_plus_e(V, B, Sp, Epp);

// Encode mu, and compute C = V + enc(mu) (mod q)
PQCLEAN_FRODOKEM1344SHAKE_CLEAN_key_encode(C, (uint16_t *)mu);
PQCLEAN_FRODOKEM1344SHAKE_CLEAN_add(C, V, C);
PQCLEAN_FRODOKEM1344SHAKE_CLEAN_pack(ct_c2, (PARAMS_LOGQ * PARAMS_NBAR * PARAMS_NBAR) / 8, C, PARAMS_NBAR * PARAMS_NBAR, PARAMS_LOGQ);

// Compute ss = F(ct||KK)
memcpy(Fin_ct, ct, CRYPTO_CIPHERTEXTBYTES);
memcpy(Fin_k, k, CRYPTO_BYTES);
shake(ss, CRYPTO_BYTES, Fin, CRYPTO_CIPHERTEXTBYTES + CRYPTO_BYTES);

// Cleanup:
PQCLEAN_FRODOKEM1344SHAKE_CLEAN_clear_bytes((uint8_t *)V, PARAMS_NBAR * PARAMS_NBAR * sizeof(uint16_t));
PQCLEAN_FRODOKEM1344SHAKE_CLEAN_clear_bytes((uint8_t *)Sp, PARAMS_N * PARAMS_NBAR * sizeof(uint16_t));
PQCLEAN_FRODOKEM1344SHAKE_CLEAN_clear_bytes((uint8_t *)Ep, PARAMS_N * PARAMS_NBAR * sizeof(uint16_t));
PQCLEAN_FRODOKEM1344SHAKE_CLEAN_clear_bytes((uint8_t *)Epp, PARAMS_NBAR * PARAMS_NBAR * sizeof(uint16_t));
PQCLEAN_FRODOKEM1344SHAKE_CLEAN_clear_bytes(mu, BYTES_MU);
PQCLEAN_FRODOKEM1344SHAKE_CLEAN_clear_bytes(G2out, 2 * CRYPTO_BYTES);
PQCLEAN_FRODOKEM1344SHAKE_CLEAN_clear_bytes(Fin_k, CRYPTO_BYTES);
PQCLEAN_FRODOKEM1344SHAKE_CLEAN_clear_bytes(shake_input_seedSE, 1 + CRYPTO_BYTES);
return 0;
}


int PQCLEAN_FRODOKEM1344SHAKE_CLEAN_crypto_kem_dec(uint8_t *ss, const uint8_t *ct, const uint8_t *sk) {
// FrodoKEM's key decapsulation
uint16_t B[PARAMS_N * PARAMS_NBAR] = {0};
uint16_t Bp[PARAMS_N * PARAMS_NBAR] = {0};
uint16_t W[PARAMS_NBAR * PARAMS_NBAR] = {0}; // contains secret data
uint16_t C[PARAMS_NBAR * PARAMS_NBAR] = {0};
uint16_t CC[PARAMS_NBAR * PARAMS_NBAR] = {0};
uint16_t BBp[PARAMS_N * PARAMS_NBAR] = {0};
uint16_t Sp[(2 * PARAMS_N + PARAMS_NBAR)*PARAMS_NBAR] = {0}; // contains secret data
uint16_t *Ep = &Sp[PARAMS_N * PARAMS_NBAR]; // contains secret data
uint16_t *Epp = &Sp[2 * PARAMS_N * PARAMS_NBAR]; // contains secret data
const uint8_t *ct_c1 = &ct[0];
const uint8_t *ct_c2 = &ct[(PARAMS_LOGQ * PARAMS_N * PARAMS_NBAR) / 8];
const uint8_t *sk_s = &sk[0];
const uint8_t *sk_pk = &sk[CRYPTO_BYTES];
const uint16_t *sk_S = (uint16_t *) &sk[CRYPTO_BYTES + CRYPTO_PUBLICKEYBYTES];
uint16_t S[PARAMS_N * PARAMS_NBAR]; // contains secret data
const uint8_t *sk_pkh = &sk[CRYPTO_BYTES + CRYPTO_PUBLICKEYBYTES + 2 * PARAMS_N * PARAMS_NBAR];
const uint8_t *pk_seedA = &sk_pk[0];
const uint8_t *pk_b = &sk_pk[BYTES_SEED_A];
uint8_t G2in[BYTES_PKHASH + BYTES_MU]; // contains secret data via muprime
uint8_t *pkh = &G2in[0];
uint8_t *muprime = &G2in[BYTES_PKHASH]; // contains secret data
uint8_t G2out[2 * CRYPTO_BYTES]; // contains secret data
uint8_t *seedSEprime = &G2out[0]; // contains secret data
uint8_t *kprime = &G2out[CRYPTO_BYTES]; // contains secret data
uint8_t Fin[CRYPTO_CIPHERTEXTBYTES + CRYPTO_BYTES]; // contains secret data via Fin_k
uint8_t *Fin_ct = &Fin[0];
uint8_t *Fin_k = &Fin[CRYPTO_CIPHERTEXTBYTES]; // contains secret data
uint8_t shake_input_seedSEprime[1 + CRYPTO_BYTES]; // contains secret data

for (size_t i = 0; i < PARAMS_N * PARAMS_NBAR; i++) {
S[i] = PQCLEAN_FRODOKEM1344SHAKE_CLEAN_LE_TO_UINT16(sk_S[i]);
}

// Compute W = C - Bp*S (mod q), and decode the randomness mu
PQCLEAN_FRODOKEM1344SHAKE_CLEAN_unpack(Bp, PARAMS_N * PARAMS_NBAR, ct_c1, (PARAMS_LOGQ * PARAMS_N * PARAMS_NBAR) / 8, PARAMS_LOGQ);
PQCLEAN_FRODOKEM1344SHAKE_CLEAN_unpack(C, PARAMS_NBAR * PARAMS_NBAR, ct_c2, (PARAMS_LOGQ * PARAMS_NBAR * PARAMS_NBAR) / 8, PARAMS_LOGQ);
PQCLEAN_FRODOKEM1344SHAKE_CLEAN_mul_bs(W, Bp, S);
PQCLEAN_FRODOKEM1344SHAKE_CLEAN_sub(W, C, W);
PQCLEAN_FRODOKEM1344SHAKE_CLEAN_key_decode((uint16_t *)muprime, W);

// Generate (seedSE' || k') = G_2(pkh || mu')
memcpy(pkh, sk_pkh, BYTES_PKHASH);
shake(G2out, CRYPTO_BYTES + CRYPTO_BYTES, G2in, BYTES_PKHASH + BYTES_MU);

// Generate Sp and Ep, and compute BBp = Sp*A + Ep. Generate A on-the-fly
shake_input_seedSEprime[0] = 0x96;
memcpy(&shake_input_seedSEprime[1], seedSEprime, CRYPTO_BYTES);
shake((uint8_t *)Sp, (2 * PARAMS_N + PARAMS_NBAR) * PARAMS_NBAR * sizeof(uint16_t), shake_input_seedSEprime, 1 + CRYPTO_BYTES);
for (size_t i = 0; i < (2 * PARAMS_N + PARAMS_NBAR) * PARAMS_NBAR; i++) {
Sp[i] = PQCLEAN_FRODOKEM1344SHAKE_CLEAN_LE_TO_UINT16(Sp[i]);
}
PQCLEAN_FRODOKEM1344SHAKE_CLEAN_sample_n(Sp, PARAMS_N * PARAMS_NBAR);
PQCLEAN_FRODOKEM1344SHAKE_CLEAN_sample_n(Ep, PARAMS_N * PARAMS_NBAR);
PQCLEAN_FRODOKEM1344SHAKE_CLEAN_mul_add_sa_plus_e(BBp, Sp, Ep, pk_seedA);

// Generate Epp, and compute W = Sp*B + Epp
PQCLEAN_FRODOKEM1344SHAKE_CLEAN_sample_n(Epp, PARAMS_NBAR * PARAMS_NBAR);
PQCLEAN_FRODOKEM1344SHAKE_CLEAN_unpack(B, PARAMS_N * PARAMS_NBAR, pk_b, CRYPTO_PUBLICKEYBYTES - BYTES_SEED_A, PARAMS_LOGQ);
PQCLEAN_FRODOKEM1344SHAKE_CLEAN_mul_add_sb_plus_e(W, B, Sp, Epp);

// Encode mu, and compute CC = W + enc(mu') (mod q)
PQCLEAN_FRODOKEM1344SHAKE_CLEAN_key_encode(CC, (uint16_t *)muprime);
PQCLEAN_FRODOKEM1344SHAKE_CLEAN_add(CC, W, CC);

// Prepare input to F
memcpy(Fin_ct, ct, CRYPTO_CIPHERTEXTBYTES);

// Reducing BBp modulo q
for (size_t i = 0; i < PARAMS_N * PARAMS_NBAR; i++) {
BBp[i] = BBp[i] & ((1 << PARAMS_LOGQ) - 1);
}

// Is (Bp == BBp & C == CC) = true
if (memcmp(Bp, BBp, 2 * PARAMS_N * PARAMS_NBAR) == 0 && memcmp(C, CC, 2 * PARAMS_NBAR * PARAMS_NBAR) == 0) {
// Load k' to do ss = F(ct || k')
memcpy(Fin_k, kprime, CRYPTO_BYTES);
} else {
// Load s to do ss = F(ct || s)
memcpy(Fin_k, sk_s, CRYPTO_BYTES);
}
shake(ss, CRYPTO_BYTES, Fin, CRYPTO_CIPHERTEXTBYTES + CRYPTO_BYTES);

// Cleanup:
PQCLEAN_FRODOKEM1344SHAKE_CLEAN_clear_bytes((uint8_t *)W, PARAMS_NBAR * PARAMS_NBAR * sizeof(uint16_t));
PQCLEAN_FRODOKEM1344SHAKE_CLEAN_clear_bytes((uint8_t *)Sp, PARAMS_N * PARAMS_NBAR * sizeof(uint16_t));
PQCLEAN_FRODOKEM1344SHAKE_CLEAN_clear_bytes((uint8_t *)S, PARAMS_N * PARAMS_NBAR * sizeof(uint16_t));
PQCLEAN_FRODOKEM1344SHAKE_CLEAN_clear_bytes((uint8_t *)Ep, PARAMS_N * PARAMS_NBAR * sizeof(uint16_t));
PQCLEAN_FRODOKEM1344SHAKE_CLEAN_clear_bytes((uint8_t *)Epp, PARAMS_NBAR * PARAMS_NBAR * sizeof(uint16_t));
PQCLEAN_FRODOKEM1344SHAKE_CLEAN_clear_bytes(muprime, BYTES_MU);
PQCLEAN_FRODOKEM1344SHAKE_CLEAN_clear_bytes(G2out, 2 * CRYPTO_BYTES);
PQCLEAN_FRODOKEM1344SHAKE_CLEAN_clear_bytes(Fin_k, CRYPTO_BYTES);
PQCLEAN_FRODOKEM1344SHAKE_CLEAN_clear_bytes(shake_input_seedSEprime, 1 + CRYPTO_BYTES);
return 0;
}

+ 79
- 0
crypto_kem/frodokem1344shake/clean/matrix_shake.c Просмотреть файл

@@ -0,0 +1,79 @@
/********************************************************************************************
* FrodoKEM: Learning with Errors Key Encapsulation
*
* Abstract: matrix arithmetic functions used by the KEM
*********************************************************************************************/

#include <stdint.h>
#include <string.h>

#include "fips202.h"

#include "api.h"
#include "common.h"
#include "params.h"

int PQCLEAN_FRODOKEM1344SHAKE_CLEAN_mul_add_as_plus_e(uint16_t *out, const uint16_t *s, const uint16_t *e, const uint8_t *seed_A) {
// Generate-and-multiply: generate matrix A (N x N) row-wise, multiply by s on the right.
// Inputs: s, e (N x N_BAR)
// Output: out = A*s + e (N x N_BAR)
int i, j, k;
int16_t A[PARAMS_N * PARAMS_N] = {0};

uint8_t seed_A_separated[2 + BYTES_SEED_A];
uint16_t *seed_A_origin = (uint16_t *)&seed_A_separated;
memcpy(&seed_A_separated[2], seed_A, BYTES_SEED_A);
for (i = 0; i < PARAMS_N; i++) {
seed_A_origin[0] = PQCLEAN_FRODOKEM1344SHAKE_CLEAN_UINT16_TO_LE((uint16_t) i);
shake128((uint8_t *)(A + i * PARAMS_N), (unsigned long long)(2 * PARAMS_N), seed_A_separated, 2 + BYTES_SEED_A);
}
for (i = 0; i < PARAMS_N * PARAMS_N; i++) {
A[i] = PQCLEAN_FRODOKEM1344SHAKE_CLEAN_LE_TO_UINT16(A[i]);
}
memcpy(out, e, PARAMS_NBAR * PARAMS_N * sizeof(uint16_t));

for (i = 0; i < PARAMS_N; i++) { // Matrix multiplication-addition A*s + e
for (k = 0; k < PARAMS_NBAR; k++) {
uint16_t sum = 0;
for (j = 0; j < PARAMS_N; j++) {
sum += A[i * PARAMS_N + j] * s[k * PARAMS_N + j];
}
out[i * PARAMS_NBAR + k] += sum; // Adding e. No need to reduce modulo 2^15, extra bits are taken care of during packing later on.
}
}

return 1;
}


int PQCLEAN_FRODOKEM1344SHAKE_CLEAN_mul_add_sa_plus_e(uint16_t *out, const uint16_t *s, const uint16_t *e, const uint8_t *seed_A) {
// Generate-and-multiply: generate matrix A (N x N) column-wise, multiply by s' on the left.
// Inputs: s', e' (N_BAR x N)
// Output: out = s'*A + e' (N_BAR x N)
int i, j, k;
int16_t A[PARAMS_N * PARAMS_N] = {0};

uint8_t seed_A_separated[2 + BYTES_SEED_A];
uint16_t *seed_A_origin = (uint16_t *)&seed_A_separated;
memcpy(&seed_A_separated[2], seed_A, BYTES_SEED_A);
for (i = 0; i < PARAMS_N; i++) {
seed_A_origin[0] = PQCLEAN_FRODOKEM1344SHAKE_CLEAN_UINT16_TO_LE((uint16_t) i);
shake128((uint8_t *)(A + i * PARAMS_N), (unsigned long long)(2 * PARAMS_N), seed_A_separated, 2 + BYTES_SEED_A);
}
for (i = 0; i < PARAMS_N * PARAMS_N; i++) {
A[i] = PQCLEAN_FRODOKEM1344SHAKE_CLEAN_LE_TO_UINT16(A[i]);
}
memcpy(out, e, PARAMS_NBAR * PARAMS_N * sizeof(uint16_t));

for (i = 0; i < PARAMS_N; i++) { // Matrix multiplication-addition A*s + e
for (k = 0; k < PARAMS_NBAR; k++) {
uint16_t sum = 0;
for (j = 0; j < PARAMS_N; j++) {
sum += A[j * PARAMS_N + i] * s[k * PARAMS_N + j];
}
out[k * PARAMS_N + i] += sum; // Adding e. No need to reduce modulo 2^15, extra bits are taken care of during packing later on.
}
}

return 1;
}

+ 33
- 0
crypto_kem/frodokem1344shake/clean/noise.c Просмотреть файл

@@ -0,0 +1,33 @@
/********************************************************************************************
* FrodoKEM: Learning with Errors Key Encapsulation
*
* Abstract: noise sampling functions
*********************************************************************************************/

#include <stdint.h>

#include "api.h"
#include "params.h"

static uint16_t CDF_TABLE[CDF_TABLE_LEN] = CDF_TABLE_DATA;

void PQCLEAN_FRODOKEM1344SHAKE_CLEAN_sample_n(uint16_t *s, const size_t n) {
// Fills vector s with n samples from the noise distribution which requires 16 bits to sample.
// The distribution is specified by its CDF.
// Input: pseudo-random values (2*n bytes) passed in s. The input is overwritten by the output.
unsigned int i, j;

for (i = 0; i < n; ++i) {
uint8_t sample = 0;
uint16_t prnd = s[i] >> 1; // Drop the least significant bit
uint8_t sign = s[i] & 0x1; // Pick the least significant bit

// No need to compare with the last value.
for (j = 0; j < (unsigned int)(CDF_TABLE_LEN - 1); j++) {
// Constant time comparison: 1 if CDF_TABLE[j] < s, 0 otherwise. Uses the fact that CDF_TABLE[j] and s fit in 15 bits.
sample += (uint16_t)(CDF_TABLE[j] - prnd) >> 15;
}
// Assuming that sign is either 0 or 1, flips sample iff sign = 1
s[i] = ((-sign) ^ sample) + sign;
}
}

+ 27
- 0
crypto_kem/frodokem1344shake/clean/params.h Просмотреть файл

@@ -0,0 +1,27 @@
#ifndef PARAMS_H
#define PARAMS_H

#define CRYPTO_SECRETKEYBYTES PQCLEAN_FRODOKEM1344SHAKE_CLEAN_CRYPTO_SECRETKEYBYTES
#define CRYPTO_PUBLICKEYBYTES PQCLEAN_FRODOKEM1344SHAKE_CLEAN_CRYPTO_PUBLICKEYBYTES
#define CRYPTO_BYTES PQCLEAN_FRODOKEM1344SHAKE_CLEAN_CRYPTO_BYTES
#define CRYPTO_CIPHERTEXTBYTES PQCLEAN_FRODOKEM1344SHAKE_CLEAN_CRYPTO_CIPHERTEXTBYTES

#define PARAMS_N 1344
#define PARAMS_NBAR 8
#define PARAMS_LOGQ 16
#define PARAMS_Q (1 << PARAMS_LOGQ)
#define PARAMS_EXTRACTED_BITS 4
#define PARAMS_STRIPE_STEP 8
#define PARAMS_PARALLEL 4
#define BYTES_SEED_A 16
#define BYTES_MU ((PARAMS_EXTRACTED_BITS * PARAMS_NBAR * PARAMS_NBAR) / 8)
#define BYTES_PKHASH CRYPTO_BYTES

// Selecting SHAKE XOF function for the KEM and noise sampling
#define shake shake256

// CDF table
#define CDF_TABLE_DATA {9142, 23462, 30338, 32361, 32725, 32765, 32767}
#define CDF_TABLE_LEN 7

#endif

+ 234
- 0
crypto_kem/frodokem1344shake/clean/util.c Просмотреть файл

@@ -0,0 +1,234 @@
/********************************************************************************************
* FrodoKEM: Learning with Errors Key Encapsulation
*
* Abstract: additional functions for FrodoKEM
*********************************************************************************************/

#include <stdint.h>
#include <string.h>

#include "api.h"
#include "params.h"

#define min(x, y) (((x) < (y)) ? (x) : (y))

uint16_t PQCLEAN_FRODOKEM1344SHAKE_CLEAN_LE_TO_UINT16(const uint16_t n) {
return (((uint8_t *) &(n))[0] | (((uint8_t *) &(n))[1] << 8));
}

uint16_t PQCLEAN_FRODOKEM1344SHAKE_CLEAN_UINT16_TO_LE(const uint16_t n) {
uint16_t y;
uint8_t *z = (uint8_t *) &y;
z[0] = n & 0xFF;
z[1] = (n & 0xFF00) >> 8;
return y;
}

void PQCLEAN_FRODOKEM1344SHAKE_CLEAN_mul_bs(uint16_t *out, const uint16_t *b, const uint16_t *s) {
// Multiply by s on the right
// Inputs: b (N_BAR x N), s (N x N_BAR)
// Output: out = b*s (N_BAR x N_BAR)
int i, j, k;

for (i = 0; i < PARAMS_NBAR; i++) {
for (j = 0; j < PARAMS_NBAR; j++) {
out[i * PARAMS_NBAR + j] = 0;
for (k = 0; k < PARAMS_N; k++) {
out[i * PARAMS_NBAR + j] += b[i * PARAMS_N + k] * s[j * PARAMS_N + k];
}
out[i * PARAMS_NBAR + j] = (uint32_t)(out[i * PARAMS_NBAR + j]) & ((1 << PARAMS_LOGQ) - 1);
}
}
}


void PQCLEAN_FRODOKEM1344SHAKE_CLEAN_mul_add_sb_plus_e(uint16_t *out, const uint16_t *b, const uint16_t *s, const uint16_t *e) {
// Multiply by s on the left
// Inputs: b (N x N_BAR), s (N_BAR x N), e (N_BAR x N_BAR)
// Output: out = s*b + e (N_BAR x N_BAR)
int i, j, k;

for (k = 0; k < PARAMS_NBAR; k++) {
for (i = 0; i < PARAMS_NBAR; i++) {
out[k * PARAMS_NBAR + i] = e[k * PARAMS_NBAR + i];
for (j = 0; j < PARAMS_N; j++) {
out[k * PARAMS_NBAR + i] += s[k * PARAMS_N + j] * b[j * PARAMS_NBAR + i];
}
out[k * PARAMS_NBAR + i] = (uint32_t)(out[k * PARAMS_NBAR + i]) & ((1 << PARAMS_LOGQ) - 1);
}
}
}


void PQCLEAN_FRODOKEM1344SHAKE_CLEAN_add(uint16_t *out, const uint16_t *a, const uint16_t *b) {
// Add a and b
// Inputs: a, b (N_BAR x N_BAR)
// Output: c = a + b

for (size_t i = 0; i < (PARAMS_NBAR * PARAMS_NBAR); i++) {
out[i] = (a[i] + b[i]) & ((1 << PARAMS_LOGQ) - 1);
}
}


void PQCLEAN_FRODOKEM1344SHAKE_CLEAN_sub(uint16_t *out, const uint16_t *a, const uint16_t *b) {
// Subtract a and b
// Inputs: a, b (N_BAR x N_BAR)
// Output: c = a - b

for (size_t i = 0; i < (PARAMS_NBAR * PARAMS_NBAR); i++) {
out[i] = (a[i] - b[i]) & ((1 << PARAMS_LOGQ) - 1);
}
}


void PQCLEAN_FRODOKEM1344SHAKE_CLEAN_key_encode(uint16_t *out, const uint16_t *in) {
// Encoding
unsigned int i, j, npieces_word = 8;
unsigned int nwords = (PARAMS_NBAR * PARAMS_NBAR) / 8;
uint64_t temp, mask = ((uint64_t)1 << PARAMS_EXTRACTED_BITS) - 1;
uint16_t *pos = out;

for (i = 0; i < nwords; i++) {
temp = 0;
for (j = 0; j < PARAMS_EXTRACTED_BITS; j++) {
temp |= ((uint64_t)((uint8_t *)in)[i * PARAMS_EXTRACTED_BITS + j]) << (8 * j);
}
for (j = 0; j < npieces_word; j++) {
*pos = (uint16_t)((temp & mask) << (PARAMS_LOGQ - PARAMS_EXTRACTED_BITS));
temp >>= PARAMS_EXTRACTED_BITS;
pos++;
}
}
}


void PQCLEAN_FRODOKEM1344SHAKE_CLEAN_key_decode(uint16_t *out, const uint16_t *in) {
// Decoding
unsigned int i, j, index = 0, npieces_word = 8;
unsigned int nwords = (PARAMS_NBAR * PARAMS_NBAR) / 8;
uint16_t temp, maskex = ((uint16_t)1 << PARAMS_EXTRACTED_BITS) - 1, maskq = ((uint16_t)1 << PARAMS_LOGQ) - 1;
uint8_t *pos = (uint8_t *)out;
uint64_t templong;

for (i = 0; i < nwords; i++) {
templong = 0;
for (j = 0; j < npieces_word; j++) { // temp = floor(in*2^{-11}+0.5)
temp = ((in[index] & maskq) + (1 << (PARAMS_LOGQ - PARAMS_EXTRACTED_BITS - 1))) >> (PARAMS_LOGQ - PARAMS_EXTRACTED_BITS);
templong |= ((uint64_t)(temp & maskex)) << (PARAMS_EXTRACTED_BITS * j);
index++;
}
for (j = 0; j < PARAMS_EXTRACTED_BITS; j++) {
pos[i * PARAMS_EXTRACTED_BITS + j] = (templong >> (8 * j)) & 0xFF;
}
}
}


void PQCLEAN_FRODOKEM1344SHAKE_CLEAN_pack(uint8_t *out, const size_t outlen, const uint16_t *in, const size_t inlen, const uint8_t lsb) {
// Pack the input uint16 vector into a char output vector, copying lsb bits from each input element.
// If inlen * lsb / 8 > outlen, only outlen * 8 bits are copied.
memset(out, 0, outlen);

size_t i = 0; // whole bytes already filled in
size_t j = 0; // whole uint16_t already copied
uint16_t w = 0; // the leftover, not yet copied
uint8_t bits = 0; // the number of lsb in w

while (i < outlen && (j < inlen || ((j == inlen) && (bits > 0)))) {
/*
in: | | |********|********|
^
j
w : | ****|
^
bits
out:|**|**|**|**|**|**|**|**|* |
^^
ib
*/
uint8_t b = 0; // bits in out[i] already filled in
while (b < 8) {
int nbits = min(8 - b, bits);
uint16_t mask = (1 << nbits) - 1;
uint8_t t = (uint8_t) ((w >> (bits - nbits)) & mask); // the bits to copy from w to out
out[i] = out[i] + (t << (8 - b - nbits));
b += (uint8_t) nbits;
bits -= (uint8_t) nbits;
w &= ~(mask << bits); // not strictly necessary; mostly for debugging

if (bits == 0) {
if (j < inlen) {
w = in[j];
bits = lsb;
j++;
} else {
break; // the input vector is exhausted
}
}
}
if (b == 8) { // out[i] is filled in
i++;
}
}
}


void PQCLEAN_FRODOKEM1344SHAKE_CLEAN_unpack(uint16_t *out, const size_t outlen, const uint8_t *in, const size_t inlen, const uint8_t lsb) {
// Unpack the input char vector into a uint16_t output vector, copying lsb bits
// for each output element from input. outlen must be at least ceil(inlen * 8 / lsb).
memset(out, 0, outlen * sizeof(uint16_t));

size_t i = 0; // whole uint16_t already filled in
size_t j = 0; // whole bytes already copied
uint8_t w = 0; // the leftover, not yet copied
uint8_t bits = 0; // the number of lsb bits of w

while (i < outlen && (j < inlen || ((j == inlen) && (bits > 0)))) {
/*
in: | | | | | | |**|**|...
^
j
w : | *|
^
bits
out:| *****| *****| *** | |...
^ ^
i b
*/
uint8_t b = 0; // bits in out[i] already filled in
while (b < lsb) {
int nbits = min(lsb - b, bits);
uint16_t mask = (1 << nbits) - 1;
uint8_t t = (w >> (bits - nbits)) & mask; // the bits to copy from w to out
out[i] = out[i] + (t << (lsb - b - nbits));
b += (uint8_t) nbits;
bits -= (uint8_t) nbits;
w &= ~(mask << bits); // not strictly necessary; mostly for debugging

if (bits == 0) {
if (j < inlen) {
w = in[j];
bits = 8;
j++;
} else {
break; // the input vector is exhausted
}
}
}
if (b == lsb) { // out[i] is filled in
i++;
}
}
}


void PQCLEAN_FRODOKEM1344SHAKE_CLEAN_clear_bytes(uint8_t *mem, size_t n) {
// Clear 8-bit bytes from memory. "n" indicates the number of bytes to be zeroed.
// This function uses the volatile type qualifier to inform the compiler not to optimize out the memory clearing.
volatile uint8_t *v = mem;

for (size_t i = 0; i < n; i++) {
v[i] = 0;
}
}

+ 15
- 15
crypto_kem/frodokem640shake/META.yml Просмотреть файл

@@ -2,23 +2,23 @@ name: FrodoKEM-640-SHAKE
type: kem
claimed-nist-level: 1
length-public-key: 9616
length-secret-key: 19888
length-ciphertext: 9720
length-shared-secret: 16
testvectors-sha256: 521ff891de20efe74e6584d09612dae989427ac76261a41630c4e4d6a4fc78a4
testvectors-sha256: 8f922de02d41005fcc3c4164b2ab74c4c7b588ed69e34e22607d1ae4ab13d2c5
principal-submitter: Douglas Stebila, University of Waterloo
auxiliary-submitters:
- Erdem Alkim
- Joppe W. Bos, NXP Semiconductors
- Léo Ducas, CWI
- Patrick Longa, Microsoft Research
- Ilya Mironov, Google
- Michael Naehrig, Microsoft Research
- Valeria Nikolaenko
- Chris Peikert, University of Michigan
- Ananth Raghunathan, Google
- Karen Easterbrook, Microsoft Research
- Brian LaMacchia, Microsoft Research
- Erdem Alkim
- Joppe W. Bos, NXP Semiconductors
- Léo Ducas, CWI
- Patrick Longa, Microsoft Research
- Ilya Mironov, Google
- Michael Naehrig, Microsoft Research
- Valeria Nikolaenko
- Chris Peikert, University of Michigan
- Ananth Raghunathan, Google
- Karen Easterbrook, Microsoft Research
- Brian LaMacchia, Microsoft Research
implementations:
- name: clean
version: https://github.com/Microsoft/PQCrypto-LWEKE/commit/437e228fca580a82435cab09f30ae14b03183119
- name: clean
version: https://github.com/Microsoft/PQCrypto-LWEKE/commit/437e228fca580a82435cab09f30ae14b03183119
length-secret-key: 19888

+ 24
- 0
crypto_kem/frodokem976shake/META.yml Просмотреть файл

@@ -0,0 +1,24 @@
name: FrodoKEM-976-SHAKE
type: kem
claimed-nist-level: 3
length-public-key: 15632
length-ciphertext: 15744
length-shared-secret: 24
testvectors-sha256: 00707dc8158c6e51e70e9a7b23a87054c5f2167b77a2e5940b8e82519834717b
principal-submitter: Douglas Stebila, University of Waterloo
auxiliary-submitters:
- Erdem Alkim
- Joppe W. Bos, NXP Semiconductors
- Léo Ducas, CWI
- Patrick Longa, Microsoft Research
- Ilya Mironov, Google
- Michael Naehrig, Microsoft Research
- Valeria Nikolaenko
- Chris Peikert, University of Michigan
- Ananth Raghunathan, Google
- Karen Easterbrook, Microsoft Research
- Brian LaMacchia, Microsoft Research
implementations:
- name: clean
version: https://github.com/Microsoft/PQCrypto-LWEKE/commit/437e228fca580a82435cab09f30ae14b03183119
length-secret-key: 31296

+ 21
- 0
crypto_kem/frodokem976shake/clean/LICENSE Просмотреть файл

@@ -0,0 +1,21 @@
MIT License

Copyright (c) Microsoft Corporation. All rights reserved.

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE

+ 19
- 0
crypto_kem/frodokem976shake/clean/Makefile Просмотреть файл

@@ -0,0 +1,19 @@
# This Makefile can be used with GNU Make or BSD Make

LIB=libfrodokem976shake_clean.a
HEADERS=api.h params.h common.h
OBJECTS=kem.o matrix_shake.o noise.o util.o

CFLAGS=-Wall -Wextra -Wpedantic -Werror -std=c99 -I../../../common $(EXTRAFLAGS)

all: $(LIB)

%.o: %.c $(HEADERS)
$(CC) $(CFLAGS) -c -o $@ $<

$(LIB): $(OBJECTS)
$(AR) -r $@ $(OBJECTS)

clean:
$(RM) $(OBJECTS)
$(RM) $(LIB)

+ 19
- 0
crypto_kem/frodokem976shake/clean/Makefile.Microsoft_nmake Просмотреть файл

@@ -0,0 +1,19 @@
# This Makefile can be used with Microsoft Visual Studio's nmake using the command:
# nmake /f Makefile.Microsoft_nmake

LIBRARY=libfrodokem976shake_clean.lib
OBJECTS=kem.obj matrix_shake.obj noise.obj util.obj

CFLAGS=/nologo /I ..\..\..\common /W4 /WX

all: $(LIBRARY)

# Make sure objects are recompiled if headers change.
$(OBJECTS): *.h

$(LIBRARY): $(OBJECTS)
LIB.EXE /NOLOGO /WX /OUT:$@ $**

clean:
-DEL $(OBJECTS)
-DEL $(LIBRARY)

+ 20
- 0
crypto_kem/frodokem976shake/clean/api.h Просмотреть файл

@@ -0,0 +1,20 @@
#ifndef PQCLEAN_FRODOKEM976SHAKE_CLEAN_API_H
#define PQCLEAN_FRODOKEM976SHAKE_CLEAN_API_H

#include <stddef.h>
#include <stdint.h>

#define PQCLEAN_FRODOKEM976SHAKE_CLEAN_CRYPTO_SECRETKEYBYTES 31296 // sizeof(s) + CRYPTO_PUBLICKEYBYTES + 2*PARAMS_N*PARAMS_NBAR + BYTES_PKHASH
#define PQCLEAN_FRODOKEM976SHAKE_CLEAN_CRYPTO_PUBLICKEYBYTES 15632 // sizeof(seed_A) + (PARAMS_LOGQ*PARAMS_N*PARAMS_NBAR)/8
#define PQCLEAN_FRODOKEM976SHAKE_CLEAN_CRYPTO_BYTES 24
#define PQCLEAN_FRODOKEM976SHAKE_CLEAN_CRYPTO_CIPHERTEXTBYTES 15744 // (PARAMS_LOGQ*PARAMS_N*PARAMS_NBAR)/8 + (PARAMS_LOGQ*PARAMS_NBAR*PARAMS_NBAR)/8

#define PQCLEAN_FRODOKEM976SHAKE_CLEAN_CRYPTO_ALGNAME "FrodoKEM-976-SHAKE"

int PQCLEAN_FRODOKEM976SHAKE_CLEAN_crypto_kem_keypair(uint8_t *pk, uint8_t *sk);

int PQCLEAN_FRODOKEM976SHAKE_CLEAN_crypto_kem_enc(uint8_t *ct, uint8_t *ss, const uint8_t *pk);

int PQCLEAN_FRODOKEM976SHAKE_CLEAN_crypto_kem_dec(uint8_t *ss, const uint8_t *ct, const uint8_t *sk);

#endif

+ 19
- 0
crypto_kem/frodokem976shake/clean/common.h Просмотреть файл

@@ -0,0 +1,19 @@
#ifndef COMMON_H
#define COMMON_H

int PQCLEAN_FRODOKEM976SHAKE_CLEAN_mul_add_as_plus_e(uint16_t *out, const uint16_t *s, const uint16_t *e, const uint8_t *seed_A);
int PQCLEAN_FRODOKEM976SHAKE_CLEAN_mul_add_sa_plus_e(uint16_t *out, const uint16_t *s, const uint16_t *e, const uint8_t *seed_A);
void PQCLEAN_FRODOKEM976SHAKE_CLEAN_sample_n(uint16_t *s, size_t n);
void PQCLEAN_FRODOKEM976SHAKE_CLEAN_mul_bs(uint16_t *out, const uint16_t *b, const uint16_t *s);
void PQCLEAN_FRODOKEM976SHAKE_CLEAN_mul_add_sb_plus_e(uint16_t *out, const uint16_t *b, const uint16_t *s, const uint16_t *e);
void PQCLEAN_FRODOKEM976SHAKE_CLEAN_add(uint16_t *out, const uint16_t *a, const uint16_t *b);
void PQCLEAN_FRODOKEM976SHAKE_CLEAN_sub(uint16_t *out, const uint16_t *a, const uint16_t *b);
void PQCLEAN_FRODOKEM976SHAKE_CLEAN_key_encode(uint16_t *out, const uint16_t *in);
void PQCLEAN_FRODOKEM976SHAKE_CLEAN_key_decode(uint16_t *out, const uint16_t *in);
void PQCLEAN_FRODOKEM976SHAKE_CLEAN_pack(uint8_t *out, size_t outlen, const uint16_t *in, size_t inlen, uint8_t lsb);
void PQCLEAN_FRODOKEM976SHAKE_CLEAN_unpack(uint16_t *out, size_t outlen, const uint8_t *in, size_t inlen, uint8_t lsb);
void PQCLEAN_FRODOKEM976SHAKE_CLEAN_clear_bytes(uint8_t *mem, size_t n);
uint16_t PQCLEAN_FRODOKEM976SHAKE_CLEAN_LE_TO_UINT16(uint16_t n);
uint16_t PQCLEAN_FRODOKEM976SHAKE_CLEAN_UINT16_TO_LE(uint16_t n);

#endif

+ 238
- 0
crypto_kem/frodokem976shake/clean/kem.c Просмотреть файл

@@ -0,0 +1,238 @@
/********************************************************************************************
* FrodoKEM: Learning with Errors Key Encapsulation
*
* Abstract: Key Encapsulation Mechanism (KEM) based on Frodo
*********************************************************************************************/

#include <stdint.h>
#include <string.h>

#include "fips202.h"
#include "randombytes.h"

#include "api.h"
#include "common.h"
#include "params.h"

int PQCLEAN_FRODOKEM976SHAKE_CLEAN_crypto_kem_keypair(uint8_t *pk, uint8_t *sk) {
// FrodoKEM's key generation
// Outputs: public key pk ( BYTES_SEED_A + (PARAMS_LOGQ*PARAMS_N*PARAMS_NBAR)/8 bytes)
// secret key sk (CRYPTO_BYTES + BYTES_SEED_A + (PARAMS_LOGQ*PARAMS_N*PARAMS_NBAR)/8 + 2*PARAMS_N*PARAMS_NBAR + BYTES_PKHASH bytes)
uint8_t *pk_seedA = &pk[0];
uint8_t *pk_b = &pk[BYTES_SEED_A];
uint8_t *sk_s = &sk[0];
uint8_t *sk_pk = &sk[CRYPTO_BYTES];
uint8_t *sk_S = &sk[CRYPTO_BYTES + CRYPTO_PUBLICKEYBYTES];
uint8_t *sk_pkh = &sk[CRYPTO_BYTES + CRYPTO_PUBLICKEYBYTES + 2 * PARAMS_N * PARAMS_NBAR];
uint16_t B[PARAMS_N * PARAMS_NBAR] = {0};
uint16_t S[2 * PARAMS_N * PARAMS_NBAR] = {0}; // contains secret data
uint16_t *E = &S[PARAMS_N * PARAMS_NBAR]; // contains secret data
uint8_t randomness[2 * CRYPTO_BYTES + BYTES_SEED_A]; // contains secret data via randomness_s and randomness_seedSE
uint8_t *randomness_s = &randomness[0]; // contains secret data
uint8_t *randomness_seedSE = &randomness[CRYPTO_BYTES]; // contains secret data
uint8_t *randomness_z = &randomness[2 * CRYPTO_BYTES];
uint8_t shake_input_seedSE[1 + CRYPTO_BYTES]; // contains secret data

// Generate the secret value s, the seed for S and E, and the seed for the seed for A. Add seed_A to the public key
randombytes(randomness, CRYPTO_BYTES + CRYPTO_BYTES + BYTES_SEED_A);
shake(pk_seedA, BYTES_SEED_A, randomness_z, BYTES_SEED_A);

// Generate S and E, and compute B = A*S + E. Generate A on-the-fly
shake_input_seedSE[0] = 0x5F;
memcpy(&shake_input_seedSE[1], randomness_seedSE, CRYPTO_BYTES);
shake((uint8_t *)S, 2 * PARAMS_N * PARAMS_NBAR * sizeof(uint16_t), shake_input_seedSE, 1 + CRYPTO_BYTES);
for (size_t i = 0; i < 2 * PARAMS_N * PARAMS_NBAR; i++) {
S[i] = PQCLEAN_FRODOKEM976SHAKE_CLEAN_LE_TO_UINT16(S[i]);
}
PQCLEAN_FRODOKEM976SHAKE_CLEAN_sample_n(S, PARAMS_N * PARAMS_NBAR);
PQCLEAN_FRODOKEM976SHAKE_CLEAN_sample_n(E, PARAMS_N * PARAMS_NBAR);
PQCLEAN_FRODOKEM976SHAKE_CLEAN_mul_add_as_plus_e(B, S, E, pk);

// Encode the second part of the public key
PQCLEAN_FRODOKEM976SHAKE_CLEAN_pack(pk_b, CRYPTO_PUBLICKEYBYTES - BYTES_SEED_A, B, PARAMS_N * PARAMS_NBAR, PARAMS_LOGQ);

// Add s, pk and S to the secret key
memcpy(sk_s, randomness_s, CRYPTO_BYTES);
memcpy(sk_pk, pk, CRYPTO_PUBLICKEYBYTES);
for (size_t i = 0; i < PARAMS_N * PARAMS_NBAR; i++) {
S[i] = PQCLEAN_FRODOKEM976SHAKE_CLEAN_UINT16_TO_LE(S[i]);
}
memcpy(sk_S, S, 2 * PARAMS_N * PARAMS_NBAR);

// Add H(pk) to the secret key
shake(sk_pkh, BYTES_PKHASH, pk, CRYPTO_PUBLICKEYBYTES);

// Cleanup:
PQCLEAN_FRODOKEM976SHAKE_CLEAN_clear_bytes((uint8_t *)S, PARAMS_N * PARAMS_NBAR * sizeof(uint16_t));
PQCLEAN_FRODOKEM976SHAKE_CLEAN_clear_bytes((uint8_t *)E, PARAMS_N * PARAMS_NBAR * sizeof(uint16_t));
PQCLEAN_FRODOKEM976SHAKE_CLEAN_clear_bytes(randomness, 2 * CRYPTO_BYTES);
PQCLEAN_FRODOKEM976SHAKE_CLEAN_clear_bytes(shake_input_seedSE, 1 + CRYPTO_BYTES);
return 0;
}


int PQCLEAN_FRODOKEM976SHAKE_CLEAN_crypto_kem_enc(uint8_t *ct, uint8_t *ss, const uint8_t *pk) {
// FrodoKEM's key encapsulation
const uint8_t *pk_seedA = &pk[0];
const uint8_t *pk_b = &pk[BYTES_SEED_A];
uint8_t *ct_c1 = &ct[0];
uint8_t *ct_c2 = &ct[(PARAMS_LOGQ * PARAMS_N * PARAMS_NBAR) / 8];
uint16_t B[PARAMS_N * PARAMS_NBAR] = {0};
uint16_t V[PARAMS_NBAR * PARAMS_NBAR] = {0}; // contains secret data
uint16_t C[PARAMS_NBAR * PARAMS_NBAR] = {0};
uint16_t Bp[PARAMS_N * PARAMS_NBAR] = {0};
uint16_t Sp[(2 * PARAMS_N + PARAMS_NBAR)*PARAMS_NBAR] = {0}; // contains secret data
uint16_t *Ep = &Sp[PARAMS_N * PARAMS_NBAR]; // contains secret data
uint16_t *Epp = &Sp[2 * PARAMS_N * PARAMS_NBAR]; // contains secret data
uint8_t G2in[BYTES_PKHASH + BYTES_MU]; // contains secret data via mu
uint8_t *pkh = &G2in[0];
uint8_t *mu = &G2in[BYTES_PKHASH]; // contains secret data
uint8_t G2out[2 * CRYPTO_BYTES]; // contains secret data
uint8_t *seedSE = &G2out[0]; // contains secret data
uint8_t *k = &G2out[CRYPTO_BYTES]; // contains secret data
uint8_t Fin[CRYPTO_CIPHERTEXTBYTES + CRYPTO_BYTES]; // contains secret data via Fin_k
uint8_t *Fin_ct = &Fin[0];
uint8_t *Fin_k = &Fin[CRYPTO_CIPHERTEXTBYTES]; // contains secret data
uint8_t shake_input_seedSE[1 + CRYPTO_BYTES]; // contains secret data

// pkh <- G_1(pk), generate random mu, compute (seedSE || k) = G_2(pkh || mu)
shake(pkh, BYTES_PKHASH, pk, CRYPTO_PUBLICKEYBYTES);
randombytes(mu, BYTES_MU);
shake(G2out, CRYPTO_BYTES + CRYPTO_BYTES, G2in, BYTES_PKHASH + BYTES_MU);

// Generate Sp and Ep, and compute Bp = Sp*A + Ep. Generate A on-the-fly
shake_input_seedSE[0] = 0x96;
memcpy(&shake_input_seedSE[1], seedSE, CRYPTO_BYTES);
shake((uint8_t *)Sp, (2 * PARAMS_N + PARAMS_NBAR) * PARAMS_NBAR * sizeof(uint16_t), shake_input_seedSE, 1 + CRYPTO_BYTES);
for (size_t i = 0; i < (2 * PARAMS_N + PARAMS_NBAR) * PARAMS_NBAR; i++) {
Sp[i] = PQCLEAN_FRODOKEM976SHAKE_CLEAN_LE_TO_UINT16(Sp[i]);
}
PQCLEAN_FRODOKEM976SHAKE_CLEAN_sample_n(Sp, PARAMS_N * PARAMS_NBAR);
PQCLEAN_FRODOKEM976SHAKE_CLEAN_sample_n(Ep, PARAMS_N * PARAMS_NBAR);
PQCLEAN_FRODOKEM976SHAKE_CLEAN_mul_add_sa_plus_e(Bp, Sp, Ep, pk_seedA);
PQCLEAN_FRODOKEM976SHAKE_CLEAN_pack(ct_c1, (PARAMS_LOGQ * PARAMS_N * PARAMS_NBAR) / 8, Bp, PARAMS_N * PARAMS_NBAR, PARAMS_LOGQ);

// Generate Epp, and compute V = Sp*B + Epp
PQCLEAN_FRODOKEM976SHAKE_CLEAN_sample_n(Epp, PARAMS_NBAR * PARAMS_NBAR);
PQCLEAN_FRODOKEM976SHAKE_CLEAN_unpack(B, PARAMS_N * PARAMS_NBAR, pk_b, CRYPTO_PUBLICKEYBYTES - BYTES_SEED_A, PARAMS_LOGQ);
PQCLEAN_FRODOKEM976SHAKE_CLEAN_mul_add_sb_plus_e(V, B, Sp, Epp);

// Encode mu, and compute C = V + enc(mu) (mod q)
PQCLEAN_FRODOKEM976SHAKE_CLEAN_key_encode(C, (uint16_t *)mu);
PQCLEAN_FRODOKEM976SHAKE_CLEAN_add(C, V, C);
PQCLEAN_FRODOKEM976SHAKE_CLEAN_pack(ct_c2, (PARAMS_LOGQ * PARAMS_NBAR * PARAMS_NBAR) / 8, C, PARAMS_NBAR * PARAMS_NBAR, PARAMS_LOGQ);

// Compute ss = F(ct||KK)
memcpy(Fin_ct, ct, CRYPTO_CIPHERTEXTBYTES);
memcpy(Fin_k, k, CRYPTO_BYTES);
shake(ss, CRYPTO_BYTES, Fin, CRYPTO_CIPHERTEXTBYTES + CRYPTO_BYTES);

// Cleanup:
PQCLEAN_FRODOKEM976SHAKE_CLEAN_clear_bytes((uint8_t *)V, PARAMS_NBAR * PARAMS_NBAR * sizeof(uint16_t));
PQCLEAN_FRODOKEM976SHAKE_CLEAN_clear_bytes((uint8_t *)Sp, PARAMS_N * PARAMS_NBAR * sizeof(uint16_t));
PQCLEAN_FRODOKEM976SHAKE_CLEAN_clear_bytes((uint8_t *)Ep, PARAMS_N * PARAMS_NBAR * sizeof(uint16_t));
PQCLEAN_FRODOKEM976SHAKE_CLEAN_clear_bytes((uint8_t *)Epp, PARAMS_NBAR * PARAMS_NBAR * sizeof(uint16_t));
PQCLEAN_FRODOKEM976SHAKE_CLEAN_clear_bytes(mu, BYTES_MU);
PQCLEAN_FRODOKEM976SHAKE_CLEAN_clear_bytes(G2out, 2 * CRYPTO_BYTES);
PQCLEAN_FRODOKEM976SHAKE_CLEAN_clear_bytes(Fin_k, CRYPTO_BYTES);
PQCLEAN_FRODOKEM976SHAKE_CLEAN_clear_bytes(shake_input_seedSE, 1 + CRYPTO_BYTES);
return 0;
}


int PQCLEAN_FRODOKEM976SHAKE_CLEAN_crypto_kem_dec(uint8_t *ss, const uint8_t *ct, const uint8_t *sk) {
// FrodoKEM's key decapsulation
uint16_t B[PARAMS_N * PARAMS_NBAR] = {0};
uint16_t Bp[PARAMS_N * PARAMS_NBAR] = {0};
uint16_t W[PARAMS_NBAR * PARAMS_NBAR] = {0}; // contains secret data
uint16_t C[PARAMS_NBAR * PARAMS_NBAR] = {0};
uint16_t CC[PARAMS_NBAR * PARAMS_NBAR] = {0};
uint16_t BBp[PARAMS_N * PARAMS_NBAR] = {0};
uint16_t Sp[(2 * PARAMS_N + PARAMS_NBAR)*PARAMS_NBAR] = {0}; // contains secret data
uint16_t *Ep = &Sp[PARAMS_N * PARAMS_NBAR]; // contains secret data
uint16_t *Epp = &Sp[2 * PARAMS_N * PARAMS_NBAR]; // contains secret data
const uint8_t *ct_c1 = &ct[0];
const uint8_t *ct_c2 = &ct[(PARAMS_LOGQ * PARAMS_N * PARAMS_NBAR) / 8];
const uint8_t *sk_s = &sk[0];
const uint8_t *sk_pk = &sk[CRYPTO_BYTES];
const uint16_t *sk_S = (uint16_t *) &sk[CRYPTO_BYTES + CRYPTO_PUBLICKEYBYTES];
uint16_t S[PARAMS_N * PARAMS_NBAR]; // contains secret data
const uint8_t *sk_pkh = &sk[CRYPTO_BYTES + CRYPTO_PUBLICKEYBYTES + 2 * PARAMS_N * PARAMS_NBAR];
const uint8_t *pk_seedA = &sk_pk[0];
const uint8_t *pk_b = &sk_pk[BYTES_SEED_A];
uint8_t G2in[BYTES_PKHASH + BYTES_MU]; // contains secret data via muprime
uint8_t *pkh = &G2in[0];
uint8_t *muprime = &G2in[BYTES_PKHASH]; // contains secret data
uint8_t G2out[2 * CRYPTO_BYTES]; // contains secret data
uint8_t *seedSEprime = &G2out[0]; // contains secret data
uint8_t *kprime = &G2out[CRYPTO_BYTES]; // contains secret data
uint8_t Fin[CRYPTO_CIPHERTEXTBYTES + CRYPTO_BYTES]; // contains secret data via Fin_k
uint8_t *Fin_ct = &Fin[0];
uint8_t *Fin_k = &Fin[CRYPTO_CIPHERTEXTBYTES]; // contains secret data
uint8_t shake_input_seedSEprime[1 + CRYPTO_BYTES]; // contains secret data

for (size_t i = 0; i < PARAMS_N * PARAMS_NBAR; i++) {
S[i] = PQCLEAN_FRODOKEM976SHAKE_CLEAN_LE_TO_UINT16(sk_S[i]);
}

// Compute W = C - Bp*S (mod q), and decode the randomness mu
PQCLEAN_FRODOKEM976SHAKE_CLEAN_unpack(Bp, PARAMS_N * PARAMS_NBAR, ct_c1, (PARAMS_LOGQ * PARAMS_N * PARAMS_NBAR) / 8, PARAMS_LOGQ);
PQCLEAN_FRODOKEM976SHAKE_CLEAN_unpack(C, PARAMS_NBAR * PARAMS_NBAR, ct_c2, (PARAMS_LOGQ * PARAMS_NBAR * PARAMS_NBAR) / 8, PARAMS_LOGQ);
PQCLEAN_FRODOKEM976SHAKE_CLEAN_mul_bs(W, Bp, S);
PQCLEAN_FRODOKEM976SHAKE_CLEAN_sub(W, C, W);
PQCLEAN_FRODOKEM976SHAKE_CLEAN_key_decode((uint16_t *)muprime, W);

// Generate (seedSE' || k') = G_2(pkh || mu')
memcpy(pkh, sk_pkh, BYTES_PKHASH);
shake(G2out, CRYPTO_BYTES + CRYPTO_BYTES, G2in, BYTES_PKHASH + BYTES_MU);

// Generate Sp and Ep, and compute BBp = Sp*A + Ep. Generate A on-the-fly
shake_input_seedSEprime[0] = 0x96;
memcpy(&shake_input_seedSEprime[1], seedSEprime, CRYPTO_BYTES);
shake((uint8_t *)Sp, (2 * PARAMS_N + PARAMS_NBAR) * PARAMS_NBAR * sizeof(uint16_t), shake_input_seedSEprime, 1 + CRYPTO_BYTES);
for (size_t i = 0; i < (2 * PARAMS_N + PARAMS_NBAR) * PARAMS_NBAR; i++) {
Sp[i] = PQCLEAN_FRODOKEM976SHAKE_CLEAN_LE_TO_UINT16(Sp[i]);
}
PQCLEAN_FRODOKEM976SHAKE_CLEAN_sample_n(Sp, PARAMS_N * PARAMS_NBAR);
PQCLEAN_FRODOKEM976SHAKE_CLEAN_sample_n(Ep, PARAMS_N * PARAMS_NBAR);
PQCLEAN_FRODOKEM976SHAKE_CLEAN_mul_add_sa_plus_e(BBp, Sp, Ep, pk_seedA);

// Generate Epp, and compute W = Sp*B + Epp
PQCLEAN_FRODOKEM976SHAKE_CLEAN_sample_n(Epp, PARAMS_NBAR * PARAMS_NBAR);
PQCLEAN_FRODOKEM976SHAKE_CLEAN_unpack(B, PARAMS_N * PARAMS_NBAR, pk_b, CRYPTO_PUBLICKEYBYTES - BYTES_SEED_A, PARAMS_LOGQ);
PQCLEAN_FRODOKEM976SHAKE_CLEAN_mul_add_sb_plus_e(W, B, Sp, Epp);

// Encode mu, and compute CC = W + enc(mu') (mod q)
PQCLEAN_FRODOKEM976SHAKE_CLEAN_key_encode(CC, (uint16_t *)muprime);
PQCLEAN_FRODOKEM976SHAKE_CLEAN_add(CC, W, CC);

// Prepare input to F
memcpy(Fin_ct, ct, CRYPTO_CIPHERTEXTBYTES);

// Reducing BBp modulo q
for (size_t i = 0; i < PARAMS_N * PARAMS_NBAR; i++) {
BBp[i] = BBp[i] & ((1 << PARAMS_LOGQ) - 1);
}

// Is (Bp == BBp & C == CC) = true
if (memcmp(Bp, BBp, 2 * PARAMS_N * PARAMS_NBAR) == 0 && memcmp(C, CC, 2 * PARAMS_NBAR * PARAMS_NBAR) == 0) {
// Load k' to do ss = F(ct || k')
memcpy(Fin_k, kprime, CRYPTO_BYTES);
} else {
// Load s to do ss = F(ct || s)
memcpy(Fin_k, sk_s, CRYPTO_BYTES);
}
shake(ss, CRYPTO_BYTES, Fin, CRYPTO_CIPHERTEXTBYTES + CRYPTO_BYTES);

// Cleanup:
PQCLEAN_FRODOKEM976SHAKE_CLEAN_clear_bytes((uint8_t *)W, PARAMS_NBAR * PARAMS_NBAR * sizeof(uint16_t));
PQCLEAN_FRODOKEM976SHAKE_CLEAN_clear_bytes((uint8_t *)Sp, PARAMS_N * PARAMS_NBAR * sizeof(uint16_t));
PQCLEAN_FRODOKEM976SHAKE_CLEAN_clear_bytes((uint8_t *)S, PARAMS_N * PARAMS_NBAR * sizeof(uint16_t));
PQCLEAN_FRODOKEM976SHAKE_CLEAN_clear_bytes((uint8_t *)Ep, PARAMS_N * PARAMS_NBAR * sizeof(uint16_t));
PQCLEAN_FRODOKEM976SHAKE_CLEAN_clear_bytes((uint8_t *)Epp, PARAMS_NBAR * PARAMS_NBAR * sizeof(uint16_t));
PQCLEAN_FRODOKEM976SHAKE_CLEAN_clear_bytes(muprime, BYTES_MU);
PQCLEAN_FRODOKEM976SHAKE_CLEAN_clear_bytes(G2out, 2 * CRYPTO_BYTES);
PQCLEAN_FRODOKEM976SHAKE_CLEAN_clear_bytes(Fin_k, CRYPTO_BYTES);
PQCLEAN_FRODOKEM976SHAKE_CLEAN_clear_bytes(shake_input_seedSEprime, 1 + CRYPTO_BYTES);
return 0;
}

+ 79
- 0
crypto_kem/frodokem976shake/clean/matrix_shake.c Просмотреть файл

@@ -0,0 +1,79 @@
/********************************************************************************************
* FrodoKEM: Learning with Errors Key Encapsulation
*
* Abstract: matrix arithmetic functions used by the KEM
*********************************************************************************************/

#include <stdint.h>
#include <string.h>

#include "fips202.h"

#include "api.h"
#include "common.h"
#include "params.h"

int PQCLEAN_FRODOKEM976SHAKE_CLEAN_mul_add_as_plus_e(uint16_t *out, const uint16_t *s, const uint16_t *e, const uint8_t *seed_A) {
// Generate-and-multiply: generate matrix A (N x N) row-wise, multiply by s on the right.
// Inputs: s, e (N x N_BAR)
// Output: out = A*s + e (N x N_BAR)
int i, j, k;
int16_t A[PARAMS_N * PARAMS_N] = {0};

uint8_t seed_A_separated[2 + BYTES_SEED_A];
uint16_t *seed_A_origin = (uint16_t *)&seed_A_separated;
memcpy(&seed_A_separated[2], seed_A, BYTES_SEED_A);
for (i = 0; i < PARAMS_N; i++) {
seed_A_origin[0] = PQCLEAN_FRODOKEM976SHAKE_CLEAN_UINT16_TO_LE((uint16_t) i);
shake128((uint8_t *)(A + i * PARAMS_N), (unsigned long long)(2 * PARAMS_N), seed_A_separated, 2 + BYTES_SEED_A);
}
for (i = 0; i < PARAMS_N * PARAMS_N; i++) {
A[i] = PQCLEAN_FRODOKEM976SHAKE_CLEAN_LE_TO_UINT16(A[i]);
}
memcpy(out, e, PARAMS_NBAR * PARAMS_N * sizeof(uint16_t));

for (i = 0; i < PARAMS_N; i++) { // Matrix multiplication-addition A*s + e
for (k = 0; k < PARAMS_NBAR; k++) {
uint16_t sum = 0;
for (j = 0; j < PARAMS_N; j++) {
sum += A[i * PARAMS_N + j] * s[k * PARAMS_N + j];
}
out[i * PARAMS_NBAR + k] += sum; // Adding e. No need to reduce modulo 2^15, extra bits are taken care of during packing later on.
}
}

return 1;
}


int PQCLEAN_FRODOKEM976SHAKE_CLEAN_mul_add_sa_plus_e(uint16_t *out, const uint16_t *s, const uint16_t *e, const uint8_t *seed_A) {
// Generate-and-multiply: generate matrix A (N x N) column-wise, multiply by s' on the left.
// Inputs: s', e' (N_BAR x N)
// Output: out = s'*A + e' (N_BAR x N)
int i, j, k;
int16_t A[PARAMS_N * PARAMS_N] = {0};

uint8_t seed_A_separated[2 + BYTES_SEED_A];
uint16_t *seed_A_origin = (uint16_t *)&seed_A_separated;
memcpy(&seed_A_separated[2], seed_A, BYTES_SEED_A);
for (i = 0; i < PARAMS_N; i++) {
seed_A_origin[0] = PQCLEAN_FRODOKEM976SHAKE_CLEAN_UINT16_TO_LE((uint16_t) i);
shake128((uint8_t *)(A + i * PARAMS_N), (unsigned long long)(2 * PARAMS_N), seed_A_separated, 2 + BYTES_SEED_A);
}
for (i = 0; i < PARAMS_N * PARAMS_N; i++) {
A[i] = PQCLEAN_FRODOKEM976SHAKE_CLEAN_LE_TO_UINT16(A[i]);
}
memcpy(out, e, PARAMS_NBAR * PARAMS_N * sizeof(uint16_t));

for (i = 0; i < PARAMS_N; i++) { // Matrix multiplication-addition A*s + e
for (k = 0; k < PARAMS_NBAR; k++) {
uint16_t sum = 0;
for (j = 0; j < PARAMS_N; j++) {
sum += A[j * PARAMS_N + i] * s[k * PARAMS_N + j];
}
out[k * PARAMS_N + i] += sum; // Adding e. No need to reduce modulo 2^15, extra bits are taken care of during packing later on.
}
}

return 1;
}

+ 33
- 0
crypto_kem/frodokem976shake/clean/noise.c Просмотреть файл

@@ -0,0 +1,33 @@
/********************************************************************************************
* FrodoKEM: Learning with Errors Key Encapsulation
*
* Abstract: noise sampling functions
*********************************************************************************************/

#include <stdint.h>

#include "api.h"
#include "params.h"

static uint16_t CDF_TABLE[CDF_TABLE_LEN] = CDF_TABLE_DATA;

void PQCLEAN_FRODOKEM976SHAKE_CLEAN_sample_n(uint16_t *s, const size_t n) {
// Fills vector s with n samples from the noise distribution which requires 16 bits to sample.
// The distribution is specified by its CDF.
// Input: pseudo-random values (2*n bytes) passed in s. The input is overwritten by the output.
unsigned int i, j;

for (i = 0; i < n; ++i) {
uint8_t sample = 0;
uint16_t prnd = s[i] >> 1; // Drop the least significant bit
uint8_t sign = s[i] & 0x1; // Pick the least significant bit

// No need to compare with the last value.
for (j = 0; j < (unsigned int)(CDF_TABLE_LEN - 1); j++) {
// Constant time comparison: 1 if CDF_TABLE[j] < s, 0 otherwise. Uses the fact that CDF_TABLE[j] and s fit in 15 bits.
sample += (uint16_t)(CDF_TABLE[j] - prnd) >> 15;
}
// Assuming that sign is either 0 or 1, flips sample iff sign = 1
s[i] = ((-sign) ^ sample) + sign;
}
}

+ 27
- 0
crypto_kem/frodokem976shake/clean/params.h Просмотреть файл

@@ -0,0 +1,27 @@
#ifndef PARAMS_H
#define PARAMS_H

#define CRYPTO_SECRETKEYBYTES PQCLEAN_FRODOKEM976SHAKE_CLEAN_CRYPTO_SECRETKEYBYTES
#define CRYPTO_PUBLICKEYBYTES PQCLEAN_FRODOKEM976SHAKE_CLEAN_CRYPTO_PUBLICKEYBYTES
#define CRYPTO_BYTES PQCLEAN_FRODOKEM976SHAKE_CLEAN_CRYPTO_BYTES
#define CRYPTO_CIPHERTEXTBYTES PQCLEAN_FRODOKEM976SHAKE_CLEAN_CRYPTO_CIPHERTEXTBYTES

#define PARAMS_N 976
#define PARAMS_NBAR 8
#define PARAMS_LOGQ 16
#define PARAMS_Q (1 << PARAMS_LOGQ)
#define PARAMS_EXTRACTED_BITS 3
#define PARAMS_STRIPE_STEP 8
#define PARAMS_PARALLEL 4
#define BYTES_SEED_A 16
#define BYTES_MU ((PARAMS_EXTRACTED_BITS * PARAMS_NBAR * PARAMS_NBAR) / 8)
#define BYTES_PKHASH CRYPTO_BYTES

// Selecting SHAKE XOF function for the KEM and noise sampling
#define shake shake256

// CDF table
#define CDF_TABLE_DATA {5638, 15915, 23689, 28571, 31116, 32217, 32613, 32731, 32760, 32766, 32767}
#define CDF_TABLE_LEN 11

#endif

+ 234
- 0
crypto_kem/frodokem976shake/clean/util.c Просмотреть файл

@@ -0,0 +1,234 @@
/********************************************************************************************
* FrodoKEM: Learning with Errors Key Encapsulation
*
* Abstract: additional functions for FrodoKEM
*********************************************************************************************/

#include <stdint.h>
#include <string.h>

#include "api.h"
#include "params.h"

#define min(x, y) (((x) < (y)) ? (x) : (y))

uint16_t PQCLEAN_FRODOKEM976SHAKE_CLEAN_LE_TO_UINT16(const uint16_t n) {
return (((uint8_t *) &(n))[0] | (((uint8_t *) &(n))[1] << 8));
}

uint16_t PQCLEAN_FRODOKEM976SHAKE_CLEAN_UINT16_TO_LE(const uint16_t n) {
uint16_t y;
uint8_t *z = (uint8_t *) &y;
z[0] = n & 0xFF;
z[1] = (n & 0xFF00) >> 8;
return y;
}

void PQCLEAN_FRODOKEM976SHAKE_CLEAN_mul_bs(uint16_t *out, const uint16_t *b, const uint16_t *s) {
// Multiply by s on the right
// Inputs: b (N_BAR x N), s (N x N_BAR)
// Output: out = b*s (N_BAR x N_BAR)
int i, j, k;

for (i = 0; i < PARAMS_NBAR; i++) {
for (j = 0; j < PARAMS_NBAR; j++) {
out[i * PARAMS_NBAR + j] = 0;
for (k = 0; k < PARAMS_N; k++) {
out[i * PARAMS_NBAR + j] += b[i * PARAMS_N + k] * s[j * PARAMS_N + k];
}
out[i * PARAMS_NBAR + j] = (uint32_t)(out[i * PARAMS_NBAR + j]) & ((1 << PARAMS_LOGQ) - 1);
}
}
}


void PQCLEAN_FRODOKEM976SHAKE_CLEAN_mul_add_sb_plus_e(uint16_t *out, const uint16_t *b, const uint16_t *s, const uint16_t *e) {
// Multiply by s on the left
// Inputs: b (N x N_BAR), s (N_BAR x N), e (N_BAR x N_BAR)
// Output: out = s*b + e (N_BAR x N_BAR)
int i, j, k;

for (k = 0; k < PARAMS_NBAR; k++) {
for (i = 0; i < PARAMS_NBAR; i++) {
out[k * PARAMS_NBAR + i] = e[k * PARAMS_NBAR + i];
for (j = 0; j < PARAMS_N; j++) {
out[k * PARAMS_NBAR + i] += s[k * PARAMS_N + j] * b[j * PARAMS_NBAR + i];
}
out[k * PARAMS_NBAR + i] = (uint32_t)(out[k * PARAMS_NBAR + i]) & ((1 << PARAMS_LOGQ) - 1);
}
}
}


void PQCLEAN_FRODOKEM976SHAKE_CLEAN_add(uint16_t *out, const uint16_t *a, const uint16_t *b) {
// Add a and b
// Inputs: a, b (N_BAR x N_BAR)
// Output: c = a + b

for (size_t i = 0; i < (PARAMS_NBAR * PARAMS_NBAR); i++) {
out[i] = (a[i] + b[i]) & ((1 << PARAMS_LOGQ) - 1);
}
}


void PQCLEAN_FRODOKEM976SHAKE_CLEAN_sub(uint16_t *out, const uint16_t *a, const uint16_t *b) {
// Subtract a and b
// Inputs: a, b (N_BAR x N_BAR)
// Output: c = a - b

for (size_t i = 0; i < (PARAMS_NBAR * PARAMS_NBAR); i++) {
out[i] = (a[i] - b[i]) & ((1 << PARAMS_LOGQ) - 1);
}
}


void PQCLEAN_FRODOKEM976SHAKE_CLEAN_key_encode(uint16_t *out, const uint16_t *in) {
// Encoding
unsigned int i, j, npieces_word = 8;
unsigned int nwords = (PARAMS_NBAR * PARAMS_NBAR) / 8;
uint64_t temp, mask = ((uint64_t)1 << PARAMS_EXTRACTED_BITS) - 1;
uint16_t *pos = out;

for (i = 0; i < nwords; i++) {
temp = 0;
for (j = 0; j < PARAMS_EXTRACTED_BITS; j++) {
temp |= ((uint64_t)((uint8_t *)in)[i * PARAMS_EXTRACTED_BITS + j]) << (8 * j);
}
for (j = 0; j < npieces_word; j++) {
*pos = (uint16_t)((temp & mask) << (PARAMS_LOGQ - PARAMS_EXTRACTED_BITS));
temp >>= PARAMS_EXTRACTED_BITS;
pos++;
}
}
}


void PQCLEAN_FRODOKEM976SHAKE_CLEAN_key_decode(uint16_t *out, const uint16_t *in) {
// Decoding
unsigned int i, j, index = 0, npieces_word = 8;
unsigned int nwords = (PARAMS_NBAR * PARAMS_NBAR) / 8;
uint16_t temp, maskex = ((uint16_t)1 << PARAMS_EXTRACTED_BITS) - 1, maskq = ((uint16_t)1 << PARAMS_LOGQ) - 1;
uint8_t *pos = (uint8_t *)out;
uint64_t templong;

for (i = 0; i < nwords; i++) {
templong = 0;
for (j = 0; j < npieces_word; j++) { // temp = floor(in*2^{-11}+0.5)
temp = ((in[index] & maskq) + (1 << (PARAMS_LOGQ - PARAMS_EXTRACTED_BITS - 1))) >> (PARAMS_LOGQ - PARAMS_EXTRACTED_BITS);
templong |= ((uint64_t)(temp & maskex)) << (PARAMS_EXTRACTED_BITS * j);
index++;
}
for (j = 0; j < PARAMS_EXTRACTED_BITS; j++) {
pos[i * PARAMS_EXTRACTED_BITS + j] = (templong >> (8 * j)) & 0xFF;
}
}
}


void PQCLEAN_FRODOKEM976SHAKE_CLEAN_pack(uint8_t *out, const size_t outlen, const uint16_t *in, const size_t inlen, const uint8_t lsb) {
// Pack the input uint16 vector into a char output vector, copying lsb bits from each input element.
// If inlen * lsb / 8 > outlen, only outlen * 8 bits are copied.
memset(out, 0, outlen);

size_t i = 0; // whole bytes already filled in
size_t j = 0; // whole uint16_t already copied
uint16_t w = 0; // the leftover, not yet copied
uint8_t bits = 0; // the number of lsb in w

while (i < outlen && (j < inlen || ((j == inlen) && (bits > 0)))) {
/*
in: | | |********|********|
^
j
w : | ****|
^
bits
out:|**|**|**|**|**|**|**|**|* |
^^
ib
*/
uint8_t b = 0; // bits in out[i] already filled in
while (b < 8) {
int nbits = min(8 - b, bits);
uint16_t mask = (1 << nbits) - 1;
uint8_t t = (uint8_t) ((w >> (bits - nbits)) & mask); // the bits to copy from w to out
out[i] = out[i] + (t << (8 - b - nbits));
b += (uint8_t) nbits;
bits -= (uint8_t) nbits;
w &= ~(mask << bits); // not strictly necessary; mostly for debugging

if (bits == 0) {
if (j < inlen) {
w = in[j];
bits = lsb;
j++;
} else {
break; // the input vector is exhausted
}
}
}
if (b == 8) { // out[i] is filled in
i++;
}
}
}


void PQCLEAN_FRODOKEM976SHAKE_CLEAN_unpack(uint16_t *out, const size_t outlen, const uint8_t *in, const size_t inlen, const uint8_t lsb) {
// Unpack the input char vector into a uint16_t output vector, copying lsb bits
// for each output element from input. outlen must be at least ceil(inlen * 8 / lsb).
memset(out, 0, outlen * sizeof(uint16_t));

size_t i = 0; // whole uint16_t already filled in
size_t j = 0; // whole bytes already copied
uint8_t w = 0; // the leftover, not yet copied
uint8_t bits = 0; // the number of lsb bits of w

while (i < outlen && (j < inlen || ((j == inlen) && (bits > 0)))) {
/*
in: | | | | | | |**|**|...
^
j
w : | *|
^
bits
out:| *****| *****| *** | |...
^ ^
i b
*/
uint8_t b = 0; // bits in out[i] already filled in
while (b < lsb) {
int nbits = min(lsb - b, bits);
uint16_t mask = (1 << nbits) - 1;
uint8_t t = (w >> (bits - nbits)) & mask; // the bits to copy from w to out
out[i] = out[i] + (t << (lsb - b - nbits));
b += (uint8_t) nbits;
bits -= (uint8_t) nbits;
w &= ~(mask << bits); // not strictly necessary; mostly for debugging

if (bits == 0) {
if (j < inlen) {
w = in[j];
bits = 8;
j++;
} else {
break; // the input vector is exhausted
}
}
}
if (b == lsb) { // out[i] is filled in
i++;
}
}
}


void PQCLEAN_FRODOKEM976SHAKE_CLEAN_clear_bytes(uint8_t *mem, size_t n) {
// Clear 8-bit bytes from memory. "n" indicates the number of bytes to be zeroed.
// This function uses the volatile type qualifier to inform the compiler not to optimize out the memory clearing.
volatile uint8_t *v = mem;

for (size_t i = 0; i < n; i++) {
v[i] = 0;
}
}

+ 2
- 2
crypto_kem/kyber768/META.yml Просмотреть файл

@@ -2,10 +2,9 @@ name: Kyber768
type: kem
claimed-nist-level: 3
length-public-key: 1088
length-secret-key: 2400
length-ciphertext: 1152
length-shared-secret: 32
testvectors-sha256: 0e002ee528febdab1709f100df79ceb00b31a809e03a4fb84e3a72c39235d372
testvectors-sha256: 2f5cf9937959eb4a3bc910f71e830e9e0de029b28093c6192d2c3e915913016f
principal-submitter: Peter Schwabe
auxiliary-submitters:
- Roberto Avanzi
@@ -20,3 +19,4 @@ auxiliary-submitters:
implementations:
- name: clean
version: https://github.com/pq-crystals/kyber/commit/ab996e7460e5356b0e23aa034e7c2fe6922e60e6
length-secret-key: 2400

+ 4
- 6
crypto_kem/kyber768/clean/api.h Просмотреть файл

@@ -3,12 +3,10 @@

#include <stdint.h>

#include "params.h"

#define PQCLEAN_KYBER768_CLEAN_CRYPTO_SECRETKEYBYTES KYBER_SECRETKEYBYTES
#define PQCLEAN_KYBER768_CLEAN_CRYPTO_PUBLICKEYBYTES KYBER_PUBLICKEYBYTES
#define PQCLEAN_KYBER768_CLEAN_CRYPTO_CIPHERTEXTBYTES KYBER_CIPHERTEXTBYTES
#define PQCLEAN_KYBER768_CLEAN_CRYPTO_BYTES KYBER_SYMBYTES
#define PQCLEAN_KYBER768_CLEAN_CRYPTO_SECRETKEYBYTES 2400
#define PQCLEAN_KYBER768_CLEAN_CRYPTO_PUBLICKEYBYTES 1088
#define PQCLEAN_KYBER768_CLEAN_CRYPTO_CIPHERTEXTBYTES 1152
#define PQCLEAN_KYBER768_CLEAN_CRYPTO_BYTES 32

#define PQCLEAN_KYBER768_CLEAN_CRYPTO_ALGNAME "Kyber768"



+ 0
- 54
crypto_kem/kyber768/clean/cbd.c Просмотреть файл

@@ -32,32 +32,6 @@ static uint64_t load_littleendian(const unsigned char *x, int bytes) {
* - const unsigned char *buf: pointer to input byte array
**************************************************/
void PQCLEAN_KYBER768_CLEAN_cbd(poly *r, const unsigned char *buf) {
#if KYBER_ETA == 3
uint32_t t, d, a[4], b[4];
int i, j;

for (i = 0; i < KYBER_N / 4; i++) {
t = (uint32_t)load_littleendian(buf + 3 * i, 3);
d = 0;
for (j = 0; j < 3; j++) {
d += (t >> j) & 0x249249;
}

a[0] = d & 0x7;
b[0] = (d >> 3) & 0x7;
a[1] = (d >> 6) & 0x7;
b[1] = (d >> 9) & 0x7;
a[2] = (d >> 12) & 0x7;
b[2] = (d >> 15) & 0x7;
a[3] = (d >> 18) & 0x7;
b[3] = (d >> 21);

r->coeffs[4 * i + 0] = (uint16_t)(a[0] + KYBER_Q - b[0]);
r->coeffs[4 * i + 1] = (uint16_t)(a[1] + KYBER_Q - b[1]);
r->coeffs[4 * i + 2] = (uint16_t)(a[2] + KYBER_Q - b[2]);
r->coeffs[4 * i + 3] = (uint16_t)(a[3] + KYBER_Q - b[3]);
}
#elif KYBER_ETA == 4
uint32_t t, d, a[4], b[4];
int i, j;

@@ -82,32 +56,4 @@ void PQCLEAN_KYBER768_CLEAN_cbd(poly *r, const unsigned char *buf) {
r->coeffs[4 * i + 2] = (uint16_t)(a[2] + KYBER_Q - b[2]);
r->coeffs[4 * i + 3] = (uint16_t)(a[3] + KYBER_Q - b[3]);
}
#elif KYBER_ETA == 5
uint64_t t, d, a[4], b[4];
int i, j;

for (i = 0; i < KYBER_N / 4; i++) {
t = load_littleendian(buf + 5 * i, 5);
d = 0;
for (j = 0; j < 5; j++) {
d += (t >> j) & 0x0842108421UL;
}

a[0] = d & 0x1f;
b[0] = (d >> 5) & 0x1f;
a[1] = (d >> 10) & 0x1f;
b[1] = (d >> 15) & 0x1f;
a[2] = (d >> 20) & 0x1f;
b[2] = (d >> 25) & 0x1f;
a[3] = (d >> 30) & 0x1f;
b[3] = (d >> 35);

r->coeffs[4 * i + 0] = (uint16_t)(a[0] + KYBER_Q - b[0]);
r->coeffs[4 * i + 1] = (uint16_t)(a[1] + KYBER_Q - b[1]);
r->coeffs[4 * i + 2] = (uint16_t)(a[2] + KYBER_Q - b[2]);
r->coeffs[4 * i + 3] = (uint16_t)(a[3] + KYBER_Q - b[3]);
}
#else
#error "poly_getnoise in poly.c only supports eta in {3,4,5}"
#endif
}

+ 0
- 18
crypto_sign/dilithium-iii/META.yml Просмотреть файл

@@ -1,18 +0,0 @@
name: Dilithium-III
type: signature
claimed-nist-level: 3
length-public-key: 1472
length-secret-key: 3504
length-signature: 2701
testvectors-sha256: e1852a975842c44a683c914ed131d95bee9b786c36c41e47bb77d7dd3c0c07be
principal-submitter: Vadim Lyubashevsky
auxiliary-submitters:
- Léo Ducas
- Eike Kiltz
- Tancrède Lepoint
- Peter Schwabe
- Gregor Seiler
- Damien Stehlé
implementations:
- name: clean
version: https://github.com/pq-crystals/dilithium/commit/ffa89bdbc12a8ee178ccec4890aeea5449ef937a

+ 0
- 1
crypto_sign/dilithium-iii/clean/LICENSE Просмотреть файл

@@ -1 +0,0 @@
Public Domain

+ 0
- 30
crypto_sign/dilithium-iii/clean/api.h Просмотреть файл

@@ -1,30 +0,0 @@
#ifndef PQCLEAN_DILITHIUMIII_CLEAN_API_H
#define PQCLEAN_DILITHIUMIII_CLEAN_API_H

#include <stddef.h>
#include <stdint.h>

#define MODE 2

#define PQCLEAN_DILITHIUMIII_CLEAN_CRYPTO_PUBLICKEYBYTES 1472U
#define PQCLEAN_DILITHIUMIII_CLEAN_CRYPTO_SECRETKEYBYTES 3504U
#define PQCLEAN_DILITHIUMIII_CLEAN_CRYPTO_BYTES 2701U

#define PQCLEAN_DILITHIUMIII_CLEAN_CRYPTO_ALGNAME "Dilithium-III"

int PQCLEAN_DILITHIUMIII_CLEAN_crypto_sign_keypair(uint8_t *pk,
uint8_t *sk);

int PQCLEAN_DILITHIUMIII_CLEAN_crypto_sign(uint8_t *sm,
size_t *smlen,
const uint8_t *msg,
size_t len,
const uint8_t *sk);

int PQCLEAN_DILITHIUMIII_CLEAN_crypto_sign_open(uint8_t *m,
size_t *mlen,
const uint8_t *sm,
size_t smlen,
const uint8_t *pk);

#endif

+ 0
- 139
crypto_sign/dilithium-iii/clean/ntt.c Просмотреть файл

@@ -1,139 +0,0 @@
#include "ntt.h"
#include "params.h"
#include "poly.h"
#include "reduce.h"

/* Roots of unity in order needed by forward ntt */
static const uint32_t PQCLEAN_DILITHIUMIII_CLEAN_zetas[N] = {
0, 25847, 5771523, 7861508, 237124, 7602457, 7504169, 466468,
1826347, 2353451, 8021166, 6288512, 3119733, 5495562, 3111497, 2680103,
2725464, 1024112, 7300517, 3585928, 7830929, 7260833, 2619752, 6271868,
6262231, 4520680, 6980856, 5102745, 1757237, 8360995, 4010497, 280005,
2706023, 95776, 3077325, 3530437, 6718724, 4788269, 5842901, 3915439,
4519302, 5336701, 3574422, 5512770, 3539968, 8079950, 2348700, 7841118,
6681150, 6736599, 3505694, 4558682, 3507263, 6239768, 6779997, 3699596,
811944, 531354, 954230, 3881043, 3900724, 5823537, 2071892, 5582638,
4450022, 6851714, 4702672, 5339162, 6927966, 3475950, 2176455, 6795196,
7122806, 1939314, 4296819, 7380215, 5190273, 5223087, 4747489, 126922,
3412210, 7396998, 2147896, 2715295, 5412772, 4686924, 7969390, 5903370,
7709315, 7151892, 8357436, 7072248, 7998430, 1349076, 1852771, 6949987,
5037034, 264944, 508951, 3097992, 44288, 7280319, 904516, 3958618,
4656075, 8371839, 1653064, 5130689, 2389356, 8169440, 759969, 7063561,
189548, 4827145, 3159746, 6529015, 5971092, 8202977, 1315589, 1341330,
1285669, 6795489, 7567685, 6940675, 5361315, 4499357, 4751448, 3839961,
2091667, 3407706, 2316500, 3817976, 5037939, 2244091, 5933984, 4817955,
266997, 2434439, 7144689, 3513181, 4860065, 4621053, 7183191, 5187039,
900702, 1859098, 909542, 819034, 495491, 6767243, 8337157, 7857917,
7725090, 5257975, 2031748, 3207046, 4823422, 7855319, 7611795, 4784579,
342297, 286988, 5942594, 4108315, 3437287, 5038140, 1735879, 203044,
2842341, 2691481, 5790267, 1265009, 4055324, 1247620, 2486353, 1595974,
4613401, 1250494, 2635921, 4832145, 5386378, 1869119, 1903435, 7329447,
7047359, 1237275, 5062207, 6950192, 7929317, 1312455, 3306115, 6417775,
7100756, 1917081, 5834105, 7005614, 1500165, 777191, 2235880, 3406031,
7838005, 5548557, 6709241, 6533464, 5796124, 4656147, 594136, 4603424,
6366809, 2432395, 2454455, 8215696, 1957272, 3369112, 185531, 7173032,
5196991, 162844, 1616392, 3014001, 810149, 1652634, 4686184, 6581310,
5341501, 3523897, 3866901, 269760, 2213111, 7404533, 1717735, 472078,
7953734, 1723600, 6577327, 1910376, 6712985, 7276084, 8119771, 4546524,
5441381, 6144432, 7959518, 6094090, 183443, 7403526, 1612842, 4834730,
7826001, 3919660, 8332111, 7018208, 3937738, 1400424, 7534263, 1976782
};

/* Roots of unity in order needed by inverse ntt */
static const uint32_t PQCLEAN_DILITHIUMIII_CLEAN_zetas_inv[N] = {
6403635, 846154, 6979993, 4442679, 1362209, 48306, 4460757, 554416,
3545687, 6767575, 976891, 8196974, 2286327, 420899, 2235985, 2939036,
3833893, 260646, 1104333, 1667432, 6470041, 1803090, 6656817, 426683,
7908339, 6662682, 975884, 6167306, 8110657, 4513516, 4856520, 3038916,
1799107, 3694233, 6727783, 7570268, 5366416, 6764025, 8217573, 3183426,
1207385, 8194886, 5011305, 6423145, 164721, 5925962, 5948022, 2013608,
3776993, 7786281, 3724270, 2584293, 1846953, 1671176, 2831860, 542412,
4974386, 6144537, 7603226, 6880252, 1374803, 2546312, 6463336, 1279661,
1962642, 5074302, 7067962, 451100, 1430225, 3318210, 7143142, 1333058,
1050970, 6476982, 6511298, 2994039, 3548272, 5744496, 7129923, 3767016,
6784443, 5894064, 7132797, 4325093, 7115408, 2590150, 5688936, 5538076,
8177373, 6644538, 3342277, 4943130, 4272102, 2437823, 8093429, 8038120,
3595838, 768622, 525098, 3556995, 5173371, 6348669, 3122442, 655327,
522500, 43260, 1613174, 7884926, 7561383, 7470875, 6521319, 7479715,
3193378, 1197226, 3759364, 3520352, 4867236, 1235728, 5945978, 8113420,
3562462, 2446433, 6136326, 3342478, 4562441, 6063917, 4972711, 6288750,
4540456, 3628969, 3881060, 3019102, 1439742, 812732, 1584928, 7094748,
7039087, 7064828, 177440, 2409325, 1851402, 5220671, 3553272, 8190869,
1316856, 7620448, 210977, 5991061, 3249728, 6727353, 8578, 3724342,
4421799, 7475901, 1100098, 8336129, 5282425, 7871466, 8115473, 3343383,
1430430, 6527646, 7031341, 381987, 1308169, 22981, 1228525, 671102,
2477047, 411027, 3693493, 2967645, 5665122, 6232521, 983419, 4968207,
8253495, 3632928, 3157330, 3190144, 1000202, 4083598, 6441103, 1257611,
1585221, 6203962, 4904467, 1452451, 3041255, 3677745, 1528703, 3930395,
2797779, 6308525, 2556880, 4479693, 4499374, 7426187, 7849063, 7568473,
4680821, 1600420, 2140649, 4873154, 3821735, 4874723, 1643818, 1699267,
539299, 6031717, 300467, 4840449, 2867647, 4805995, 3043716, 3861115,
4464978, 2537516, 3592148, 1661693, 4849980, 5303092, 8284641, 5674394,
8100412, 4369920, 19422, 6623180, 3277672, 1399561, 3859737, 2118186,
2108549, 5760665, 1119584, 549488, 4794489, 1079900, 7356305, 5654953,
5700314, 5268920, 2884855, 5260684, 2091905, 359251, 6026966, 6554070,
7913949, 876248, 777960, 8143293, 518909, 2608894, 8354570
};

/*************************************************
* Name: ntt
*
* Description: Forward NTT, in-place. No modular reduction is performed after
* additions or subtractions. Hence output coefficients can be up
* to 16*Q larger than the coefficients of the input polynomial.
* Output vector is in bitreversed order.
*
* Arguments: - uint32_t p[N]: input/output coefficient array
**************************************************/
void PQCLEAN_DILITHIUMIII_CLEAN_ntt(uint32_t p[N]) {
unsigned int len, start, j, k;
uint32_t zeta, t;

k = 1;
for (len = 128; len > 0; len >>= 1) {
for (start = 0; start < N; start = j + len) {
zeta = PQCLEAN_DILITHIUMIII_CLEAN_zetas[k++];
for (j = start; j < start + len; ++j) {
t = PQCLEAN_DILITHIUMIII_CLEAN_montgomery_reduce(
(uint64_t)zeta * p[j + len]);
p[j + len] = p[j] + 2 * Q - t;
p[j] = p[j] + t;
}
}
}
}

/*************************************************
* Name: invntt_frominvmont
*
* Description: Inverse NTT and multiplication by Montgomery factor 2^32.
* In-place. No modular reductions after additions or
* subtractions. Input coefficient need to be smaller than 2*Q.
* Output coefficient are smaller than 2*Q.
*
* Arguments: - uint32_t p[N]: input/output coefficient array
**************************************************/
void PQCLEAN_DILITHIUMIII_CLEAN_invntt_frominvmont(uint32_t p[N]) {
unsigned int start, len, j, k;
uint32_t t, zeta;
const uint32_t f =
(((uint64_t)MONT * MONT % Q) * (Q - 1) % Q) * ((Q - 1) >> 8) % Q;

k = 0;
for (len = 1; len < N; len <<= 1) {
for (start = 0; start < N; start = j + len) {
zeta = PQCLEAN_DILITHIUMIII_CLEAN_zetas_inv[k++];
for (j = start; j < start + len; ++j) {
t = p[j];
p[j] = t + p[j + len];
p[j + len] = t + 256 * Q - p[j + len];
p[j + len] = PQCLEAN_DILITHIUMIII_CLEAN_montgomery_reduce(
(uint64_t)zeta * p[j + len]);
}
}
}

for (j = 0; j < N; ++j) {
p[j] = PQCLEAN_DILITHIUMIII_CLEAN_montgomery_reduce((uint64_t)f * p[j]);
}
}

+ 0
- 10
crypto_sign/dilithium-iii/clean/ntt.h Просмотреть файл

@@ -1,10 +0,0 @@
#ifndef NTT_H
#define NTT_H

#include "params.h"
#include <stdint.h>

void PQCLEAN_DILITHIUMIII_CLEAN_ntt(uint32_t p[N]);
void PQCLEAN_DILITHIUMIII_CLEAN_invntt_frominvmont(uint32_t p[N]);

#endif

+ 0
- 301
crypto_sign/dilithium-iii/clean/packing.c Просмотреть файл

@@ -1,301 +0,0 @@
#include "packing.h"
#include "params.h"
#include "poly.h"
#include "polyvec.h"

/*************************************************
* Name: pack_pk
*
* Description: Bit-pack public key pk = (rho, t1).
*
* Arguments: - unsigned char pk[]: output byte array
* - const unsigned char rho[]: byte array containing rho
* - const polyveck *t1: pointer to vector t1
**************************************************/
void PQCLEAN_DILITHIUMIII_CLEAN_pack_pk(unsigned char pk[CRYPTO_PUBLICKEYBYTES],
const unsigned char rho[SEEDBYTES],
const polyveck *t1) {
unsigned int i;

for (i = 0; i < SEEDBYTES; ++i) {
pk[i] = rho[i];
}
pk += SEEDBYTES;

for (i = 0; i < K; ++i) {
PQCLEAN_DILITHIUMIII_CLEAN_polyt1_pack(pk + i * POLT1_SIZE_PACKED,
t1->vec + i);
}
}

/*************************************************
* Name: unpack_pk
*
* Description: Unpack public key pk = (rho, t1).
*
* Arguments: - const unsigned char rho[]: output byte array for rho
* - const polyveck *t1: pointer to output vector t1
* - unsigned char pk[]: byte array containing bit-packed pk
**************************************************/
void PQCLEAN_DILITHIUMIII_CLEAN_unpack_pk(
unsigned char rho[SEEDBYTES], polyveck *t1,
const unsigned char pk[CRYPTO_PUBLICKEYBYTES]) {
unsigned int i;

for (i = 0; i < SEEDBYTES; ++i) {
rho[i] = pk[i];
}
pk += SEEDBYTES;

for (i = 0; i < K; ++i) {
PQCLEAN_DILITHIUMIII_CLEAN_polyt1_unpack(t1->vec + i,
pk + i * POLT1_SIZE_PACKED);
}
}

/*************************************************
* Name: pack_sk
*
* Description: Bit-pack secret key sk = (rho, key, tr, s1, s2, t0).
*
* Arguments: - unsigned char sk[]: output byte array
* - const unsigned char rho[]: byte array containing rho
* - const unsigned char key[]: byte array containing key
* - const unsigned char tr[]: byte array containing tr
* - const polyvecl *s1: pointer to vector s1
* - const polyveck *s2: pointer to vector s2
* - const polyveck *t0: pointer to vector t0
**************************************************/
void PQCLEAN_DILITHIUMIII_CLEAN_pack_sk(unsigned char sk[CRYPTO_SECRETKEYBYTES],
const unsigned char rho[SEEDBYTES],
const unsigned char key[SEEDBYTES],
const unsigned char tr[CRHBYTES],
const polyvecl *s1, const polyveck *s2,
const polyveck *t0) {
unsigned int i;

for (i = 0; i < SEEDBYTES; ++i) {
sk[i] = rho[i];
}
sk += SEEDBYTES;

for (i = 0; i < SEEDBYTES; ++i) {
sk[i] = key[i];
}
sk += SEEDBYTES;

for (i = 0; i < CRHBYTES; ++i) {
sk[i] = tr[i];
}
sk += CRHBYTES;

for (i = 0; i < L; ++i) {
PQCLEAN_DILITHIUMIII_CLEAN_polyeta_pack(sk + i * POLETA_SIZE_PACKED,
s1->vec + i);
}
sk += L * POLETA_SIZE_PACKED;

for (i = 0; i < K; ++i) {
PQCLEAN_DILITHIUMIII_CLEAN_polyeta_pack(sk + i * POLETA_SIZE_PACKED,
s2->vec + i);
}
sk += K * POLETA_SIZE_PACKED;

for (i = 0; i < K; ++i) {
PQCLEAN_DILITHIUMIII_CLEAN_polyt0_pack(sk + i * POLT0_SIZE_PACKED,
t0->vec + i);
}
}

/*************************************************
* Name: unpack_sk
*
* Description: Unpack secret key sk = (rho, key, tr, s1, s2, t0).
*
* Arguments: - const unsigned char rho[]: output byte array for rho
* - const unsigned char key[]: output byte array for key
* - const unsigned char tr[]: output byte array for tr
* - const polyvecl *s1: pointer to output vector s1
* - const polyveck *s2: pointer to output vector s2
* - const polyveck *r0: pointer to output vector t0
* - unsigned char sk[]: byte array containing bit-packed sk
**************************************************/
void PQCLEAN_DILITHIUMIII_CLEAN_unpack_sk(
unsigned char rho[SEEDBYTES], unsigned char key[SEEDBYTES],
unsigned char tr[CRHBYTES], polyvecl *s1, polyveck *s2, polyveck *t0,
const unsigned char sk[CRYPTO_SECRETKEYBYTES]) {
unsigned int i;

for (i = 0; i < SEEDBYTES; ++i) {
rho[i] = sk[i];
}
sk += SEEDBYTES;

for (i = 0; i < SEEDBYTES; ++i) {
key[i] = sk[i];
}
sk += SEEDBYTES;

for (i = 0; i < CRHBYTES; ++i) {
tr[i] = sk[i];
}
sk += CRHBYTES;

for (i = 0; i < L; ++i) {
PQCLEAN_DILITHIUMIII_CLEAN_polyeta_unpack(s1->vec + i,
sk + i * POLETA_SIZE_PACKED);
}
sk += L * POLETA_SIZE_PACKED;

for (i = 0; i < K; ++i) {
PQCLEAN_DILITHIUMIII_CLEAN_polyeta_unpack(s2->vec + i,
sk + i * POLETA_SIZE_PACKED);
}
sk += K * POLETA_SIZE_PACKED;

for (i = 0; i < K; ++i) {
PQCLEAN_DILITHIUMIII_CLEAN_polyt0_unpack(t0->vec + i,
sk + i * POLT0_SIZE_PACKED);
}
}

/*************************************************
* Name: pack_sig
*
* Description: Bit-pack signature sig = (z, h, c).
*
* Arguments: - unsigned char sig[]: output byte array
* - const polyvecl *z: pointer to vector z
* - const polyveck *h: pointer to hint vector h
* - const poly *c: pointer to challenge polynomial
**************************************************/
void PQCLEAN_DILITHIUMIII_CLEAN_pack_sig(unsigned char sig[CRYPTO_BYTES],
const polyvecl *z, const polyveck *h,
const poly *c) {
unsigned int i, j, k;
uint64_t signs, mask;

for (i = 0; i < L; ++i) {
PQCLEAN_DILITHIUMIII_CLEAN_polyz_pack(sig + i * POLZ_SIZE_PACKED, z->vec + i);
}
sig += L * POLZ_SIZE_PACKED;

/* Encode h */
k = 0;
for (i = 0; i < K; ++i) {
for (j = 0; j < N; ++j) {
if (h->vec[i].coeffs[j] != 0) {
sig[k++] = j;
}
}

sig[OMEGA + i] = k;
}
while (k < OMEGA) {
sig[k++] = 0;
}
sig += OMEGA + K;

/* Encode c */
signs = 0;
mask = 1;
for (i = 0; i < N / 8; ++i) {
sig[i] = 0;
for (j = 0; j < 8; ++j) {
if (c->coeffs[8 * i + j] != 0) {
sig[i] |= (1U << j);
if (c->coeffs[8 * i + j] == (Q - 1)) {
signs |= mask;
}
mask <<= 1;
}
}
}
sig += N / 8;
for (i = 0; i < 8; ++i) {
sig[i] = signs >> 8 * i;
}
}

/*************************************************
* Name: unpack_sig
*
* Description: Unpack signature sig = (z, h, c).
*
* Arguments: - polyvecl *z: pointer to output vector z
* - polyveck *h: pointer to output hint vector h
* - poly *c: pointer to output challenge polynomial
* - const unsigned char sig[]: byte array containing
* bit-packed signature
*
* Returns 1 in case of malformed signature; otherwise 0.
**************************************************/
int PQCLEAN_DILITHIUMIII_CLEAN_unpack_sig(polyvecl *z, polyveck *h, poly *c,
const unsigned char sig[CRYPTO_BYTES]) {
unsigned int i, j, k;
uint64_t signs, mask;

for (i = 0; i < L; ++i) {
PQCLEAN_DILITHIUMIII_CLEAN_polyz_unpack(z->vec + i,
sig + i * POLZ_SIZE_PACKED);
}
sig += L * POLZ_SIZE_PACKED;

/* Decode h */
k = 0;
for (i = 0; i < K; ++i) {
for (j = 0; j < N; ++j) {
h->vec[i].coeffs[j] = 0;
}

if (sig[OMEGA + i] < k || sig[OMEGA + i] > OMEGA) {
return 1;
}

for (j = k; j < sig[OMEGA + i]; ++j) {
/* Coefficients are ordered for strong unforgeability */
if (j > k && sig[j] <= sig[j - 1]) {
return 1;
}
h->vec[i].coeffs[sig[j]] = 1;
}

k = sig[OMEGA + i];
}

/* Extra indices are zero for strong unforgeability */
for (j = k; j < OMEGA; ++j) {
if (sig[j]) {
return 1;
}
}

sig += OMEGA + K;

/* Decode c */
for (i = 0; i < N; ++i) {
c->coeffs[i] = 0;
}

signs = 0;
for (i = 0; i < 8; ++i) {
signs |= (uint64_t)sig[N / 8 + i] << 8 * i;
}

/* Extra sign bits are zero for strong unforgeability */
if (signs >> 60) {
return 1;
}

mask = 1;
for (i = 0; i < N / 8; ++i) {
for (j = 0; j < 8; ++j) {
if ((sig[i] >> j) & 0x01) {
c->coeffs[8 * i + j] = (signs & mask) ? Q - 1 : 1;
mask <<= 1;
}
}
}

return 0;
}

+ 0
- 30
crypto_sign/dilithium-iii/clean/packing.h Просмотреть файл

@@ -1,30 +0,0 @@
#ifndef PACKING_H
#define PACKING_H

#include "params.h"
#include "polyvec.h"

void PQCLEAN_DILITHIUMIII_CLEAN_pack_pk(unsigned char pk[CRYPTO_PUBLICKEYBYTES],
const unsigned char rho[SEEDBYTES],
const polyveck *t1);
void PQCLEAN_DILITHIUMIII_CLEAN_pack_sk(unsigned char sk[CRYPTO_SECRETKEYBYTES],
const unsigned char rho[SEEDBYTES],
const unsigned char key[SEEDBYTES],
const unsigned char tr[CRHBYTES],
const polyvecl *s1, const polyveck *s2,
const polyveck *t0);
void PQCLEAN_DILITHIUMIII_CLEAN_pack_sig(unsigned char sig[CRYPTO_BYTES],
const polyvecl *z, const polyveck *h,
const poly *c);

void PQCLEAN_DILITHIUMIII_CLEAN_unpack_pk(
unsigned char rho[SEEDBYTES], polyveck *t1,
const unsigned char pk[CRYPTO_PUBLICKEYBYTES]);
void PQCLEAN_DILITHIUMIII_CLEAN_unpack_sk(
unsigned char rho[SEEDBYTES], unsigned char key[SEEDBYTES],
unsigned char tr[CRHBYTES], polyvecl *s1, polyveck *s2, polyveck *t0,
const unsigned char sk[CRYPTO_SECRETKEYBYTES]);
int PQCLEAN_DILITHIUMIII_CLEAN_unpack_sig(polyvecl *z, polyveck *h, poly *c,
const unsigned char sig[CRYPTO_BYTES]);

#endif

+ 0
- 68
crypto_sign/dilithium-iii/clean/params.h Просмотреть файл

@@ -1,68 +0,0 @@
#ifndef PARAMS_H
#define PARAMS_H

#ifndef MODE
#define MODE 2
#endif

#define SEEDBYTES 32U
#define CRHBYTES 48U
#define N 256U
#define Q 8380417U
#define QBITS 23U
#define ROOT_OF_UNITY 1753U
#define D 14U
#define GAMMA1 ((Q - 1U) / 16U)
#define GAMMA2 (GAMMA1 / 2U)
#define ALPHA (2U * GAMMA2)

#if MODE == 0
#define K 3U
#define L 2U
#define ETA 7U
#define SETABITS 4U
#define BETA 375U
#define OMEGA 64U

#elif MODE == 1
#define K 4U
#define L 3U
#define ETA 6U
#define SETABITS 4U
#define BETA 325U
#define OMEGA 80U

#elif MODE == 2
#define K 5U
#define L 4U
#define ETA 5U
#define SETABITS 4U
#define BETA 275U
#define OMEGA 96U

#elif MODE == 3
#define K 6U
#define L 5U
#define ETA 3U
#define SETABITS 3U
#define BETA 175U
#define OMEGA 120U

#endif

#define POL_SIZE_PACKED ((N * QBITS) / 8)
#define POLT1_SIZE_PACKED ((N * (QBITS - D)) / 8)
#define POLT0_SIZE_PACKED ((N * D) / 8)
#define POLETA_SIZE_PACKED ((N * SETABITS) / 8)
#define POLZ_SIZE_PACKED ((N * (QBITS - 3)) / 8)
#define POLW1_SIZE_PACKED ((N * 4) / 8)
#define POLVECK_SIZE_PACKED (K * POL_SIZE_PACKED)
#define POLVECL_SIZE_PACKED (L * POL_SIZE_PACKED)

#define CRYPTO_PUBLICKEYBYTES (SEEDBYTES + K * POLT1_SIZE_PACKED)
#define CRYPTO_SECRETKEYBYTES \
(2 * SEEDBYTES + (L + K) * POLETA_SIZE_PACKED + CRHBYTES + \
K * POLT0_SIZE_PACKED)
#define CRYPTO_BYTES (L * POLZ_SIZE_PACKED + (OMEGA + K) + (N / 8 + 8))

#endif

+ 0
- 777
crypto_sign/dilithium-iii/clean/poly.c Просмотреть файл

@@ -1,777 +0,0 @@
#include "poly.h"
#include "fips202.h"
#include "ntt.h"
#include "params.h"
#include "reduce.h"
#include "rounding.h"
#include <stdint.h>

/*************************************************
* Name: poly_reduce
*
* Description: Reduce all coefficients of input polynomial to representative
* in [0,2*Q[.
*
* Arguments: - poly *a: pointer to input/output polynomial
**************************************************/
void PQCLEAN_DILITHIUMIII_CLEAN_poly_reduce(poly *a) {
unsigned int i;

for (i = 0; i < N; ++i) {
a->coeffs[i] = PQCLEAN_DILITHIUMIII_CLEAN_reduce32(a->coeffs[i]);
}
}

/*************************************************
* Name: poly_csubq
*
* Description: For all coefficients of input polynomial subtract Q if
* coefficient is bigger than Q.
*
* Arguments: - poly *a: pointer to input/output polynomial
**************************************************/
void PQCLEAN_DILITHIUMIII_CLEAN_poly_csubq(poly *a) {
unsigned int i;

for (i = 0; i < N; ++i) {
a->coeffs[i] = PQCLEAN_DILITHIUMIII_CLEAN_csubq(a->coeffs[i]);
}
}

/*************************************************
* Name: poly_freeze
*
* Description: Reduce all coefficients of the polynomial to standard
* representatives.
*
* Arguments: - poly *a: pointer to input/output polynomial
**************************************************/
void PQCLEAN_DILITHIUMIII_CLEAN_poly_freeze(poly *a) {
unsigned int i;

for (i = 0; i < N; ++i) {
a->coeffs[i] = PQCLEAN_DILITHIUMIII_CLEAN_freeze(a->coeffs[i]);
}
}

/*************************************************
* Name: poly_add
*
* Description: Add polynomials. No modular reduction is performed.
*
* Arguments: - poly *c: pointer to output polynomial
* - const poly *a: pointer to first summand
* - const poly *b: pointer to second summand
**************************************************/
void PQCLEAN_DILITHIUMIII_CLEAN_poly_add(poly *c, const poly *a, const poly *b) {
unsigned int i;

for (i = 0; i < N; ++i) {
c->coeffs[i] = a->coeffs[i] + b->coeffs[i];
}
}

/*************************************************
* Name: poly_sub
*
* Description: Subtract polynomials. Assumes coefficients of second input
* polynomial to be less than 2*Q. No modular reduction is
* performed.
*
* Arguments: - poly *c: pointer to output polynomial
* - const poly *a: pointer to first input polynomial
* - const poly *b: pointer to second input polynomial to be
* subtraced from first input polynomial
**************************************************/
void PQCLEAN_DILITHIUMIII_CLEAN_poly_sub(poly *c, const poly *a, const poly *b) {
unsigned int i;

for (i = 0; i < N; ++i) {
c->coeffs[i] = a->coeffs[i] + 2 * Q - b->coeffs[i];
}
}

/*************************************************
* Name: poly_neg
*
* Description: Negate polynomial. Assumes input coefficients to be standard
* representatives.
*
* Arguments: - poly *a: pointer to input/output polynomial
**************************************************/
void PQCLEAN_DILITHIUMIII_CLEAN_poly_neg(poly *a) {
unsigned int i;

for (i = 0; i < N; ++i) {
a->coeffs[i] = Q - a->coeffs[i];
}
}

/*************************************************
* Name: poly_shiftl
*
* Description: Multiply polynomial by 2^k without modular reduction. Assumes
* input coefficients to be less than 2^{32-k}.
*
* Arguments: - poly *a: pointer to input/output polynomial
* - unsigned int k: exponent
**************************************************/
void PQCLEAN_DILITHIUMIII_CLEAN_poly_shiftl(poly *a, unsigned int k) {
unsigned int i;

for (i = 0; i < N; ++i) {
a->coeffs[i] <<= k;
}
}

/*************************************************
* Name: poly_ntt
*
* Description: Forward NTT. Output coefficients can be up to 16*Q larger than
* input coefficients.
*
* Arguments: - poly *a: pointer to input/output polynomial
**************************************************/
void PQCLEAN_DILITHIUMIII_CLEAN_poly_ntt(poly *a) {
PQCLEAN_DILITHIUMIII_CLEAN_ntt(a->coeffs);
}

/*************************************************
* Name: poly_invntt_montgomery
*
* Description: Inverse NTT and multiplication with 2^{32}. Input coefficients
* need to be less than 2*Q. Output coefficients are less than 2*Q.
*
* Arguments: - poly *a: pointer to input/output polynomial
**************************************************/
void PQCLEAN_DILITHIUMIII_CLEAN_poly_invntt_montgomery(poly *a) {
PQCLEAN_DILITHIUMIII_CLEAN_invntt_frominvmont(a->coeffs);
}

/*************************************************
* Name: poly_pointwise_invmontgomery
*
* Description: Pointwise multiplication of polynomials in NTT domain
* representation and multiplication of resulting polynomial
* with 2^{-32}. Output coefficients are less than 2*Q if input
* coefficient are less than 22*Q.
*
* Arguments: - poly *c: pointer to output polynomial
* - const poly *a: pointer to first input polynomial
* - const poly *b: pointer to second input polynomial
**************************************************/
void PQCLEAN_DILITHIUMIII_CLEAN_poly_pointwise_invmontgomery(poly *c, const poly *a,
const poly *b) {
unsigned int i;

for (i = 0; i < N; ++i) {
c->coeffs[i] = PQCLEAN_DILITHIUMIII_CLEAN_montgomery_reduce(
(uint64_t)a->coeffs[i] * b->coeffs[i]);
}
}

/*************************************************
* Name: poly_power2round
*
* Description: For all coefficients c of the input polynomial,
* compute c0, c1 such that c mod Q = c1*2^D + c0
* with -2^{D-1} < c0 <= 2^{D-1}. Assumes coefficients to be
* standard representatives.
*
* Arguments: - poly *a1: pointer to output polynomial with coefficients c1
* - poly *a0: pointer to output polynomial with coefficients Q +
*a0
* - const poly *v: pointer to input polynomial
**************************************************/
void PQCLEAN_DILITHIUMIII_CLEAN_poly_power2round(poly *a1, poly *a0, const poly *a) {
unsigned int i;

for (i = 0; i < N; ++i) {
a1->coeffs[i] =
PQCLEAN_DILITHIUMIII_CLEAN_power2round(a->coeffs[i], a0->coeffs + i);
}
}

/*************************************************
* Name: poly_decompose
*
* Description: For all coefficients c of the input polynomial,
* compute high and low bits c0, c1 such c mod Q = c1*ALPHA + c0
* with -ALPHA/2 < c0 <= ALPHA/2 except c1 = (Q-1)/ALPHA where we
* set c1 = 0 and -ALPHA/2 <= c0 = c mod Q - Q < 0.
* Assumes coefficients to be standard representatives.
*
* Arguments: - poly *a1: pointer to output polynomial with coefficients c1
* - poly *a0: pointer to output polynomial with coefficients Q +
*a0
* - const poly *c: pointer to input polynomial
**************************************************/
void PQCLEAN_DILITHIUMIII_CLEAN_poly_decompose(poly *a1, poly *a0, const poly *a) {
unsigned int i;

for (i = 0; i < N; ++i) {
a1->coeffs[i] =
PQCLEAN_DILITHIUMIII_CLEAN_decompose(a->coeffs[i], a0->coeffs + i);
}
}

/*************************************************
* Name: poly_make_hint
*
* Description: Compute hint polynomial. The coefficients of which indicate
* whether the high bits of the corresponding coefficients
* of the first input polynomial and of the sum of the input
* polynomials differ.
*
* Arguments: - poly *h: pointer to output hint polynomial
* - const poly *a: pointer to first input polynomial
* - const poly *b: pointer to second input polynomial
*
* Returns number of 1 bits.
**************************************************/
unsigned int PQCLEAN_DILITHIUMIII_CLEAN_poly_make_hint(poly *h, const poly *a,
const poly *b) {
unsigned int i, s = 0;

for (i = 0; i < N; ++i) {
h->coeffs[i] =
PQCLEAN_DILITHIUMIII_CLEAN_make_hint(a->coeffs[i], b->coeffs[i]);
s += h->coeffs[i];
}
return s;
}

/*************************************************
* Name: poly_use_hint
*
* Description: Use hint polynomial to correct the high bits of a polynomial.
*
* Arguments: - poly *a: pointer to output polynomial with corrected high bits
* - const poly *b: pointer to input polynomial
* - const poly *h: pointer to input hint polynomial
**************************************************/
void PQCLEAN_DILITHIUMIII_CLEAN_poly_use_hint(poly *a, const poly *b, const poly *h) {
unsigned int i;

for (i = 0; i < N; ++i) {
a->coeffs[i] =
PQCLEAN_DILITHIUMIII_CLEAN_use_hint(b->coeffs[i], h->coeffs[i]);
}
}

/*************************************************
* Name: poly_chknorm
*
* Description: Check infinity norm of polynomial against given bound.
* Assumes input coefficients to be standard representatives.
*
* Arguments: - const poly *a: pointer to polynomial
* - uint32_t B: norm bound
*
* Returns 0 if norm is strictly smaller than B and 1 otherwise.
**************************************************/
int PQCLEAN_DILITHIUMIII_CLEAN_poly_chknorm(const poly *a, uint32_t B) {
unsigned int i;
int32_t t;

/* It is ok to leak which coefficient violates the bound since
the probability for each coefficient is independent of secret
data but we must not leak the sign of the centralized representative. */
for (i = 0; i < N; ++i) {
/* Absolute value of centralized representative */
t = (Q - 1) / 2 - a->coeffs[i];
t ^= (t >> 31);
t = (Q - 1) / 2 - t;

if ((uint32_t)t >= B) {
return 1;
}
}
return 0;
}

/*************************************************
* Name: poly_uniform
*
* Description: Sample uniformly random polynomial using stream of random bytes.
* Assumes that enough random bytes are given (e.g.
* 5*SHAKE128_RATE bytes).
*
* Arguments: - poly *a: pointer to output polynomial
* - const unsigned char *buf: array of random bytes
**************************************************/
void PQCLEAN_DILITHIUMIII_CLEAN_poly_uniform(poly *a, const unsigned char *buf) {
unsigned int ctr, pos;
uint32_t t;

ctr = pos = 0;
while (ctr < N) {
t = buf[pos++];
t |= (uint32_t)buf[pos++] << 8;
t |= (uint32_t)buf[pos++] << 16;
t &= 0x7FFFFF;

if (t < Q) {
a->coeffs[ctr++] = t;
}
}
}

/*************************************************
* Name: rej_eta
*
* Description: Sample uniformly random coefficients in [-ETA, ETA] by
* performing rejection sampling using array of random bytes.
*
* Arguments: - uint32_t *a: pointer to output array (allocated)
* - unsigned int len: number of coefficients to be sampled
* - const unsigned char *buf: array of random bytes
* - unsigned int buflen: length of array of random bytes
*
* Returns number of sampled coefficients. Can be smaller than len if not enough
* random bytes were given.
**************************************************/
static unsigned int rej_eta(uint32_t *a, unsigned int len,
const unsigned char *buf, unsigned int buflen) {
#if ETA > 7
#error "rej_eta() assumes ETA <= 7"
#endif
unsigned int ctr, pos;
unsigned char t0, t1;

ctr = pos = 0;
while (ctr < len && pos < buflen) {
#if ETA <= 3
t0 = buf[pos] & 0x07;
t1 = buf[pos++] >> 5;
#else
t0 = buf[pos] & 0x0F;
t1 = buf[pos++] >> 4;
#endif

if (t0 <= 2 * ETA) {
a[ctr++] = Q + ETA - t0;
}
if (t1 <= 2 * ETA && ctr < len) {
a[ctr++] = Q + ETA - t1;
}
}
return ctr;
}

/*************************************************
* Name: poly_uniform_eta
*
* Description: Sample polynomial with uniformly random coefficients
* in [-ETA,ETA] by performing rejection sampling using the
* output stream from SHAKE256(seed|nonce).
*
* Arguments: - poly *a: pointer to output polynomial
* - const unsigned char seed[]: byte array with seed of length
* SEEDBYTES
* - unsigned char nonce: nonce byte
**************************************************/
void PQCLEAN_DILITHIUMIII_CLEAN_poly_uniform_eta(poly *a,
const unsigned char seed[SEEDBYTES],
unsigned char nonce) {
unsigned int i, ctr;
unsigned char inbuf[SEEDBYTES + 1];
/* Probability that we need more than 2 blocks: < 2^{-84}
Probability that we need more than 3 blocks: < 2^{-352} */
unsigned char outbuf[2 * SHAKE256_RATE];
uint64_t state[25];

for (i = 0; i < SEEDBYTES; ++i) {
inbuf[i] = seed[i];
}
inbuf[SEEDBYTES] = nonce;

shake256_absorb(state, inbuf, SEEDBYTES + 1);
shake256_squeezeblocks(outbuf, 2, state);

ctr = rej_eta(a->coeffs, N, outbuf, 2 * SHAKE256_RATE);
if (ctr < N) {
shake256_squeezeblocks(outbuf, 1, state);
rej_eta(a->coeffs + ctr, N - ctr, outbuf, SHAKE256_RATE);
}
}

/*************************************************
* Name: rej_gamma1m1
*
* Description: Sample uniformly random coefficients
* in [-(GAMMA1 - 1), GAMMA1 - 1] by performing rejection sampling
* using array of random bytes.
*
* Arguments: - uint32_t *a: pointer to output array (allocated)
* - unsigned int len: number of coefficients to be sampled
* - const unsigned char *buf: array of random bytes
* - unsigned int buflen: length of array of random bytes
*
* Returns number of sampled coefficients. Can be smaller than len if not enough
* random bytes were given.
**************************************************/
static unsigned int rej_gamma1m1(uint32_t *a, unsigned int len,
const unsigned char *buf,
unsigned int buflen) {
#if GAMMA1 > (1 << 19)
#error "rej_gamma1m1() assumes GAMMA1 - 1 fits in 19 bits"
#endif
unsigned int ctr, pos;
uint32_t t0, t1;

ctr = pos = 0;
while (ctr < len && pos + 5 <= buflen) {
t0 = buf[pos];
t0 |= (uint32_t)buf[pos + 1] << 8;
t0 |= (uint32_t)buf[pos + 2] << 16;
t0 &= 0xFFFFF;

t1 = buf[pos + 2] >> 4;
t1 |= (uint32_t)buf[pos + 3] << 4;
t1 |= (uint32_t)buf[pos + 4] << 12;

pos += 5;

if (t0 <= 2 * GAMMA1 - 2) {
a[ctr++] = Q + GAMMA1 - 1 - t0;
}
if (t1 <= 2 * GAMMA1 - 2 && ctr < len) {
a[ctr++] = Q + GAMMA1 - 1 - t1;
}
}

return ctr;
}

/*************************************************
* Name: poly_uniform_gamma1m1
*
* Description: Sample polynomial with uniformly random coefficients
* in [-(GAMMA1 - 1), GAMMA1 - 1] by performing rejection
* sampling on output stream of SHAKE256(seed|nonce).
*
* Arguments: - poly *a: pointer to output polynomial
* - const unsigned char seed[]: byte array with seed of length
* SEEDBYTES + CRHBYTES
* - uint16_t nonce: 16-bit nonce
**************************************************/
void PQCLEAN_DILITHIUMIII_CLEAN_poly_uniform_gamma1m1(
poly *a, const unsigned char seed[SEEDBYTES + CRHBYTES], uint16_t nonce) {
unsigned int i, ctr;
unsigned char inbuf[SEEDBYTES + CRHBYTES + 2];
/* Probability that we need more than 5 blocks: < 2^{-81}
Probability that we need more than 6 blocks: < 2^{-467} */
unsigned char outbuf[5 * SHAKE256_RATE];
uint64_t state[25];

for (i = 0; i < SEEDBYTES + CRHBYTES; ++i) {
inbuf[i] = seed[i];
}
inbuf[SEEDBYTES + CRHBYTES] = nonce & 0xFF;
inbuf[SEEDBYTES + CRHBYTES + 1] = nonce >> 8;

shake256_absorb(state, inbuf, SEEDBYTES + CRHBYTES + 2);
shake256_squeezeblocks(outbuf, 5, state);

ctr = rej_gamma1m1(a->coeffs, N, outbuf, 5 * SHAKE256_RATE);
if (ctr < N) {
/* There are no bytes left in outbuf
since 5*SHAKE256_RATE is divisible by 5 */
shake256_squeezeblocks(outbuf, 1, state);
rej_gamma1m1(a->coeffs + ctr, N - ctr, outbuf, SHAKE256_RATE);
}
}

/*************************************************
* Name: polyeta_pack
*
* Description: Bit-pack polynomial with coefficients in [-ETA,ETA].
* Input coefficients are assumed to lie in [Q-ETA,Q+ETA].
*
* Arguments: - unsigned char *r: pointer to output byte array with at least
* POLETA_SIZE_PACKED bytes
* - const poly *a: pointer to input polynomial
**************************************************/
void PQCLEAN_DILITHIUMIII_CLEAN_polyeta_pack(unsigned char *r, const poly *a) {
#if ETA > 7
#error "polyeta_pack() assumes ETA <= 7"
#endif
unsigned int i;
unsigned char t[8];

#if ETA <= 3
for (i = 0; i < N / 8; ++i) {
t[0] = Q + ETA - a->coeffs[8 * i + 0];
t[1] = Q + ETA - a->coeffs[8 * i + 1];
t[2] = Q + ETA - a->coeffs[8 * i + 2];
t[3] = Q + ETA - a->coeffs[8 * i + 3];
t[4] = Q + ETA - a->coeffs[8 * i + 4];
t[5] = Q + ETA - a->coeffs[8 * i + 5];
t[6] = Q + ETA - a->coeffs[8 * i + 6];
t[7] = Q + ETA - a->coeffs[8 * i + 7];

r[3 * i + 0] = t[0];
r[3 * i + 0] |= t[1] << 3;
r[3 * i + 0] |= t[2] << 6;
r[3 * i + 1] = t[2] >> 2;
r[3 * i + 1] |= t[3] << 1;
r[3 * i + 1] |= t[4] << 4;
r[3 * i + 1] |= t[5] << 7;
r[3 * i + 2] = t[5] >> 1;
r[3 * i + 2] |= t[6] << 2;
r[3 * i + 2] |= t[7] << 5;
}
#else
for (i = 0; i < N / 2; ++i) {
t[0] = Q + ETA - a->coeffs[2 * i + 0];
t[1] = Q + ETA - a->coeffs[2 * i + 1];
r[i] = t[0] | (t[1] << 4);
}
#endif
}

/*************************************************
* Name: polyeta_unpack
*
* Description: Unpack polynomial with coefficients in [-ETA,ETA].
* Output coefficients lie in [Q-ETA,Q+ETA].
*
* Arguments: - poly *r: pointer to output polynomial
* - const unsigned char *a: byte array with bit-packed polynomial
**************************************************/
void PQCLEAN_DILITHIUMIII_CLEAN_polyeta_unpack(poly *r, const unsigned char *a) {
unsigned int i;

#if ETA <= 3
for (i = 0; i < N / 8; ++i) {
r->coeffs[8 * i + 0] = a[3 * i + 0] & 0x07;
r->coeffs[8 * i + 1] = (a[3 * i + 0] >> 3) & 0x07;
r->coeffs[8 * i + 2] =
(a[3 * i + 0] >> 6) | ((a[3 * i + 1] & 0x01) << 2);
r->coeffs[8 * i + 3] = (a[3 * i + 1] >> 1) & 0x07;
r->coeffs[8 * i + 4] = (a[3 * i + 1] >> 4) & 0x07;
r->coeffs[8 * i + 5] =
(a[3 * i + 1] >> 7) | ((a[3 * i + 2] & 0x03) << 1);
r->coeffs[8 * i + 6] = (a[3 * i + 2] >> 2) & 0x07;
r->coeffs[8 * i + 7] = (a[3 * i + 2] >> 5);

r->coeffs[8 * i + 0] = Q + ETA - r->coeffs[8 * i + 0];
r->coeffs[8 * i + 1] = Q + ETA - r->coeffs[8 * i + 1];
r->coeffs[8 * i + 2] = Q + ETA - r->coeffs[8 * i + 2];
r->coeffs[8 * i + 3] = Q + ETA - r->coeffs[8 * i + 3];
r->coeffs[8 * i + 4] = Q + ETA - r->coeffs[8 * i + 4];
r->coeffs[8 * i + 5] = Q + ETA - r->coeffs[8 * i + 5];
r->coeffs[8 * i + 6] = Q + ETA - r->coeffs[8 * i + 6];
r->coeffs[8 * i + 7] = Q + ETA - r->coeffs[8 * i + 7];
}
#else
for (i = 0; i < N / 2; ++i) {
r->coeffs[2 * i + 0] = a[i] & 0x0F;
r->coeffs[2 * i + 1] = a[i] >> 4;
r->coeffs[2 * i + 0] = Q + ETA - r->coeffs[2 * i + 0];
r->coeffs[2 * i + 1] = Q + ETA - r->coeffs[2 * i + 1];
}
#endif
}

/*************************************************
* Name: polyt1_pack
*
* Description: Bit-pack polynomial t1 with coefficients fitting in 9 bits.
* Input coefficients are assumed to be standard representatives.
*
* Arguments: - unsigned char *r: pointer to output byte array with at least
* POLT1_SIZE_PACKED bytes
* - const poly *a: pointer to input polynomial
**************************************************/
void PQCLEAN_DILITHIUMIII_CLEAN_polyt1_pack(unsigned char *r, const poly *a) {
#if D != 14
#error "polyt1_pack() assumes D == 14"
#endif
unsigned int i;

for (i = 0; i < N / 8; ++i) {
r[9 * i + 0] = a->coeffs[8 * i + 0] & 0xFF;
r[9 * i + 1] = (a->coeffs[8 * i + 0] >> 8) | ((a->coeffs[8 * i + 1] & 0x7F) << 1);
r[9 * i + 2] = (a->coeffs[8 * i + 1] >> 7) | ((a->coeffs[8 * i + 2] & 0x3F) << 2);
r[9 * i + 3] = (a->coeffs[8 * i + 2] >> 6) | ((a->coeffs[8 * i + 3] & 0x1F) << 3);
r[9 * i + 4] = (a->coeffs[8 * i + 3] >> 5) | ((a->coeffs[8 * i + 4] & 0x0F) << 4);
r[9 * i + 5] = (a->coeffs[8 * i + 4] >> 4) | ((a->coeffs[8 * i + 5] & 0x07) << 5);
r[9 * i + 6] = (a->coeffs[8 * i + 5] >> 3) | ((a->coeffs[8 * i + 6] & 0x03) << 6);
r[9 * i + 7] = (a->coeffs[8 * i + 6] >> 2) | ((a->coeffs[8 * i + 7] & 0x01) << 7);
r[9 * i + 8] = a->coeffs[8 * i + 7] >> 1;
}
}

/*************************************************
* Name: polyt1_unpack
*
* Description: Unpack polynomial t1 with 9-bit coefficients.
* Output coefficients are standard representatives.
*
* Arguments: - poly *r: pointer to output polynomial
* - const unsigned char *a: byte array with bit-packed polynomial
**************************************************/
void PQCLEAN_DILITHIUMIII_CLEAN_polyt1_unpack(poly *r, const unsigned char *a) {
unsigned int i;

for (i = 0; i < N / 8; ++i) {
r->coeffs[8 * i + 0] = a[9 * i + 0] | ((uint32_t)(a[9 * i + 1] & 0x01) << 8);
r->coeffs[8 * i + 1] = (a[9 * i + 1] >> 1) | ((uint32_t)(a[9 * i + 2] & 0x03) << 7);
r->coeffs[8 * i + 2] = (a[9 * i + 2] >> 2) | ((uint32_t)(a[9 * i + 3] & 0x07) << 6);
r->coeffs[8 * i + 3] = (a[9 * i + 3] >> 3) | ((uint32_t)(a[9 * i + 4] & 0x0F) << 5);
r->coeffs[8 * i + 4] = (a[9 * i + 4] >> 4) | ((uint32_t)(a[9 * i + 5] & 0x1F) << 4);
r->coeffs[8 * i + 5] = (a[9 * i + 5] >> 5) | ((uint32_t)(a[9 * i + 6] & 0x3F) << 3);
r->coeffs[8 * i + 6] = (a[9 * i + 6] >> 6) | ((uint32_t)(a[9 * i + 7] & 0x7F) << 2);
r->coeffs[8 * i + 7] = (a[9 * i + 7] >> 7) | ((uint32_t)(a[9 * i + 8] & 0xFF) << 1);
}
}

/*************************************************
* Name: polyt0_pack
*
* Description: Bit-pack polynomial t0 with coefficients in ]-2^{D-1}, 2^{D-1}].
* Input coefficients are assumed to lie in ]Q-2^{D-1}, Q+2^{D-1}].
*
* Arguments: - unsigned char *r: pointer to output byte array with at least
* POLT0_SIZE_PACKED bytes
* - const poly *a: pointer to input polynomial
**************************************************/
void PQCLEAN_DILITHIUMIII_CLEAN_polyt0_pack(unsigned char *r, const poly *a) {
unsigned int i;
uint32_t t[4];

for (i = 0; i < N / 4; ++i) {
t[0] = Q + (1 << (D - 1)) - a->coeffs[4 * i + 0];
t[1] = Q + (1 << (D - 1)) - a->coeffs[4 * i + 1];
t[2] = Q + (1 << (D - 1)) - a->coeffs[4 * i + 2];
t[3] = Q + (1 << (D - 1)) - a->coeffs[4 * i + 3];

r[7 * i + 0] = t[0];
r[7 * i + 1] = t[0] >> 8;
r[7 * i + 1] |= t[1] << 6;
r[7 * i + 2] = t[1] >> 2;
r[7 * i + 3] = t[1] >> 10;
r[7 * i + 3] |= t[2] << 4;
r[7 * i + 4] = t[2] >> 4;
r[7 * i + 5] = t[2] >> 12;
r[7 * i + 5] |= t[3] << 2;
r[7 * i + 6] = t[3] >> 6;
}
}

/*************************************************
* Name: polyt0_unpack
*
* Description: Unpack polynomial t0 with coefficients in ]-2^{D-1}, 2^{D-1}].
* Output coefficients lie in ]Q-2^{D-1},Q+2^{D-1}].
*
* Arguments: - poly *r: pointer to output polynomial
* - const unsigned char *a: byte array with bit-packed polynomial
**************************************************/
void PQCLEAN_DILITHIUMIII_CLEAN_polyt0_unpack(poly *r, const unsigned char *a) {
unsigned int i;

for (i = 0; i < N / 4; ++i) {
r->coeffs[4 * i + 0] = a[7 * i + 0];
r->coeffs[4 * i + 0] |= (uint32_t)(a[7 * i + 1] & 0x3F) << 8;

r->coeffs[4 * i + 1] = a[7 * i + 1] >> 6;
r->coeffs[4 * i + 1] |= (uint32_t)a[7 * i + 2] << 2;
r->coeffs[4 * i + 1] |= (uint32_t)(a[7 * i + 3] & 0x0F) << 10;

r->coeffs[4 * i + 2] = a[7 * i + 3] >> 4;
r->coeffs[4 * i + 2] |= (uint32_t)a[7 * i + 4] << 4;
r->coeffs[4 * i + 2] |= (uint32_t)(a[7 * i + 5] & 0x03) << 12;

r->coeffs[4 * i + 3] = a[7 * i + 5] >> 2;
r->coeffs[4 * i + 3] |= (uint32_t)a[7 * i + 6] << 6;

r->coeffs[4 * i + 0] = Q + (1 << (D - 1)) - r->coeffs[4 * i + 0];
r->coeffs[4 * i + 1] = Q + (1 << (D - 1)) - r->coeffs[4 * i + 1];
r->coeffs[4 * i + 2] = Q + (1 << (D - 1)) - r->coeffs[4 * i + 2];
r->coeffs[4 * i + 3] = Q + (1 << (D - 1)) - r->coeffs[4 * i + 3];
}
}

/*************************************************
* Name: polyz_pack
*
* Description: Bit-pack polynomial z with coefficients
* in [-(GAMMA1 - 1), GAMMA1 - 1].
* Input coefficients are assumed to be standard representatives.
*
* Arguments: - unsigned char *r: pointer to output byte array with at least
* POLZ_SIZE_PACKED bytes
* - const poly *a: pointer to input polynomial
**************************************************/
void PQCLEAN_DILITHIUMIII_CLEAN_polyz_pack(unsigned char *r, const poly *a) {
#if GAMMA1 > (1 << 19)
#error "polyz_pack() assumes GAMMA1 <= 2^{19}"
#endif
unsigned int i;
uint32_t t[2];

for (i = 0; i < N / 2; ++i) {
/* Map to {0,...,2*GAMMA1 - 2} */
t[0] = GAMMA1 - 1 - a->coeffs[2 * i + 0];
t[0] += ((int32_t)t[0] >> 31) & Q;
t[1] = GAMMA1 - 1 - a->coeffs[2 * i + 1];
t[1] += ((int32_t)t[1] >> 31) & Q;

r[5 * i + 0] = t[0];
r[5 * i + 1] = t[0] >> 8;
r[5 * i + 2] = t[0] >> 16;
r[5 * i + 2] |= t[1] << 4;
r[5 * i + 3] = t[1] >> 4;
r[5 * i + 4] = t[1] >> 12;
}
}

/*************************************************
* Name: polyz_unpack
*
* Description: Unpack polynomial z with coefficients
* in [-(GAMMA1 - 1), GAMMA1 - 1].
* Output coefficients are standard representatives.
*
* Arguments: - poly *r: pointer to output polynomial
* - const unsigned char *a: byte array with bit-packed polynomial
**************************************************/
void PQCLEAN_DILITHIUMIII_CLEAN_polyz_unpack(poly *r, const unsigned char *a) {
unsigned int i;

for (i = 0; i < N / 2; ++i) {
r->coeffs[2 * i + 0] = a[5 * i + 0];
r->coeffs[2 * i + 0] |= (uint32_t)a[5 * i + 1] << 8;
r->coeffs[2 * i + 0] |= (uint32_t)(a[5 * i + 2] & 0x0F) << 16;

r->coeffs[2 * i + 1] = a[5 * i + 2] >> 4;
r->coeffs[2 * i + 1] |= (uint32_t)a[5 * i + 3] << 4;
r->coeffs[2 * i + 1] |= (uint32_t)a[5 * i + 4] << 12;

r->coeffs[2 * i + 0] = GAMMA1 - 1 - r->coeffs[2 * i + 0];
r->coeffs[2 * i + 0] += ((int32_t)r->coeffs[2 * i + 0] >> 31) & Q;
r->coeffs[2 * i + 1] = GAMMA1 - 1 - r->coeffs[2 * i + 1];
r->coeffs[2 * i + 1] += ((int32_t)r->coeffs[2 * i + 1] >> 31) & Q;
}
}

/*************************************************
* Name: polyw1_pack
*
* Description: Bit-pack polynomial w1 with coefficients in [0, 15].
* Input coefficients are assumed to be standard representatives.
*
* Arguments: - unsigned char *r: pointer to output byte array with at least
* POLW1_SIZE_PACKED bytes
* - const poly *a: pointer to input polynomial
**************************************************/
void PQCLEAN_DILITHIUMIII_CLEAN_polyw1_pack(unsigned char *r, const poly *a) {
unsigned int i;

for (i = 0; i < N / 2; ++i) {
r[i] = a->coeffs[2 * i + 0] | (a->coeffs[2 * i + 1] << 4);
}
}

+ 0
- 53
crypto_sign/dilithium-iii/clean/poly.h Просмотреть файл

@@ -1,53 +0,0 @@
#ifndef POLY_H
#define POLY_H

#include "fips202.h"
#include "params.h"
#include <stdint.h>

typedef struct {
uint32_t coeffs[N];
} poly;

void PQCLEAN_DILITHIUMIII_CLEAN_poly_reduce(poly *a);
void PQCLEAN_DILITHIUMIII_CLEAN_poly_csubq(poly *a);
void PQCLEAN_DILITHIUMIII_CLEAN_poly_freeze(poly *a);

void PQCLEAN_DILITHIUMIII_CLEAN_poly_add(poly *c, const poly *a, const poly *b);
void PQCLEAN_DILITHIUMIII_CLEAN_poly_sub(poly *c, const poly *a, const poly *b);
void PQCLEAN_DILITHIUMIII_CLEAN_poly_neg(poly *a);
void PQCLEAN_DILITHIUMIII_CLEAN_poly_shiftl(poly *a, unsigned int k);

void PQCLEAN_DILITHIUMIII_CLEAN_poly_ntt(poly *a);
void PQCLEAN_DILITHIUMIII_CLEAN_poly_invntt_montgomery(poly *a);
void PQCLEAN_DILITHIUMIII_CLEAN_poly_pointwise_invmontgomery(poly *c, const poly *a,
const poly *b);

void PQCLEAN_DILITHIUMIII_CLEAN_poly_power2round(poly *a1, poly *a0, const poly *a);
void PQCLEAN_DILITHIUMIII_CLEAN_poly_decompose(poly *a1, poly *a0, const poly *a);
unsigned int PQCLEAN_DILITHIUMIII_CLEAN_poly_make_hint(poly *h, const poly *a,
const poly *b);
void PQCLEAN_DILITHIUMIII_CLEAN_poly_use_hint(poly *a, const poly *b, const poly *h);

int PQCLEAN_DILITHIUMIII_CLEAN_poly_chknorm(const poly *a, uint32_t B);
void PQCLEAN_DILITHIUMIII_CLEAN_poly_uniform(poly *a, const unsigned char *buf);
void PQCLEAN_DILITHIUMIII_CLEAN_poly_uniform_eta(poly *a,
const unsigned char seed[SEEDBYTES],
unsigned char nonce);
void PQCLEAN_DILITHIUMIII_CLEAN_poly_uniform_gamma1m1(
poly *a, const unsigned char seed[SEEDBYTES + CRHBYTES], uint16_t nonce);

void PQCLEAN_DILITHIUMIII_CLEAN_polyeta_pack(unsigned char *r, const poly *a);
void PQCLEAN_DILITHIUMIII_CLEAN_polyeta_unpack(poly *r, const unsigned char *a);

void PQCLEAN_DILITHIUMIII_CLEAN_polyt1_pack(unsigned char *r, const poly *a);
void PQCLEAN_DILITHIUMIII_CLEAN_polyt1_unpack(poly *r, const unsigned char *a);

void PQCLEAN_DILITHIUMIII_CLEAN_polyt0_pack(unsigned char *r, const poly *a);
void PQCLEAN_DILITHIUMIII_CLEAN_polyt0_unpack(poly *r, const unsigned char *a);

void PQCLEAN_DILITHIUMIII_CLEAN_polyz_pack(unsigned char *r, const poly *a);
void PQCLEAN_DILITHIUMIII_CLEAN_polyz_unpack(poly *r, const unsigned char *a);

void PQCLEAN_DILITHIUMIII_CLEAN_polyw1_pack(unsigned char *r, const poly *a);
#endif

+ 0
- 367
crypto_sign/dilithium-iii/clean/polyvec.c Просмотреть файл

@@ -1,367 +0,0 @@
#include "polyvec.h"
#include "params.h"
#include "poly.h"
#include <stdint.h>

/**************************************************************/
/************ Vectors of polynomials of length L **************/
/**************************************************************/

/*************************************************
* Name: polyvecl_freeze
*
* Description: Reduce coefficients of polynomials in vector of length L
* to standard representatives.
*
* Arguments: - polyvecl *v: pointer to input/output vector
**************************************************/
void PQCLEAN_DILITHIUMIII_CLEAN_polyvecl_freeze(polyvecl *v) {
unsigned int i;

for (i = 0; i < L; ++i) {
PQCLEAN_DILITHIUMIII_CLEAN_poly_freeze(v->vec + i);
}
}

/*************************************************
* Name: polyvecl_add
*
* Description: Add vectors of polynomials of length L.
* No modular reduction is performed.
*
* Arguments: - polyvecl *w: pointer to output vector
* - const polyvecl *u: pointer to first summand
* - const polyvecl *v: pointer to second summand
**************************************************/
void PQCLEAN_DILITHIUMIII_CLEAN_polyvecl_add(polyvecl *w, const polyvecl *u,
const polyvecl *v) {
unsigned int i;

for (i = 0; i < L; ++i) {
PQCLEAN_DILITHIUMIII_CLEAN_poly_add(w->vec + i, u->vec + i, v->vec + i);
}
}

/*************************************************
* Name: polyvecl_ntt
*
* Description: Forward NTT of all polynomials in vector of length L. Output
* coefficients can be up to 16*Q larger than input coefficients.
*
* Arguments: - polyvecl *v: pointer to input/output vector
**************************************************/
void PQCLEAN_DILITHIUMIII_CLEAN_polyvecl_ntt(polyvecl *v) {
unsigned int i;

for (i = 0; i < L; ++i) {
PQCLEAN_DILITHIUMIII_CLEAN_poly_ntt(v->vec + i);
}
}

/*************************************************
* Name: polyvecl_pointwise_acc_invmontgomery
*
* Description: Pointwise multiply vectors of polynomials of length L, multiply
* resulting vector by 2^{-32} and add (accumulate) polynomials
* in it. Input/output vectors are in NTT domain representation.
* Input coefficients are assumed to be less than 22*Q. Output
* coeffcient are less than 2*L*Q.
*
* Arguments: - poly *w: output polynomial
* - const polyvecl *u: pointer to first input vector
* - const polyvecl *v: pointer to second input vector
**************************************************/
void PQCLEAN_DILITHIUMIII_CLEAN_polyvecl_pointwise_acc_invmontgomery(
poly *w, const polyvecl *u, const polyvecl *v) {
unsigned int i;
poly t;

PQCLEAN_DILITHIUMIII_CLEAN_poly_pointwise_invmontgomery(w, u->vec + 0,
v->vec + 0);

for (i = 1; i < L; ++i) {
PQCLEAN_DILITHIUMIII_CLEAN_poly_pointwise_invmontgomery(&t, u->vec + i,
v->vec + i);
PQCLEAN_DILITHIUMIII_CLEAN_poly_add(w, w, &t);
}
}

/*************************************************
* Name: polyvecl_chknorm
*
* Description: Check infinity norm of polynomials in vector of length L.
* Assumes input coefficients to be standard representatives.
*
* Arguments: - const polyvecl *v: pointer to vector
* - uint32_t B: norm bound
*
* Returns 0 if norm of all polynomials is strictly smaller than B and 1
* otherwise.
**************************************************/
int PQCLEAN_DILITHIUMIII_CLEAN_polyvecl_chknorm(const polyvecl *v, uint32_t bound) {
unsigned int i;
int ret = 0;

for (i = 0; i < L; ++i) {
ret |= PQCLEAN_DILITHIUMIII_CLEAN_poly_chknorm(v->vec + i, bound);
}

return ret;
}

/**************************************************************/
/************ Vectors of polynomials of length K **************/
/**************************************************************/

/*************************************************
* Name: polyveck_reduce
*
* Description: Reduce coefficients of polynomials in vector of length K
* to representatives in [0,2*Q[.
*
* Arguments: - polyveck *v: pointer to input/output vector
**************************************************/
void PQCLEAN_DILITHIUMIII_CLEAN_polyveck_reduce(polyveck *v) {
unsigned int i;

for (i = 0; i < K; ++i) {
PQCLEAN_DILITHIUMIII_CLEAN_poly_reduce(v->vec + i);
}
}

/*************************************************
* Name: polyveck_csubq
*
* Description: For all coefficients of polynomials in vector of length K
* subtract Q if coefficient is bigger than Q.
*
* Arguments: - polyveck *v: pointer to input/output vector
**************************************************/
void PQCLEAN_DILITHIUMIII_CLEAN_polyveck_csubq(polyveck *v) {
unsigned int i;

for (i = 0; i < K; ++i) {
PQCLEAN_DILITHIUMIII_CLEAN_poly_csubq(v->vec + i);
}
}

/*************************************************
* Name: polyveck_freeze
*
* Description: Reduce coefficients of polynomials in vector of length K
* to standard representatives.
*
* Arguments: - polyveck *v: pointer to input/output vector
**************************************************/
void PQCLEAN_DILITHIUMIII_CLEAN_polyveck_freeze(polyveck *v) {
unsigned int i;

for (i = 0; i < K; ++i) {
PQCLEAN_DILITHIUMIII_CLEAN_poly_freeze(v->vec + i);
}
}

/*************************************************
* Name: polyveck_add
*
* Description: Add vectors of polynomials of length K.
* No modular reduction is performed.
*
* Arguments: - polyveck *w: pointer to output vector
* - const polyveck *u: pointer to first summand
* - const polyveck *v: pointer to second summand
**************************************************/
void PQCLEAN_DILITHIUMIII_CLEAN_polyveck_add(polyveck *w, const polyveck *u,
const polyveck *v) {
unsigned int i;

for (i = 0; i < K; ++i) {
PQCLEAN_DILITHIUMIII_CLEAN_poly_add(w->vec + i, u->vec + i, v->vec + i);
}
}

/*************************************************
* Name: polyveck_sub
*
* Description: Subtract vectors of polynomials of length K.
* Assumes coefficients of polynomials in second input vector
* to be less than 2*Q. No modular reduction is performed.
*
* Arguments: - polyveck *w: pointer to output vector
* - const polyveck *u: pointer to first input vector
* - const polyveck *v: pointer to second input vector to be
* subtracted from first input vector
**************************************************/
void PQCLEAN_DILITHIUMIII_CLEAN_polyveck_sub(polyveck *w, const polyveck *u,
const polyveck *v) {
unsigned int i;

for (i = 0; i < K; ++i) {
PQCLEAN_DILITHIUMIII_CLEAN_poly_sub(w->vec + i, u->vec + i, v->vec + i);
}
}

/*************************************************
* Name: polyveck_shiftl
*
* Description: Multiply vector of polynomials of Length K by 2^k without
*modular reduction. Assumes input coefficients to be less than 2^{32-k}.
*
* Arguments: - polyveck *v: pointer to input/output vector
* - unsigned int k: exponent
**************************************************/
void PQCLEAN_DILITHIUMIII_CLEAN_polyveck_shiftl(polyveck *v, unsigned int k) {
unsigned int i;

for (i = 0; i < K; ++i) {
PQCLEAN_DILITHIUMIII_CLEAN_poly_shiftl(v->vec + i, k);
}
}

/*************************************************
* Name: polyveck_ntt
*
* Description: Forward NTT of all polynomials in vector of length K. Output
* coefficients can be up to 16*Q larger than input coefficients.
*
* Arguments: - polyveck *v: pointer to input/output vector
**************************************************/
void PQCLEAN_DILITHIUMIII_CLEAN_polyveck_ntt(polyveck *v) {
unsigned int i;

for (i = 0; i < K; ++i) {
PQCLEAN_DILITHIUMIII_CLEAN_poly_ntt(v->vec + i);
}
}

/*************************************************
* Name: polyveck_invntt_montgomery
*
* Description: Inverse NTT and multiplication by 2^{32} of polynomials
* in vector of length K. Input coefficients need to be less
* than 2*Q.
*
* Arguments: - polyveck *v: pointer to input/output vector
**************************************************/
void PQCLEAN_DILITHIUMIII_CLEAN_polyveck_invntt_montgomery(polyveck *v) {
unsigned int i;

for (i = 0; i < K; ++i) {
PQCLEAN_DILITHIUMIII_CLEAN_poly_invntt_montgomery(v->vec + i);
}
}

/*************************************************
* Name: polyveck_chknorm
*
* Description: Check infinity norm of polynomials in vector of length K.
* Assumes input coefficients to be standard representatives.
*
* Arguments: - const polyveck *v: pointer to vector
* - uint32_t B: norm bound
*
* Returns 0 if norm of all polynomials are strictly smaller than B and 1
* otherwise.
**************************************************/
int PQCLEAN_DILITHIUMIII_CLEAN_polyveck_chknorm(const polyveck *v, uint32_t bound) {
unsigned int i;
int ret = 0;

for (i = 0; i < K; ++i) {
ret |= PQCLEAN_DILITHIUMIII_CLEAN_poly_chknorm(v->vec + i, bound);
}

return ret;
}

/*************************************************
* Name: polyveck_power2round
*
* Description: For all coefficients a of polynomials in vector of length K,
* compute a0, a1 such that a mod Q = a1*2^D + a0
* with -2^{D-1} < a0 <= 2^{D-1}. Assumes coefficients to be
* standard representatives.
*
* Arguments: - polyveck *v1: pointer to output vector of polynomials with
* coefficients a1
* - polyveck *v0: pointer to output vector of polynomials with
* coefficients Q + a0
* - const polyveck *v: pointer to input vector
**************************************************/
void PQCLEAN_DILITHIUMIII_CLEAN_polyveck_power2round(polyveck *v1, polyveck *v0,
const polyveck *v) {
unsigned int i;

for (i = 0; i < K; ++i) {
PQCLEAN_DILITHIUMIII_CLEAN_poly_power2round(v1->vec + i, v0->vec + i,
v->vec + i);
}
}

/*************************************************
* Name: polyveck_decompose
*
* Description: For all coefficients a of polynomials in vector of length K,
* compute high and low bits a0, a1 such a mod Q = a1*ALPHA + a0
* with -ALPHA/2 < a0 <= ALPHA/2 except a1 = (Q-1)/ALPHA where we
* set a1 = 0 and -ALPHA/2 <= a0 = a mod Q - Q < 0.
* Assumes coefficients to be standard representatives.
*
* Arguments: - polyveck *v1: pointer to output vector of polynomials with
* coefficients a1
* - polyveck *v0: pointer to output vector of polynomials with
* coefficients Q + a0
* - const polyveck *v: pointer to input vector
**************************************************/
void PQCLEAN_DILITHIUMIII_CLEAN_polyveck_decompose(polyveck *v1, polyveck *v0,
const polyveck *v) {
unsigned int i;

for (i = 0; i < K; ++i) {
PQCLEAN_DILITHIUMIII_CLEAN_poly_decompose(v1->vec + i, v0->vec + i,
v->vec + i);
}
}

/*************************************************
* Name: polyveck_make_hint
*
* Description: Compute hint vector.
*
* Arguments: - polyveck *h: pointer to output vector
* - const polyveck *u: pointer to first input vector
* - const polyveck *u: pointer to second input vector
*
* Returns number of 1 bits.
**************************************************/
unsigned int PQCLEAN_DILITHIUMIII_CLEAN_polyveck_make_hint(polyveck *h,
const polyveck *u,
const polyveck *v) {
unsigned int i, s = 0;

for (i = 0; i < K; ++i) {
s += PQCLEAN_DILITHIUMIII_CLEAN_poly_make_hint(h->vec + i, u->vec + i,
v->vec + i);
}

return s;
}

/*************************************************
* Name: polyveck_use_hint
*
* Description: Use hint vector to correct the high bits of input vector.
*
* Arguments: - polyveck *w: pointer to output vector of polynomials with
* corrected high bits
* - const polyveck *u: pointer to input vector
* - const polyveck *h: pointer to input hint vector
**************************************************/
void PQCLEAN_DILITHIUMIII_CLEAN_polyveck_use_hint(polyveck *w, const polyveck *u,
const polyveck *h) {
unsigned int i;

for (i = 0; i < K; ++i) {
PQCLEAN_DILITHIUMIII_CLEAN_poly_use_hint(w->vec + i, u->vec + i, h->vec + i);
}
}

+ 0
- 54
crypto_sign/dilithium-iii/clean/polyvec.h Просмотреть файл

@@ -1,54 +0,0 @@
#ifndef POLYVEC_H
#define POLYVEC_H

#include "params.h"
#include "poly.h"
#include <stdint.h>

/* Vectors of polynomials of length L */
typedef struct {
poly vec[L];
} polyvecl;

void PQCLEAN_DILITHIUMIII_CLEAN_polyvecl_freeze(polyvecl *v);

void PQCLEAN_DILITHIUMIII_CLEAN_polyvecl_add(polyvecl *w, const polyvecl *u,
const polyvecl *v);

void PQCLEAN_DILITHIUMIII_CLEAN_polyvecl_ntt(polyvecl *v);
void PQCLEAN_DILITHIUMIII_CLEAN_polyvecl_pointwise_acc_invmontgomery(
poly *w, const polyvecl *u, const polyvecl *v);

int PQCLEAN_DILITHIUMIII_CLEAN_polyvecl_chknorm(const polyvecl *v, uint32_t bound);

/* Vectors of polynomials of length K */
typedef struct {
poly vec[K];
} polyveck;

void PQCLEAN_DILITHIUMIII_CLEAN_polyveck_reduce(polyveck *v);
void PQCLEAN_DILITHIUMIII_CLEAN_polyveck_csubq(polyveck *v);
void PQCLEAN_DILITHIUMIII_CLEAN_polyveck_freeze(polyveck *v);

void PQCLEAN_DILITHIUMIII_CLEAN_polyveck_add(polyveck *w, const polyveck *u,
const polyveck *v);
void PQCLEAN_DILITHIUMIII_CLEAN_polyveck_sub(polyveck *w, const polyveck *u,
const polyveck *v);
void PQCLEAN_DILITHIUMIII_CLEAN_polyveck_shiftl(polyveck *v, unsigned int k);

void PQCLEAN_DILITHIUMIII_CLEAN_polyveck_ntt(polyveck *v);
void PQCLEAN_DILITHIUMIII_CLEAN_polyveck_invntt_montgomery(polyveck *v);

int PQCLEAN_DILITHIUMIII_CLEAN_polyveck_chknorm(const polyveck *v, uint32_t bound);

void PQCLEAN_DILITHIUMIII_CLEAN_polyveck_power2round(polyveck *v1, polyveck *v0,
const polyveck *v);
void PQCLEAN_DILITHIUMIII_CLEAN_polyveck_decompose(polyveck *v1, polyveck *v0,
const polyveck *v);
unsigned int PQCLEAN_DILITHIUMIII_CLEAN_polyveck_make_hint(polyveck *h,
const polyveck *u,
const polyveck *v);
void PQCLEAN_DILITHIUMIII_CLEAN_polyveck_use_hint(polyveck *w, const polyveck *u,
const polyveck *h);

#endif

+ 0
- 74
crypto_sign/dilithium-iii/clean/reduce.c Просмотреть файл

@@ -1,74 +0,0 @@
#include "reduce.h"
#include "params.h"
#include <stdint.h>

/*************************************************
* Name: montgomery_reduce
*
* Description: For finite field element a with 0 <= a <= Q*2^32,
* compute r \equiv a*2^{-32} (mod Q) such that 0 <= r < 2*Q.
*
* Arguments: - uint64_t: finite field element a
*
* Returns r.
**************************************************/
uint32_t PQCLEAN_DILITHIUMIII_CLEAN_montgomery_reduce(uint64_t a) {
uint64_t t;

t = a * QINV;
t &= (1ULL << 32) - 1;
t *= Q;
t = a + t;
t >>= 32;
return t;
}

/*************************************************
* Name: reduce32
*
* Description: For finite field element a, compute r \equiv a (mod Q)
* such that 0 <= r < 2*Q.
*
* Arguments: - uint32_t: finite field element a
*
* Returns r.
**************************************************/
uint32_t PQCLEAN_DILITHIUMIII_CLEAN_reduce32(uint32_t a) {
uint32_t t;

t = a & 0x7FFFFF;
a >>= 23;
t += (a << 13) - a;
return t;
}

/*************************************************
* Name: csubq
*
* Description: Subtract Q if input coefficient is bigger than Q.
*
* Arguments: - uint32_t: finite field element a
*
* Returns r.
**************************************************/
uint32_t PQCLEAN_DILITHIUMIII_CLEAN_csubq(uint32_t a) {
a -= Q;
a += ((int32_t)a >> 31) & Q;
return a;
}

/*************************************************
* Name: freeze
*
* Description: For finite field element a, compute standard
* representative r = a mod Q.
*
* Arguments: - uint32_t: finite field element a
*
* Returns r.
**************************************************/
uint32_t PQCLEAN_DILITHIUMIII_CLEAN_freeze(uint32_t a) {
a = PQCLEAN_DILITHIUMIII_CLEAN_reduce32(a);
a = PQCLEAN_DILITHIUMIII_CLEAN_csubq(a);
return a;
}

+ 0
- 21
crypto_sign/dilithium-iii/clean/reduce.h Просмотреть файл

@@ -1,21 +0,0 @@
#ifndef REDUCE_H
#define REDUCE_H

#include <stdint.h>

#define MONT 4193792U // 2^32 % Q
#define QINV 4236238847U // -q^(-1) mod 2^32

/* a <= Q*2^32 => r < 2*Q */
uint32_t PQCLEAN_DILITHIUMIII_CLEAN_montgomery_reduce(uint64_t a);

/* r < 2*Q */
uint32_t PQCLEAN_DILITHIUMIII_CLEAN_reduce32(uint32_t a);

/* a < 2*Q => r < Q */
uint32_t PQCLEAN_DILITHIUMIII_CLEAN_csubq(uint32_t a);

/* r < Q */
uint32_t PQCLEAN_DILITHIUMIII_CLEAN_freeze(uint32_t a);

#endif

+ 0
- 119
crypto_sign/dilithium-iii/clean/rounding.c Просмотреть файл

@@ -1,119 +0,0 @@
#include "params.h"
#include <stdint.h>

/*************************************************
* Name: power2round
*
* Description: For finite field element a, compute a0, a1 such that
* a mod Q = a1*2^D + a0 with -2^{D-1} < a0 <= 2^{D-1}.
* Assumes a to be standard representative.
*
* Arguments: - uint32_t a: input element
* - uint32_t *a0: pointer to output element Q + a0
*
* Returns a1.
**************************************************/
uint32_t PQCLEAN_DILITHIUMIII_CLEAN_power2round(uint32_t a, uint32_t *a0) {
int32_t t;

/* Centralized remainder mod 2^D */
t = a & ((1 << D) - 1);
t -= (1 << (D - 1)) + 1;
t += (t >> 31) & (1 << D);
t -= (1 << (D - 1)) - 1;
*a0 = Q + t;
a = (a - t) >> D;
return a;
}

/*************************************************
* Name: decompose
*
* Description: For finite field element a, compute high and low bits a0, a1
*such that a mod Q = a1*ALPHA + a0 with -ALPHA/2 < a0 <= ALPHA/2 except if a1 =
*(Q-1)/ALPHA where we set a1 = 0 and -ALPHA/2 <= a0 = a mod Q - Q < 0. Assumes
*a to be standard representative.
*
* Arguments: - uint32_t a: input element
* - uint32_t *a0: pointer to output element Q + a0
*
* Returns a1.
**************************************************/
uint32_t PQCLEAN_DILITHIUMIII_CLEAN_decompose(uint32_t a, uint32_t *a0) {
#if ALPHA != (Q - 1) / 16
#error "decompose assumes ALPHA == (Q-1)/16"
#endif
int32_t t, u;

/* Centralized remainder mod ALPHA */
t = a & 0x7FFFF;
t += (a >> 19) << 9;
t -= ALPHA / 2 + 1;
t += (t >> 31) & ALPHA;
t -= ALPHA / 2 - 1;
a -= t;

/* Divide by ALPHA (possible to avoid) */
u = a - 1;
u >>= 31;
a = (a >> 19) + 1;
a -= u & 1;

/* Border case */
*a0 = Q + t - (a >> 4);
a &= 0xF;
return a;
}

/*************************************************
* Name: make_hint
*
* Description: Compute hint bit indicating whether or not high bits of two
* finite field elements differ. Assumes input elements to be
* standard representatives.
*
* Arguments: - uint32_t a: first input element
* - uint32_t b: second input element
*
* Returns 1 if high bits of a and b differ and 0 otherwise.
**************************************************/
unsigned int PQCLEAN_DILITHIUMIII_CLEAN_make_hint(const uint32_t a,
const uint32_t b) {
uint32_t t;

return PQCLEAN_DILITHIUMIII_CLEAN_decompose(a, &t) !=
PQCLEAN_DILITHIUMIII_CLEAN_decompose(b, &t);
}

/*************************************************
* Name: use_hint
*
* Description: Correct high bits according to hint.
*
* Arguments: - uint32_t a: input element
* - unsigned int hint: hint bit
*
* Returns corrected high bits.
**************************************************/
uint32_t PQCLEAN_DILITHIUMIII_CLEAN_use_hint(const uint32_t a,
const unsigned int hint) {
uint32_t a0, a1;

a1 = PQCLEAN_DILITHIUMIII_CLEAN_decompose(a, &a0);
if (hint == 0) {
return a1;
}
if (a0 > Q) {
return (a1 + 1) & 0xF;
}
return (a1 - 1) & 0xF;

/* If decompose does not divide out ALPHA:
if(hint == 0)
return a1;
else if(a0 > Q)
return (a1 + ALPHA) % (Q - 1);
else
return (a1 - ALPHA) % (Q - 1);
*/
}

+ 0
- 11
crypto_sign/dilithium-iii/clean/rounding.h Просмотреть файл

@@ -1,11 +0,0 @@
#ifndef ROUNDING_H
#define ROUNDING_H

#include <stdint.h>

uint32_t PQCLEAN_DILITHIUMIII_CLEAN_power2round(uint32_t a, uint32_t *a0);
uint32_t PQCLEAN_DILITHIUMIII_CLEAN_decompose(uint32_t a, uint32_t *a0);
unsigned int PQCLEAN_DILITHIUMIII_CLEAN_make_hint(uint32_t a, uint32_t b);
uint32_t PQCLEAN_DILITHIUMIII_CLEAN_use_hint(uint32_t a, unsigned int hint);

#endif

+ 0
- 402
crypto_sign/dilithium-iii/clean/sign.c Просмотреть файл

@@ -1,402 +0,0 @@
#include "sign.h"
#include "fips202.h"
#include "packing.h"
#include "params.h"
#include "poly.h"
#include "polyvec.h"
#include "randombytes.h"
#include <stdint.h>

/*************************************************
* Name: expand_mat
*
* Description: Implementation of ExpandA. Generates matrix A with uniformly
* random coefficients a_{i,j} by performing rejection
* sampling on the output stream of SHAKE128(rho|i|j).
*
* Arguments: - polyvecl mat[K]: output matrix
* - const unsigned char rho[]: byte array containing seed rho
**************************************************/
void PQCLEAN_DILITHIUMIII_CLEAN_expand_mat(polyvecl mat[K],
const unsigned char rho[SEEDBYTES]) {
unsigned int i, j;
unsigned char inbuf[SEEDBYTES + 1];
/* Don't change this to smaller values,
* sampling later assumes sufficient SHAKE output!
* Probability that we need more than 5 blocks: < 2^{-132}.
* Probability that we need more than 6 blocks: < 2^{-546}. */
unsigned char outbuf[5 * SHAKE128_RATE];

for (i = 0; i < SEEDBYTES; ++i) {
inbuf[i] = rho[i];
}

for (i = 0; i < K; ++i) {
for (j = 0; j < L; ++j) {
inbuf[SEEDBYTES] = i + (j << 4);
shake128(outbuf, sizeof(outbuf), inbuf, SEEDBYTES + 1);
PQCLEAN_DILITHIUMIII_CLEAN_poly_uniform(mat[i].vec + j, outbuf);
}
}
}

/*************************************************
* Name: challenge
*
* Description: Implementation of H. Samples polynomial with 60 nonzero
* coefficients in {-1,1} using the output stream of
* SHAKE256(mu|w1).
*
* Arguments: - poly *c: pointer to output polynomial
* - const unsigned char mu[]: byte array containing mu
* - const polyveck *w1: pointer to vector w1
**************************************************/
void PQCLEAN_DILITHIUMIII_CLEAN_challenge(poly *c, const unsigned char mu[CRHBYTES],
const polyveck *w1) {
unsigned int i, b, pos;
unsigned char inbuf[CRHBYTES + K * POLW1_SIZE_PACKED];
unsigned char outbuf[SHAKE256_RATE];
uint64_t state[25], signs, mask;

for (i = 0; i < CRHBYTES; ++i) {
inbuf[i] = mu[i];
}
for (i = 0; i < K; ++i) {
PQCLEAN_DILITHIUMIII_CLEAN_polyw1_pack(
inbuf + CRHBYTES + i * POLW1_SIZE_PACKED, w1->vec + i);
}

shake256_absorb(state, inbuf, sizeof(inbuf));
shake256_squeezeblocks(outbuf, 1, state);

signs = 0;
for (i = 0; i < 8; ++i) {
signs |= (uint64_t)outbuf[i] << 8 * i;
}

pos = 8;
mask = 1;

for (i = 0; i < N; ++i) {
c->coeffs[i] = 0;
}

for (i = 196; i < 256; ++i) {
do {
if (pos >= SHAKE256_RATE) {
shake256_squeezeblocks(outbuf, 1, state);
pos = 0;
}

b = outbuf[pos++];
} while (b > i);

c->coeffs[i] = c->coeffs[b];
c->coeffs[b] = (signs & mask) ? Q - 1 : 1;
mask <<= 1;
}
}

/*************************************************
* Name: crypto_sign_keypair
*
* Description: Generates public and private key.
*
* Arguments: - uint8_t *pk: pointer to output public key (allocated
* array of CRYPTO_PUBLICKEYBYTES bytes)
* - uint8_t *sk: pointer to output private key (allocated
* array of CRYPTO_SECRETKEYBYTES bytes)
*
* Returns 0 (success)
**************************************************/
int PQCLEAN_DILITHIUMIII_CLEAN_crypto_sign_keypair(uint8_t *pk,
uint8_t *sk) {
unsigned int i;
unsigned char seedbuf[3 * SEEDBYTES];
unsigned char tr[CRHBYTES];
unsigned char *rho, *rhoprime, *key;
uint16_t nonce = 0;
polyvecl mat[K];
polyvecl s1, s1hat;
polyveck s2, t, t1, t0;

/* Expand 32 bytes of randomness into rho, rhoprime and key */
randombytes(seedbuf, SEEDBYTES);
shake256(seedbuf, 3 * SEEDBYTES, seedbuf, SEEDBYTES);
rho = seedbuf;
rhoprime = rho + SEEDBYTES;
key = rho + 2 * SEEDBYTES;

/* Expand matrix */
PQCLEAN_DILITHIUMIII_CLEAN_expand_mat(mat, rho);

/* Sample short vectors s1 and s2 */
for (i = 0; i < L; ++i) {
PQCLEAN_DILITHIUMIII_CLEAN_poly_uniform_eta(s1.vec + i, rhoprime, nonce++);
}
for (i = 0; i < K; ++i) {
PQCLEAN_DILITHIUMIII_CLEAN_poly_uniform_eta(s2.vec + i, rhoprime, nonce++);
}

/* Matrix-vector multiplication */
s1hat = s1;
PQCLEAN_DILITHIUMIII_CLEAN_polyvecl_ntt(&s1hat);
for (i = 0; i < K; ++i) {
PQCLEAN_DILITHIUMIII_CLEAN_polyvecl_pointwise_acc_invmontgomery(
t.vec + i, mat + i, &s1hat);
PQCLEAN_DILITHIUMIII_CLEAN_poly_reduce(t.vec + i);
PQCLEAN_DILITHIUMIII_CLEAN_poly_invntt_montgomery(t.vec + i);
}

/* Add noise vector s2 */
PQCLEAN_DILITHIUMIII_CLEAN_polyveck_add(&t, &t, &s2);

/* Extract t1 and write public key */
PQCLEAN_DILITHIUMIII_CLEAN_polyveck_freeze(&t);
PQCLEAN_DILITHIUMIII_CLEAN_polyveck_power2round(&t1, &t0, &t);
PQCLEAN_DILITHIUMIII_CLEAN_pack_pk(pk, rho, &t1);

/* Compute CRH(rho, t1) and write secret key */
shake256(tr, CRHBYTES, pk, CRYPTO_PUBLICKEYBYTES);
PQCLEAN_DILITHIUMIII_CLEAN_pack_sk(sk, rho, key, tr, &s1, &s2, &t0);

return 0;
}

/*************************************************
* Name: crypto_sign
*
* Description: Compute signed message.
*
* Arguments: - uint8_t *sm: pointer to output signed message (allocated
* array with CRYPTO_BYTES + mlen bytes),
* can be equal to m
* - size_t *smlen: pointer to output length of signed
* message
* - const uint8_t *m: pointer to message to be signed
* - size_t mlen: length of message
* - const uint8_t *sk: pointer to bit-packed secret key
*
* Returns 0 (success)
**************************************************/
int PQCLEAN_DILITHIUMIII_CLEAN_crypto_sign(uint8_t *sm,
size_t *smlen,
const uint8_t *m,
size_t mlen,
const uint8_t *sk) {
unsigned long long i, j;
unsigned int n;
unsigned char seedbuf[2 * SEEDBYTES + CRHBYTES]; // TODO(thom): nonce in seedbuf (2x)
unsigned char tr[CRHBYTES];
unsigned char *rho, *key, *mu;
uint16_t nonce = 0;
poly c, chat;
polyvecl mat[K], s1, y, yhat, z;
polyveck s2, t0, w, w1;
polyveck h, wcs2, wcs20, ct0, tmp;

rho = seedbuf;
key = seedbuf + SEEDBYTES;
mu = seedbuf + 2 * SEEDBYTES;
PQCLEAN_DILITHIUMIII_CLEAN_unpack_sk(rho, key, tr, &s1, &s2, &t0, sk);

/* Copy tr and message into the sm buffer,
* backwards since m and sm can be equal in SUPERCOP API */
for (i = 1; i <= mlen; ++i) {
sm[CRYPTO_BYTES + mlen - i] = m[mlen - i];
}
for (i = 0; i < CRHBYTES; ++i) {
sm[CRYPTO_BYTES - CRHBYTES + i] = tr[i];
}

/* Compute CRH(tr, msg) */
shake256(mu, CRHBYTES, sm + CRYPTO_BYTES - CRHBYTES, CRHBYTES + mlen);

/* Expand matrix and transform vectors */
PQCLEAN_DILITHIUMIII_CLEAN_expand_mat(mat, rho);
PQCLEAN_DILITHIUMIII_CLEAN_polyvecl_ntt(&s1);
PQCLEAN_DILITHIUMIII_CLEAN_polyveck_ntt(&s2);
PQCLEAN_DILITHIUMIII_CLEAN_polyveck_ntt(&t0);

rej:
/* Sample intermediate vector y */
for (i = 0; i < L; ++i) {
PQCLEAN_DILITHIUMIII_CLEAN_poly_uniform_gamma1m1(y.vec + i, key, nonce++);
}

/* Matrix-vector multiplication */
yhat = y;
PQCLEAN_DILITHIUMIII_CLEAN_polyvecl_ntt(&yhat);
for (i = 0; i < K; ++i) {
PQCLEAN_DILITHIUMIII_CLEAN_polyvecl_pointwise_acc_invmontgomery(
w.vec + i, mat + i, &yhat);
PQCLEAN_DILITHIUMIII_CLEAN_poly_reduce(w.vec + i);
PQCLEAN_DILITHIUMIII_CLEAN_poly_invntt_montgomery(w.vec + i);
}

/* Decompose w and call the random oracle */
PQCLEAN_DILITHIUMIII_CLEAN_polyveck_csubq(&w);
PQCLEAN_DILITHIUMIII_CLEAN_polyveck_decompose(&w1, &tmp, &w);
PQCLEAN_DILITHIUMIII_CLEAN_challenge(&c, mu, &w1);

/* Compute z, reject if it reveals secret */
chat = c;
PQCLEAN_DILITHIUMIII_CLEAN_poly_ntt(&chat);
for (i = 0; i < L; ++i) {
PQCLEAN_DILITHIUMIII_CLEAN_poly_pointwise_invmontgomery(z.vec + i, &chat,
s1.vec + i);
PQCLEAN_DILITHIUMIII_CLEAN_poly_invntt_montgomery(z.vec + i);
}
PQCLEAN_DILITHIUMIII_CLEAN_polyvecl_add(&z, &z, &y);
PQCLEAN_DILITHIUMIII_CLEAN_polyvecl_freeze(&z);
if (PQCLEAN_DILITHIUMIII_CLEAN_polyvecl_chknorm(&z, GAMMA1 - BETA)) {
goto rej;
}

/* Compute w - cs2, reject if w1 can not be computed from it */
for (i = 0; i < K; ++i) {
PQCLEAN_DILITHIUMIII_CLEAN_poly_pointwise_invmontgomery(wcs2.vec + i, &chat,
s2.vec + i);
PQCLEAN_DILITHIUMIII_CLEAN_poly_invntt_montgomery(wcs2.vec + i);
}
PQCLEAN_DILITHIUMIII_CLEAN_polyveck_sub(&wcs2, &w, &wcs2);
PQCLEAN_DILITHIUMIII_CLEAN_polyveck_freeze(&wcs2);
PQCLEAN_DILITHIUMIII_CLEAN_polyveck_decompose(&tmp, &wcs20, &wcs2);
PQCLEAN_DILITHIUMIII_CLEAN_polyveck_csubq(&wcs20);
if (PQCLEAN_DILITHIUMIII_CLEAN_polyveck_chknorm(&wcs20, GAMMA2 - BETA)) {
goto rej;
}

for (i = 0; i < K; ++i) {
for (j = 0; j < N; ++j) {
if (tmp.vec[i].coeffs[j] != w1.vec[i].coeffs[j]) {
goto rej;
}
}
}

/* Compute hints for w1 */
for (i = 0; i < K; ++i) {
PQCLEAN_DILITHIUMIII_CLEAN_poly_pointwise_invmontgomery(ct0.vec + i, &chat,
t0.vec + i);
PQCLEAN_DILITHIUMIII_CLEAN_poly_invntt_montgomery(ct0.vec + i);
}

PQCLEAN_DILITHIUMIII_CLEAN_polyveck_csubq(&ct0);
if (PQCLEAN_DILITHIUMIII_CLEAN_polyveck_chknorm(&ct0, GAMMA2)) {
goto rej;
}

PQCLEAN_DILITHIUMIII_CLEAN_polyveck_add(&tmp, &wcs2, &ct0);
PQCLEAN_DILITHIUMIII_CLEAN_polyveck_csubq(&tmp);
n = PQCLEAN_DILITHIUMIII_CLEAN_polyveck_make_hint(&h, &wcs2, &tmp);
if (n > OMEGA) {
goto rej;
}

/* Write signature */
PQCLEAN_DILITHIUMIII_CLEAN_pack_sig(sm, &z, &h, &c);

*smlen = mlen + CRYPTO_BYTES;
return 0;
}

/*************************************************
* Name: crypto_sign_open
*
* Description: Verify signed message.
*
* Arguments: - uint8_t *m: pointer to output message (allocated
* array with smlen bytes), can be equal to sm
* - size_t *mlen: pointer to output length of message
* - const uint8_t *sm: pointer to signed message
* - size_t smlen: length of signed message
* - const uint8_t *sk: pointer to bit-packed public key
*
* Returns 0 if signed message could be verified correctly and -1 otherwise
**************************************************/
int PQCLEAN_DILITHIUMIII_CLEAN_crypto_sign_open(uint8_t *m,
size_t *mlen,
const uint8_t *sm,
size_t smlen,
const uint8_t *pk) {
unsigned long long i;
unsigned char rho[SEEDBYTES];
unsigned char mu[CRHBYTES];
poly c, chat, cp;
polyvecl mat[K], z;
polyveck t1, w1, h, tmp1, tmp2;

if (smlen < CRYPTO_BYTES) {
goto badsig;
}

*mlen = smlen - CRYPTO_BYTES;

PQCLEAN_DILITHIUMIII_CLEAN_unpack_pk(rho, &t1, pk);
if (PQCLEAN_DILITHIUMIII_CLEAN_unpack_sig(&z, &h, &c, sm)) {
goto badsig;
}
if (PQCLEAN_DILITHIUMIII_CLEAN_polyvecl_chknorm(&z, GAMMA1 - BETA)) {
goto badsig;
}

/* Compute CRH(CRH(rho, t1), msg) using m as "playground" buffer */
if (sm != m) {
for (i = 0; i < *mlen; ++i) {
m[CRYPTO_BYTES + i] = sm[CRYPTO_BYTES + i];
}
}

shake256(m + CRYPTO_BYTES - CRHBYTES, CRHBYTES, pk, CRYPTO_PUBLICKEYBYTES);
shake256(mu, CRHBYTES, m + CRYPTO_BYTES - CRHBYTES, CRHBYTES + *mlen);

/* Matrix-vector multiplication; compute Az - c2^dt1 */
PQCLEAN_DILITHIUMIII_CLEAN_expand_mat(mat, rho);
PQCLEAN_DILITHIUMIII_CLEAN_polyvecl_ntt(&z);
for (i = 0; i < K; ++i) {
PQCLEAN_DILITHIUMIII_CLEAN_polyvecl_pointwise_acc_invmontgomery(tmp1.vec + i,
mat + i, &z);
}

chat = c;
PQCLEAN_DILITHIUMIII_CLEAN_poly_ntt(&chat);
PQCLEAN_DILITHIUMIII_CLEAN_polyveck_shiftl(&t1, D);
PQCLEAN_DILITHIUMIII_CLEAN_polyveck_ntt(&t1);
for (i = 0; i < K; ++i) {
PQCLEAN_DILITHIUMIII_CLEAN_poly_pointwise_invmontgomery(tmp2.vec + i, &chat,
t1.vec + i);
}

PQCLEAN_DILITHIUMIII_CLEAN_polyveck_sub(&tmp1, &tmp1, &tmp2);
PQCLEAN_DILITHIUMIII_CLEAN_polyveck_reduce(&tmp1);
PQCLEAN_DILITHIUMIII_CLEAN_polyveck_invntt_montgomery(&tmp1);

/* Reconstruct w1 */
PQCLEAN_DILITHIUMIII_CLEAN_polyveck_csubq(&tmp1);
PQCLEAN_DILITHIUMIII_CLEAN_polyveck_use_hint(&w1, &tmp1, &h);

/* Call random oracle and verify challenge */
PQCLEAN_DILITHIUMIII_CLEAN_challenge(&cp, mu, &w1);
for (i = 0; i < N; ++i) {
if (c.coeffs[i] != cp.coeffs[i]) {
goto badsig;
}
}

/* All good, copy msg, return 0 */
for (i = 0; i < *mlen; ++i) {
m[i] = sm[CRYPTO_BYTES + i];
}

return 0;

/* Signature verification failed */
badsig:
*mlen = 0;
for (i = 0; i < smlen; ++i) {
m[i] = 0;
}

return -1;
}

+ 0
- 30
crypto_sign/dilithium-iii/clean/sign.h Просмотреть файл

@@ -1,30 +0,0 @@
#ifndef SIGN_H
#define SIGN_H
#include <stddef.h>
#include <stdint.h>

#include "params.h"
#include "poly.h"
#include "polyvec.h"

void PQCLEAN_DILITHIUMIII_CLEAN_expand_mat(polyvecl mat[K],
const uint8_t rho[SEEDBYTES]);
void PQCLEAN_DILITHIUMIII_CLEAN_challenge(poly *c, const uint8_t mu[CRHBYTES],
const polyveck *w1);

int PQCLEAN_DILITHIUMIII_CLEAN_crypto_sign_keypair(uint8_t *pk,
uint8_t *sk);

int PQCLEAN_DILITHIUMIII_CLEAN_crypto_sign(uint8_t *sm,
size_t *smlen,
const uint8_t *m,
size_t mlen,
const uint8_t *sk);

int PQCLEAN_DILITHIUMIII_CLEAN_crypto_sign_open(uint8_t *m,
size_t *mlen,
const uint8_t *sm,
size_t smlen,
const uint8_t *pk);

#endif

+ 27
- 0
crypto_sign/sphincs-shake256-128f-simple/META.yml Просмотреть файл

@@ -0,0 +1,27 @@
name: SPHINCS+
type: signature
claimed-nist-level: 1
length-public-key: 32
length-signature: 16976
testvectors-sha256: a14cb8e4f149493fc5979e465e09ce943e8d669186ff5c7c3d11239fa869def6
principal-submitter: Andreas Hülsing
auxiliary-submitters:
- Jean-Philippe Aumasson
- Daniel J. Bernstein,
- Christoph Dobraunig
- Maria Eichlseder
- Scott Fluhrer
- Stefan-Lukas Gazdag
- Panos Kampanakis
- Stefan Kölbl
- Tanja Lange
- Martin M. Lauridsen
- Florian Mendel
- Ruben Niederhagen
- Christian Rechberger
- Joost Rijneveld
- Peter Schwabe
implementations:
- name: clean
version: https://github.com/sphincs/sphincsplus/commit/492ec4f1f6d3b3dc4b435783bbaaf4e41cdb6f32
length-secret-key: 64

+ 116
- 0
crypto_sign/sphincs-shake256-128f-simple/clean/LICENSE Просмотреть файл

@@ -0,0 +1,116 @@
CC0 1.0 Universal

Statement of Purpose

The laws of most jurisdictions throughout the world automatically confer
exclusive Copyright and Related Rights (defined below) upon the creator and
subsequent owner(s) (each and all, an "owner") of an original work of
authorship and/or a database (each, a "Work").

Certain owners wish to permanently relinquish those rights to a Work for the
purpose of contributing to a commons of creative, cultural and scientific
works ("Commons") that the public can reliably and without fear of later
claims of infringement build upon, modify, incorporate in other works, reuse
and redistribute as freely as possible in any form whatsoever and for any
purposes, including without limitation commercial purposes. These owners may
contribute to the Commons to promote the ideal of a free culture and the
further production of creative, cultural and scientific works, or to gain
reputation or greater distribution for their Work in part through the use and
efforts of others.

For these and/or other purposes and motivations, and without any expectation
of additional consideration or compensation, the person associating CC0 with a
Work (the "Affirmer"), to the extent that he or she is an owner of Copyright
and Related Rights in the Work, voluntarily elects to apply CC0 to the Work
and publicly distribute the Work under its terms, with knowledge of his or her
Copyright and Related Rights in the Work and the meaning and intended legal
effect of CC0 on those rights.

1. Copyright and Related Rights. A Work made available under CC0 may be
protected by copyright and related or neighboring rights ("Copyright and
Related Rights"). Copyright and Related Rights include, but are not limited
to, the following:

i. the right to reproduce, adapt, distribute, perform, display, communicate,
and translate a Work;

ii. moral rights retained by the original author(s) and/or performer(s);

iii. publicity and privacy rights pertaining to a person's image or likeness
depicted in a Work;

iv. rights protecting against unfair competition in regards to a Work,
subject to the limitations in paragraph 4(a), below;

v. rights protecting the extraction, dissemination, use and reuse of data in
a Work;

vi. database rights (such as those arising under Directive 96/9/EC of the
European Parliament and of the Council of 11 March 1996 on the legal
protection of databases, and under any national implementation thereof,
including any amended or successor version of such directive); and

vii. other similar, equivalent or corresponding rights throughout the world
based on applicable law or treaty, and any national implementations thereof.

2. Waiver. To the greatest extent permitted by, but not in contravention of,
applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and
unconditionally waives, abandons, and surrenders all of Affirmer's Copyright
and Related Rights and associated claims and causes of action, whether now
known or unknown (including existing as well as future claims and causes of
action), in the Work (i) in all territories worldwide, (ii) for the maximum
duration provided by applicable law or treaty (including future time
extensions), (iii) in any current or future medium and for any number of
copies, and (iv) for any purpose whatsoever, including without limitation
commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes
the Waiver for the benefit of each member of the public at large and to the
detriment of Affirmer's heirs and successors, fully intending that such Waiver
shall not be subject to revocation, rescission, cancellation, termination, or
any other legal or equitable action to disrupt the quiet enjoyment of the Work
by the public as contemplated by Affirmer's express Statement of Purpose.

3. Public License Fallback. Should any part of the Waiver for any reason be
judged legally invalid or ineffective under applicable law, then the Waiver
shall be preserved to the maximum extent permitted taking into account
Affirmer's express Statement of Purpose. In addition, to the extent the Waiver
is so judged Affirmer hereby grants to each affected person a royalty-free,
non transferable, non sublicensable, non exclusive, irrevocable and
unconditional license to exercise Affirmer's Copyright and Related Rights in
the Work (i) in all territories worldwide, (ii) for the maximum duration
provided by applicable law or treaty (including future time extensions), (iii)
in any current or future medium and for any number of copies, and (iv) for any
purpose whatsoever, including without limitation commercial, advertising or
promotional purposes (the "License"). The License shall be deemed effective as
of the date CC0 was applied by Affirmer to the Work. Should any part of the
License for any reason be judged legally invalid or ineffective under
applicable law, such partial invalidity or ineffectiveness shall not
invalidate the remainder of the License, and in such case Affirmer hereby
affirms that he or she will not (i) exercise any of his or her remaining
Copyright and Related Rights in the Work or (ii) assert any associated claims
and causes of action with respect to the Work, in either case contrary to
Affirmer's express Statement of Purpose.

4. Limitations and Disclaimers.

a. No trademark or patent rights held by Affirmer are waived, abandoned,
surrendered, licensed or otherwise affected by this document.

b. Affirmer offers the Work as-is and makes no representations or warranties
of any kind concerning the Work, express, implied, statutory or otherwise,
including without limitation warranties of title, merchantability, fitness
for a particular purpose, non infringement, or the absence of latent or
other defects, accuracy, or the present or absence of errors, whether or not
discoverable, all to the greatest extent permissible under applicable law.

c. Affirmer disclaims responsibility for clearing rights of other persons
that may apply to the Work or any use thereof, including without limitation
any person's Copyright and Related Rights in the Work. Further, Affirmer
disclaims responsibility for obtaining any necessary consents, permissions
or other rights required for any use of the Work.

d. Affirmer understands and acknowledges that Creative Commons is not a
party to this document and has no duty or obligation with respect to this
CC0 or use of the Work.

For more information, please see
<http://creativecommons.org/publicdomain/zero/1.0/>

+ 20
- 0
crypto_sign/sphincs-shake256-128f-simple/clean/Makefile Просмотреть файл

@@ -0,0 +1,20 @@
# This Makefile can be used with GNU Make or BSD Make

LIB=libsphincs-shake256-128f-simple_clean.a

HEADERS = params.h address.h wots.h utils.h fors.h api.h hash.h thash.h
OBJECTS = address.o wots.o utils.o fors.o sign.o hash_shake256.o thash_shake256_simple.o

CFLAGS=-Wall -Wextra -Wpedantic -Werror -std=c99 -I../../../common $(EXTRAFLAGS)

all: $(LIB)

%.o: %.c $(HEADERS)
$(CC) $(CFLAGS) -c -o $@ $<

$(LIB): $(OBJECTS)
$(AR) -r $@ $(OBJECTS)

clean:
$(RM) $(OBJECTS)
$(RM) $(LIB)

crypto_sign/dilithium-iii/clean/Makefile.Microsoft_nmake → crypto_sign/sphincs-shake256-128f-simple/clean/Makefile.Microsoft_nmake Просмотреть файл

@@ -1,10 +1,10 @@
# This Makefile can be used with Microsoft Visual Studio's nmake using the command:
# nmake /f Makefile.Microsoft_nmake

LIBRARY=libdilithium-iii_clean.lib
OBJECTS=ntt.obj packing.obj poly.obj polyvec.obj reduce.obj rounding.obj sign.obj
LIBRARY=libsphincs-shake256-128f-simple_clean.lib
OBJECTS=address.obj wots.obj utils.obj fors.obj sign.obj hash_shake256.obj thash_shake256_simple.obj

CFLAGS=/nologo /I ..\..\..\common /W1 /WX # FIXME: ideally would use /W4 instead of /W1, but too many failures in Dilithium right now
CFLAGS=/nologo /I ..\..\..\common /W4 /WX

all: $(LIBRARY)


+ 77
- 0
crypto_sign/sphincs-shake256-128f-simple/clean/address.c Просмотреть файл

@@ -0,0 +1,77 @@
#include <stdint.h>

#include "params.h"
#include "utils.h"

void PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_addr_to_bytes(
unsigned char *bytes, const uint32_t addr[8]) {
int i;

for (i = 0; i < 8; i++) {
PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_ull_to_bytes(
bytes + i * 4, 4, addr[i]);
}
}

void PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_set_layer_addr(
uint32_t addr[8], uint32_t layer) {
addr[0] = layer;
}

void PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_set_tree_addr(
uint32_t addr[8], uint64_t tree) {
addr[1] = 0;
addr[2] = (uint32_t) (tree >> 32);
addr[3] = (uint32_t) tree;
}

void PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_set_type(
uint32_t addr[8], uint32_t type) {
addr[4] = type;
}

void PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_copy_subtree_addr(
uint32_t out[8], const uint32_t in[8]) {
out[0] = in[0];
out[1] = in[1];
out[2] = in[2];
out[3] = in[3];
}

/* These functions are used for OTS addresses. */

void PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_set_keypair_addr(
uint32_t addr[8], uint32_t keypair) {
addr[5] = keypair;
}

void PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_copy_keypair_addr(
uint32_t out[8], const uint32_t in[8]) {
out[0] = in[0];
out[1] = in[1];
out[2] = in[2];
out[3] = in[3];
out[5] = in[5];
}

void PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_set_chain_addr(
uint32_t addr[8], uint32_t chain) {
addr[6] = chain;
}

void PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_set_hash_addr(
uint32_t addr[8], uint32_t hash) {
addr[7] = hash;
}

/* These functions are used for all hash tree addresses (including FORS). */

void PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_set_tree_height(
uint32_t addr[8], uint32_t tree_height) {
addr[6] = tree_height;
}

void PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_set_tree_index(
uint32_t addr[8], uint32_t tree_index) {
addr[7] = tree_index;
}

+ 50
- 0
crypto_sign/sphincs-shake256-128f-simple/clean/address.h Просмотреть файл

@@ -0,0 +1,50 @@
#ifndef SPX_ADDRESS_H
#define SPX_ADDRESS_H

#include <stdint.h>

#define SPX_ADDR_TYPE_WOTS 0
#define SPX_ADDR_TYPE_WOTSPK 1
#define SPX_ADDR_TYPE_HASHTREE 2
#define SPX_ADDR_TYPE_FORSTREE 3
#define SPX_ADDR_TYPE_FORSPK 4

void PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_addr_to_bytes(
unsigned char *bytes, const uint32_t addr[8]);

void PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_set_layer_addr(
uint32_t addr[8], uint32_t layer);

void PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_set_tree_addr(
uint32_t addr[8], uint64_t tree);

void PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_set_type(
uint32_t addr[8], uint32_t type);

/* Copies the layer and tree part of one address into the other */
void PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_copy_subtree_addr(
uint32_t out[8], const uint32_t in[8]);

/* These functions are used for WOTS and FORS addresses. */

void PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_set_keypair_addr(
uint32_t addr[8], uint32_t keypair);

void PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_set_chain_addr(
uint32_t addr[8], uint32_t chain);

void PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_set_hash_addr(
uint32_t addr[8], uint32_t hash);

void PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_copy_keypair_addr(
uint32_t out[8], const uint32_t in[8]);

/* These functions are used for all hash tree addresses (including FORS). */

void PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_set_tree_height(
uint32_t addr[8], uint32_t tree_height);

void PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_set_tree_index(
uint32_t addr[8], uint32_t tree_index);

#endif

+ 78
- 0
crypto_sign/sphincs-shake256-128f-simple/clean/api.h Просмотреть файл

@@ -0,0 +1,78 @@
#ifndef PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_API_H
#define PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_API_H

#include <stddef.h>
#include <stdint.h>

#define PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_CRYPTO_ALGNAME "SPHINCS+"

#define PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_CRYPTO_SECRETKEYBYTES 64
#define PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_CRYPTO_PUBLICKEYBYTES 32
#define PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_CRYPTO_BYTES 16976
#define PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_CRYPTO_SEEDBYTES 48

/*
* Returns the length of a secret key, in bytes
*/
size_t PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_crypto_sign_secretkeybytes(void);

/*
* Returns the length of a public key, in bytes
*/
size_t PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_crypto_sign_publickeybytes(void);

/*
* Returns the length of a signature, in bytes
*/
size_t PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_crypto_sign_bytes(void);

/*
* Returns the length of the seed required to generate a key pair, in bytes
*/
size_t PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_crypto_sign_seedbytes(void);

/*
* Generates a SPHINCS+ key pair given a seed.
* Format sk: [SK_SEED || SK_PRF || PUB_SEED || root]
* Format pk: [root || PUB_SEED]
*/
int PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_crypto_sign_seed_keypair(
uint8_t *pk, uint8_t *sk, const uint8_t *seed);

/*
* Generates a SPHINCS+ key pair.
* Format sk: [SK_SEED || SK_PRF || PUB_SEED || root]
* Format pk: [root || PUB_SEED]
*/
int PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_crypto_sign_keypair(
uint8_t *pk, uint8_t *sk);

/**
* Returns an array containing a detached signature.
*/
int PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_crypto_sign_signature(
uint8_t *sig, size_t *siglen,
const uint8_t *m, size_t mlen, const uint8_t *sk);

/**
* Verifies a detached signature and message under a given public key.
*/
int PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_crypto_sign_verify(
const uint8_t *sig, size_t siglen,
const uint8_t *m, size_t mlen, const uint8_t *pk);

/**
* Returns an array containing the signature followed by the message.
*/
int PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_crypto_sign(
uint8_t *sm, size_t *smlen,
const uint8_t *m, size_t mlen, const uint8_t *sk);

/**
* Verifies a given signature-message pair under a given public key.
*/
int PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_crypto_sign_open(
uint8_t *m, size_t *mlen,
const uint8_t *sm, size_t smlen, const uint8_t *pk);

#endif

+ 164
- 0
crypto_sign/sphincs-shake256-128f-simple/clean/fors.c Просмотреть файл

@@ -0,0 +1,164 @@
#include <stdint.h>
#include <stdlib.h>
#include <string.h>

#include "address.h"
#include "fors.h"
#include "hash.h"
#include "thash.h"
#include "utils.h"

static void fors_gen_sk(unsigned char *sk, const unsigned char *sk_seed,
uint32_t fors_leaf_addr[8]) {
PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_prf_addr(
sk, sk_seed, fors_leaf_addr);
}

static void fors_sk_to_leaf(unsigned char *leaf, const unsigned char *sk,
const unsigned char *pub_seed,
uint32_t fors_leaf_addr[8]) {
PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_thash_1(
leaf, sk, pub_seed, fors_leaf_addr);
}

static void fors_gen_leaf(unsigned char *leaf, const unsigned char *sk_seed,
const unsigned char *pub_seed,
uint32_t addr_idx, const uint32_t fors_tree_addr[8]) {
uint32_t fors_leaf_addr[8] = {0};

/* Only copy the parts that must be kept in fors_leaf_addr. */
PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_copy_keypair_addr(
fors_leaf_addr, fors_tree_addr);
PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_set_type(
fors_leaf_addr, SPX_ADDR_TYPE_FORSTREE);
PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_set_tree_index(
fors_leaf_addr, addr_idx);

fors_gen_sk(leaf, sk_seed, fors_leaf_addr);
fors_sk_to_leaf(leaf, leaf, pub_seed, fors_leaf_addr);
}

/**
* Interprets m as SPX_FORS_HEIGHT-bit unsigned integers.
* Assumes m contains at least SPX_FORS_HEIGHT * SPX_FORS_TREES bits.
* Assumes indices has space for SPX_FORS_TREES integers.
*/
static void message_to_indices(uint32_t *indices, const unsigned char *m) {
unsigned int i, j;
unsigned int offset = 0;

for (i = 0; i < SPX_FORS_TREES; i++) {
indices[i] = 0;
for (j = 0; j < SPX_FORS_HEIGHT; j++) {
indices[i] ^= ((m[offset >> 3] >> (offset & 0x7)) & 0x1) << j;
offset++;
}
}
}

/**
* Signs a message m, deriving the secret key from sk_seed and the FTS address.
* Assumes m contains at least SPX_FORS_HEIGHT * SPX_FORS_TREES bits.
*/
void PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_fors_sign(
unsigned char *sig, unsigned char *pk,
const unsigned char *m,
const unsigned char *sk_seed, const unsigned char *pub_seed,
const uint32_t fors_addr[8]) {
uint32_t indices[SPX_FORS_TREES];
unsigned char roots[SPX_FORS_TREES * SPX_N];
uint32_t fors_tree_addr[8] = {0};
uint32_t fors_pk_addr[8] = {0};
uint32_t idx_offset;
unsigned int i;

PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_copy_keypair_addr(
fors_tree_addr, fors_addr);
PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_copy_keypair_addr(
fors_pk_addr, fors_addr);

PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_set_type(
fors_tree_addr, SPX_ADDR_TYPE_FORSTREE);
PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_set_type(
fors_pk_addr, SPX_ADDR_TYPE_FORSPK);

message_to_indices(indices, m);

for (i = 0; i < SPX_FORS_TREES; i++) {
idx_offset = i * (1 << SPX_FORS_HEIGHT);

PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_set_tree_height(
fors_tree_addr, 0);
PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_set_tree_index(
fors_tree_addr, indices[i] + idx_offset);

/* Include the secret key part that produces the selected leaf node. */
fors_gen_sk(sig, sk_seed, fors_tree_addr);
sig += SPX_N;

/* Compute the authentication path for this leaf node. */
PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_treehash_FORS_HEIGHT(
roots + i * SPX_N, sig, sk_seed, pub_seed,
indices[i], idx_offset, fors_gen_leaf, fors_tree_addr);
sig += SPX_N * SPX_FORS_HEIGHT;
}

/* Hash horizontally across all tree roots to derive the public key. */
PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_thash_FORS_TREES(
pk, roots, pub_seed, fors_pk_addr);
}

/**
* Derives the FORS public key from a signature.
* This can be used for verification by comparing to a known public key, or to
* subsequently verify a signature on the derived public key. The latter is the
* typical use-case when used as an FTS below an OTS in a hypertree.
* Assumes m contains at least SPX_FORS_HEIGHT * SPX_FORS_TREES bits.
*/
void PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_fors_pk_from_sig(
unsigned char *pk,
const unsigned char *sig, const unsigned char *m,
const unsigned char *pub_seed, const uint32_t fors_addr[8]) {
uint32_t indices[SPX_FORS_TREES];
unsigned char roots[SPX_FORS_TREES * SPX_N];
unsigned char leaf[SPX_N];
uint32_t fors_tree_addr[8] = {0};
uint32_t fors_pk_addr[8] = {0};
uint32_t idx_offset;
unsigned int i;

PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_copy_keypair_addr(
fors_tree_addr, fors_addr);
PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_copy_keypair_addr(
fors_pk_addr, fors_addr);

PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_set_type(
fors_tree_addr, SPX_ADDR_TYPE_FORSTREE);
PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_set_type(
fors_pk_addr, SPX_ADDR_TYPE_FORSPK);

message_to_indices(indices, m);

for (i = 0; i < SPX_FORS_TREES; i++) {
idx_offset = i * (1 << SPX_FORS_HEIGHT);

PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_set_tree_height(
fors_tree_addr, 0);
PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_set_tree_index(
fors_tree_addr, indices[i] + idx_offset);

/* Derive the leaf from the included secret key part. */
fors_sk_to_leaf(leaf, sig, pub_seed, fors_tree_addr);
sig += SPX_N;

/* Derive the corresponding root node of this tree. */
PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_compute_root(
roots + i * SPX_N, leaf, indices[i], idx_offset, sig,
SPX_FORS_HEIGHT, pub_seed, fors_tree_addr);
sig += SPX_N * SPX_FORS_HEIGHT;
}

/* Hash horizontally across all tree roots to derive the public key. */
PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_thash_FORS_TREES(
pk, roots, pub_seed, fors_pk_addr);
}

+ 30
- 0
crypto_sign/sphincs-shake256-128f-simple/clean/fors.h Просмотреть файл

@@ -0,0 +1,30 @@
#ifndef SPX_FORS_H
#define SPX_FORS_H

#include <stdint.h>

#include "params.h"

/**
* Signs a message m, deriving the secret key from sk_seed and the FTS address.
* Assumes m contains at least SPX_FORS_HEIGHT * SPX_FORS_TREES bits.
*/
void PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_fors_sign(
unsigned char *sig, unsigned char *pk,
const unsigned char *m,
const unsigned char *sk_seed, const unsigned char *pub_seed,
const uint32_t fors_addr[8]);

/**
* Derives the FORS public key from a signature.
* This can be used for verification by comparing to a known public key, or to
* subsequently verify a signature on the derived public key. The latter is the
* typical use-case when used as an FTS below an OTS in a hypertree.
* Assumes m contains at least SPX_FORS_HEIGHT * SPX_FORS_TREES bits.
*/
void PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_fors_pk_from_sig(
unsigned char *pk,
const unsigned char *sig, const unsigned char *m,
const unsigned char *pub_seed, const uint32_t fors_addr[8]);

#endif

+ 22
- 0
crypto_sign/sphincs-shake256-128f-simple/clean/hash.h Просмотреть файл

@@ -0,0 +1,22 @@
#ifndef SPX_HASH_H
#define SPX_HASH_H

#include <stdint.h>

void PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_initialize_hash_function(
const unsigned char *pub_seed, const unsigned char *sk_seed);

void PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_prf_addr(
unsigned char *out, const unsigned char *key, const uint32_t addr[8]);

void PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_gen_message_random(
unsigned char *R,
const unsigned char *sk_prf, const unsigned char *optrand,
const unsigned char *m, size_t mlen);

void PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_hash_message(
unsigned char *digest, uint64_t *tree, uint32_t *leaf_idx,
const unsigned char *R, const unsigned char *pk,
const unsigned char *m, size_t mlen);

#endif

+ 86
- 0
crypto_sign/sphincs-shake256-128f-simple/clean/hash_shake256.c Просмотреть файл

@@ -0,0 +1,86 @@
#include <stdint.h>
#include <string.h>

#include "address.h"
#include "fips202.h"
#include "hash.h"
#include "params.h"
#include "utils.h"

/* For SHAKE256, there is no immediate reason to initialize at the start,
so this function is an empty operation. */
void PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_initialize_hash_function(
const unsigned char *pub_seed, const unsigned char *sk_seed) {
(void)pub_seed; /* Suppress an 'unused parameter' warning. */
(void)sk_seed; /* Suppress an 'unused parameter' warning. */
}

/*
* Computes PRF(key, addr), given a secret key of SPX_N bytes and an address
*/
void PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_prf_addr(
unsigned char *out, const unsigned char *key, const uint32_t addr[8]) {
unsigned char buf[SPX_N + SPX_ADDR_BYTES];

memcpy(buf, key, SPX_N);
PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_addr_to_bytes(buf + SPX_N, addr);

shake256(out, SPX_N, buf, SPX_N + SPX_ADDR_BYTES);
}

/**
* Computes the message-dependent randomness R, using a secret seed and an
* optional randomization value as well as the message.
*/
void PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_gen_message_random(
unsigned char *R,
const unsigned char *sk_prf, const unsigned char *optrand,
const unsigned char *m, size_t mlen) {
uint64_t s_inc[26];

shake256_inc_init(s_inc);
shake256_inc_absorb(s_inc, sk_prf, SPX_N);
shake256_inc_absorb(s_inc, optrand, SPX_N);
shake256_inc_absorb(s_inc, m, mlen);
shake256_inc_finalize(s_inc);
shake256_inc_squeeze(R, SPX_N, s_inc);
}

/**
* Computes the message hash using R, the public key, and the message.
* Outputs the message digest and the index of the leaf. The index is split in
* the tree index and the leaf index, for convenient copying to an address.
*/
void PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_hash_message(
unsigned char *digest, uint64_t *tree, uint32_t *leaf_idx,
const unsigned char *R, const unsigned char *pk,
const unsigned char *m, size_t mlen) {
#define SPX_TREE_BITS (SPX_TREE_HEIGHT * (SPX_D - 1))
#define SPX_TREE_BYTES ((SPX_TREE_BITS + 7) / 8)
#define SPX_LEAF_BITS SPX_TREE_HEIGHT
#define SPX_LEAF_BYTES ((SPX_LEAF_BITS + 7) / 8)
#define SPX_DGST_BYTES (SPX_FORS_MSG_BYTES + SPX_TREE_BYTES + SPX_LEAF_BYTES)

unsigned char buf[SPX_DGST_BYTES];
unsigned char *bufp = buf;
uint64_t s_inc[26];

shake256_inc_init(s_inc);
shake256_inc_absorb(s_inc, R, SPX_N);
shake256_inc_absorb(s_inc, pk, SPX_PK_BYTES);
shake256_inc_absorb(s_inc, m, mlen);
shake256_inc_finalize(s_inc);
shake256_inc_squeeze(buf, SPX_DGST_BYTES, s_inc);

memcpy(digest, bufp, SPX_FORS_MSG_BYTES);
bufp += SPX_FORS_MSG_BYTES;

*tree = PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_bytes_to_ull(
bufp, SPX_TREE_BYTES);
*tree &= (~(uint64_t)0) >> (64 - SPX_TREE_BITS);
bufp += SPX_TREE_BYTES;

*leaf_idx = (uint32_t)PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_bytes_to_ull(
bufp, SPX_LEAF_BYTES);
*leaf_idx &= (~(uint32_t)0) >> (32 - SPX_LEAF_BITS);
}

+ 53
- 0
crypto_sign/sphincs-shake256-128f-simple/clean/params.h Просмотреть файл

@@ -0,0 +1,53 @@
#ifndef SPX_PARAMS_H
#define SPX_PARAMS_H

/* Hash output length in bytes. */
#define SPX_N 16
/* Height of the hypertree. */
#define SPX_FULL_HEIGHT 60
/* Number of subtree layer. */
#define SPX_D 20
/* FORS tree dimensions. */
#define SPX_FORS_HEIGHT 9
#define SPX_FORS_TREES 30
/* Winternitz parameter, */
#define SPX_WOTS_W 16

/* The hash function is defined by linking a different hash.c file, as opposed
to setting a #define constant. */

/* For clarity */
#define SPX_ADDR_BYTES 32

/* WOTS parameters. */
#define SPX_WOTS_LOGW 4

#define SPX_WOTS_LEN1 (8 * SPX_N / SPX_WOTS_LOGW)

/* SPX_WOTS_LEN2 is floor(log(len_1 * (w - 1)) / log(w)) + 1; we precompute */
#define SPX_WOTS_LEN2 3

#define SPX_WOTS_LEN (SPX_WOTS_LEN1 + SPX_WOTS_LEN2)
#define SPX_WOTS_BYTES (SPX_WOTS_LEN * SPX_N)
#define SPX_WOTS_PK_BYTES SPX_WOTS_BYTES

/* Subtree size. */
#define SPX_TREE_HEIGHT (SPX_FULL_HEIGHT / SPX_D)

/* FORS parameters. */
#define SPX_FORS_MSG_BYTES ((SPX_FORS_HEIGHT * SPX_FORS_TREES + 7) / 8)
#define SPX_FORS_BYTES ((SPX_FORS_HEIGHT + 1) * SPX_FORS_TREES * SPX_N)
#define SPX_FORS_PK_BYTES SPX_N

/* Resulting SPX sizes. */
#define SPX_BYTES (SPX_N + SPX_FORS_BYTES + SPX_D * SPX_WOTS_BYTES +\
SPX_FULL_HEIGHT * SPX_N)
#define SPX_PK_BYTES (2 * SPX_N)
#define SPX_SK_BYTES (2 * SPX_N + SPX_PK_BYTES)

/* Optionally, signing can be made non-deterministic using optrand.
This can help counter side-channel attacks that would benefit from
getting a large number of traces when the signer uses the same nodes. */
#define SPX_OPTRAND_BYTES 32

#endif

+ 344
- 0
crypto_sign/sphincs-shake256-128f-simple/clean/sign.c Просмотреть файл

@@ -0,0 +1,344 @@
#include <stddef.h>
#include <stdint.h>
#include <string.h>

#include "address.h"
#include "api.h"
#include "fors.h"
#include "hash.h"
#include "params.h"
#include "randombytes.h"
#include "thash.h"
#include "utils.h"
#include "wots.h"

/**
* Computes the leaf at a given address. First generates the WOTS key pair,
* then computes leaf by hashing horizontally.
*/
static void wots_gen_leaf(unsigned char *leaf, const unsigned char *sk_seed,
const unsigned char *pub_seed,
uint32_t addr_idx, const uint32_t tree_addr[8]) {
unsigned char pk[SPX_WOTS_BYTES];
uint32_t wots_addr[8] = {0};
uint32_t wots_pk_addr[8] = {0};

PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_set_type(
wots_addr, SPX_ADDR_TYPE_WOTS);
PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_set_type(
wots_pk_addr, SPX_ADDR_TYPE_WOTSPK);

PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_copy_subtree_addr(
wots_addr, tree_addr);
PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_set_keypair_addr(
wots_addr, addr_idx);
PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_wots_gen_pk(
pk, sk_seed, pub_seed, wots_addr);

PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_copy_keypair_addr(
wots_pk_addr, wots_addr);
PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_thash_WOTS_LEN(
leaf, pk, pub_seed, wots_pk_addr);
}

/*
* Returns the length of a secret key, in bytes
*/
size_t PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_crypto_sign_secretkeybytes(void) {
return PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_CRYPTO_SECRETKEYBYTES;
}

/*
* Returns the length of a public key, in bytes
*/
size_t PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_crypto_sign_publickeybytes(void) {
return PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_CRYPTO_PUBLICKEYBYTES;
}

/*
* Returns the length of a signature, in bytes
*/
size_t PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_crypto_sign_bytes(void) {
return PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_CRYPTO_BYTES;
}

/*
* Returns the length of the seed required to generate a key pair, in bytes
*/
size_t PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_crypto_sign_seedbytes(void) {
return PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_CRYPTO_SEEDBYTES;
}

/*
* Generates an SPX key pair given a seed of length
* Format sk: [SK_SEED || SK_PRF || PUB_SEED || root]
* Format pk: [PUB_SEED || root]
*/
int PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_crypto_sign_seed_keypair(
uint8_t *pk, uint8_t *sk, const uint8_t *seed) {
/* We do not need the auth path in key generation, but it simplifies the
code to have just one treehash routine that computes both root and path
in one function. */
unsigned char auth_path[SPX_TREE_HEIGHT * SPX_N];
uint32_t top_tree_addr[8] = {0};

PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_set_layer_addr(
top_tree_addr, SPX_D - 1);
PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_set_type(
top_tree_addr, SPX_ADDR_TYPE_HASHTREE);

/* Initialize SK_SEED, SK_PRF and PUB_SEED from seed. */
memcpy(sk, seed, PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_CRYPTO_SEEDBYTES);

memcpy(pk, sk + 2 * SPX_N, SPX_N);

/* This hook allows the hash function instantiation to do whatever
preparation or computation it needs, based on the public seed. */
PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_initialize_hash_function(pk, sk);

/* Compute root node of the top-most subtree. */
PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_treehash_TREE_HEIGHT(
sk + 3 * SPX_N, auth_path, sk, sk + 2 * SPX_N, 0, 0,
wots_gen_leaf, top_tree_addr);

memcpy(pk + SPX_N, sk + 3 * SPX_N, SPX_N);

return 0;
}

/*
* Generates an SPX key pair.
* Format sk: [SK_SEED || SK_PRF || PUB_SEED || root]
* Format pk: [PUB_SEED || root]
*/
int PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_crypto_sign_keypair(
uint8_t *pk, uint8_t *sk) {
unsigned char seed[PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_CRYPTO_SEEDBYTES];
randombytes(seed, PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_CRYPTO_SEEDBYTES);
PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_crypto_sign_seed_keypair(
pk, sk, seed);

return 0;
}

/**
* Returns an array containing a detached signature.
*/
int PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_crypto_sign_signature(
uint8_t *sig, size_t *siglen,
const uint8_t *m, size_t mlen, const uint8_t *sk) {
const unsigned char *sk_seed = sk;
const unsigned char *sk_prf = sk + SPX_N;
const unsigned char *pk = sk + 2 * SPX_N;
const unsigned char *pub_seed = pk;

unsigned char optrand[SPX_N];
unsigned char mhash[SPX_FORS_MSG_BYTES];
unsigned char root[SPX_N];
uint32_t i;
uint64_t tree;
uint32_t idx_leaf;
uint32_t wots_addr[8] = {0};
uint32_t tree_addr[8] = {0};

/* This hook allows the hash function instantiation to do whatever
preparation or computation it needs, based on the public seed. */
PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_initialize_hash_function(
pub_seed, sk_seed);

PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_set_type(
wots_addr, SPX_ADDR_TYPE_WOTS);
PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_set_type(
tree_addr, SPX_ADDR_TYPE_HASHTREE);

/* Optionally, signing can be made non-deterministic using optrand.
This can help counter side-channel attacks that would benefit from
getting a large number of traces when the signer uses the same nodes. */
randombytes(optrand, SPX_N);
/* Compute the digest randomization value. */
PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_gen_message_random(
sig, sk_prf, optrand, m, mlen);

/* Derive the message digest and leaf index from R, PK and M. */
PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_hash_message(
mhash, &tree, &idx_leaf, sig, pk, m, mlen);
sig += SPX_N;

PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_set_tree_addr(wots_addr, tree);
PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_set_keypair_addr(
wots_addr, idx_leaf);

/* Sign the message hash using FORS. */
PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_fors_sign(
sig, root, mhash, sk_seed, pub_seed, wots_addr);
sig += SPX_FORS_BYTES;

for (i = 0; i < SPX_D; i++) {
PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_set_layer_addr(tree_addr, i);
PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_set_tree_addr(tree_addr, tree);

PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_copy_subtree_addr(
wots_addr, tree_addr);
PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_set_keypair_addr(
wots_addr, idx_leaf);

/* Compute a WOTS signature. */
PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_wots_sign(
sig, root, sk_seed, pub_seed, wots_addr);
sig += SPX_WOTS_BYTES;

/* Compute the authentication path for the used WOTS leaf. */
PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_treehash_TREE_HEIGHT(
root, sig, sk_seed, pub_seed, idx_leaf, 0,
wots_gen_leaf, tree_addr);
sig += SPX_TREE_HEIGHT * SPX_N;

/* Update the indices for the next layer. */
idx_leaf = (tree & ((1 << SPX_TREE_HEIGHT) - 1));
tree = tree >> SPX_TREE_HEIGHT;
}

*siglen = SPX_BYTES;

return 0;
}

/**
* Verifies a detached signature and message under a given public key.
*/
int PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_crypto_sign_verify(
const uint8_t *sig, size_t siglen,
const uint8_t *m, size_t mlen, const uint8_t *pk) {
const unsigned char *pub_seed = pk;
const unsigned char *pub_root = pk + SPX_N;
unsigned char mhash[SPX_FORS_MSG_BYTES];
unsigned char wots_pk[SPX_WOTS_BYTES];
unsigned char root[SPX_N];
unsigned char leaf[SPX_N];
unsigned int i;
uint64_t tree;
uint32_t idx_leaf;
uint32_t wots_addr[8] = {0};
uint32_t tree_addr[8] = {0};
uint32_t wots_pk_addr[8] = {0};

if (siglen != SPX_BYTES) {
return -1;
}

/* This hook allows the hash function instantiation to do whatever
preparation or computation it needs, based on the public seed. */
PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_initialize_hash_function(
pub_seed, NULL);

PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_set_type(
wots_addr, SPX_ADDR_TYPE_WOTS);
PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_set_type(
tree_addr, SPX_ADDR_TYPE_HASHTREE);
PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_set_type(
wots_pk_addr, SPX_ADDR_TYPE_WOTSPK);

/* Derive the message digest and leaf index from R || PK || M. */
/* The additional SPX_N is a result of the hash domain separator. */
PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_hash_message(
mhash, &tree, &idx_leaf, sig, pk, m, mlen);
sig += SPX_N;

/* Layer correctly defaults to 0, so no need to set_layer_addr */
PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_set_tree_addr(wots_addr, tree);
PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_set_keypair_addr(
wots_addr, idx_leaf);

PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_fors_pk_from_sig(
root, sig, mhash, pub_seed, wots_addr);
sig += SPX_FORS_BYTES;

/* For each subtree.. */
for (i = 0; i < SPX_D; i++) {
PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_set_layer_addr(tree_addr, i);
PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_set_tree_addr(tree_addr, tree);

PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_copy_subtree_addr(
wots_addr, tree_addr);
PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_set_keypair_addr(
wots_addr, idx_leaf);

PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_copy_keypair_addr(
wots_pk_addr, wots_addr);

/* The WOTS public key is only correct if the signature was correct. */
/* Initially, root is the FORS pk, but on subsequent iterations it is
the root of the subtree below the currently processed subtree. */
PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_wots_pk_from_sig(
wots_pk, sig, root, pub_seed, wots_addr);
sig += SPX_WOTS_BYTES;

/* Compute the leaf node using the WOTS public key. */
PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_thash_WOTS_LEN(
leaf, wots_pk, pub_seed, wots_pk_addr);

/* Compute the root node of this subtree. */
PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_compute_root(
root, leaf, idx_leaf, 0, sig, SPX_TREE_HEIGHT,
pub_seed, tree_addr);
sig += SPX_TREE_HEIGHT * SPX_N;

/* Update the indices for the next layer. */
idx_leaf = (tree & ((1 << SPX_TREE_HEIGHT) - 1));
tree = tree >> SPX_TREE_HEIGHT;
}

/* Check if the root node equals the root node in the public key. */
if (memcmp(root, pub_root, SPX_N) != 0) {
return -1;
}

return 0;
}


/**
* Returns an array containing the signature followed by the message.
*/
int PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_crypto_sign(
uint8_t *sm, size_t *smlen,
const uint8_t *m, size_t mlen, const uint8_t *sk) {
size_t siglen;

PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_crypto_sign_signature(
sm, &siglen, m, mlen, sk);

memmove(sm + SPX_BYTES, m, mlen);
*smlen = siglen + mlen;

return 0;
}

/**
* Verifies a given signature-message pair under a given public key.
*/
int PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_crypto_sign_open(
uint8_t *m, size_t *mlen,
const uint8_t *sm, size_t smlen, const uint8_t *pk) {
/* The API caller does not necessarily know what size a signature should be
but SPHINCS+ signatures are always exactly SPX_BYTES. */
if (smlen < SPX_BYTES) {
memset(m, 0, smlen);
*mlen = 0;
return -1;
}

*mlen = smlen - SPX_BYTES;

if (PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_crypto_sign_verify(
sm, SPX_BYTES, sm + SPX_BYTES, *mlen, pk)) {
memset(m, 0, smlen);
*mlen = 0;
return -1;
}

/* If verification was successful, move the message to the right place. */
memmove(m, sm + SPX_BYTES, *mlen);

return 0;
}

+ 22
- 0
crypto_sign/sphincs-shake256-128f-simple/clean/thash.h Просмотреть файл

@@ -0,0 +1,22 @@
#ifndef SPX_THASH_H
#define SPX_THASH_H

#include <stdint.h>

void PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_thash_1(
unsigned char *out, const unsigned char *in,
const unsigned char *pub_seed, uint32_t addr[8]);

void PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_thash_2(
unsigned char *out, const unsigned char *in,
const unsigned char *pub_seed, uint32_t addr[8]);

void PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_thash_WOTS_LEN(
unsigned char *out, const unsigned char *in,
const unsigned char *pub_seed, uint32_t addr[8]);

void PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_thash_FORS_TREES(
unsigned char *out, const unsigned char *in,
const unsigned char *pub_seed, uint32_t addr[8]);

#endif

+ 61
- 0
crypto_sign/sphincs-shake256-128f-simple/clean/thash_shake256_simple.c Просмотреть файл

@@ -0,0 +1,61 @@
#include <stdint.h>
#include <string.h>

#include "thash.h"
#include "address.h"
#include "params.h"

#include "fips202.h"

/**
* Takes an array of inblocks concatenated arrays of SPX_N bytes.
*/
static void PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_thash(
unsigned char *out, unsigned char *buf,
const unsigned char *in, unsigned int inblocks,
const unsigned char *pub_seed, uint32_t addr[8]) {

memcpy(buf, pub_seed, SPX_N);
PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_addr_to_bytes(buf + SPX_N, addr);
memcpy(buf + SPX_N + SPX_ADDR_BYTES, in, inblocks * SPX_N);

shake256(out, SPX_N, buf, SPX_N + SPX_ADDR_BYTES + inblocks * SPX_N);
}

/* The wrappers below ensure that we use fixed-size buffers on the stack */

void PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_thash_1(
unsigned char *out, const unsigned char *in,
const unsigned char *pub_seed, uint32_t addr[8]) {

unsigned char buf[SPX_N + SPX_ADDR_BYTES + 1 * SPX_N];
PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_thash(
out, buf, in, 1, pub_seed, addr);
}

void PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_thash_2(
unsigned char *out, const unsigned char *in,
const unsigned char *pub_seed, uint32_t addr[8]) {

unsigned char buf[SPX_N + SPX_ADDR_BYTES + 2 * SPX_N];
PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_thash(
out, buf, in, 2, pub_seed, addr);
}

void PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_thash_WOTS_LEN(
unsigned char *out, const unsigned char *in,
const unsigned char *pub_seed, uint32_t addr[8]) {

unsigned char buf[SPX_N + SPX_ADDR_BYTES + SPX_WOTS_LEN * SPX_N];
PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_thash(
out, buf, in, SPX_WOTS_LEN, pub_seed, addr);
}

void PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_thash_FORS_TREES(
unsigned char *out, const unsigned char *in,
const unsigned char *pub_seed, uint32_t addr[8]) {

unsigned char buf[SPX_N + SPX_ADDR_BYTES + SPX_FORS_TREES * SPX_N];
PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_thash(
out, buf, in, SPX_FORS_TREES, pub_seed, addr);
}

+ 192
- 0
crypto_sign/sphincs-shake256-128f-simple/clean/utils.c Просмотреть файл

@@ -0,0 +1,192 @@
#include <stddef.h>
#include <string.h>

#include "address.h"
#include "hash.h"
#include "params.h"
#include "thash.h"
#include "utils.h"

/**
* Converts the value of 'in' to 'outlen' bytes in big-endian byte order.
*/
void PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_ull_to_bytes(
unsigned char *out, size_t outlen, unsigned long long in) {

/* Iterate over out in decreasing order, for big-endianness. */
for (size_t i = outlen; i > 0; i--) {
out[i - 1] = in & 0xff;
in = in >> 8;
}
}

/**
* Converts the inlen bytes in 'in' from big-endian byte order to an integer.
*/
unsigned long long PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_bytes_to_ull(
const unsigned char *in, size_t inlen) {
unsigned long long retval = 0;

for (size_t i = 0; i < inlen; i++) {
retval |= ((unsigned long long)in[i]) << (8 * (inlen - 1 - i));
}
return retval;
}

/**
* Computes a root node given a leaf and an auth path.
* Expects address to be complete other than the tree_height and tree_index.
*/
void PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_compute_root(
unsigned char *root, const unsigned char *leaf,
uint32_t leaf_idx, uint32_t idx_offset,
const unsigned char *auth_path, uint32_t tree_height,
const unsigned char *pub_seed, uint32_t addr[8]) {
uint32_t i;
unsigned char buffer[2 * SPX_N];

/* If leaf_idx is odd (last bit = 1), current path element is a right child
and auth_path has to go left. Otherwise it is the other way around. */
if (leaf_idx & 1) {
memcpy(buffer + SPX_N, leaf, SPX_N);
memcpy(buffer, auth_path, SPX_N);
} else {
memcpy(buffer, leaf, SPX_N);
memcpy(buffer + SPX_N, auth_path, SPX_N);
}
auth_path += SPX_N;

for (i = 0; i < tree_height - 1; i++) {
leaf_idx >>= 1;
idx_offset >>= 1;
/* Set the address of the node we're creating. */
PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_set_tree_height(addr, i + 1);
PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_set_tree_index(
addr, leaf_idx + idx_offset);

/* Pick the right or left neighbor, depending on parity of the node. */
if (leaf_idx & 1) {
PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_thash_2(
buffer + SPX_N, buffer, pub_seed, addr);
memcpy(buffer, auth_path, SPX_N);
} else {
PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_thash_2(
buffer, buffer, pub_seed, addr);
memcpy(buffer + SPX_N, auth_path, SPX_N);
}
auth_path += SPX_N;
}

/* The last iteration is exceptional; we do not copy an auth_path node. */
leaf_idx >>= 1;
idx_offset >>= 1;
PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_set_tree_height(addr, tree_height);
PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_set_tree_index(
addr, leaf_idx + idx_offset);
PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_thash_2(
root, buffer, pub_seed, addr);
}

/**
* For a given leaf index, computes the authentication path and the resulting
* root node using Merkle's TreeHash algorithm.
* Expects the layer and tree parts of the tree_addr to be set, as well as the
* tree type (i.e. SPX_ADDR_TYPE_HASHTREE or SPX_ADDR_TYPE_FORSTREE).
* Applies the offset idx_offset to indices before building addresses, so that
* it is possible to continue counting indices across trees.
*/
static void PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_treehash(
unsigned char *root, unsigned char *auth_path,
unsigned char *stack, unsigned int *heights,
const unsigned char *sk_seed, const unsigned char *pub_seed,
uint32_t leaf_idx, uint32_t idx_offset, uint32_t tree_height,
void (*gen_leaf)(
unsigned char * /* leaf */,
const unsigned char * /* sk_seed */,
const unsigned char * /* pub_seed */,
uint32_t /* addr_idx */, const uint32_t[8] /* tree_addr */),
uint32_t tree_addr[8]) {

unsigned int offset = 0;
uint32_t idx;
uint32_t tree_idx;

for (idx = 0; idx < (uint32_t)(1 << tree_height); idx++) {
/* Add the next leaf node to the stack. */
gen_leaf(stack + offset * SPX_N,
sk_seed, pub_seed, idx + idx_offset, tree_addr);
offset++;
heights[offset - 1] = 0;

/* If this is a node we need for the auth path.. */
if ((leaf_idx ^ 0x1) == idx) {
memcpy(auth_path, stack + (offset - 1)*SPX_N, SPX_N);
}

/* While the top-most nodes are of equal height.. */
while (offset >= 2 && heights[offset - 1] == heights[offset - 2]) {
/* Compute index of the new node, in the next layer. */
tree_idx = (idx >> (heights[offset - 1] + 1));

/* Set the address of the node we're creating. */
PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_set_tree_height(
tree_addr, heights[offset - 1] + 1);
PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_set_tree_index(
tree_addr, tree_idx + (idx_offset >> (heights[offset - 1] + 1)));
/* Hash the top-most nodes from the stack together. */
PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_thash_2(
stack + (offset - 2)*SPX_N, stack + (offset - 2)*SPX_N,
pub_seed, tree_addr);
offset--;
/* Note that the top-most node is now one layer higher. */
heights[offset - 1]++;

/* If this is a node we need for the auth path.. */
if (((leaf_idx >> heights[offset - 1]) ^ 0x1) == tree_idx) {
memcpy(auth_path + heights[offset - 1]*SPX_N,
stack + (offset - 1)*SPX_N, SPX_N);
}
}
}
memcpy(root, stack, SPX_N);
}

/* The wrappers below ensure that we use fixed-size buffers on the stack */

void PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_treehash_FORS_HEIGHT(
unsigned char *root, unsigned char *auth_path,
const unsigned char *sk_seed, const unsigned char *pub_seed,
uint32_t leaf_idx, uint32_t idx_offset,
void (*gen_leaf)(
unsigned char * /* leaf */,
const unsigned char * /* sk_seed */,
const unsigned char * /* pub_seed */,
uint32_t /* addr_idx */, const uint32_t[8] /* tree_addr */),
uint32_t tree_addr[8]) {

unsigned char stack[(SPX_FORS_HEIGHT + 1)*SPX_N];
unsigned int heights[SPX_FORS_HEIGHT + 1];

PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_treehash(
root, auth_path, stack, heights, sk_seed, pub_seed,
leaf_idx, idx_offset, SPX_FORS_HEIGHT, gen_leaf, tree_addr);
}

void PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_treehash_TREE_HEIGHT(
unsigned char *root, unsigned char *auth_path,
const unsigned char *sk_seed, const unsigned char *pub_seed,
uint32_t leaf_idx, uint32_t idx_offset,
void (*gen_leaf)(
unsigned char * /* leaf */,
const unsigned char * /* sk_seed */,
const unsigned char * /* pub_seed */,
uint32_t /* addr_idx */, const uint32_t[8] /* tree_addr */),
uint32_t tree_addr[8]) {

unsigned char stack[(SPX_TREE_HEIGHT + 1)*SPX_N];
unsigned int heights[SPX_TREE_HEIGHT + 1];

PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_treehash(
root, auth_path, stack, heights, sk_seed, pub_seed,
leaf_idx, idx_offset, SPX_TREE_HEIGHT, gen_leaf, tree_addr);
}

+ 60
- 0
crypto_sign/sphincs-shake256-128f-simple/clean/utils.h Просмотреть файл

@@ -0,0 +1,60 @@
#ifndef SPX_UTILS_H
#define SPX_UTILS_H

#include "params.h"
#include <stddef.h>
#include <stdint.h>

/**
* Converts the value of 'in' to 'outlen' bytes in big-endian byte order.
*/
void PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_ull_to_bytes(
unsigned char *out, size_t outlen, unsigned long long in);

/**
* Converts the inlen bytes in 'in' from big-endian byte order to an integer.
*/
unsigned long long PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_bytes_to_ull(
const unsigned char *in, size_t inlen);

/**
* Computes a root node given a leaf and an auth path.
* Expects address to be complete other than the tree_height and tree_index.
*/
void PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_compute_root(
unsigned char *root, const unsigned char *leaf,
uint32_t leaf_idx, uint32_t idx_offset,
const unsigned char *auth_path, uint32_t tree_height,
const unsigned char *pub_seed, uint32_t addr[8]);

/**
* For a given leaf index, computes the authentication path and the resulting
* root node using Merkle's TreeHash algorithm.
* Expects the layer and tree parts of the tree_addr to be set, as well as the
* tree type (i.e. SPX_ADDR_TYPE_HASHTREE or SPX_ADDR_TYPE_FORSTREE).
* Applies the offset idx_offset to indices before building addresses, so that
* it is possible to continue counting indices across trees.
*/
void PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_treehash_FORS_HEIGHT(
unsigned char *root, unsigned char *auth_path,
const unsigned char *sk_seed, const unsigned char *pub_seed,
uint32_t leaf_idx, uint32_t idx_offset,
void (*gen_leaf)(
unsigned char * /* leaf */,
const unsigned char * /* sk_seed */,
const unsigned char * /* pub_seed */,
uint32_t /* addr_idx */, const uint32_t[8] /* tree_addr */),
uint32_t tree_addr[8]);

void PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_treehash_TREE_HEIGHT(
unsigned char *root, unsigned char *auth_path,
const unsigned char *sk_seed, const unsigned char *pub_seed,
uint32_t leaf_idx, uint32_t idx_offset,
void (*gen_leaf)(
unsigned char * /* leaf */,
const unsigned char * /* sk_seed */,
const unsigned char * /* pub_seed */,
uint32_t /* addr_idx */, const uint32_t[8] /* tree_addr */),
uint32_t tree_addr[8]);

#endif

+ 159
- 0
crypto_sign/sphincs-shake256-128f-simple/clean/wots.c Просмотреть файл

@@ -0,0 +1,159 @@
#include <stdint.h>
#include <string.h>

#include "utils.h"
#include "address.h"
#include "hash.h"
#include "params.h"
#include "thash.h"
#include "wots.h"

// TODO clarify address expectations, and make them more uniform.
// TODO i.e. do we expect types to be set already?
// TODO and do we expect modifications or copies?

/**
* Computes the starting value for a chain, i.e. the secret key.
* Expects the address to be complete up to the chain address.
*/
static void wots_gen_sk(unsigned char *sk, const unsigned char *sk_seed,
uint32_t wots_addr[8]) {
/* Make sure that the hash address is actually zeroed. */
PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_set_hash_addr(wots_addr, 0);

/* Generate sk element. */
PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_prf_addr(sk, sk_seed, wots_addr);
}

/**
* Computes the chaining function.
* out and in have to be n-byte arrays.
*
* Interprets in as start-th value of the chain.
* addr has to contain the address of the chain.
*/
static void gen_chain(unsigned char *out, const unsigned char *in,
unsigned int start, unsigned int steps,
const unsigned char *pub_seed, uint32_t addr[8]) {
uint32_t i;

/* Initialize out with the value at position 'start'. */
memcpy(out, in, SPX_N);

/* Iterate 'steps' calls to the hash function. */
for (i = start; i < (start + steps) && i < SPX_WOTS_W; i++) {
PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_set_hash_addr(addr, i);
PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_thash_1(
out, out, pub_seed, addr);
}
}

/**
* base_w algorithm as described in draft.
* Interprets an array of bytes as integers in base w.
* This only works when log_w is a divisor of 8.
*/
static void base_w(int *output, const int out_len, const unsigned char *input) {
int in = 0;
int out = 0;
unsigned char total = 0;
int bits = 0;
int consumed;

for (consumed = 0; consumed < out_len; consumed++) {
if (bits == 0) {
total = input[in];
in++;
bits += 8;
}
bits -= SPX_WOTS_LOGW;
output[out] = (total >> bits) & (SPX_WOTS_W - 1);
out++;
}
}

/* Computes the WOTS+ checksum over a message (in base_w). */
static void wots_checksum(int *csum_base_w, const int *msg_base_w) {
int csum = 0;
unsigned char csum_bytes[(SPX_WOTS_LEN2 * SPX_WOTS_LOGW + 7) / 8];
unsigned int i;

/* Compute checksum. */
for (i = 0; i < SPX_WOTS_LEN1; i++) {
csum += SPX_WOTS_W - 1 - msg_base_w[i];
}

/* Convert checksum to base_w. */
/* Make sure expected empty zero bits are the least significant bits. */
csum = csum << (8 - ((SPX_WOTS_LEN2 * SPX_WOTS_LOGW) % 8));
PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_ull_to_bytes(
csum_bytes, sizeof(csum_bytes), csum);
base_w(csum_base_w, SPX_WOTS_LEN2, csum_bytes);
}

/* Takes a message and derives the matching chain lengths. */
static void chain_lengths(int *lengths, const unsigned char *msg) {
base_w(lengths, SPX_WOTS_LEN1, msg);
wots_checksum(lengths + SPX_WOTS_LEN1, lengths);
}

/**
* WOTS key generation. Takes a 32 byte sk_seed, expands it to WOTS private key
* elements and computes the corresponding public key.
* It requires the seed pub_seed (used to generate bitmasks and hash keys)
* and the address of this WOTS key pair.
*
* Writes the computed public key to 'pk'.
*/
void PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_wots_gen_pk(
unsigned char *pk, const unsigned char *sk_seed,
const unsigned char *pub_seed, uint32_t addr[8]) {
uint32_t i;

for (i = 0; i < SPX_WOTS_LEN; i++) {
PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_set_chain_addr(addr, i);
wots_gen_sk(pk + i * SPX_N, sk_seed, addr);
gen_chain(pk + i * SPX_N, pk + i * SPX_N,
0, SPX_WOTS_W - 1, pub_seed, addr);
}
}

/**
* Takes a n-byte message and the 32-byte sk_see to compute a signature 'sig'.
*/
void PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_wots_sign(
unsigned char *sig, const unsigned char *msg,
const unsigned char *sk_seed, const unsigned char *pub_seed,
uint32_t addr[8]) {
int lengths[SPX_WOTS_LEN];
uint32_t i;

chain_lengths(lengths, msg);

for (i = 0; i < SPX_WOTS_LEN; i++) {
PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_set_chain_addr(addr, i);
wots_gen_sk(sig + i * SPX_N, sk_seed, addr);
gen_chain(sig + i * SPX_N, sig + i * SPX_N, 0, lengths[i], pub_seed, addr);
}
}

/**
* Takes a WOTS signature and an n-byte message, computes a WOTS public key.
*
* Writes the computed public key to 'pk'.
*/
void PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_wots_pk_from_sig(
unsigned char *pk,
const unsigned char *sig, const unsigned char *msg,
const unsigned char *pub_seed, uint32_t addr[8]) {
int lengths[SPX_WOTS_LEN];
uint32_t i;

chain_lengths(lengths, msg);

for (i = 0; i < SPX_WOTS_LEN; i++) {
PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_set_chain_addr(addr, i);
gen_chain(pk + i * SPX_N, sig + i * SPX_N,
lengths[i], SPX_WOTS_W - 1 - lengths[i], pub_seed, addr);
}
}

+ 38
- 0
crypto_sign/sphincs-shake256-128f-simple/clean/wots.h Просмотреть файл

@@ -0,0 +1,38 @@
#ifndef SPX_WOTS_H
#define SPX_WOTS_H

#include "params.h"
#include <stdint.h>

/**
* WOTS key generation. Takes a 32 byte seed for the private key, expands it to
* a full WOTS private key and computes the corresponding public key.
* It requires the seed pub_seed (used to generate bitmasks and hash keys)
* and the address of this WOTS key pair.
*
* Writes the computed public key to 'pk'.
*/
void PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_wots_gen_pk(
unsigned char *pk, const unsigned char *sk_seed,
const unsigned char *pub_seed, uint32_t addr[8]);

/**
* Takes a n-byte message and the 32-byte seed for the private key to compute a
* signature that is placed at 'sig'.
*/
void PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_wots_sign(
unsigned char *sig, const unsigned char *msg,
const unsigned char *sk_seed, const unsigned char *pub_seed,
uint32_t addr[8]);

/**
* Takes a WOTS signature and an n-byte message, computes a WOTS public key.
*
* Writes the computed public key to 'pk'.
*/
void PQCLEAN_SPHINCSSHAKE256128FSIMPLE_CLEAN_wots_pk_from_sig(
unsigned char *pk,
const unsigned char *sig, const unsigned char *msg,
const unsigned char *pub_seed, uint32_t addr[8]);

#endif

+ 4
- 1
test/Makefile Просмотреть файл

@@ -15,7 +15,10 @@ COMMON_HEADERS=$(COMMON_DIR)/*.h
DEST_DIR=../bin

# This -Wall was supported by the European Commission through the ERC Starting Grant 805031 (EPOQUE)
CFLAGS=-Wall -Wextra -Wpedantic -Werror -Wundef -std=c99 -I$(COMMON_DIR) $(EXTRAFLAGS)
CFLAGS=-Wall -Wextra -Wpedantic -Werror -std=c99 \
-Wundef -Wshadow -Wcast-align -Wpointer-arith \
-fstrict-aliasing -fno-common -pipe \
-I$(COMMON_DIR) $(EXTRAFLAGS)

all: $(DEST_DIR)/functest_$(SCHEME)_$(IMPLEMENTATION) \
$(DEST_DIR)/testvectors_$(SCHEME)_$(IMPLEMENTATION) \


+ 2
- 2
test/Makefile.Microsoft_nmake Просмотреть файл

@@ -41,13 +41,13 @@ $(DEST_DIR)\functest_$(SCHEME)_$(IMPLEMENTATION).exe: build-scheme $(COMMON_OBJE
-MKDIR $(DEST_DIR)
-DEL functest.obj
$(CC) /c crypto_$(TYPE)\functest.c $(CFLAGS) /I $(SCHEME_DIR) /DPQCLEAN_NAMESPACE=PQCLEAN_$(SCHEME_UPPERCASE)_$(IMPLEMENTATION_UPPERCASE)
LINK.EXE /OUT:$@ functest.obj $(COMMON_OBJECTS_NOPATH) randombytes.obj $(SCHEME_DIR)\lib$(SCHEME)_$(IMPLEMENTATION).lib Advapi32.lib
LINK.EXE /STACK:8192000 /OUT:$@ functest.obj $(COMMON_OBJECTS_NOPATH) randombytes.obj $(SCHEME_DIR)\lib$(SCHEME)_$(IMPLEMENTATION).lib Advapi32.lib

$(DEST_DIR)\testvectors_$(SCHEME)_$(IMPLEMENTATION).exe: build-scheme $(COMMON_OBJECTS) $(COMMON_DIR)\notrandombytes.obj
-MKDIR $(DEST_DIR)
-DEL testvectors.obj
$(CC) /c crypto_$(TYPE)\testvectors.c $(CFLAGS) /I $(SCHEME_DIR) /DPQCLEAN_NAMESPACE=PQCLEAN_$(SCHEME_UPPERCASE)_$(IMPLEMENTATION_UPPERCASE)
LINK.EXE /OUT:$@ testvectors.obj $(COMMON_OBJECTS_NOPATH) notrandombytes.obj $(SCHEME_DIR)\lib$(SCHEME)_$(IMPLEMENTATION).lib
LINK.EXE /STACK:8192000 /OUT:$@ testvectors.obj $(COMMON_OBJECTS_NOPATH) notrandombytes.obj $(SCHEME_DIR)\lib$(SCHEME)_$(IMPLEMENTATION).lib

$(DEST_DIR)\printparams_$(SCHEME)_$(IMPLEMENTATION).exe: crypto_$(TYPE)\printparams.c $(SCHEME_DIR)\api.h
-MKDIR $(DEST_DIR)


+ 3
- 3
test/crypto_kem/functest.c Просмотреть файл

@@ -5,7 +5,7 @@
#include "api.h"
#include "randombytes.h"

#define NTESTS 10
#define NTESTS 5

const uint8_t canary[8] = {
0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF
@@ -161,7 +161,7 @@ static int test_invalid_sk_a(void) {

if (!memcmp(key_a, key_b, CRYPTO_BYTES)) {
printf("ERROR invalid sk_a\n");
return 1;
return -1;
}
}

@@ -199,7 +199,7 @@ static int test_invalid_ciphertext(void) {

if (!memcmp(key_a, key_b, CRYPTO_BYTES)) {
printf("ERROR invalid ciphertext\n");
return 1;
return -1;
}
}



+ 1
- 1
test/crypto_kem/testvectors.c Просмотреть файл

@@ -6,7 +6,7 @@
#include "api.h"
#include "randombytes.h"

#define NTESTS 100
#define NTESTS 5

static void printbytes(const uint8_t *x, size_t xlen) {
size_t i;


+ 72
- 1
test/crypto_sign/functest.c Просмотреть файл

@@ -6,7 +6,7 @@
#include "api.h"
#include "randombytes.h"

#define NTESTS 15
#define NTESTS 5
#define MLEN 32

const uint8_t canary[8] = {
@@ -44,6 +44,8 @@ static int check_canary(const uint8_t *d) {
#define crypto_sign_keypair NAMESPACE(crypto_sign_keypair)
#define crypto_sign NAMESPACE(crypto_sign)
#define crypto_sign_open NAMESPACE(crypto_sign_open)
#define crypto_sign_signature NAMESPACE(crypto_sign_signature)
#define crypto_sign_verify NAMESPACE(crypto_sign_verify)

#define RETURNS_ZERO(f) \
if ((f) != 0) { \
@@ -133,6 +135,74 @@ static int test_sign(void) {
return 0;
}

static int test_sign_detached(void) {
/*
* This is most likely going to be aligned by the compiler.
* 16 extra bytes for canary
* 1 extra byte for unalignment
*/
uint8_t pk_aligned[CRYPTO_PUBLICKEYBYTES + 16 + 1];
uint8_t sk_aligned[CRYPTO_SECRETKEYBYTES + 16 + 1];
uint8_t sig_aligned[CRYPTO_BYTES + 16 + 1];
uint8_t m_aligned[MLEN + 16 + 1];

/*
* Make sure all pointers are odd.
* This ensures that the implementation does not assume anything about the
* data alignment. For example this would catch if an implementation
* directly uses these pointers to load into vector registers using movdqa.
*/
uint8_t *pk = (uint8_t *) ((uintptr_t) pk_aligned|(uintptr_t) 1);
uint8_t *sk = (uint8_t *) ((uintptr_t) sk_aligned|(uintptr_t) 1);
uint8_t *sig = (uint8_t *) ((uintptr_t) sig_aligned|(uintptr_t) 1);
uint8_t *m = (uint8_t *) ((uintptr_t) m_aligned|(uintptr_t) 1);

size_t siglen;
int returncode;

int i;
/*
* Write 8 byte canary before and after the actual memory regions.
* This is used to validate that the implementation does not assume
* anything about the placement of data in memory
* (e.g., assuming that the pk is always behind the sk)
*/
write_canary(pk);
write_canary(pk + CRYPTO_PUBLICKEYBYTES + 8);
write_canary(sk);
write_canary(sk + CRYPTO_SECRETKEYBYTES + 8);
write_canary(sig);
write_canary(sig + CRYPTO_BYTES + 8);
write_canary(m);
write_canary(m + MLEN + 8);

for (i = 0; i < NTESTS; i++) {
RETURNS_ZERO(crypto_sign_keypair(pk + 8, sk + 8));

randombytes(m + 8, MLEN);
RETURNS_ZERO(crypto_sign_signature(sig + 8, &siglen, m + 8, MLEN, sk + 8));

if ((returncode =
crypto_sign_verify(sig + 8, siglen, m + 8, MLEN, pk + 8)) != 0) {
fprintf(stderr, "ERROR Signature did not verify correctly!\n");
if (returncode > 0) {
fprintf(stderr, "ERROR return code should be < 0 on failure");
}
return 1;
}
// Validate that the implementation did not touch the canary
if (check_canary(pk) || check_canary(pk + CRYPTO_PUBLICKEYBYTES + 8) ||
check_canary(sk) || check_canary(sk + CRYPTO_SECRETKEYBYTES + 8) ||
check_canary(sig) || check_canary(sig + CRYPTO_BYTES + 8) ||
check_canary(m) || check_canary(m + MLEN + 8)) {
fprintf(stderr, "ERROR canary overwritten\n");
return 1;
}
}

return 0;
}

static int test_wrong_pk(void) {
uint8_t pk[CRYPTO_PUBLICKEYBYTES];
uint8_t pk2[CRYPTO_PUBLICKEYBYTES];
@@ -175,6 +245,7 @@ int main(void) {
puts(CRYPTO_ALGNAME);
int result = 0;
result += test_sign();
result += test_sign_detached();
result += test_wrong_pk();

return result;


+ 9
- 2
test/crypto_sign/testvectors.c Просмотреть файл

@@ -6,7 +6,6 @@
#include "api.h"
#include "randombytes.h"

#define NTESTS 100
#define MAXMLEN 2048

static void printbytes(const uint8_t *x, size_t xlen) {
@@ -29,6 +28,8 @@ static void printbytes(const uint8_t *x, size_t xlen) {
#define crypto_sign_keypair NAMESPACE(crypto_sign_keypair)
#define crypto_sign NAMESPACE(crypto_sign)
#define crypto_sign_open NAMESPACE(crypto_sign_open)
#define crypto_sign_signature NAMESPACE(crypto_sign_signature)
#define crypto_sign_verify NAMESPACE(crypto_sign_verify)

int main(void) {
uint8_t sk[CRYPTO_SECRETKEYBYTES];
@@ -36,14 +37,17 @@ int main(void) {

uint8_t mi[MAXMLEN];
uint8_t sm[MAXMLEN + CRYPTO_BYTES];
uint8_t sig[CRYPTO_BYTES];

size_t smlen;
size_t siglen;
size_t mlen;

int r;
size_t i, k;

for (i = 0; i < MAXMLEN; i = (i == 0) ? i + 1 : i << 1) {
/* i = 0, 1, 4, 16, 64, 256, 1024 */
for (i = 0; i < MAXMLEN; i = (i == 0) ? i + 1 : i << 2) {
randombytes(mi, i);

crypto_sign_keypair(pk, sk);
@@ -52,12 +56,15 @@ int main(void) {
printbytes(sk, CRYPTO_SECRETKEYBYTES);

crypto_sign(sm, &smlen, mi, i, sk);
crypto_sign_signature(sig, &siglen, mi, i, sk);

printbytes(sm, smlen);
printbytes(sig, siglen);

// By relying on m == sm we prevent having to allocate CRYPTO_BYTES
// twice
r = crypto_sign_open(sm, &mlen, sm, smlen, pk);
r |= crypto_sign_verify(sig, siglen, mi, i, pk);

if (r) {
printf("ERROR: signature verification failed\n");


+ 9
- 0
test/duplicate_consistency/frodokem1344shake_clean.yml Просмотреть файл

@@ -0,0 +1,9 @@
source:
scheme: frodokem640shake
implementation: clean
files:
- common.h
- kem.c
- matrix_shake.c
- noise.c
- util.c

+ 9
- 0
test/duplicate_consistency/frodokem976shake_clean.yml Просмотреть файл

@@ -0,0 +1,9 @@
source:
scheme: frodokem640shake
implementation: clean
files:
- common.h
- kem.c
- matrix_shake.c
- noise.c
- util.c

+ 17
- 8
test/pqclean.py Просмотреть файл

@@ -40,14 +40,15 @@ class Scheme:
def all_schemes_of_type(type: str) -> list:
schemes = []
p = os.path.join('..', 'crypto_' + type)
for d in os.listdir(p):
if os.path.isdir(os.path.join(p, d)):
if type == 'kem':
schemes.append(KEM(d))
elif type == 'sign':
schemes.append(Signature(d))
else:
assert('Unknown type')
if os.path.isdir(p):
for d in os.listdir(p):
if os.path.isdir(os.path.join(p, d)):
if type == 'kem':
schemes.append(KEM(d))
elif type == 'sign':
schemes.append(Signature(d))
else:
assert('Unknown type')
return schemes

def metadata(self):
@@ -69,10 +70,18 @@ class Implementation:
def __init__(self, scheme, name):
self.scheme = scheme
self.name = name
def metadata(self):
for i in self.scheme.metadata()['implementations']:
if i['name'] == self.name:
return i

def path(self, base='..') -> str:
return os.path.join(self.scheme.path(), self.name)

def namespace_prefix(self):
return 'PQCLEAN_{}_{}_'.format(self.scheme.name.upper(), self.name.upper()).replace('-', '')

def libname(self) -> str:
if os.name == 'nt':
return "lib{}_{}.lib".format(self.scheme.name, self.name)


+ 32
- 0
test/test_api_h.py Просмотреть файл

@@ -0,0 +1,32 @@
import os
import re

import pqclean


def test_preprocessor():
for scheme in pqclean.Scheme.all_schemes():
for implementation in scheme.implementations:
yield check_preprocessor, implementation


def check_preprocessor(implementation: pqclean.Implementation):
apipath = os.path.join(implementation.path(), 'api.h')
errors = []
p = re.compile(r'^\s*#include\s*"')
with open(apipath) as f:
for i, line in enumerate(f):
if p.match(line):
errors.append("\n at {}:{}".format(apipath, i+1))
if errors:
raise AssertionError(
"Prohibited external include in api.h" + "".join(errors)
)

if __name__ == "__main__":
try:
import nose2
nose2.main()
except ImportError:
import nose
nose.runmodule()

+ 4
- 0
test/test_char.py Просмотреть файл

@@ -11,6 +11,10 @@ import helpers


def test_char():
if not(os.path.exists(os.path.join('pycparser', '.git'))):
helpers.run_subprocess(
['git', 'submodule', 'update', '--init']
)
for scheme in pqclean.Scheme.all_schemes():
for implementation in scheme.implementations:
yield check_char, implementation


+ 42
- 0
test/test_duplicate_consistency.py Просмотреть файл

@@ -0,0 +1,42 @@
"""
Checks that files duplicated across schemes/implementations are consistent.
"""

import os
import pqclean
import helpers
import unittest
import yaml

def test_duplicate_consistency():
for scheme in pqclean.Scheme.all_schemes():
for implementation in scheme.implementations:
if os.path.isfile(os.path.join('duplicate_consistency', '{}_{}.yml'.format(scheme.name, implementation.name))):
yield check_duplicate_consistency, implementation

def file_get_contents(filename):
with open(filename) as f:
return f.read()

def check_duplicate_consistency(implementation):
helpers.skip_windows()
metafile = os.path.join('duplicate_consistency', '{}_{}.yml'.format(implementation.scheme.name, implementation.name))
with open(metafile, encoding='utf-8') as f:
metadata = yaml.load(f.read())
source = pqclean.Implementation.by_name(metadata['source']['scheme'], metadata['source']['implementation'])
for file in metadata['files']:
transformed_src = helpers.run_subprocess(
['sed', '-e', 's/{}/{}/g'.format(source.namespace_prefix(), implementation.namespace_prefix()), os.path.join(source.path(), file)]
)
this_src = file_get_contents(os.path.join(implementation.path(), file))
print(os.path.join(implementation.path(), file))
print(this_src)
assert(transformed_src == this_src)

if __name__ == '__main__':
try:
import nose2
nose2.main()
except ImportError:
import nose
nose.runmodule()

+ 8
- 5
test/test_metadata.py Просмотреть файл

@@ -29,6 +29,8 @@ def check_metadata(scheme):

implementation_names_in_yaml = set(
i['name'] for i in metadata['implementations'])
if len(implementation_names_in_yaml) != len(metadata['implementations']):
raise AssertionError("Implementations in YAML file are not distinct")
implementations_on_disk = set(i.name for i in scheme.implementations)
if implementation_names_in_yaml != implementations_on_disk:
raise AssertionError("Implementations in YAML file {} and "
@@ -42,7 +44,6 @@ EXPECTED_FIELDS = {
'type': {'type': str},
'claimed-nist-level': {'type': int, 'min': 1, 'max': 5},
'length-public-key': {'type': int, 'min': 1},
'length-secret-key': {'type': int, 'min': 1},
'testvectors-sha256': {'type': str, 'length': 64},
'principal-submitter': {'type': str},
'auxiliary-submitters': {'type': list, 'elements': {'type': str}},
@@ -53,6 +54,7 @@ EXPECTED_FIELDS = {
'spec': {
'name': {'type': str},
'version': {'type': str},
'length-secret-key': {'type': int, 'min': 1},
},
},
},
@@ -70,14 +72,15 @@ SIGNATURE_FIELDS = {

def check_spec(metadata, spec):
for field, props in spec:
if field not in metadata:
if field not in metadata and 'optional' not in props:
raise AssertionError("Field '{}' not present.".format(field))

# validate element
check_element(field, metadata[field], props)
if field in metadata:
check_element(field, metadata[field], props)

# delete it to detect extras
del metadata[field]
# delete it to detect extras
del metadata[field]

# Done checking all specified fields, check if we have extras
for field, value in metadata.items():


+ 3
- 1
test/test_metadata_sizes.py Просмотреть файл

@@ -13,6 +13,8 @@ def test_metadata_sizes():

def check_metadata_sizes(implementation):
metadata = implementation.scheme.metadata()
impl_meta = next((impl for impl in metadata['implementations']
if impl['name'] == implementation.name), None)
helpers.make('printparams',
TYPE=implementation.scheme.type,
SCHEME=implementation.scheme.name,
@@ -30,7 +32,7 @@ def check_metadata_sizes(implementation):

parsed = json.loads(out)

assert parsed['CRYPTO_SECRETKEYBYTES'] == metadata['length-secret-key']
assert parsed['CRYPTO_SECRETKEYBYTES'] == impl_meta['length-secret-key']
assert parsed['CRYPTO_PUBLICKEYBYTES'] == metadata['length-public-key']

if implementation.scheme.type == 'kem':


+ 37
- 0
test/test_preprocessor.py Просмотреть файл

@@ -0,0 +1,37 @@
import os
from glob import glob

import pqclean
from helpers import run_subprocess, ensure_available


def test_preprocessor():
for scheme in pqclean.Scheme.all_schemes():
for implementation in scheme.implementations:
yield check_preprocessor, implementation


def check_preprocessor(implementation: pqclean.Implementation):
cfiles = implementation.cfiles()
hfiles = implementation.hfiles()
errors = []
for file in hfiles + cfiles:
with open(file) as f:
for i, line in enumerate(f):
line = line.strip()
if file in hfiles and i == 0 and line.startswith('#ifndef'):
continue
if line.startswith('#if'):
errors.append("\n at {}:{}".format(file, i+1))
if errors:
raise AssertionError(
"Prohibited use of preprocessor conditional" + "".join(errors)
)

if __name__ == "__main__":
try:
import nose2
nose2.main()
except ImportError:
import nose
nose.runmodule()

Загрузка…
Отмена
Сохранить