You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

owcpa.c 6.1 KiB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. #include "owcpa.h"
  2. #include "poly.h"
  3. #include "sample.h"
  4. static int owcpa_check_r(const poly *r) {
  5. /* Check that r is in message space. */
  6. /* Note: Assumes that r has coefficients in {0, 1, ..., q-1} */
  7. int i;
  8. uint64_t t = 0;
  9. uint16_t c;
  10. for (i = 0; i < NTRU_N; i++) {
  11. c = MODQ(r->coeffs[i] + 1);
  12. t |= c & (NTRU_Q - 4); /* 0 if c is in {0,1,2,3} */
  13. t |= (c + 1) & 0x4; /* 0 if c is in {0,1,2} */
  14. }
  15. t |= r->coeffs[NTRU_N - 1]; /* Coefficient n-1 must be zero */
  16. t = (~t + 1); // two's complement
  17. t >>= 63;
  18. return (int) t;
  19. }
  20. static int owcpa_check_m(const poly *m) {
  21. /* Check that m is in message space. */
  22. /* Note: Assumes that m has coefficients in {0,1,2}. */
  23. int i;
  24. uint64_t t = 0;
  25. uint16_t p1 = 0;
  26. uint16_t m1 = 0;
  27. for (i = 0; i < NTRU_N; i++) {
  28. p1 += m->coeffs[i] & 0x01;
  29. m1 += (m->coeffs[i] & 0x02) >> 1;
  30. }
  31. /* Need p1 = m1 and p1 + m1 = NTRU_WEIGHT */
  32. t |= p1 ^ m1;
  33. t |= (p1 + m1) ^ NTRU_WEIGHT;
  34. t = (~t + 1); // two's complement
  35. t >>= 63;
  36. return (int) t;
  37. }
  38. void PQCLEAN_NTRUHPS4096821_CLEAN_owcpa_samplemsg(unsigned char msg[NTRU_OWCPA_MSGBYTES],
  39. const unsigned char seed[NTRU_SAMPLE_RM_BYTES]) {
  40. poly r, m;
  41. PQCLEAN_NTRUHPS4096821_CLEAN_sample_rm(&r, &m, seed);
  42. PQCLEAN_NTRUHPS4096821_CLEAN_poly_S3_tobytes(msg, &r);
  43. PQCLEAN_NTRUHPS4096821_CLEAN_poly_S3_tobytes(msg + NTRU_PACK_TRINARY_BYTES, &m);
  44. }
  45. void PQCLEAN_NTRUHPS4096821_CLEAN_owcpa_keypair(unsigned char *pk,
  46. unsigned char *sk,
  47. const unsigned char seed[NTRU_SAMPLE_FG_BYTES]) {
  48. int i;
  49. poly x1, x2, x3, x4, x5;
  50. poly *f = &x1, *invf_mod3 = &x2;
  51. poly *g = &x3, *G = &x2;
  52. poly *Gf = &x3, *invGf = &x4, *tmp = &x5;
  53. poly *invh = &x3, *h = &x3;
  54. PQCLEAN_NTRUHPS4096821_CLEAN_sample_fg(f, g, seed);
  55. PQCLEAN_NTRUHPS4096821_CLEAN_poly_S3_inv(invf_mod3, f);
  56. PQCLEAN_NTRUHPS4096821_CLEAN_poly_S3_tobytes(sk, f);
  57. PQCLEAN_NTRUHPS4096821_CLEAN_poly_S3_tobytes(sk + NTRU_PACK_TRINARY_BYTES, invf_mod3);
  58. /* Lift coeffs of f and g from Z_p to Z_q */
  59. PQCLEAN_NTRUHPS4096821_CLEAN_poly_Z3_to_Zq(f);
  60. PQCLEAN_NTRUHPS4096821_CLEAN_poly_Z3_to_Zq(g);
  61. /* G = 3*g */
  62. for (i = 0; i < NTRU_N; i++) {
  63. G->coeffs[i] = MODQ(3 * g->coeffs[i]);
  64. }
  65. PQCLEAN_NTRUHPS4096821_CLEAN_poly_Rq_mul(Gf, G, f);
  66. PQCLEAN_NTRUHPS4096821_CLEAN_poly_Rq_inv(invGf, Gf);
  67. PQCLEAN_NTRUHPS4096821_CLEAN_poly_Rq_mul(tmp, invGf, f);
  68. PQCLEAN_NTRUHPS4096821_CLEAN_poly_Sq_mul(invh, tmp, f);
  69. PQCLEAN_NTRUHPS4096821_CLEAN_poly_Sq_tobytes(sk + 2 * NTRU_PACK_TRINARY_BYTES, invh);
  70. PQCLEAN_NTRUHPS4096821_CLEAN_poly_Rq_mul(tmp, invGf, G);
  71. PQCLEAN_NTRUHPS4096821_CLEAN_poly_Rq_mul(h, tmp, G);
  72. PQCLEAN_NTRUHPS4096821_CLEAN_poly_Rq_sum_zero_tobytes(pk, h);
  73. }
  74. void PQCLEAN_NTRUHPS4096821_CLEAN_owcpa_enc(unsigned char *c,
  75. const unsigned char *rm,
  76. const unsigned char *pk) {
  77. int i;
  78. poly x1, x2, x3;
  79. poly *h = &x1, *liftm = &x1;
  80. poly *r = &x2, *m = &x2;
  81. poly *ct = &x3;
  82. PQCLEAN_NTRUHPS4096821_CLEAN_poly_Rq_sum_zero_frombytes(h, pk);
  83. PQCLEAN_NTRUHPS4096821_CLEAN_poly_S3_frombytes(r, rm);
  84. PQCLEAN_NTRUHPS4096821_CLEAN_poly_Z3_to_Zq(r);
  85. PQCLEAN_NTRUHPS4096821_CLEAN_poly_Rq_mul(ct, r, h);
  86. PQCLEAN_NTRUHPS4096821_CLEAN_poly_S3_frombytes(m, rm + NTRU_PACK_TRINARY_BYTES);
  87. PQCLEAN_NTRUHPS4096821_CLEAN_poly_lift(liftm, m);
  88. for (i = 0; i < NTRU_N; i++) {
  89. ct->coeffs[i] = MODQ(ct->coeffs[i] + liftm->coeffs[i]);
  90. }
  91. PQCLEAN_NTRUHPS4096821_CLEAN_poly_Rq_sum_zero_tobytes(c, ct);
  92. }
  93. int PQCLEAN_NTRUHPS4096821_CLEAN_owcpa_dec(unsigned char *rm,
  94. const unsigned char *ciphertext,
  95. const unsigned char *secretkey) {
  96. int i;
  97. int fail;
  98. poly x1, x2, x3, x4;
  99. poly *c = &x1, *f = &x2, *cf = &x3;
  100. poly *mf = &x2, *finv3 = &x3, *m = &x4;
  101. poly *liftm = &x2, *invh = &x3, *r = &x4;
  102. poly *b = &x1;
  103. PQCLEAN_NTRUHPS4096821_CLEAN_poly_Rq_sum_zero_frombytes(c, ciphertext);
  104. PQCLEAN_NTRUHPS4096821_CLEAN_poly_S3_frombytes(f, secretkey);
  105. PQCLEAN_NTRUHPS4096821_CLEAN_poly_Z3_to_Zq(f);
  106. PQCLEAN_NTRUHPS4096821_CLEAN_poly_Rq_mul(cf, c, f);
  107. PQCLEAN_NTRUHPS4096821_CLEAN_poly_Rq_to_S3(mf, cf);
  108. PQCLEAN_NTRUHPS4096821_CLEAN_poly_S3_frombytes(finv3, secretkey + NTRU_PACK_TRINARY_BYTES);
  109. PQCLEAN_NTRUHPS4096821_CLEAN_poly_S3_mul(m, mf, finv3);
  110. PQCLEAN_NTRUHPS4096821_CLEAN_poly_S3_tobytes(rm + NTRU_PACK_TRINARY_BYTES, m);
  111. /* NOTE: For the IND-CCA2 KEM we must ensure that c = Enc(h, (r,m)). */
  112. /* We can avoid re-computing r*h + Lift(m) as long as we check that */
  113. /* r (defined as b/h mod (q, Phi_n)) and m are in the message space. */
  114. /* (m can take any value in S3 in NTRU_HRSS) */
  115. fail = 0;
  116. fail |= owcpa_check_m(m);
  117. /* b = c - Lift(m) mod (q, x^n - 1) */
  118. PQCLEAN_NTRUHPS4096821_CLEAN_poly_lift(liftm, m);
  119. for (i = 0; i < NTRU_N; i++) {
  120. b->coeffs[i] = MODQ(c->coeffs[i] - liftm->coeffs[i]);
  121. }
  122. /* r = b / h mod (q, Phi_n) */
  123. PQCLEAN_NTRUHPS4096821_CLEAN_poly_Sq_frombytes(invh, secretkey + 2 * NTRU_PACK_TRINARY_BYTES);
  124. PQCLEAN_NTRUHPS4096821_CLEAN_poly_Sq_mul(r, b, invh);
  125. /* NOTE: Our definition of r as b/h mod (q, Phi_n) follows Figure 4 of */
  126. /* [Sch18] https://eprint.iacr.org/2018/1174/20181203:032458. */
  127. /* This differs from Figure 10 of Saito--Xagawa--Yamakawa */
  128. /* [SXY17] https://eprint.iacr.org/2017/1005/20180516:055500 */
  129. /* where r gets a final reduction modulo p. */
  130. /* We need this change to use Proposition 1 of [Sch18]. */
  131. /* Proposition 1 of [Sch18] shows that re-encryption with (r,m) yields c. */
  132. /* if and only if fail==0 after the following call to owcpa_check_r */
  133. /* The procedure given in Fig. 8 of [Sch18] can be skipped because we have */
  134. /* c(1) = 0 due to the use of poly_Rq_sum_zero_{to,from}bytes. */
  135. fail |= owcpa_check_r(r);
  136. PQCLEAN_NTRUHPS4096821_CLEAN_poly_trinary_Zq_to_Z3(r);
  137. PQCLEAN_NTRUHPS4096821_CLEAN_poly_S3_tobytes(rm, r);
  138. return fail;
  139. }