kyber512r3_indcpa.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325
  1. #include <stddef.h>
  2. #include <stdint.h>
  3. #include "kyber512r3_params.h"
  4. #include "kyber512r3_indcpa.h"
  5. #include "kyber512r3_poly.h"
  6. #include "kyber512r3_polyvec.h"
  7. #include "kyber512r3_fips202.h"
  8. #include "kyber512r3_symmetric.h"
  9. #include "pq-crypto/s2n_pq_random.h"
  10. #include "utils/s2n_safety.h"
  11. S2N_ENSURE_PORTABLE_OPTIMIZATIONS
  12. /*************************************************
  13. * Name: pack_pk
  14. *
  15. * Description: Serialize the public key as concatenation of the
  16. * serialized vector of polynomials pk
  17. * and the public seed used to generate the matrix A.
  18. *
  19. * Arguments: uint8_t *r: pointer to the output serialized public key
  20. * polyvec *pk: pointer to the input public-key polyvec
  21. * const uint8_t *seed: pointer to the input public seed
  22. **************************************************/
  23. static void pack_pk(uint8_t r[S2N_KYBER_512_R3_INDCPA_PUBLICKEYBYTES], polyvec *pk, const uint8_t seed[S2N_KYBER_512_R3_SYMBYTES]) {
  24. polyvec_tobytes(r, pk);
  25. for (size_t i = 0; i < S2N_KYBER_512_R3_SYMBYTES; i++) {
  26. r[i + S2N_KYBER_512_R3_POLYVECBYTES] = seed[i];
  27. }
  28. }
  29. /*************************************************
  30. * Name: unpack_pk
  31. *
  32. * Description: De-serialize public key from a byte array;
  33. * approximate inverse of pack_pk
  34. *
  35. * Arguments: - polyvec *pk: pointer to output public-key
  36. * polynomial vector
  37. * - uint8_t *seed: pointer to output seed to generate
  38. * matrix A
  39. * - const uint8_t *packedpk: pointer to input serialized public key
  40. **************************************************/
  41. static void unpack_pk(polyvec *pk, uint8_t seed[S2N_KYBER_512_R3_SYMBYTES], const uint8_t packedpk[S2N_KYBER_512_R3_INDCPA_PUBLICKEYBYTES]) {
  42. polyvec_frombytes(pk, packedpk);
  43. for (size_t i = 0; i < S2N_KYBER_512_R3_SYMBYTES; i++) {
  44. seed[i] = packedpk[i + S2N_KYBER_512_R3_POLYVECBYTES];
  45. }
  46. }
  47. /*************************************************
  48. * Name: pack_sk
  49. *
  50. * Description: Serialize the secret key
  51. *
  52. * Arguments: - uint8_t *r: pointer to output serialized secret key
  53. * - polyvec *sk: pointer to input vector of polynomials (secret key)
  54. **************************************************/
  55. static void pack_sk(uint8_t r[S2N_KYBER_512_R3_INDCPA_SECRETKEYBYTES], polyvec *sk) {
  56. polyvec_tobytes(r, sk);
  57. }
  58. /*************************************************
  59. * Name: unpack_sk
  60. *
  61. * Description: De-serialize the secret key;
  62. * inverse of pack_sk
  63. *
  64. * Arguments: - polyvec *sk: pointer to output vector of
  65. * polynomials (secret key)
  66. * - const uint8_t *packedsk: pointer to input serialized secret key
  67. **************************************************/
  68. static void unpack_sk(polyvec *sk, const uint8_t packedsk[S2N_KYBER_512_R3_INDCPA_SECRETKEYBYTES]) {
  69. polyvec_frombytes(sk, packedsk);
  70. }
  71. /*************************************************
  72. * Name: pack_ciphertext
  73. *
  74. * Description: Serialize the ciphertext as concatenation of the
  75. * compressed and serialized vector of polynomials b
  76. * and the compressed and serialized polynomial v
  77. *
  78. * Arguments: uint8_t *r: pointer to the output serialized ciphertext
  79. * poly *pk: pointer to the input vector of polynomials b
  80. * poly *v: pointer to the input polynomial v
  81. **************************************************/
  82. static void pack_ciphertext(uint8_t r[S2N_KYBER_512_R3_INDCPA_BYTES], polyvec *b, poly *v) {
  83. polyvec_compress(r, b);
  84. poly_compress(r + S2N_KYBER_512_R3_POLYVECCOMPRESSEDBYTES, v);
  85. }
  86. /*************************************************
  87. * Name: unpack_ciphertext
  88. *
  89. * Description: De-serialize and decompress ciphertext from a byte array;
  90. * approximate inverse of pack_ciphertext
  91. *
  92. * Arguments: - polyvec *b: pointer to the output vector of polynomials b
  93. * - poly *v: pointer to the output polynomial v
  94. * - const uint8_t *c: pointer to the input serialized ciphertext
  95. **************************************************/
  96. static void unpack_ciphertext(polyvec *b, poly *v, const uint8_t c[S2N_KYBER_512_R3_INDCPA_BYTES]) {
  97. polyvec_decompress(b, c);
  98. poly_decompress(v, c + S2N_KYBER_512_R3_POLYVECCOMPRESSEDBYTES);
  99. }
  100. /*************************************************
  101. * Name: rej_uniform
  102. *
  103. * Description: Run rejection sampling on uniform random bytes to generate
  104. * uniform random integers mod q
  105. *
  106. * Arguments: - int16_t *r: pointer to output buffer
  107. * - unsigned int len: requested number of 16-bit integers
  108. * (uniform mod q)
  109. * - const uint8_t *buf: pointer to input buffer
  110. * (assumed to be uniform random bytes)
  111. * - unsigned int buflen: length of input buffer in bytes
  112. *
  113. * Returns number of sampled 16-bit integers (at most len)
  114. **************************************************/
  115. static unsigned int rej_uniform(int16_t *r, unsigned int len, const uint8_t *buf, unsigned int buflen) {
  116. unsigned int ctr, pos;
  117. ctr = pos = 0;
  118. while (ctr < len && pos + 3 <= buflen) {
  119. uint16_t val0 = ((buf[pos + 0] >> 0) | ((uint16_t)buf[pos + 1] << 8)) & 0xFFF;
  120. uint16_t val1 = ((buf[pos + 1] >> 4) | ((uint16_t)buf[pos + 2] << 4)) & 0xFFF;
  121. pos += 3;
  122. if (val0 < S2N_KYBER_512_R3_Q) {
  123. r[ctr++] = val0;
  124. }
  125. if (ctr < len && val1 < S2N_KYBER_512_R3_Q) {
  126. r[ctr++] = val1;
  127. }
  128. }
  129. return ctr;
  130. }
  131. /*************************************************
  132. * Name: gen_matrix
  133. *
  134. * Description: Deterministically generate matrix A (or the transpose of A)
  135. * from a seed. Entries of the matrix are polynomials that look
  136. * uniformly random. Performs rejection sampling on output of
  137. * a XOF
  138. *
  139. * Arguments: - polyvec *a: pointer to ouptput matrix A
  140. * - const uint8_t *seed: pointer to input seed
  141. * - int transposed: boolean deciding whether A or A^T
  142. * is generated
  143. **************************************************/
  144. #define XOF_BLOCKBYTES 168
  145. #define GEN_MATRIX_NBLOCKS ((12*S2N_KYBER_512_R3_N/8*(1 << 12)/S2N_KYBER_512_R3_Q + XOF_BLOCKBYTES)/XOF_BLOCKBYTES)
  146. static void gen_matrix(polyvec *a, const uint8_t seed[S2N_KYBER_512_R3_SYMBYTES], int transposed) {
  147. unsigned int ctr, buflen, off;
  148. uint8_t buf[GEN_MATRIX_NBLOCKS * XOF_BLOCKBYTES + 2];
  149. xof_state state;
  150. for (unsigned int i = 0; i < S2N_KYBER_512_R3_K; i++) {
  151. for (unsigned int j = 0; j < S2N_KYBER_512_R3_K; j++) {
  152. if (transposed) {
  153. kyber_shake128_absorb(&state, seed, i, j);
  154. } else {
  155. kyber_shake128_absorb(&state, seed, j, i);
  156. }
  157. shake128_squeezeblocks(buf, GEN_MATRIX_NBLOCKS, &state);
  158. buflen = GEN_MATRIX_NBLOCKS * XOF_BLOCKBYTES;
  159. ctr = rej_uniform(a[i].vec[j].coeffs, S2N_KYBER_512_R3_N, buf, buflen);
  160. while (ctr < S2N_KYBER_512_R3_N) {
  161. off = buflen % 3;
  162. for (unsigned int k = 0; k < off; k++) {
  163. buf[k] = buf[buflen - off + k];
  164. }
  165. shake128_squeezeblocks(buf + off, 1, &state);
  166. buflen = off + XOF_BLOCKBYTES;
  167. ctr += rej_uniform(a[i].vec[j].coeffs + ctr, S2N_KYBER_512_R3_N - ctr, buf, buflen);
  168. }
  169. }
  170. }
  171. }
  172. /*************************************************
  173. * Name: indcpa_keypair
  174. *
  175. * Description: Generates public and private key for the CPA-secure
  176. * public-key encryption scheme underlying Kyber
  177. *
  178. * Arguments: - uint8_t *pk: pointer to output public key
  179. * (of length S2N_KYBER_512_R3_INDCPA_PUBLICKEYBYTES bytes)
  180. * - uint8_t *sk: pointer to output private key
  181. * (of length S2N_KYBER_512_R3_INDCPA_SECRETKEYBYTES bytes)
  182. *
  183. * Returns: 0 on success
  184. * !0 on failure
  185. **************************************************/
  186. int indcpa_keypair(uint8_t pk[S2N_KYBER_512_R3_INDCPA_PUBLICKEYBYTES], uint8_t sk[S2N_KYBER_512_R3_INDCPA_SECRETKEYBYTES]) {
  187. uint8_t buf[2 * S2N_KYBER_512_R3_SYMBYTES];
  188. const uint8_t *publicseed = buf;
  189. const uint8_t *noiseseed = buf + S2N_KYBER_512_R3_SYMBYTES;
  190. uint8_t nonce = 0;
  191. polyvec a[S2N_KYBER_512_R3_K], e, pkpv, skpv;
  192. POSIX_GUARD_RESULT(s2n_get_random_bytes(buf, S2N_KYBER_512_R3_SYMBYTES));
  193. sha3_512(buf, buf, S2N_KYBER_512_R3_SYMBYTES);
  194. gen_matrix(a, publicseed, 0);
  195. for (unsigned int i = 0; i < S2N_KYBER_512_R3_K; i++) {
  196. poly_getnoise_eta1(&skpv.vec[i], noiseseed, nonce++);
  197. }
  198. for (unsigned int i = 0; i < S2N_KYBER_512_R3_K; i++) {
  199. poly_getnoise_eta1(&e.vec[i], noiseseed, nonce++);
  200. }
  201. polyvec_ntt(&skpv);
  202. polyvec_ntt(&e);
  203. //* matrix-vector multiplication */
  204. for (unsigned int i = 0; i < S2N_KYBER_512_R3_K; i++) {
  205. polyvec_pointwise_acc_montgomery(&pkpv.vec[i], &a[i], &skpv);
  206. poly_tomont(&pkpv.vec[i]);
  207. }
  208. polyvec_add(&pkpv, &pkpv, &e);
  209. polyvec_reduce(&pkpv);
  210. pack_sk(sk, &skpv);
  211. pack_pk(pk, &pkpv, publicseed);
  212. return 0;
  213. }
  214. /*************************************************
  215. * Name: indcpa_enc
  216. *
  217. * Description: Encryption function of the CPA-secure
  218. * public-key encryption scheme underlying Kyber.
  219. *
  220. * Arguments: - uint8_t *c: pointer to output ciphertext
  221. * (of length S2N_KYBER_512_R3_INDCPA_BYTES bytes)
  222. * - const uint8_t *m: pointer to input message
  223. * (of length S2N_KYBER_512_R3_INDCPA_MSGBYTES bytes)
  224. * - const uint8_t *pk: pointer to input public key
  225. * (of length S2N_KYBER_512_R3_INDCPA_PUBLICKEYBYTES)
  226. * - const uint8_t *coins: pointer to input random coins
  227. * used as seed (of length S2N_KYBER_512_R3_SYMBYTES)
  228. * to deterministically generate all
  229. * randomness
  230. **************************************************/
  231. void indcpa_enc(uint8_t c[S2N_KYBER_512_R3_INDCPA_BYTES], const uint8_t m[S2N_KYBER_512_R3_INDCPA_MSGBYTES],
  232. const uint8_t pk[S2N_KYBER_512_R3_INDCPA_PUBLICKEYBYTES], const uint8_t coins[S2N_KYBER_512_R3_SYMBYTES]) {
  233. uint8_t seed[S2N_KYBER_512_R3_SYMBYTES];
  234. uint8_t nonce = 0;
  235. polyvec sp, pkpv, ep, at[S2N_KYBER_512_R3_K], bp;
  236. poly v, k, epp;
  237. unpack_pk(&pkpv, seed, pk);
  238. poly_frommsg(&k, m);
  239. gen_matrix(at, seed, 1);
  240. for (unsigned int i = 0; i < S2N_KYBER_512_R3_K; i++) {
  241. poly_getnoise_eta1(sp.vec + i, coins, nonce++);
  242. }
  243. for (unsigned int i = 0; i < S2N_KYBER_512_R3_K; i++) {
  244. poly_getnoise_eta2(ep.vec + i, coins, nonce++);
  245. }
  246. poly_getnoise_eta2(&epp, coins, nonce++);
  247. polyvec_ntt(&sp);
  248. /* matrix-vector multiplication */
  249. for (unsigned int i = 0; i < S2N_KYBER_512_R3_K; i++) {
  250. polyvec_pointwise_acc_montgomery(&bp.vec[i], &at[i], &sp);
  251. }
  252. polyvec_pointwise_acc_montgomery(&v, &pkpv, &sp);
  253. polyvec_invntt_tomont(&bp);
  254. poly_invntt_tomont(&v);
  255. polyvec_add(&bp, &bp, &ep);
  256. poly_add(&v, &v, &epp);
  257. poly_add(&v, &v, &k);
  258. polyvec_reduce(&bp);
  259. poly_reduce(&v);
  260. pack_ciphertext(c, &bp, &v);
  261. }
  262. /*************************************************
  263. * Name: indcpa_dec
  264. *
  265. * Description: Decryption function of the CPA-secure
  266. * public-key encryption scheme underlying Kyber.
  267. *
  268. * Arguments: - uint8_t *m: pointer to output decrypted message
  269. * (of length S2N_KYBER_512_R3_INDCPA_MSGBYTES)
  270. * - const uint8_t *c: pointer to input ciphertext
  271. * (of length S2N_KYBER_512_R3_INDCPA_BYTES)
  272. * - const uint8_t *sk: pointer to input secret key
  273. * (of length S2N_KYBER_512_R3_INDCPA_SECRETKEYBYTES)
  274. **************************************************/
  275. void indcpa_dec(uint8_t m[S2N_KYBER_512_R3_INDCPA_MSGBYTES], const uint8_t c[S2N_KYBER_512_R3_INDCPA_BYTES],
  276. const uint8_t sk[S2N_KYBER_512_R3_INDCPA_SECRETKEYBYTES]) {
  277. polyvec bp, skpv;
  278. poly v, mp;
  279. unpack_ciphertext(&bp, &v, c);
  280. unpack_sk(&skpv, sk);
  281. polyvec_ntt(&bp);
  282. polyvec_pointwise_acc_montgomery(&mp, &skpv, &bp);
  283. poly_invntt_tomont(&mp);
  284. poly_sub(&mp, &v, &mp);
  285. poly_reduce(&mp);
  286. poly_tomsg(m, &mp);
  287. }