25개 이상의 토픽을 선택하실 수 없습니다. Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

239 lines
13 KiB

  1. /********************************************************************************************
  2. * FrodoKEM: Learning with Errors Key Encapsulation
  3. *
  4. * Abstract: Key Encapsulation Mechanism (KEM) based on Frodo
  5. *********************************************************************************************/
  6. #include <stdint.h>
  7. #include <string.h>
  8. #include "fips202.h"
  9. #include "randombytes.h"
  10. #include "api.h"
  11. #include "common.h"
  12. #include "params.h"
  13. int PQCLEAN_FRODOKEM976AES_OPT_crypto_kem_keypair(uint8_t *pk, uint8_t *sk) {
  14. // FrodoKEM's key generation
  15. // Outputs: public key pk ( BYTES_SEED_A + (PARAMS_LOGQ*PARAMS_N*PARAMS_NBAR)/8 bytes)
  16. // secret key sk (CRYPTO_BYTES + BYTES_SEED_A + (PARAMS_LOGQ*PARAMS_N*PARAMS_NBAR)/8 + 2*PARAMS_N*PARAMS_NBAR + BYTES_PKHASH bytes)
  17. uint8_t *pk_seedA = &pk[0];
  18. uint8_t *pk_b = &pk[BYTES_SEED_A];
  19. uint8_t *sk_s = &sk[0];
  20. uint8_t *sk_pk = &sk[CRYPTO_BYTES];
  21. uint8_t *sk_S = &sk[CRYPTO_BYTES + CRYPTO_PUBLICKEYBYTES];
  22. uint8_t *sk_pkh = &sk[CRYPTO_BYTES + CRYPTO_PUBLICKEYBYTES + 2 * PARAMS_N * PARAMS_NBAR];
  23. uint16_t B[PARAMS_N * PARAMS_NBAR] = {0};
  24. uint16_t S[2 * PARAMS_N * PARAMS_NBAR] = {0}; // contains secret data
  25. uint16_t *E = &S[PARAMS_N * PARAMS_NBAR]; // contains secret data
  26. uint8_t randomness[2 * CRYPTO_BYTES + BYTES_SEED_A]; // contains secret data via randomness_s and randomness_seedSE
  27. uint8_t *randomness_s = &randomness[0]; // contains secret data
  28. uint8_t *randomness_seedSE = &randomness[CRYPTO_BYTES]; // contains secret data
  29. uint8_t *randomness_z = &randomness[2 * CRYPTO_BYTES];
  30. uint8_t shake_input_seedSE[1 + CRYPTO_BYTES]; // contains secret data
  31. // 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
  32. randombytes(randomness, CRYPTO_BYTES + CRYPTO_BYTES + BYTES_SEED_A);
  33. shake(pk_seedA, BYTES_SEED_A, randomness_z, BYTES_SEED_A);
  34. // Generate S and E, and compute B = A*S + E. Generate A on-the-fly
  35. shake_input_seedSE[0] = 0x5F;
  36. memcpy(&shake_input_seedSE[1], randomness_seedSE, CRYPTO_BYTES);
  37. shake((uint8_t *)S, 2 * PARAMS_N * PARAMS_NBAR * sizeof(uint16_t), shake_input_seedSE, 1 + CRYPTO_BYTES);
  38. for (size_t i = 0; i < 2 * PARAMS_N * PARAMS_NBAR; i++) {
  39. S[i] = PQCLEAN_FRODOKEM976AES_OPT_LE_TO_UINT16(S[i]);
  40. }
  41. PQCLEAN_FRODOKEM976AES_OPT_sample_n(S, PARAMS_N * PARAMS_NBAR);
  42. PQCLEAN_FRODOKEM976AES_OPT_sample_n(E, PARAMS_N * PARAMS_NBAR);
  43. PQCLEAN_FRODOKEM976AES_OPT_mul_add_as_plus_e(B, S, E, pk);
  44. // Encode the second part of the public key
  45. PQCLEAN_FRODOKEM976AES_OPT_pack(pk_b, CRYPTO_PUBLICKEYBYTES - BYTES_SEED_A, B, PARAMS_N * PARAMS_NBAR, PARAMS_LOGQ);
  46. // Add s, pk and S to the secret key
  47. memcpy(sk_s, randomness_s, CRYPTO_BYTES);
  48. memcpy(sk_pk, pk, CRYPTO_PUBLICKEYBYTES);
  49. for (size_t i = 0; i < PARAMS_N * PARAMS_NBAR; i++) {
  50. S[i] = PQCLEAN_FRODOKEM976AES_OPT_UINT16_TO_LE(S[i]);
  51. }
  52. memcpy(sk_S, S, 2 * PARAMS_N * PARAMS_NBAR);
  53. // Add H(pk) to the secret key
  54. shake(sk_pkh, BYTES_PKHASH, pk, CRYPTO_PUBLICKEYBYTES);
  55. // Cleanup:
  56. PQCLEAN_FRODOKEM976AES_OPT_clear_bytes((uint8_t *)S, PARAMS_N * PARAMS_NBAR * sizeof(uint16_t));
  57. PQCLEAN_FRODOKEM976AES_OPT_clear_bytes((uint8_t *)E, PARAMS_N * PARAMS_NBAR * sizeof(uint16_t));
  58. PQCLEAN_FRODOKEM976AES_OPT_clear_bytes(randomness, 2 * CRYPTO_BYTES);
  59. PQCLEAN_FRODOKEM976AES_OPT_clear_bytes(shake_input_seedSE, 1 + CRYPTO_BYTES);
  60. return 0;
  61. }
  62. int PQCLEAN_FRODOKEM976AES_OPT_crypto_kem_enc(uint8_t *ct, uint8_t *ss, const uint8_t *pk) {
  63. // FrodoKEM's key encapsulation
  64. const uint8_t *pk_seedA = &pk[0];
  65. const uint8_t *pk_b = &pk[BYTES_SEED_A];
  66. uint8_t *ct_c1 = &ct[0];
  67. uint8_t *ct_c2 = &ct[(PARAMS_LOGQ * PARAMS_N * PARAMS_NBAR) / 8];
  68. uint16_t B[PARAMS_N * PARAMS_NBAR] = {0};
  69. uint16_t V[PARAMS_NBAR * PARAMS_NBAR] = {0}; // contains secret data
  70. uint16_t C[PARAMS_NBAR * PARAMS_NBAR] = {0};
  71. uint16_t Bp[PARAMS_N * PARAMS_NBAR] = {0};
  72. uint16_t Sp[(2 * PARAMS_N + PARAMS_NBAR)*PARAMS_NBAR] = {0}; // contains secret data
  73. uint16_t *Ep = &Sp[PARAMS_N * PARAMS_NBAR]; // contains secret data
  74. uint16_t *Epp = &Sp[2 * PARAMS_N * PARAMS_NBAR]; // contains secret data
  75. uint8_t G2in[BYTES_PKHASH + BYTES_MU]; // contains secret data via mu
  76. uint8_t *pkh = &G2in[0];
  77. uint8_t *mu = &G2in[BYTES_PKHASH]; // contains secret data
  78. uint8_t G2out[2 * CRYPTO_BYTES]; // contains secret data
  79. uint8_t *seedSE = &G2out[0]; // contains secret data
  80. uint8_t *k = &G2out[CRYPTO_BYTES]; // contains secret data
  81. uint8_t Fin[CRYPTO_CIPHERTEXTBYTES + CRYPTO_BYTES]; // contains secret data via Fin_k
  82. uint8_t *Fin_ct = &Fin[0];
  83. uint8_t *Fin_k = &Fin[CRYPTO_CIPHERTEXTBYTES]; // contains secret data
  84. uint8_t shake_input_seedSE[1 + CRYPTO_BYTES]; // contains secret data
  85. // pkh <- G_1(pk), generate random mu, compute (seedSE || k) = G_2(pkh || mu)
  86. shake(pkh, BYTES_PKHASH, pk, CRYPTO_PUBLICKEYBYTES);
  87. randombytes(mu, BYTES_MU);
  88. shake(G2out, CRYPTO_BYTES + CRYPTO_BYTES, G2in, BYTES_PKHASH + BYTES_MU);
  89. // Generate Sp and Ep, and compute Bp = Sp*A + Ep. Generate A on-the-fly
  90. shake_input_seedSE[0] = 0x96;
  91. memcpy(&shake_input_seedSE[1], seedSE, CRYPTO_BYTES);
  92. shake((uint8_t *)Sp, (2 * PARAMS_N + PARAMS_NBAR) * PARAMS_NBAR * sizeof(uint16_t), shake_input_seedSE, 1 + CRYPTO_BYTES);
  93. for (size_t i = 0; i < (2 * PARAMS_N + PARAMS_NBAR) * PARAMS_NBAR; i++) {
  94. Sp[i] = PQCLEAN_FRODOKEM976AES_OPT_LE_TO_UINT16(Sp[i]);
  95. }
  96. PQCLEAN_FRODOKEM976AES_OPT_sample_n(Sp, PARAMS_N * PARAMS_NBAR);
  97. PQCLEAN_FRODOKEM976AES_OPT_sample_n(Ep, PARAMS_N * PARAMS_NBAR);
  98. PQCLEAN_FRODOKEM976AES_OPT_mul_add_sa_plus_e(Bp, Sp, Ep, pk_seedA);
  99. PQCLEAN_FRODOKEM976AES_OPT_pack(ct_c1, (PARAMS_LOGQ * PARAMS_N * PARAMS_NBAR) / 8, Bp, PARAMS_N * PARAMS_NBAR, PARAMS_LOGQ);
  100. // Generate Epp, and compute V = Sp*B + Epp
  101. PQCLEAN_FRODOKEM976AES_OPT_sample_n(Epp, PARAMS_NBAR * PARAMS_NBAR);
  102. PQCLEAN_FRODOKEM976AES_OPT_unpack(B, PARAMS_N * PARAMS_NBAR, pk_b, CRYPTO_PUBLICKEYBYTES - BYTES_SEED_A, PARAMS_LOGQ);
  103. PQCLEAN_FRODOKEM976AES_OPT_mul_add_sb_plus_e(V, B, Sp, Epp);
  104. // Encode mu, and compute C = V + enc(mu) (mod q)
  105. PQCLEAN_FRODOKEM976AES_OPT_key_encode(C, (uint16_t *)mu);
  106. PQCLEAN_FRODOKEM976AES_OPT_add(C, V, C);
  107. PQCLEAN_FRODOKEM976AES_OPT_pack(ct_c2, (PARAMS_LOGQ * PARAMS_NBAR * PARAMS_NBAR) / 8, C, PARAMS_NBAR * PARAMS_NBAR, PARAMS_LOGQ);
  108. // Compute ss = F(ct||KK)
  109. memcpy(Fin_ct, ct, CRYPTO_CIPHERTEXTBYTES);
  110. memcpy(Fin_k, k, CRYPTO_BYTES);
  111. shake(ss, CRYPTO_BYTES, Fin, CRYPTO_CIPHERTEXTBYTES + CRYPTO_BYTES);
  112. // Cleanup:
  113. PQCLEAN_FRODOKEM976AES_OPT_clear_bytes((uint8_t *)V, PARAMS_NBAR * PARAMS_NBAR * sizeof(uint16_t));
  114. PQCLEAN_FRODOKEM976AES_OPT_clear_bytes((uint8_t *)Sp, PARAMS_N * PARAMS_NBAR * sizeof(uint16_t));
  115. PQCLEAN_FRODOKEM976AES_OPT_clear_bytes((uint8_t *)Ep, PARAMS_N * PARAMS_NBAR * sizeof(uint16_t));
  116. PQCLEAN_FRODOKEM976AES_OPT_clear_bytes((uint8_t *)Epp, PARAMS_NBAR * PARAMS_NBAR * sizeof(uint16_t));
  117. PQCLEAN_FRODOKEM976AES_OPT_clear_bytes(mu, BYTES_MU);
  118. PQCLEAN_FRODOKEM976AES_OPT_clear_bytes(G2out, 2 * CRYPTO_BYTES);
  119. PQCLEAN_FRODOKEM976AES_OPT_clear_bytes(Fin_k, CRYPTO_BYTES);
  120. PQCLEAN_FRODOKEM976AES_OPT_clear_bytes(shake_input_seedSE, 1 + CRYPTO_BYTES);
  121. return 0;
  122. }
  123. int PQCLEAN_FRODOKEM976AES_OPT_crypto_kem_dec(uint8_t *ss, const uint8_t *ct, const uint8_t *sk) {
  124. // FrodoKEM's key decapsulation
  125. uint16_t B[PARAMS_N * PARAMS_NBAR] = {0};
  126. uint16_t Bp[PARAMS_N * PARAMS_NBAR] = {0};
  127. uint16_t W[PARAMS_NBAR * PARAMS_NBAR] = {0}; // contains secret data
  128. uint16_t C[PARAMS_NBAR * PARAMS_NBAR] = {0};
  129. uint16_t CC[PARAMS_NBAR * PARAMS_NBAR] = {0};
  130. uint16_t BBp[PARAMS_N * PARAMS_NBAR] = {0};
  131. uint16_t Sp[(2 * PARAMS_N + PARAMS_NBAR)*PARAMS_NBAR] = {0}; // contains secret data
  132. uint16_t *Ep = &Sp[PARAMS_N * PARAMS_NBAR]; // contains secret data
  133. uint16_t *Epp = &Sp[2 * PARAMS_N * PARAMS_NBAR]; // contains secret data
  134. const uint8_t *ct_c1 = &ct[0];
  135. const uint8_t *ct_c2 = &ct[(PARAMS_LOGQ * PARAMS_N * PARAMS_NBAR) / 8];
  136. const uint8_t *sk_s = &sk[0];
  137. const uint8_t *sk_pk = &sk[CRYPTO_BYTES];
  138. const uint16_t *sk_S = (uint16_t *) &sk[CRYPTO_BYTES + CRYPTO_PUBLICKEYBYTES];
  139. uint16_t S[PARAMS_N * PARAMS_NBAR]; // contains secret data
  140. const uint8_t *sk_pkh = &sk[CRYPTO_BYTES + CRYPTO_PUBLICKEYBYTES + 2 * PARAMS_N * PARAMS_NBAR];
  141. const uint8_t *pk_seedA = &sk_pk[0];
  142. const uint8_t *pk_b = &sk_pk[BYTES_SEED_A];
  143. uint8_t G2in[BYTES_PKHASH + BYTES_MU]; // contains secret data via muprime
  144. uint8_t *pkh = &G2in[0];
  145. uint8_t *muprime = &G2in[BYTES_PKHASH]; // contains secret data
  146. uint8_t G2out[2 * CRYPTO_BYTES]; // contains secret data
  147. uint8_t *seedSEprime = &G2out[0]; // contains secret data
  148. uint8_t *kprime = &G2out[CRYPTO_BYTES]; // contains secret data
  149. uint8_t Fin[CRYPTO_CIPHERTEXTBYTES + CRYPTO_BYTES]; // contains secret data via Fin_k
  150. uint8_t *Fin_ct = &Fin[0];
  151. uint8_t *Fin_k = &Fin[CRYPTO_CIPHERTEXTBYTES]; // contains secret data
  152. uint8_t shake_input_seedSEprime[1 + CRYPTO_BYTES]; // contains secret data
  153. for (size_t i = 0; i < PARAMS_N * PARAMS_NBAR; i++) {
  154. S[i] = PQCLEAN_FRODOKEM976AES_OPT_LE_TO_UINT16(sk_S[i]);
  155. }
  156. // Compute W = C - Bp*S (mod q), and decode the randomness mu
  157. PQCLEAN_FRODOKEM976AES_OPT_unpack(Bp, PARAMS_N * PARAMS_NBAR, ct_c1, (PARAMS_LOGQ * PARAMS_N * PARAMS_NBAR) / 8, PARAMS_LOGQ);
  158. PQCLEAN_FRODOKEM976AES_OPT_unpack(C, PARAMS_NBAR * PARAMS_NBAR, ct_c2, (PARAMS_LOGQ * PARAMS_NBAR * PARAMS_NBAR) / 8, PARAMS_LOGQ);
  159. PQCLEAN_FRODOKEM976AES_OPT_mul_bs(W, Bp, S);
  160. PQCLEAN_FRODOKEM976AES_OPT_sub(W, C, W);
  161. PQCLEAN_FRODOKEM976AES_OPT_key_decode((uint16_t *)muprime, W);
  162. // Generate (seedSE' || k') = G_2(pkh || mu')
  163. memcpy(pkh, sk_pkh, BYTES_PKHASH);
  164. shake(G2out, CRYPTO_BYTES + CRYPTO_BYTES, G2in, BYTES_PKHASH + BYTES_MU);
  165. // Generate Sp and Ep, and compute BBp = Sp*A + Ep. Generate A on-the-fly
  166. shake_input_seedSEprime[0] = 0x96;
  167. memcpy(&shake_input_seedSEprime[1], seedSEprime, CRYPTO_BYTES);
  168. shake((uint8_t *)Sp, (2 * PARAMS_N + PARAMS_NBAR) * PARAMS_NBAR * sizeof(uint16_t), shake_input_seedSEprime, 1 + CRYPTO_BYTES);
  169. for (size_t i = 0; i < (2 * PARAMS_N + PARAMS_NBAR) * PARAMS_NBAR; i++) {
  170. Sp[i] = PQCLEAN_FRODOKEM976AES_OPT_LE_TO_UINT16(Sp[i]);
  171. }
  172. PQCLEAN_FRODOKEM976AES_OPT_sample_n(Sp, PARAMS_N * PARAMS_NBAR);
  173. PQCLEAN_FRODOKEM976AES_OPT_sample_n(Ep, PARAMS_N * PARAMS_NBAR);
  174. PQCLEAN_FRODOKEM976AES_OPT_mul_add_sa_plus_e(BBp, Sp, Ep, pk_seedA);
  175. // Generate Epp, and compute W = Sp*B + Epp
  176. PQCLEAN_FRODOKEM976AES_OPT_sample_n(Epp, PARAMS_NBAR * PARAMS_NBAR);
  177. PQCLEAN_FRODOKEM976AES_OPT_unpack(B, PARAMS_N * PARAMS_NBAR, pk_b, CRYPTO_PUBLICKEYBYTES - BYTES_SEED_A, PARAMS_LOGQ);
  178. PQCLEAN_FRODOKEM976AES_OPT_mul_add_sb_plus_e(W, B, Sp, Epp);
  179. // Encode mu, and compute CC = W + enc(mu') (mod q)
  180. PQCLEAN_FRODOKEM976AES_OPT_key_encode(CC, (uint16_t *)muprime);
  181. PQCLEAN_FRODOKEM976AES_OPT_add(CC, W, CC);
  182. // Prepare input to F
  183. memcpy(Fin_ct, ct, CRYPTO_CIPHERTEXTBYTES);
  184. // Reducing BBp modulo q
  185. for (size_t i = 0; i < PARAMS_N * PARAMS_NBAR; i++) {
  186. BBp[i] = BBp[i] & ((1 << PARAMS_LOGQ) - 1);
  187. }
  188. // Is (Bp == BBp & C == CC) = true
  189. if (memcmp(Bp, BBp, 2 * PARAMS_N * PARAMS_NBAR) == 0 && memcmp(C, CC, 2 * PARAMS_NBAR * PARAMS_NBAR) == 0) {
  190. // Load k' to do ss = F(ct || k')
  191. memcpy(Fin_k, kprime, CRYPTO_BYTES);
  192. } else {
  193. // Load s to do ss = F(ct || s)
  194. memcpy(Fin_k, sk_s, CRYPTO_BYTES);
  195. }
  196. shake(ss, CRYPTO_BYTES, Fin, CRYPTO_CIPHERTEXTBYTES + CRYPTO_BYTES);
  197. // Cleanup:
  198. PQCLEAN_FRODOKEM976AES_OPT_clear_bytes((uint8_t *)W, PARAMS_NBAR * PARAMS_NBAR * sizeof(uint16_t));
  199. PQCLEAN_FRODOKEM976AES_OPT_clear_bytes((uint8_t *)Sp, PARAMS_N * PARAMS_NBAR * sizeof(uint16_t));
  200. PQCLEAN_FRODOKEM976AES_OPT_clear_bytes((uint8_t *)S, PARAMS_N * PARAMS_NBAR * sizeof(uint16_t));
  201. PQCLEAN_FRODOKEM976AES_OPT_clear_bytes((uint8_t *)Ep, PARAMS_N * PARAMS_NBAR * sizeof(uint16_t));
  202. PQCLEAN_FRODOKEM976AES_OPT_clear_bytes((uint8_t *)Epp, PARAMS_NBAR * PARAMS_NBAR * sizeof(uint16_t));
  203. PQCLEAN_FRODOKEM976AES_OPT_clear_bytes(muprime, BYTES_MU);
  204. PQCLEAN_FRODOKEM976AES_OPT_clear_bytes(G2out, 2 * CRYPTO_BYTES);
  205. PQCLEAN_FRODOKEM976AES_OPT_clear_bytes(Fin_k, CRYPTO_BYTES);
  206. PQCLEAN_FRODOKEM976AES_OPT_clear_bytes(shake_input_seedSEprime, 1 + CRYPTO_BYTES);
  207. return 0;
  208. }