kpqc 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (191) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +4 -0
  3. data/LICENSE +21 -0
  4. data/README.md +174 -0
  5. data/Rakefile +57 -0
  6. data/THIRD_PARTY_NOTICES.md +53 -0
  7. data/ext/kpqc/aimer128f/extconf.rb +4 -0
  8. data/ext/kpqc/aimer128s/extconf.rb +4 -0
  9. data/ext/kpqc/aimer192f/extconf.rb +4 -0
  10. data/ext/kpqc/aimer192s/extconf.rb +4 -0
  11. data/ext/kpqc/aimer256f/extconf.rb +4 -0
  12. data/ext/kpqc/aimer256s/extconf.rb +4 -0
  13. data/ext/kpqc/extconf_helper.rb +93 -0
  14. data/ext/kpqc/haetae2/extconf.rb +4 -0
  15. data/ext/kpqc/haetae3/extconf.rb +4 -0
  16. data/ext/kpqc/haetae5/extconf.rb +4 -0
  17. data/ext/kpqc/module.c +195 -0
  18. data/ext/kpqc/ntruplus1152/extconf.rb +4 -0
  19. data/ext/kpqc/ntruplus768/extconf.rb +4 -0
  20. data/ext/kpqc/ntruplus864/extconf.rb +4 -0
  21. data/ext/kpqc/randombytes.c +107 -0
  22. data/ext/kpqc/smaugt128/extconf.rb +4 -0
  23. data/ext/kpqc/smaugt192/extconf.rb +4 -0
  24. data/ext/kpqc/smaugt256/extconf.rb +4 -0
  25. data/ext/kpqc/timer/extconf.rb +4 -0
  26. data/kpqc.gemspec +41 -0
  27. data/lib/kpqc/aimer.rb +38 -0
  28. data/lib/kpqc/api.rb +129 -0
  29. data/lib/kpqc/haetae.rb +25 -0
  30. data/lib/kpqc/ntruplus.rb +25 -0
  31. data/lib/kpqc/smaugt.rb +29 -0
  32. data/lib/kpqc/types.rb +103 -0
  33. data/lib/kpqc/version.rb +6 -0
  34. data/lib/kpqc.rb +33 -0
  35. data/test/algorithm_test.rb +111 -0
  36. data/test/api_test.rb +52 -0
  37. data/test/interop.mjs +34 -0
  38. data/test/interop_test.rb +82 -0
  39. data/test/kat/aimer128f.rsp +10 -0
  40. data/test/kat/aimer128s.rsp +10 -0
  41. data/test/kat/aimer192f.rsp +10 -0
  42. data/test/kat/aimer192s.rsp +10 -0
  43. data/test/kat/aimer256f.rsp +10 -0
  44. data/test/kat/aimer256s.rsp +10 -0
  45. data/test/kat/haetae2.rsp +10 -0
  46. data/test/kat/haetae3.rsp +10 -0
  47. data/test/kat/haetae5.rsp +10 -0
  48. data/test/kat/ntruplus1152.rsp +8 -0
  49. data/test/kat/ntruplus768.rsp +8 -0
  50. data/test/kat/ntruplus864.rsp +8 -0
  51. data/test/kat/smaugt128.rsp +8 -0
  52. data/test/kat/smaugt192.rsp +8 -0
  53. data/test/kat/smaugt256.rsp +8 -0
  54. data/test/kat/timer.rsp +8 -0
  55. data/test/kat_drbg.rb +155 -0
  56. data/test/kat_test.rb +99 -0
  57. data/test/test_helper.rb +21 -0
  58. data/vendor/AIMer/LICENSE +21 -0
  59. data/vendor/AIMer/aim2.c +163 -0
  60. data/vendor/AIMer/aim2.h +36 -0
  61. data/vendor/AIMer/aim2_constant.h +74 -0
  62. data/vendor/AIMer/api.h +42 -0
  63. data/vendor/AIMer/common/crypto_declassify.h +7 -0
  64. data/vendor/AIMer/common/fips202.c +878 -0
  65. data/vendor/AIMer/common/fips202.h +166 -0
  66. data/vendor/AIMer/common/rng.h +56 -0
  67. data/vendor/AIMer/field.h +43 -0
  68. data/vendor/AIMer/field128.c +454 -0
  69. data/vendor/AIMer/field192.c +485 -0
  70. data/vendor/AIMer/field256.c +564 -0
  71. data/vendor/AIMer/hash.c +50 -0
  72. data/vendor/AIMer/hash.h +37 -0
  73. data/vendor/AIMer/params/params-aimer-128f.h +34 -0
  74. data/vendor/AIMer/params/params-aimer-128s.h +34 -0
  75. data/vendor/AIMer/params/params-aimer-192f.h +34 -0
  76. data/vendor/AIMer/params/params-aimer-192s.h +34 -0
  77. data/vendor/AIMer/params/params-aimer-256f.h +34 -0
  78. data/vendor/AIMer/params/params-aimer-256s.h +34 -0
  79. data/vendor/AIMer/params.h +5 -0
  80. data/vendor/AIMer/sign.c +631 -0
  81. data/vendor/AIMer/sign.h +40 -0
  82. data/vendor/AIMer/tree.c +75 -0
  83. data/vendor/AIMer/tree.h +26 -0
  84. data/vendor/HAETAE/LICENSE +22 -0
  85. data/vendor/HAETAE/include/api.h +54 -0
  86. data/vendor/HAETAE/include/common.h +12 -0
  87. data/vendor/HAETAE/include/config.h +42 -0
  88. data/vendor/HAETAE/include/decompose.h +19 -0
  89. data/vendor/HAETAE/include/encoding.h +20 -0
  90. data/vendor/HAETAE/include/fft.h +26 -0
  91. data/vendor/HAETAE/include/fips202.h +40 -0
  92. data/vendor/HAETAE/include/fixpoint.h +125 -0
  93. data/vendor/HAETAE/include/ntt.h +16 -0
  94. data/vendor/HAETAE/include/packing.h +58 -0
  95. data/vendor/HAETAE/include/params.h +117 -0
  96. data/vendor/HAETAE/include/poly.h +65 -0
  97. data/vendor/HAETAE/include/polyfix.h +65 -0
  98. data/vendor/HAETAE/include/polymat.h +32 -0
  99. data/vendor/HAETAE/include/polyvec.h +131 -0
  100. data/vendor/HAETAE/include/randombytes.h +39 -0
  101. data/vendor/HAETAE/include/rans_byte.h +335 -0
  102. data/vendor/HAETAE/include/reduce.h +31 -0
  103. data/vendor/HAETAE/include/sampler.h +23 -0
  104. data/vendor/HAETAE/include/symmetric.h +52 -0
  105. data/vendor/HAETAE/src/decompose.c +73 -0
  106. data/vendor/HAETAE/src/encoding.c +700 -0
  107. data/vendor/HAETAE/src/fft.c +235 -0
  108. data/vendor/HAETAE/src/fips202.c +745 -0
  109. data/vendor/HAETAE/src/fixpoint.c +143 -0
  110. data/vendor/HAETAE/src/ntt.c +98 -0
  111. data/vendor/HAETAE/src/packing.c +595 -0
  112. data/vendor/HAETAE/src/poly.c +371 -0
  113. data/vendor/HAETAE/src/polyfix.c +298 -0
  114. data/vendor/HAETAE/src/polymat.c +82 -0
  115. data/vendor/HAETAE/src/polyvec.c +534 -0
  116. data/vendor/HAETAE/src/reduce.c +96 -0
  117. data/vendor/HAETAE/src/sampler.c +310 -0
  118. data/vendor/HAETAE/src/sign.c +558 -0
  119. data/vendor/HAETAE/src/symmetric-shake.c +50 -0
  120. data/vendor/NTRUplus/LICENSE +21 -0
  121. data/vendor/NTRUplus/NTRU+1152/api.h +24 -0
  122. data/vendor/NTRUplus/NTRU+1152/fips202/fips202.c +878 -0
  123. data/vendor/NTRUplus/NTRU+1152/fips202/fips202.h +166 -0
  124. data/vendor/NTRUplus/NTRU+1152/kem.c +286 -0
  125. data/vendor/NTRUplus/NTRU+1152/ntt.c +394 -0
  126. data/vendor/NTRUplus/NTRU+1152/ntt.h +16 -0
  127. data/vendor/NTRUplus/NTRU+1152/params.h +18 -0
  128. data/vendor/NTRUplus/NTRU+1152/poly.c +318 -0
  129. data/vendor/NTRUplus/NTRU+1152/poly.h +31 -0
  130. data/vendor/NTRUplus/NTRU+1152/randombytes.h +9 -0
  131. data/vendor/NTRUplus/NTRU+1152/symmetric.c +39 -0
  132. data/vendor/NTRUplus/NTRU+1152/symmetric.h +12 -0
  133. data/vendor/NTRUplus/NTRU+768/api.h +24 -0
  134. data/vendor/NTRUplus/NTRU+768/fips202/fips202.c +878 -0
  135. data/vendor/NTRUplus/NTRU+768/fips202/fips202.h +166 -0
  136. data/vendor/NTRUplus/NTRU+768/kem.c +286 -0
  137. data/vendor/NTRUplus/NTRU+768/ntt.c +379 -0
  138. data/vendor/NTRUplus/NTRU+768/ntt.h +16 -0
  139. data/vendor/NTRUplus/NTRU+768/params.h +18 -0
  140. data/vendor/NTRUplus/NTRU+768/poly.c +320 -0
  141. data/vendor/NTRUplus/NTRU+768/poly.h +31 -0
  142. data/vendor/NTRUplus/NTRU+768/randombytes.h +9 -0
  143. data/vendor/NTRUplus/NTRU+768/symmetric.c +39 -0
  144. data/vendor/NTRUplus/NTRU+768/symmetric.h +12 -0
  145. data/vendor/NTRUplus/NTRU+864/api.h +24 -0
  146. data/vendor/NTRUplus/NTRU+864/fips202/fips202.c +878 -0
  147. data/vendor/NTRUplus/NTRU+864/fips202/fips202.h +166 -0
  148. data/vendor/NTRUplus/NTRU+864/kem.c +286 -0
  149. data/vendor/NTRUplus/NTRU+864/ntt.c +383 -0
  150. data/vendor/NTRUplus/NTRU+864/ntt.h +16 -0
  151. data/vendor/NTRUplus/NTRU+864/params.h +18 -0
  152. data/vendor/NTRUplus/NTRU+864/poly.c +314 -0
  153. data/vendor/NTRUplus/NTRU+864/poly.h +31 -0
  154. data/vendor/NTRUplus/NTRU+864/randombytes.h +9 -0
  155. data/vendor/NTRUplus/NTRU+864/symmetric.c +39 -0
  156. data/vendor/NTRUplus/NTRU+864/symmetric.h +12 -0
  157. data/vendor/SMAUG-T/LICENSE +22 -0
  158. data/vendor/SMAUG-T/include/api.h +37 -0
  159. data/vendor/SMAUG-T/include/cbd.h +15 -0
  160. data/vendor/SMAUG-T/include/ciphertext.h +45 -0
  161. data/vendor/SMAUG-T/include/common.h +12 -0
  162. data/vendor/SMAUG-T/include/config.h +48 -0
  163. data/vendor/SMAUG-T/include/dg.h +28 -0
  164. data/vendor/SMAUG-T/include/fips202.h +41 -0
  165. data/vendor/SMAUG-T/include/hash.h +21 -0
  166. data/vendor/SMAUG-T/include/hwt.h +28 -0
  167. data/vendor/SMAUG-T/include/indcpa.h +33 -0
  168. data/vendor/SMAUG-T/include/key.h +34 -0
  169. data/vendor/SMAUG-T/include/pack.h +78 -0
  170. data/vendor/SMAUG-T/include/packring.h +50 -0
  171. data/vendor/SMAUG-T/include/params.h +84 -0
  172. data/vendor/SMAUG-T/include/poly.h +41 -0
  173. data/vendor/SMAUG-T/include/randombytes.h +11 -0
  174. data/vendor/SMAUG-T/include/toomcook.h +14 -0
  175. data/vendor/SMAUG-T/include/verify.h +16 -0
  176. data/vendor/SMAUG-T/src/cbd.c +159 -0
  177. data/vendor/SMAUG-T/src/ciphertext.c +95 -0
  178. data/vendor/SMAUG-T/src/dg.c +112 -0
  179. data/vendor/SMAUG-T/src/fips202.c +745 -0
  180. data/vendor/SMAUG-T/src/hash.c +15 -0
  181. data/vendor/SMAUG-T/src/hwt.c +121 -0
  182. data/vendor/SMAUG-T/src/indcpa.c +187 -0
  183. data/vendor/SMAUG-T/src/kem.c +194 -0
  184. data/vendor/SMAUG-T/src/key.c +102 -0
  185. data/vendor/SMAUG-T/src/pack.c +349 -0
  186. data/vendor/SMAUG-T/src/packring.c +503 -0
  187. data/vendor/SMAUG-T/src/poly.c +200 -0
  188. data/vendor/SMAUG-T/src/toomcook.c +256 -0
  189. data/vendor/SMAUG-T/src/verify.c +48 -0
  190. data/vendor/SOURCES.json +130 -0
  191. metadata +280 -0
@@ -0,0 +1,558 @@
1
+ /* kpqc-py: propagate OS entropy failures (2026-09-06). */
2
+ // SPDX-License-Identifier: MIT
3
+
4
+ #include "api.h"
5
+ #include "packing.h"
6
+ #include "params.h"
7
+ #include "poly.h"
8
+ #include "polyfix.h"
9
+ #include "polymat.h"
10
+ #include "polyvec.h"
11
+ #include "randombytes.h"
12
+ #include "symmetric.h"
13
+
14
+ #include <inttypes.h>
15
+ #include <stdint.h>
16
+ #include <stdio.h>
17
+ #include <string.h>
18
+
19
+ /*************************************************
20
+ * Name: crypto_sign_keypair_internal
21
+ *
22
+ * Description: Generates public and private key.
23
+ *
24
+ * Arguments: - uint8_t *vk: pointer to output public key (allocated
25
+ * array of HAETAE_CRYPTO_PUBLICKEYBYTES bytes)
26
+ * - uint8_t *sk: pointer to output private key (allocated
27
+ * array of HAETAE_CRYPTO_SECRETKEYBYTES bytes)
28
+ * - uint8_t seed : input seed
29
+ *
30
+ * Returns 0 (success)
31
+ *
32
+ * Specification: Implements Algorithm 48, KeyGenInternal.
33
+ **************************************************/
34
+
35
+ int crypto_sign_keypair_internal(uint8_t *vk, uint8_t *sk,
36
+ uint8_t seed[HAETAE_SEEDBYTES]) {
37
+ uint8_t seedbuf[2 * HAETAE_SEEDBYTES + HAETAE_CRHBYTES] = {0};
38
+ uint16_t counter = 0;
39
+ const uint8_t *rhoprime, *sigma, *key;
40
+ polyvecm A[HAETAE_K], s1, s1hat;
41
+ polyveck b, s2;
42
+ #if (HAETAE_MODE == HAETAE_MODE2) || (HAETAE_MODE == HAETAE_MODE3)
43
+ polyveck a, b0;
44
+ #elif HAETAE_MODE == HAETAE_MODE5
45
+ polyveck s2hat;
46
+ #endif
47
+ xof256_state state;
48
+
49
+ // Get seed_A
50
+ memcpy(seedbuf, seed, HAETAE_SEEDBYTES);
51
+
52
+ // Sample seeds with entropy \rho
53
+ xof256_absorb_once(&state, seedbuf, HAETAE_SEEDBYTES);
54
+ xof256_squeeze(seedbuf, 2 * HAETAE_SEEDBYTES + HAETAE_CRHBYTES, &state);
55
+
56
+ rhoprime = seedbuf;
57
+ sigma = rhoprime + HAETAE_SEEDBYTES;
58
+ key = sigma + HAETAE_CRHBYTES;
59
+
60
+ // Expand Matrix A0 and vector a
61
+ polymatkm_expand_matA(A, rhoprime);
62
+
63
+ #if (HAETAE_MODE == HAETAE_MODE2) || (HAETAE_MODE == HAETAE_MODE3)
64
+ /**********************************************
65
+ * If there is rounding (D > 0), we need another polyveck a.
66
+ * Then, b = a + A0 * s1 + s2 and the lower D bits are
67
+ * rounded from b. The lower D bits are subsequently
68
+ * subtracted from s2.
69
+ **********************************************/
70
+ polyveck_expand_vecA(&a, rhoprime);
71
+
72
+ reject:
73
+ // Sample secret vectors s1 and s2
74
+ polyvecmk_expand_S(&s1, &s2, sigma, counter);
75
+ counter += HAETAE_M + HAETAE_K;
76
+
77
+ // b = a + A0 * s1 + s2 mod q
78
+ s1hat = s1;
79
+ polyvecm_ntt(&s1hat);
80
+ polymatkm_pointwise_montgomery(&b, A, &s1hat);
81
+ polyveck_invntt_tomont(&b);
82
+ polyveck_add(&b, &b, &s2);
83
+ polyveck_add(&b, &b, &a);
84
+ polyveck_freeze(&b);
85
+
86
+ // round off D bits
87
+ polyveck_decompose_vk(&b0, &b);
88
+ polyveck_sub(&s2, &s2, &b0);
89
+
90
+ int64_t squared_singular_value = polyvecmk_sk_singular_value(&s1, &s2);
91
+ if (squared_singular_value > HAETAE_GAMMA * HAETAE_GAMMA * HAETAE_N) {
92
+ goto reject;
93
+ }
94
+ #elif HAETAE_MODE == HAETAE_MODE5
95
+ /**********************************************
96
+ * If there is no rounding (D == 0), we store
97
+ * -2b directly in NTT domain into the public key.
98
+ **********************************************/
99
+ reject:
100
+ // Sample secret vectors s1 and s2
101
+ polyvecmk_expand_S(&s1, &s2, sigma, counter);
102
+ counter += HAETAE_M + HAETAE_K;
103
+ int64_t squared_singular_value = polyvecmk_sk_singular_value(&s1, &s2);
104
+ if (squared_singular_value > HAETAE_GAMMA * HAETAE_GAMMA * HAETAE_N) {
105
+ goto reject;
106
+ }
107
+
108
+ // b = A0 * s1 + s2 mod q
109
+ s1hat = s1;
110
+ s2hat = s2;
111
+ polyvecm_ntt(&s1hat);
112
+ polyveck_ntt(&s2hat);
113
+ polymatkm_pointwise_montgomery(&b, A, &s1hat);
114
+ polyveck_frommont(&b);
115
+ polyveck_add(&b, &b, &s2hat);
116
+ polyveck_double_negate(&b);
117
+ polyveck_caddq(&b); // directly compute and store NTT(-2b)
118
+ #endif
119
+
120
+ pack_vk(vk, &b, rhoprime);
121
+ pack_sk(sk, vk, &s1, &s2, key);
122
+
123
+ return 0;
124
+ }
125
+
126
+ /*************************************************
127
+ * Name: crypto_sign_keypair_internal
128
+ *
129
+ * Description: Generates public and private key.
130
+ *
131
+ * Arguments: - uint8_t *vk: pointer to output public key (allocated
132
+ * array of HAETAE_CRYPTO_PUBLICKEYBYTES bytes)
133
+ * - uint8_t *sk: pointer to output private key (allocated
134
+ * array of HAETAE_CRYPTO_SECRETKEYBYTES bytes)
135
+ *
136
+ * Returns 0 (success)
137
+ *
138
+ * Specification: Implements Algorithm 45, KeyGen.
139
+ **************************************************/
140
+ int crypto_sign_keypair(uint8_t *pk, uint8_t *sk) {
141
+ int ret = 0;
142
+ uint8_t seed[HAETAE_SEEDBYTES] = {0};
143
+
144
+ if (randombytes(seed, HAETAE_SEEDBYTES) != 0) return -1;
145
+
146
+ ret = crypto_sign_keypair_internal(pk, sk, seed);
147
+
148
+ return ret;
149
+ }
150
+
151
+ /*************************************************
152
+ * Name: crypto_sign_signature_internal
153
+ *
154
+ * Description: Computes signature. Internal API.
155
+ *
156
+ * Arguments: - uint8_t *sig: pointer to output signature (of length
157
+ * HAETAE_CRYPTO_BYTES)
158
+ * - size_t *siglen: pointer to output length of signature
159
+ * - uint8_t *m: pointer to message to be signed
160
+ * - size_t mlen: length of message
161
+ * - uint8_t *pre: pointer to prefix string
162
+ * - size_t prelen: length of prefix string
163
+ * - uint8_t *rnd: pointer to random seed
164
+ * - uint8_t *sk: pointer to bit-packed secret key
165
+ *
166
+ * Returns 0 (success)
167
+ *
168
+ * Specification: Implements Algorithm 49, SignInternal.
169
+ **************************************************/
170
+ int crypto_sign_signature_internal(uint8_t *sig, size_t *siglen,
171
+ const uint8_t *m, size_t mlen,
172
+ const uint8_t *pre, size_t prelen,
173
+ const uint8_t rnd[HAETAE_SEEDBYTES],
174
+ const uint8_t *sk) {
175
+
176
+ uint8_t buf[HAETAE_POLYVECK_HIGHBITS_PACKEDBYTES + HAETAE_POLYC_PACKEDBYTES] =
177
+ {0};
178
+ uint8_t seedbuf[HAETAE_CRHBYTES] = {0}, key[HAETAE_SEEDBYTES] = {0};
179
+ uint8_t mu[HAETAE_CRHBYTES] = {0};
180
+ uint8_t b = 0; // one bit
181
+ uint16_t counter = 0;
182
+ uint64_t reject1, reject2;
183
+
184
+ polyvecm s1;
185
+ polyvecl A1[HAETAE_K], cs1;
186
+ polyveck s2, cs2, highbits, Ay;
187
+ polyfixvecl y1, z1, z1tmp;
188
+ polyfixveck y2, z2, z2tmp;
189
+ polyvecl z1rnd; // round of z1
190
+ polyvecl hb_z1, lb_z1;
191
+ polyveck z2rnd, h, htmp; // round of z2
192
+ poly c, chat, z1rnd0, lsb;
193
+
194
+ xof256_state state;
195
+
196
+ unsigned int i;
197
+
198
+ // Unpack secret key
199
+ unpack_sk(A1, &s1, &s2, key, sk);
200
+
201
+ xof256_absorb_thrice(&state, sk, HAETAE_CRYPTO_PUBLICKEYBYTES, pre, prelen, m,
202
+ mlen);
203
+ xof256_squeeze(mu, HAETAE_CRHBYTES, &state);
204
+
205
+ xof256_absorb_thrice(&state, key, HAETAE_SEEDBYTES, rnd, HAETAE_SEEDBYTES, mu,
206
+ HAETAE_CRHBYTES);
207
+ xof256_squeeze(seedbuf, HAETAE_CRHBYTES, &state);
208
+
209
+ polyvecm_ntt(&s1);
210
+ polyveck_ntt(&s2);
211
+
212
+ reject:
213
+
214
+ /*------------------ 1. Sample y1 and y2 from hyperball ------------------*/
215
+ counter = polyfixveclk_sample_hyperball(&y1, &y2, &b, seedbuf, counter);
216
+
217
+ /*------------------- 2. Compute a chanllenge c --------------------------*/
218
+ // Round y1 and y2
219
+ polyfixvecl_round(&z1rnd, &y1);
220
+ polyfixveck_round(&z2rnd, &y2);
221
+
222
+ // A * round(y) mod q = A1 * round(y1) + 2 * round(y2) mod q
223
+ z1rnd0 = z1rnd.vec[0];
224
+ polyvecl_ntt(&z1rnd);
225
+ polymatkl_pointwise_montgomery(&Ay, A1, &z1rnd);
226
+ polyveck_invntt_tomont(&Ay);
227
+ polyveck_double(&z2rnd);
228
+ polyveck_add(&Ay, &Ay, &z2rnd);
229
+
230
+ // recover A * round(y) mod 2q
231
+ polyveck_poly_fromcrt(&Ay, &Ay, &z1rnd0);
232
+ polyveck_freeze2q(&Ay);
233
+
234
+ // HighBits of (A * round(y) mod 2q)
235
+ polyveck_highbits_hint(&highbits, &Ay);
236
+
237
+ // LSB(round(y_0) * j)
238
+ poly_lsb(&lsb, &z1rnd0);
239
+
240
+ // Pack HighBits of A * round(y) mod 2q and LSB of round(y0)
241
+ pack_vec_highbits(buf, &highbits);
242
+ pack_poly_lsb(buf + HAETAE_POLYVECK_HIGHBITS_PACKEDBYTES, &lsb);
243
+
244
+ // c = challenge(highbits, lsb, mu)
245
+ poly_challenge(&c, buf, mu);
246
+
247
+ /*------------------- 3. Compute z = y + (-1)^b c * s --------------------*/
248
+ // cs = c * s = c * (si1 || s2)
249
+ cs1.vec[0] = c;
250
+ chat = c;
251
+ poly_ntt(&chat);
252
+
253
+ for (i = 1; i < HAETAE_L; ++i) {
254
+ poly_pointwise_montgomery(&cs1.vec[i], &chat, &s1.vec[i - 1]);
255
+ poly_invntt_tomont(&cs1.vec[i]);
256
+ }
257
+ polyveck_poly_pointwise_montgomery(&cs2, &s2, &chat);
258
+ polyveck_invntt_tomont(&cs2);
259
+
260
+ // z = y + (-1)^b cs = z1 + z2
261
+ polyvecl_cneg(&cs1, b & 1);
262
+ polyveck_cneg(&cs2, b & 1);
263
+ polyfixvecl_add(&z1, &y1, &cs1);
264
+ polyfixveck_add(&z2, &y2, &cs2);
265
+
266
+ // reject if norm(z) >= B'
267
+ reject1 = ((uint64_t)HAETAE_B1SQ * HAETAE_LN * HAETAE_LN -
268
+ polyfixveclk_sqnorm2(&z1, &z2)) >>
269
+ 63;
270
+ reject1 &= 1;
271
+
272
+ polyfixvecl_double(&z1tmp, &z1);
273
+ polyfixveck_double(&z2tmp, &z2);
274
+
275
+ polyfixfixvecl_sub(&z1tmp, &z1tmp, &y1);
276
+ polyfixfixveck_sub(&z2tmp, &z2tmp, &y2);
277
+
278
+ // reject if norm(2z-y) < B and b' = 0
279
+ reject2 = (polyfixveclk_sqnorm2(&z1tmp, &z2tmp) -
280
+ (uint64_t)HAETAE_B0SQ * HAETAE_LN * HAETAE_LN) >>
281
+ 63;
282
+ reject2 &= 1;
283
+ reject2 &= (b & 0x2) >> 1;
284
+
285
+ if (reject1 | reject2) {
286
+ goto reject;
287
+ }
288
+
289
+ /*------------------- 4. Make a hint -------------------------------------*/
290
+ // Round z1 and z2
291
+ polyfixvecl_round(&z1rnd, &z1);
292
+ polyfixveck_round(&z2rnd, &z2);
293
+
294
+ // recover A1 * round(z1) - qcj mod 2q
295
+ polyveck_double(&z2rnd);
296
+ polyveck_sub(&htmp, &Ay, &z2rnd);
297
+ polyveck_freeze2q(&htmp);
298
+
299
+ // HighBits of (A * round(z) - qcj mod 2q) and (A1 * round(z1) - qcj mod 2q)
300
+ polyveck_highbits_hint(&htmp, &htmp);
301
+ polyveck_sub(&h, &highbits, &htmp);
302
+ polyveck_caddDQ2ALPHA(&h);
303
+
304
+ /*------------------ Decompose(z1) and Pack signature -------------------*/
305
+ polyvecl_lowbits(&lb_z1, &z1rnd);
306
+ polyvecl_highbits(&hb_z1, &z1rnd);
307
+
308
+ if (pack_sig(sig, &c, &lb_z1, &hb_z1,
309
+ &h)) { // reject if signature is too big
310
+ goto reject;
311
+ }
312
+ *siglen = HAETAE_CRYPTO_BYTES;
313
+
314
+ return 0;
315
+ }
316
+
317
+ /*************************************************
318
+ * Name: crypto_sign_signature
319
+ *
320
+ * Description: Computes signature.
321
+ *
322
+ * Arguments: - uint8_t *sig: pointer to output signature (of length
323
+ * HAETAE_CRYPTO_BYTES)
324
+ * - size_t *siglen: pointer to output length of signature
325
+ * - uint8_t *m: pointer to message to be signed
326
+ * - size_t mlen: length of message
327
+ * - uint8_t *ctx: pointer of contex string
328
+ * - size_t ctxlen: length of contex string
329
+ * - uint8_t *sk: pointer to bit-packed secret key
330
+ *
331
+ * Returns 0 (success)
332
+ *
333
+ * Specification: Implements Algorithm 46, Sign.
334
+ **************************************************/
335
+ int crypto_sign_signature(uint8_t *sig, size_t *siglen, const uint8_t *m,
336
+ size_t mlen, const uint8_t *ctx, size_t ctxlen,
337
+ const uint8_t *sk) {
338
+ uint8_t pre[256];
339
+ uint8_t rnd[HAETAE_SEEDBYTES];
340
+
341
+ if (ctxlen > 255)
342
+ return -1;
343
+
344
+ /* Prepare pre = (ctxlen, ctx) */
345
+ pre[0] = ctxlen;
346
+ memcpy(pre + 1, ctx, ctxlen);
347
+
348
+ if (randombytes(rnd, HAETAE_SEEDBYTES) != 0) return -1;
349
+
350
+ return crypto_sign_signature_internal(sig, siglen, m, mlen, pre, 1 + ctxlen,
351
+ rnd, sk);
352
+ }
353
+
354
+ /*************************************************
355
+ * Name: crypto_sign
356
+ *
357
+ * Description: Compute signed message.
358
+ *
359
+ * Arguments: - uint8_t *sm: pointer to output signed message (allocated
360
+ * array with HAETAE_CRYPTO_BYTES + mlen bytes),
361
+ * can be equal to m
362
+ * - size_t *smlen: pointer to output length of signed
363
+ * message
364
+ * - const uint8_t *m: pointer to message to be signed
365
+ * - size_t mlen: length of message
366
+ * - const uint8_t *ctx: pointer to context string
367
+ * - size_t ctxlen: length of context string
368
+ * - const uint8_t *sk: pointer to bit-packed secret key
369
+ *
370
+ * Returns 0 (success) or -1 (context string too long)
371
+ **************************************************/
372
+ int crypto_sign(uint8_t *sm, size_t *smlen, const uint8_t *m, size_t mlen,
373
+ const uint8_t *ctx, size_t ctxlen, const uint8_t *sk) {
374
+ size_t i;
375
+
376
+ for (i = 0; i < mlen; ++i)
377
+ sm[HAETAE_CRYPTO_BYTES + mlen - 1 - i] = m[mlen - 1 - i];
378
+ int ret = crypto_sign_signature(sm, smlen, sm + HAETAE_CRYPTO_BYTES, mlen,
379
+ ctx, ctxlen, sk);
380
+ *smlen += mlen;
381
+ return ret;
382
+ }
383
+
384
+ /*************************************************
385
+ * Name: crypto_sign_verify_internal
386
+ *
387
+ * Description: Verifies signature.
388
+ *
389
+ * Arguments: - uint8_t *m: pointer to input signature
390
+ * - size_t siglen: length of signature
391
+ * - const uint8_t *m: pointer to message
392
+ * - size_t mlen: length of message
393
+ * - const uint8_t *pre: pointer to prefix string
394
+ * - size_t prelen: length of prefix string
395
+ * - const uint8_t *vk: pointer to bit-packed public key
396
+ *
397
+ * Returns 0 if signature could be verified correctly and -1 otherwise
398
+ *
399
+ * Specification: Implements Algorithm 50, VerifyInternal.
400
+ **************************************************/
401
+ int crypto_sign_verify_internal(const uint8_t *sig, size_t siglen,
402
+ const uint8_t *m, size_t mlen,
403
+ const uint8_t *pre, size_t prelen,
404
+ const uint8_t *vk) {
405
+ unsigned int i;
406
+ uint8_t buf[HAETAE_POLYVECK_HIGHBITS_PACKEDBYTES + HAETAE_POLYC_PACKEDBYTES] =
407
+ {0};
408
+ uint8_t mu[HAETAE_SEEDBYTES];
409
+ uint64_t sqnorm2;
410
+ polyvecl A1[HAETAE_K], highz, lowz, z1;
411
+ polyveck highbits, h, z2, w;
412
+ poly c, cprime, wprime;
413
+
414
+ xof256_state state;
415
+
416
+ // Check signature length
417
+ if (siglen != HAETAE_CRYPTO_BYTES) {
418
+ return -1;
419
+ }
420
+ /*------------------- 1. Recover A1 --------------------------------------*/
421
+ // A1 = (-2b + qj || 2 * A0)
422
+ // Unpack public key
423
+ unpack_vk(A1, vk);
424
+
425
+ // Unpack signature and Check conditions -- A1 is used only as intermediate
426
+ // buffer for the low bits
427
+ if (unpack_sig(&c, &lowz, &highz, &h, sig)) {
428
+ return -1;
429
+ }
430
+
431
+ // Compose z1 out of HighBits(z1) and LowBits(z1)
432
+ for (i = 0; i < HAETAE_L; ++i) {
433
+ poly_compose(&z1.vec[i], &highz.vec[i], &lowz.vec[i]);
434
+ }
435
+
436
+ /*------------------- 2. Compute \tilde{z}_2 -----------------------------*/
437
+ // compute squared norm of z1 and w' before NTT
438
+ sqnorm2 = polyvecl_sqnorm2(&z1);
439
+ poly_sub(&wprime, &z1.vec[0], &c);
440
+ poly_lsb(&wprime, &wprime);
441
+
442
+ // A1 * round(z1) - qcj mod q
443
+ polyvecl_ntt(&z1);
444
+ polymatkl_pointwise_montgomery(&highbits, A1, &z1);
445
+ polyveck_invntt_tomont(&highbits);
446
+
447
+ // recover A1 * round(z1) - qcj mod 2q
448
+ polyveck_poly_fromcrt(&highbits, &highbits, &wprime);
449
+ polyveck_freeze2q(&highbits);
450
+
451
+ // recover w1
452
+ polyveck_highbits_hint(&w, &highbits);
453
+ polyveck_add(&w, &w, &h);
454
+ polyveck_csubDQ2ALPHA(&w);
455
+
456
+ // recover \tilde{z}_2 mod q
457
+ polyveck_mul_alpha(&z2, &w);
458
+ polyveck_sub(&z2, &z2, &highbits);
459
+ poly_add(&z2.vec[0], &z2.vec[0], &wprime);
460
+ polyveck_reduce2q(&z2);
461
+ polyveck_div2(&z2);
462
+
463
+ // check final norm of \tilde{z}
464
+ if (sqnorm2 + polyveck_sqnorm2(&z2) > HAETAE_B2SQ) {
465
+ return -1;
466
+ }
467
+
468
+ /*------------------- 3. Compute c_seed' and Compare ---------------------*/
469
+
470
+ // Pack highBits(A * round(z) - qcj mod 2q) and h'
471
+ pack_vec_highbits(buf, &w);
472
+ pack_poly_lsb(buf + HAETAE_POLYVECK_HIGHBITS_PACKEDBYTES, &wprime);
473
+
474
+ xof256_absorb_thrice(&state, vk, HAETAE_CRYPTO_PUBLICKEYBYTES, pre, prelen, m,
475
+ mlen);
476
+ xof256_squeeze(mu, HAETAE_SEEDBYTES, &state);
477
+ // c_seed = H(HighBits(A * y mod 2q), LSB(round(y0) * j), HAETAE_M)
478
+ poly_challenge(&cprime, buf, mu);
479
+
480
+ for (i = 0; i < HAETAE_N; ++i) {
481
+ if (c.coeffs[i] != cprime.coeffs[i]) {
482
+ return -1;
483
+ }
484
+ }
485
+ return 0;
486
+ }
487
+
488
+ /*************************************************
489
+ * Name: crypto_sign_verify
490
+ *
491
+ * Description: Verifies signature.
492
+ *
493
+ * Arguments: - uint8_t *m: pointer to input signature
494
+ * - size_t siglen: length of signature
495
+ * - const uint8_t *m: pointer to message
496
+ * - size_t mlen: length of message
497
+ * - const uint8_t *ctx: pointer to context string
498
+ * - size_t ctxlen: length of context string
499
+ * - const uint8_t *vk: pointer to bit-packed public key
500
+ *
501
+ * Returns 0 if signature could be verified correctly and -1 otherwise
502
+ *
503
+ * Specification: Implements Algorithm 47, Verify.
504
+ **************************************************/
505
+ int crypto_sign_verify(const uint8_t *sig, size_t siglen, const uint8_t *m,
506
+ size_t mlen, const uint8_t *ctx, size_t ctxlen,
507
+ const uint8_t *vk) {
508
+ uint8_t pre[257];
509
+
510
+ if (ctxlen > 255)
511
+ return -1;
512
+
513
+ pre[0] = ctxlen;
514
+ memcpy(pre + 1, ctx, ctxlen);
515
+
516
+ return crypto_sign_verify_internal(sig, siglen, m, mlen, pre, 1 + ctxlen, vk);
517
+ }
518
+
519
+ /*************************************************
520
+ * Name: crypto_sign_open
521
+ *
522
+ * Description: Verify signed message.
523
+ *
524
+ * Arguments: - uint8_t *m: pointer to output message (allocated
525
+ * array with smlen bytes), can be equal to sm
526
+ * - size_t *mlen: pointer to output length of message
527
+ * - const uint8_t *sm: pointer to signed message
528
+ * - size_t smlen: length of signed message
529
+ * - const uint8_t *vk: pointer to bit-packed public key
530
+ *
531
+ * Returns 0 if signed message could be verified correctly and -1 otherwise
532
+ **************************************************/
533
+ int crypto_sign_open(uint8_t *m, size_t *mlen, const uint8_t *sm, size_t smlen,
534
+ const uint8_t *ctx, size_t ctxlen, const uint8_t *vk) {
535
+ size_t i;
536
+
537
+ if (smlen < HAETAE_CRYPTO_BYTES)
538
+ goto badsig;
539
+
540
+ *mlen = smlen - HAETAE_CRYPTO_BYTES;
541
+ if (crypto_sign_verify(sm, HAETAE_CRYPTO_BYTES, sm + HAETAE_CRYPTO_BYTES,
542
+ *mlen, ctx, ctxlen, vk))
543
+ goto badsig;
544
+ else {
545
+ /* All good, copy msg, return 0 */
546
+ for (i = 0; i < *mlen; ++i)
547
+ m[i] = sm[HAETAE_CRYPTO_BYTES + i];
548
+ return 0;
549
+ }
550
+
551
+ badsig:
552
+ /* Signature verification failed */
553
+ *mlen = -1;
554
+ for (i = 0; i < smlen; ++i)
555
+ m[i] = 0;
556
+
557
+ return -1;
558
+ }
@@ -0,0 +1,50 @@
1
+ // SPDX-License-Identifier: MIT
2
+
3
+ #include "fips202.h"
4
+ #include "params.h"
5
+ #include "symmetric.h"
6
+
7
+ #include <stdint.h>
8
+
9
+ void shake128_stream_init(keccak_state *state,
10
+ const uint8_t seed[HAETAE_SEEDBYTES],
11
+ uint16_t nonce) {
12
+ uint8_t t[2];
13
+ t[0] = nonce;
14
+ t[1] = nonce >> 8;
15
+
16
+ shake128_init(state);
17
+ shake128_absorb(state, seed, HAETAE_SEEDBYTES);
18
+ shake128_absorb(state, t, 2);
19
+ shake128_finalize(state);
20
+ }
21
+
22
+ void shake256_stream_init(keccak_state *state,
23
+ const uint8_t seed[HAETAE_CRHBYTES], uint16_t nonce) {
24
+ uint8_t t[2];
25
+ t[0] = nonce;
26
+ t[1] = nonce >> 8;
27
+
28
+ shake256_init(state);
29
+ shake256_absorb(state, seed, HAETAE_CRHBYTES);
30
+ shake256_absorb(state, t, 2);
31
+ shake256_finalize(state);
32
+ }
33
+
34
+ void shake256_absorb_twice(keccak_state *state, const uint8_t *in1,
35
+ size_t in1len, const uint8_t *in2, size_t in2len) {
36
+ shake256_init(state);
37
+ shake256_absorb(state, in1, in1len);
38
+ shake256_absorb(state, in2, in2len);
39
+ shake256_finalize(state);
40
+ }
41
+
42
+ void shake256_absorb_thrice(keccak_state *state, const uint8_t *in1,
43
+ size_t in1len, const uint8_t *in2, size_t in2len,
44
+ const uint8_t *in3, size_t in3len) {
45
+ shake256_init(state);
46
+ shake256_absorb(state, in1, in1len);
47
+ shake256_absorb(state, in2, in2len);
48
+ shake256_absorb(state, in3, in3len);
49
+ shake256_finalize(state);
50
+ }
@@ -0,0 +1,21 @@
1
+ The MIT License
2
+
3
+ Copyright (c) 2024–2026 NTRU+ TEAM (https://www.ntruplus.org/)
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,24 @@
1
+ #ifndef API_H
2
+ #define API_H
3
+
4
+ #include "params.h"
5
+
6
+ #define CRYPTO_SECRETKEYBYTES NTRUPLUS_SECRETKEYBYTES
7
+ #define CRYPTO_PUBLICKEYBYTES NTRUPLUS_PUBLICKEYBYTES
8
+ #define CRYPTO_CIPHERTEXTBYTES NTRUPLUS_CIPHERTEXTBYTES
9
+ #define CRYPTO_BYTES NTRUPLUS_SSBYTES
10
+
11
+ #define CRYPTO_ALGNAME NTRUPLUS_ALGNAME
12
+
13
+ int crypto_kem_keypair(unsigned char *pk,
14
+ unsigned char *sk);
15
+
16
+ int crypto_kem_enc(unsigned char *ct,
17
+ unsigned char *ss,
18
+ const unsigned char *pk);
19
+
20
+ int crypto_kem_dec(unsigned char *ss,
21
+ const unsigned char *ct,
22
+ const unsigned char *sk);
23
+
24
+ #endif