ml_dsa_encoders.c 31 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019
  1. /*
  2. * Copyright 2024-2025 The OpenSSL Project Authors. All Rights Reserved.
  3. *
  4. * Licensed under the Apache License 2.0 (the "License"). You may not use
  5. * this file except in compliance with the License. You can obtain a copy
  6. * in the file LICENSE in the source distribution or at
  7. * https://www.openssl.org/source/license.html
  8. */
  9. #include <openssl/byteorder.h>
  10. #include <openssl/err.h>
  11. #include <openssl/evp.h>
  12. #include <openssl/proverr.h>
  13. #include "ml_dsa_hash.h"
  14. #include "ml_dsa_key.h"
  15. #include "ml_dsa_sign.h"
  16. #include "internal/packet.h"
  17. #define POLY_COEFF_NUM_BYTES(bits) ((bits) * (ML_DSA_NUM_POLY_COEFFICIENTS / 8))
  18. /* Cast mod_sub result in support of left-shifts that create 64-bit values. */
  19. #define mod_sub_64(a, b) ((uint64_t) mod_sub(a, b))
  20. typedef int (ENCODE_FN)(const POLY *s, WPACKET *pkt);
  21. typedef int (DECODE_FN)(POLY *s, PACKET *pkt);
  22. static ENCODE_FN poly_encode_signed_2;
  23. static ENCODE_FN poly_encode_signed_4;
  24. static ENCODE_FN poly_encode_signed_two_to_power_17;
  25. static ENCODE_FN poly_encode_signed_two_to_power_19;
  26. static DECODE_FN poly_decode_signed_2;
  27. static DECODE_FN poly_decode_signed_4;
  28. static DECODE_FN poly_decode_signed_two_to_power_17;
  29. static DECODE_FN poly_decode_signed_two_to_power_19;
  30. /* Bit packing Algorithms */
  31. /*
  32. * Encodes a polynomial into a byte string, assuming that all coefficients are
  33. * in the range 0..15 (4 bits).
  34. *
  35. * See FIPS 204, Algorithm 16, SimpleBitPack(w, b) where b = 4 bits
  36. *
  37. * i.e. Use 4 bits from each coefficient and pack them into bytes
  38. * So every 2 coefficients fit into 1 byte.
  39. *
  40. * This is used to encode w1 when signing with ML-DSA-65 and ML-DSA-87
  41. *
  42. * @param p A polynomial with coefficients all in the range (0..15)
  43. * @param pkt A packet object to write 128 bytes to.
  44. *
  45. * @returns 1 on success, or 0 on error.
  46. */
  47. static int poly_encode_4_bits(const POLY *p, WPACKET *pkt)
  48. {
  49. uint8_t *out;
  50. const uint32_t *in = p->coeff, *end = in + ML_DSA_NUM_POLY_COEFFICIENTS;
  51. if (!WPACKET_allocate_bytes(pkt, POLY_COEFF_NUM_BYTES(4), &out))
  52. return 0;
  53. do {
  54. uint32_t z0 = *in++;
  55. uint32_t z1 = *in++;
  56. *out++ = z0 | (z1 << 4);
  57. } while (in < end);
  58. return 1;
  59. }
  60. /*
  61. * Encodes a polynomial into a byte string, assuming that all coefficients are
  62. * in the range 0..43 (6 bits).
  63. *
  64. * See FIPS 204, Algorithm 16, SimpleBitPack(w, b) where b = 43
  65. *
  66. * i.e. Use 6 bits from each coefficient and pack them into bytes
  67. * So every 4 coefficients fit into 3 bytes.
  68. *
  69. * |c0||c1||c2||c3|
  70. * | /| /\ /
  71. * |6 2|4 4|2 6|
  72. *
  73. * This is used to encode w1 when signing with ML-DSA-44
  74. *
  75. * @param p A polynomial with coefficients all in the range (0..43)
  76. * @param pkt A packet object to write 96 bytes to.
  77. *
  78. * @returns 1 on success, or 0 on error.
  79. */
  80. static int poly_encode_6_bits(const POLY *p, WPACKET *pkt)
  81. {
  82. uint8_t *out;
  83. const uint32_t *in = p->coeff, *end = in + ML_DSA_NUM_POLY_COEFFICIENTS;
  84. if (!WPACKET_allocate_bytes(pkt, POLY_COEFF_NUM_BYTES(6), &out))
  85. return 0;
  86. do {
  87. uint32_t c0 = *in++;
  88. uint32_t c1 = *in++;
  89. uint32_t c2 = *in++;
  90. uint32_t c3 = *in++;
  91. *out++ = c0 | (c1 << 6);
  92. *out++ = (c1 >> 2) | (c2 << 4);
  93. *out++ = (c2 >> 4) | (c3 << 2);
  94. } while (in < end);
  95. return 1;
  96. }
  97. /*
  98. * Encodes a polynomial into a byte string, assuming that all coefficients are
  99. * unsigned 10 bit values.
  100. *
  101. * See FIPS 204, Algorithm 16, SimpleBitPack(w, b) where b = 10 bits
  102. *
  103. * i.e. Use 10 bits from each coefficient and pack them into bytes
  104. * So every 4 coefficients (c0..c3) fit into 5 bytes.
  105. * |c0||c1||c2||c3|
  106. * |\ |\ |\ |\
  107. * |8|2 6|4 4|6 2|8|
  108. *
  109. * This is used to save t1 (the high part of public key polynomial t)
  110. *
  111. * @param p A polynomial with coefficients all in the range (0..1023)
  112. * @param pkt A packet object to write 320 bytes to.
  113. *
  114. * @returns 1 on success, or 0 on error.
  115. */
  116. static int poly_encode_10_bits(const POLY *p, WPACKET *pkt)
  117. {
  118. uint8_t *out;
  119. const uint32_t *in = p->coeff, *end = in + ML_DSA_NUM_POLY_COEFFICIENTS;
  120. if (!WPACKET_allocate_bytes(pkt, POLY_COEFF_NUM_BYTES(10), &out))
  121. return 0;
  122. do {
  123. uint32_t c0 = *in++;
  124. uint32_t c1 = *in++;
  125. uint32_t c2 = *in++;
  126. uint32_t c3 = *in++;
  127. *out++ = (uint8_t)c0;
  128. *out++ = (uint8_t)((c0 >> 8) | (c1 << 2));
  129. *out++ = (uint8_t)((c1 >> 6) | (c2 << 4));
  130. *out++ = (uint8_t)((c2 >> 4) | (c3 << 6));
  131. *out++ = (uint8_t)(c3 >> 2);
  132. } while (in < end);
  133. return 1;
  134. }
  135. /*
  136. * @brief Reverses the procedure of poly_encode_10_bits().
  137. * See FIPS 204, Algorithm 18, SimpleBitUnpack(v, b) where b = 10.
  138. *
  139. * @param p A polynomial to write coefficients to.
  140. * @param pkt A packet object to read 320 bytes from.
  141. *
  142. * @returns 1 on success, or 0 on error.
  143. */
  144. static int poly_decode_10_bits(POLY *p, PACKET *pkt)
  145. {
  146. const uint8_t *in = NULL;
  147. uint32_t v, w, mask = 0x3ff; /* 10 bits */
  148. uint32_t *out = p->coeff, *end = out + ML_DSA_NUM_POLY_COEFFICIENTS;
  149. do {
  150. if (!PACKET_get_bytes(pkt, &in, 5))
  151. return 0;
  152. in = OPENSSL_load_u32_le(&v, in);
  153. w = *in;
  154. *out++ = v & mask;
  155. *out++ = (v >> 10) & mask;
  156. *out++ = (v >> 20) & mask;
  157. *out++ = (v >> 30) | (w << 2);
  158. } while (out < end);
  159. return 1;
  160. }
  161. /*
  162. * @brief Encodes a polynomial into a byte string, assuming that all
  163. * coefficients are in the range -4..4.
  164. * See FIPS 204, Algorithm 17, BitPack(w, a, b). (a = 4, b = 4)
  165. *
  166. * It uses a nibble from each coefficient and packs them into bytes
  167. * So every 2 coefficients fit into 1 byte.
  168. *
  169. * This is used to encode the private key polynomial elements of s1 and s2
  170. * for ML-DSA-65 (i.e. eta = 4)
  171. *
  172. * @param p An array of 256 coefficients all in the range -4..4
  173. * @param pkt A packet to write 128 bytes of encoded polynomial coefficients to.
  174. *
  175. * @returns 1 on success, or 0 on error.
  176. */
  177. static int poly_encode_signed_4(const POLY *p, WPACKET *pkt)
  178. {
  179. uint8_t *out;
  180. const uint32_t *in = p->coeff, *end = in + ML_DSA_NUM_POLY_COEFFICIENTS;
  181. if (!WPACKET_allocate_bytes(pkt, 32 * 4, &out))
  182. return 0;
  183. do {
  184. uint32_t z = mod_sub(4, *in++);
  185. *out++ = z | (mod_sub(4, *in++) << 4);
  186. } while (in < end);
  187. return 1;
  188. }
  189. /*
  190. * @brief Reverses the procedure of poly_encode_signed_4().
  191. * See FIPS 204, Algorithm 19, BitUnpack(v, a, b) where a = b = 4.
  192. *
  193. * @param p A polynomial to write coefficients to.
  194. * @param pkt A packet object to read 128 bytes from.
  195. *
  196. * @returns 1 on success, or 0 on error. An error will occur if any of the
  197. * coefficients are not in the correct range.
  198. */
  199. static int poly_decode_signed_4(POLY *p, PACKET *pkt)
  200. {
  201. int i, ret = 0;
  202. uint32_t v, *out = p->coeff;
  203. const uint8_t *in;
  204. uint32_t msbs, mask;
  205. for (i = 0; i < (ML_DSA_NUM_POLY_COEFFICIENTS / 8); i++) {
  206. if (!PACKET_get_bytes(pkt, &in, 4))
  207. goto err;
  208. in = OPENSSL_load_u32_le(&v, in);
  209. /*
  210. * None of the nibbles may be >= 9. So if the MSB of any nibble is set,
  211. * none of the other bits may be set. First, select all the MSBs.
  212. */
  213. msbs = v & 0x88888888u;
  214. /* For each nibble where the MSB is set, form a mask of all the other bits. */
  215. mask = (msbs >> 1) | (msbs >> 2) | (msbs >> 3);
  216. /*
  217. * A nibble is only out of range in the case of invalid input, in which case
  218. * it is okay to leak the value.
  219. */
  220. if (value_barrier_32((mask & v) != 0))
  221. goto err;
  222. *out++ = mod_sub(4, v & 15);
  223. *out++ = mod_sub(4, (v >> 4) & 15);
  224. *out++ = mod_sub(4, (v >> 8) & 15);
  225. *out++ = mod_sub(4, (v >> 12) & 15);
  226. *out++ = mod_sub(4, (v >> 16) & 15);
  227. *out++ = mod_sub(4, (v >> 20) & 15);
  228. *out++ = mod_sub(4, (v >> 24) & 15);
  229. *out++ = mod_sub(4, v >> 28);
  230. }
  231. ret = 1;
  232. err:
  233. return ret;
  234. }
  235. /*
  236. * @brief Encodes a polynomial into a byte string, assuming that all
  237. * coefficients are in the range -2..2.
  238. * See FIPS 204, Algorithm 17, BitPack(w, a, b). where a = b = 2.
  239. *
  240. * This is used to encode the private key polynomial elements of s1 and s2
  241. * for ML-DSA-44 and ML-DSA-87 (i.e. eta = 2)
  242. *
  243. * @param pkt A packet to write 128 bytes of encoded polynomial coefficients to.
  244. * @param p An array of 256 coefficients all in the range -2..2
  245. *
  246. * Use 3 bits from each coefficient and pack them into bytes
  247. * So every 8 coefficients fit into 3 bytes.
  248. * |c0 c1 c2 c3 c4 c5 c6 c7|
  249. * | / / | | / / | | /
  250. * |3 3 2| 1 3 3 1| 2 3 3|
  251. *
  252. * @param p An array of 256 coefficients all in the range -2..2
  253. * @param pkt A packet to write 64 bytes of encoded polynomial coefficients to.
  254. *
  255. * @returns 1 on success, or 0 on error.
  256. */
  257. static int poly_encode_signed_2(const POLY *p, WPACKET *pkt)
  258. {
  259. uint8_t *out;
  260. const uint32_t *in = p->coeff, *end = in + ML_DSA_NUM_POLY_COEFFICIENTS;
  261. if (!WPACKET_allocate_bytes(pkt, POLY_COEFF_NUM_BYTES(3), &out))
  262. return 0;
  263. do {
  264. uint32_t z;
  265. z = mod_sub(2, *in++);
  266. z |= mod_sub(2, *in++) << 3;
  267. z |= mod_sub(2, *in++) << 6;
  268. z |= mod_sub(2, *in++) << 9;
  269. z |= mod_sub(2, *in++) << 12;
  270. z |= mod_sub(2, *in++) << 15;
  271. z |= mod_sub(2, *in++) << 18;
  272. z |= mod_sub(2, *in++) << 21;
  273. out = OPENSSL_store_u16_le(out, (uint16_t) z);
  274. *out++ = (uint8_t) (z >> 16);
  275. } while (in < end);
  276. return 1;
  277. }
  278. /*
  279. * @brief Reverses the procedure of poly_encode_signed_2().
  280. * See FIPS 204, Algorithm 19, BitUnpack(v, a, b) where a = b = 2.
  281. *
  282. * @param p A polynomial to write coefficients to.
  283. * @param pkt A packet object to read 64 encoded bytes from.
  284. *
  285. * @returns 1 on success, or 0 on error. An error will occur if any of the
  286. * coefficients are not in the correct range.
  287. */
  288. static int poly_decode_signed_2(POLY *p, PACKET *pkt)
  289. {
  290. int i, ret = 0;
  291. uint32_t u = 0, v = 0, *out = p->coeff;
  292. uint32_t msbs, mask;
  293. const uint8_t *in;
  294. for (i = 0; i < (ML_DSA_NUM_POLY_COEFFICIENTS / 8); i++) {
  295. if (!PACKET_get_bytes(pkt, &in, 3))
  296. goto err;
  297. memcpy(&u, in, 3);
  298. OPENSSL_load_u32_le(&v, (uint8_t *)&u);
  299. /*
  300. * Each octal value (3 bits) must be <= 4, So if the MSB is set then the
  301. * bottom 2 bits must not be set.
  302. * First, select all the MSBs (Use octal representation for the mask)
  303. */
  304. msbs = v & 044444444;
  305. /* For each octal value where the MSB is set, form a mask of the 2 other bits. */
  306. mask = (msbs >> 1) | (msbs >> 2);
  307. /*
  308. * A nibble is only out of range in the case of invalid input, in which
  309. * case it is okay to leak the value.
  310. */
  311. if (value_barrier_32((mask & v) != 0))
  312. goto err;
  313. *out++ = mod_sub(2, v & 7);
  314. *out++ = mod_sub(2, (v >> 3) & 7);
  315. *out++ = mod_sub(2, (v >> 6) & 7);
  316. *out++ = mod_sub(2, (v >> 9) & 7);
  317. *out++ = mod_sub(2, (v >> 12) & 7);
  318. *out++ = mod_sub(2, (v >> 15) & 7);
  319. *out++ = mod_sub(2, (v >> 18) & 7);
  320. *out++ = mod_sub(2, (v >> 21) & 7);
  321. }
  322. ret = 1;
  323. err:
  324. return ret;
  325. }
  326. /*
  327. * @brief Encodes a polynomial into a byte string, assuming that all
  328. * coefficients are in the range (-2^12 + 1)..2^12.
  329. * See FIPS 204, Algorithm 17, BitPack(w, a, b). where a = 2^12 - 1, b = 2^12.
  330. *
  331. * This is used to encode the LSB of the public key polynomial elements of t0
  332. * (which are encoded as part of the encoded private key).
  333. *
  334. * Use 13 bits from each coefficient and pack them into bytes
  335. *
  336. * The code below packs them into 2 64 bits blocks by doing..
  337. * z0 z1 z2 z3 z4 z5 z6 z7 0
  338. * | | | | / \ | | | |
  339. * |13 13 13 13 12 |1 13 13 13 24
  340. *
  341. * @param p An array of 256 coefficients all in the range -2^12+1..2^12
  342. * @param pkt A packet to write 416 (13 * 256 / 8) bytes of encoded polynomial
  343. * coefficients to.
  344. *
  345. * @returns 1 on success, or 0 on error.
  346. */
  347. static int poly_encode_signed_two_to_power_12(const POLY *p, WPACKET *pkt)
  348. {
  349. static const uint32_t range = 1u << 12;
  350. const uint32_t *in = p->coeff, *end = in + ML_DSA_NUM_POLY_COEFFICIENTS;
  351. do {
  352. uint8_t *out;
  353. uint64_t a1, a2;
  354. if (!WPACKET_allocate_bytes(pkt, 13, &out))
  355. return 0;
  356. a1 = mod_sub_64(range, *in++);
  357. a1 |= mod_sub_64(range, *in++) << 13;
  358. a1 |= mod_sub_64(range, *in++) << 26;
  359. a1 |= mod_sub_64(range, *in++) << 39;
  360. a1 |= (a2 = mod_sub_64(range, *in++)) << 52;
  361. a2 = (a2 >> 12) | (mod_sub_64(range, *in++) << 1);
  362. a2 |= mod_sub_64(range, *in++) << 14;
  363. a2 |= mod_sub_64(range, *in++) << 27;
  364. out = OPENSSL_store_u64_le(out, a1);
  365. out = OPENSSL_store_u32_le(out, (uint32_t) a2);
  366. *out = (uint8_t) (a2 >> 32);
  367. } while (in < end);
  368. return 1;
  369. }
  370. /*
  371. * @brief Reverses the procedure of poly_encode_signed_two_to_power_12().
  372. * See FIPS 204, Algorithm 19, BitUnpack(v, a, b) where a = 2^12 - 1, b = 2^12.
  373. *
  374. * @param p A polynomial to write coefficients to.
  375. * @param pkt A packet object to read 416 encoded bytes from.
  376. *
  377. * @returns 1 on success, or 0 on error.
  378. */
  379. static int poly_decode_signed_two_to_power_12(POLY *p, PACKET *pkt)
  380. {
  381. int i, ret = 0;
  382. uint32_t *out = p->coeff;
  383. const uint8_t *in;
  384. static const uint32_t range = 1u << 12;
  385. static const uint32_t mask_13_bits = (1u << 13) - 1;
  386. for (i = 0; i < (ML_DSA_NUM_POLY_COEFFICIENTS / 8); i++) {
  387. uint64_t a1;
  388. uint32_t a2, b13;
  389. if (!PACKET_get_bytes(pkt, &in, 13))
  390. goto err;
  391. in = OPENSSL_load_u64_le(&a1, in);
  392. in = OPENSSL_load_u32_le(&a2, in);
  393. b13 = (uint32_t) *in;
  394. *out++ = mod_sub(range, a1 & mask_13_bits);
  395. *out++ = mod_sub(range, (a1 >> 13) & mask_13_bits);
  396. *out++ = mod_sub(range, (a1 >> 26) & mask_13_bits);
  397. *out++ = mod_sub(range, (a1 >> 39) & mask_13_bits);
  398. *out++ = mod_sub(range, (a1 >> 52) | ((a2 << 12) & mask_13_bits));
  399. *out++ = mod_sub(range, (a2 >> 1) & mask_13_bits);
  400. *out++ = mod_sub(range, (a2 >> 14) & mask_13_bits);
  401. *out++ = mod_sub(range, (a2 >> 27) | (b13 << 5));
  402. }
  403. ret = 1;
  404. err:
  405. return ret;
  406. }
  407. /*
  408. * @brief Encodes a polynomial into a byte string, assuming that all
  409. * coefficients are in the range (-2^19 + 1)..2^19.
  410. * See FIPS 204, Algorithm 17, BitPack(w, a, b). where a = 2^19 - 1, b = 2^19.
  411. *
  412. * This is used to encode signatures for ML-DSA-65 & ML-DSA-87 (gamma1 = 2^19)
  413. *
  414. * Use 20 bits from each coefficient and pack them into bytes
  415. *
  416. * The code below packs every 4 (20 bit) coefficients into 10 bytes
  417. * z0 z1 z2 z3
  418. * | |\ | | \
  419. * |20 12|8 20 4|16
  420. *
  421. * @param p An array of 256 coefficients all in the range -2^19+1..2^19
  422. * @param pkt A packet to write 640 (20 * 256 / 8) bytes of encoded polynomial
  423. * coefficients to.
  424. *
  425. * @returns 1 on success, or 0 on error.
  426. */
  427. static int poly_encode_signed_two_to_power_19(const POLY *p, WPACKET *pkt)
  428. {
  429. static const uint32_t range = 1u << 19;
  430. const uint32_t *in = p->coeff, *end = in + ML_DSA_NUM_POLY_COEFFICIENTS;
  431. do {
  432. uint32_t z0, z1, z2;
  433. uint8_t *out;
  434. if (!WPACKET_allocate_bytes(pkt, 10, &out))
  435. return 0;
  436. z0 = mod_sub(range, *in++);
  437. z0 |= (z1 = mod_sub(range, *in++)) << 20;
  438. z1 = (z1 >> 12) | (mod_sub(range, *in++) << 8);
  439. z1 |= (z2 = mod_sub(range, *in++)) << 28;
  440. out = OPENSSL_store_u32_le(out, z0);
  441. out = OPENSSL_store_u32_le(out, z1);
  442. out = OPENSSL_store_u16_le(out, (uint16_t) (z2 >> 4));
  443. } while (in < end);
  444. return 1;
  445. }
  446. /*
  447. * @brief Reverses the procedure of poly_encode_signed_two_to_power_19().
  448. * See FIPS 204, Algorithm 19, BitUnpack(v, a, b) where a = 2^19 - 1, b = 2^19.
  449. *
  450. * @param p A polynomial to write coefficients to.
  451. * @param pkt A packet object to read 640 encoded bytes from.
  452. *
  453. * @returns 1 on success, or 0 on error.
  454. */
  455. static int poly_decode_signed_two_to_power_19(POLY *p, PACKET *pkt)
  456. {
  457. int i, ret = 0;
  458. uint32_t *out = p->coeff;
  459. const uint8_t *in;
  460. static const uint32_t range = 1u << 19;
  461. static const uint32_t mask_20_bits = (1u << 20) - 1;
  462. for (i = 0; i < (ML_DSA_NUM_POLY_COEFFICIENTS / 4); i++) {
  463. uint32_t a1, a2;
  464. uint16_t a3;
  465. if (!PACKET_get_bytes(pkt, &in, 10))
  466. goto err;
  467. in = OPENSSL_load_u32_le(&a1, in);
  468. in = OPENSSL_load_u32_le(&a2, in);
  469. in = OPENSSL_load_u16_le(&a3, in);
  470. *out++ = mod_sub(range, a1 & mask_20_bits);
  471. *out++ = mod_sub(range, (a1 >> 20) | ((a2 & 0xFF) << 12));
  472. *out++ = mod_sub(range, (a2 >> 8) & mask_20_bits);
  473. *out++ = mod_sub(range, (a2 >> 28) | (a3 << 4));
  474. }
  475. ret = 1;
  476. err:
  477. return ret;
  478. }
  479. /*
  480. * @brief Encodes a polynomial into a byte string, assuming that all
  481. * coefficients are in the range (-2^17 + 1)..2^17.
  482. * See FIPS 204, Algorithm 17, BitPack(w, a, b). where a = 2^17 - 1, b = 2^17.
  483. *
  484. * This is used to encode signatures for ML-DSA-44 (where gamma1 = 2^17)
  485. *
  486. * Use 18 bits from each coefficient and pack them into bytes
  487. *
  488. * The code below packs every 4 (18 bit) coefficients into 9 bytes
  489. * z0 z1 z2 z3
  490. * | |\ | | \
  491. * |18 14|4 18 10| 8
  492. *
  493. * @param p An array of 256 coefficients all in the range -2^17+1..2^17
  494. * @param pkt A packet to write 576 (18 * 256 / 8) bytes of encoded polynomial
  495. * coefficients to.
  496. *
  497. * @returns 1 on success, or 0 on error.
  498. */
  499. static int poly_encode_signed_two_to_power_17(const POLY *p, WPACKET *pkt)
  500. {
  501. static const uint32_t range = 1u << 17;
  502. const uint32_t *in = p->coeff, *end = in + ML_DSA_NUM_POLY_COEFFICIENTS;
  503. do {
  504. uint8_t *out;
  505. uint32_t z0, z1, z2;
  506. if (!WPACKET_allocate_bytes(pkt, 9, &out))
  507. return 0;
  508. z0 = mod_sub(range, *in++);
  509. z0 |= (z1 = mod_sub(range, *in++)) << 18;
  510. z1 = (z1 >> 14) | (mod_sub(range, *in++) << 4);
  511. z1 |= (z2 = mod_sub(range, *in++)) << 22;
  512. out = OPENSSL_store_u32_le(out, z0);
  513. out = OPENSSL_store_u32_le(out, z1);
  514. *out = z2 >> 10;
  515. } while (in < end);
  516. return 1;
  517. }
  518. /*
  519. * @brief Reverses the procedure of poly_encode_signed_two_to_power_17().
  520. * See FIPS 204, Algorithm 19, BitUnpack(v, a, b) where a = 2^17 - 1, b = 2^17.
  521. *
  522. * @param p A polynomial to write coefficients to.
  523. * @param pkt A packet object to read 576 encoded bytes from.
  524. *
  525. * @returns 1 on success, or 0 on error.
  526. */
  527. static int poly_decode_signed_two_to_power_17(POLY *p, PACKET *pkt)
  528. {
  529. uint32_t *out = p->coeff;
  530. const uint32_t *end = out + ML_DSA_NUM_POLY_COEFFICIENTS;
  531. const uint8_t *in;
  532. static const uint32_t range = 1u << 17;
  533. static const uint32_t mask_18_bits = (1u << 18) - 1;
  534. do {
  535. uint32_t a1, a2, a3;
  536. if (!PACKET_get_bytes(pkt, &in, 9))
  537. return 0;
  538. in = OPENSSL_load_u32_le(&a1, in);
  539. in = OPENSSL_load_u32_le(&a2, in);
  540. a3 = (uint32_t) *in;
  541. *out++ = mod_sub(range, a1 & mask_18_bits);
  542. *out++ = mod_sub(range, (a1 >> 18) | ((a2 & 0xF) << 14));
  543. *out++ = mod_sub(range, (a2 >> 4) & mask_18_bits);
  544. *out++ = mod_sub(range, (a2 >> 22) | (a3 << 10));
  545. } while (out < end);
  546. return 1;
  547. }
  548. /*
  549. * @brief Encode the public key as an array of bytes.
  550. * See FIPS 204, Algorithm 22, pkEncode().
  551. *
  552. * @param key A key object containing public key values. The encoded public
  553. * key data is stored in this key.
  554. * @returns 1 if the public key was encoded successfully or 0 otherwise.
  555. */
  556. int ossl_ml_dsa_pk_encode(ML_DSA_KEY *key)
  557. {
  558. int ret = 0;
  559. size_t i, written = 0;
  560. const POLY *t1 = key->t1.poly;
  561. size_t t1_len = key->t1.num_poly;
  562. size_t enc_len = key->params->pk_len;
  563. uint8_t *enc = OPENSSL_malloc(enc_len);
  564. WPACKET pkt;
  565. if (enc == NULL)
  566. return 0;
  567. if (!WPACKET_init_static_len(&pkt, enc, enc_len, 0)
  568. || !WPACKET_memcpy(&pkt, key->rho, sizeof(key->rho)))
  569. goto err;
  570. for (i = 0; i < t1_len; i++)
  571. if (!poly_encode_10_bits(t1 + i, &pkt))
  572. goto err;
  573. if (!WPACKET_get_total_written(&pkt, &written)
  574. || written != enc_len)
  575. goto err;
  576. OPENSSL_free(key->pub_encoding);
  577. key->pub_encoding = enc;
  578. ret = 1;
  579. err:
  580. WPACKET_finish(&pkt);
  581. if (ret == 0)
  582. OPENSSL_free(enc);
  583. return ret;
  584. }
  585. /*
  586. * @brief The reverse of ossl_ml_dsa_pk_encode().
  587. * See FIPS 204, Algorithm 23, pkDecode().
  588. *
  589. * @param in An encoded public key.
  590. * @param in_len The size of |in|
  591. * @param key A key object to store the decoded public key into.
  592. *
  593. * @returns 1 if the public key was decoded successfully or 0 otherwise.
  594. */
  595. int ossl_ml_dsa_pk_decode(ML_DSA_KEY *key, const uint8_t *in, size_t in_len)
  596. {
  597. int ret = 0;
  598. size_t i;
  599. PACKET pkt;
  600. EVP_MD_CTX *ctx;
  601. if (key->priv_encoding != NULL || key->pub_encoding != NULL)
  602. return 0; /* Do not allow key mutation */
  603. if (in_len != key->params->pk_len)
  604. return 0;
  605. if (!ossl_ml_dsa_key_pub_alloc(key))
  606. return 0;
  607. ctx = EVP_MD_CTX_new();
  608. if (ctx == NULL)
  609. goto err;
  610. if (!PACKET_buf_init(&pkt, in, in_len)
  611. || !PACKET_copy_bytes(&pkt, key->rho, sizeof(key->rho)))
  612. goto err;
  613. for (i = 0; i < key->t1.num_poly; i++)
  614. if (!poly_decode_10_bits(key->t1.poly + i, &pkt))
  615. goto err;
  616. /* cache the hash of the encoded public key */
  617. if (!shake_xof(ctx, key->shake256_md, in, in_len, key->tr, sizeof(key->tr)))
  618. goto err;
  619. key->pub_encoding = OPENSSL_memdup(in, in_len);
  620. ret = (key->pub_encoding != NULL);
  621. err:
  622. EVP_MD_CTX_free(ctx);
  623. return ret;
  624. }
  625. /*
  626. * @brief Encode the private key as an array of bytes.
  627. * See FIPS 204, Algorithm 24, skEncode().
  628. *
  629. * @param key A key object containing private key values. The encoded private
  630. * key data is stored in this key.
  631. * @returns 1 if the private key was encoded successfully or 0 otherwise.
  632. */
  633. int ossl_ml_dsa_sk_encode(ML_DSA_KEY *key)
  634. {
  635. int ret = 0;
  636. const ML_DSA_PARAMS *params = key->params;
  637. size_t i, written = 0, k = params->k, l = params->l;
  638. ENCODE_FN *encode_fn;
  639. size_t enc_len = params->sk_len;
  640. const POLY *t0 = key->t0.poly;
  641. WPACKET pkt;
  642. uint8_t *enc = OPENSSL_malloc(enc_len);
  643. if (enc == NULL)
  644. return 0;
  645. /* eta is the range of private key coefficients (-eta...eta) */
  646. if (params->eta == ML_DSA_ETA_4)
  647. encode_fn = poly_encode_signed_4;
  648. else
  649. encode_fn = poly_encode_signed_2;
  650. if (!WPACKET_init_static_len(&pkt, enc, enc_len, 0)
  651. || !WPACKET_memcpy(&pkt, key->rho, sizeof(key->rho))
  652. || !WPACKET_memcpy(&pkt, key->K, sizeof(key->K))
  653. || !WPACKET_memcpy(&pkt, key->tr, sizeof(key->tr)))
  654. goto err;
  655. for (i = 0; i < l; ++i)
  656. if (!encode_fn(key->s1.poly + i, &pkt))
  657. goto err;
  658. for (i = 0; i < k; ++i)
  659. if (!encode_fn(key->s2.poly + i, &pkt))
  660. goto err;
  661. for (i = 0; i < k; ++i)
  662. if (!poly_encode_signed_two_to_power_12(t0++, &pkt))
  663. goto err;
  664. if (!WPACKET_get_total_written(&pkt, &written)
  665. || written != enc_len)
  666. goto err;
  667. OPENSSL_clear_free(key->priv_encoding, enc_len);
  668. key->priv_encoding = enc;
  669. ret = 1;
  670. err:
  671. WPACKET_finish(&pkt);
  672. if (ret == 0)
  673. OPENSSL_clear_free(enc, enc_len);
  674. return ret;
  675. }
  676. /*
  677. * @brief The reverse of ossl_ml_dsa_sk_encode().
  678. * See FIPS 204, Algorithm 24, skDecode().
  679. *
  680. * @param in An encoded private key.
  681. * @param in_len The size of |in|
  682. * @param key A key object to store the decoded private key into.
  683. *
  684. * @returns 1 if the private key was decoded successfully or 0 otherwise.
  685. */
  686. int ossl_ml_dsa_sk_decode(ML_DSA_KEY *key, const uint8_t *in, size_t in_len)
  687. {
  688. DECODE_FN *decode_fn;
  689. const ML_DSA_PARAMS *params = key->params;
  690. size_t i, k = params->k, l = params->l;
  691. uint8_t input_tr[ML_DSA_TR_BYTES];
  692. PACKET pkt;
  693. /* When loading from an explicit key, drop the seed. */
  694. OPENSSL_clear_free(key->seed, ML_DSA_SEED_BYTES);
  695. key->seed = NULL;
  696. /* Allow the key encoding to be already set to the provided pointer */
  697. if ((key->priv_encoding != NULL && key->priv_encoding != in)
  698. || key->pub_encoding != NULL)
  699. return 0; /* Do not allow key mutation */
  700. if (in_len != key->params->sk_len)
  701. return 0;
  702. if (!ossl_ml_dsa_key_priv_alloc(key))
  703. return 0;
  704. /* eta is the range of private key coefficients (-eta...eta) */
  705. if (params->eta == ML_DSA_ETA_4)
  706. decode_fn = poly_decode_signed_4;
  707. else
  708. decode_fn = poly_decode_signed_2;
  709. if (!PACKET_buf_init(&pkt, in, in_len)
  710. || !PACKET_copy_bytes(&pkt, key->rho, sizeof(key->rho))
  711. || !PACKET_copy_bytes(&pkt, key->K, sizeof(key->K))
  712. || !PACKET_copy_bytes(&pkt, input_tr, sizeof(input_tr)))
  713. return 0;
  714. for (i = 0; i < l; ++i)
  715. if (!decode_fn(key->s1.poly + i, &pkt))
  716. goto err;
  717. for (i = 0; i < k; ++i)
  718. if (!decode_fn(key->s2.poly + i, &pkt))
  719. goto err;
  720. for (i = 0; i < k; ++i)
  721. if (!poly_decode_signed_two_to_power_12(key->t0.poly + i, &pkt))
  722. goto err;
  723. if (PACKET_remaining(&pkt) != 0)
  724. goto err;
  725. if (key->priv_encoding == NULL
  726. && (key->priv_encoding = OPENSSL_memdup(in, in_len)) == NULL)
  727. goto err;
  728. /*
  729. * Computing the public key also computes its hash, which must be equal to
  730. * the |tr| value in the private key, else the key was corrupted.
  731. */
  732. if (!ossl_ml_dsa_key_public_from_private(key)
  733. || memcmp(input_tr, key->tr, sizeof(input_tr)) != 0) {
  734. ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_KEY,
  735. "%s private key does not match its pubkey part",
  736. key->params->alg);
  737. ossl_ml_dsa_key_reset(key);
  738. goto err;
  739. }
  740. return 1;
  741. err:
  742. return 0;
  743. }
  744. /*
  745. * See FIPS 204, Algorithm 20, HintBitPack().
  746. * Hint is composed of k polynomials with binary coefficients where only 'omega'
  747. * of all the coefficients are set to 1.
  748. * This can be encoded as a byte array of 'omega' polynomial coefficient index
  749. * positions for the coefficients that are set, followed by
  750. * k values of the last coefficient index used in each polynomial.
  751. */
  752. static int hint_bits_encode(const VECTOR *hint, WPACKET *pkt, uint32_t omega)
  753. {
  754. int i, j, k = hint->num_poly;
  755. size_t coeff_index = 0;
  756. POLY *p = hint->poly;
  757. uint8_t *data;
  758. if (!WPACKET_allocate_bytes(pkt, omega + k, &data))
  759. return 0;
  760. memset(data, 0, omega + k);
  761. for (i = 0; i < k; i++, p++) {
  762. for (j = 0; j < ML_DSA_NUM_POLY_COEFFICIENTS; j++)
  763. if (p->coeff[j] != 0)
  764. data[coeff_index++] = j;
  765. data[omega + i] = (uint8_t)coeff_index;
  766. }
  767. return 1;
  768. }
  769. /*
  770. * @brief Reverse the process of hint_bits_encode()
  771. * See FIPS 204, Algorithm 21, HintBitUnpack()
  772. *
  773. * @returns 1 if the hints were successfully unpacked, or 0
  774. * if 'pkt' is too small or malformed.
  775. */
  776. static int hint_bits_decode(VECTOR *hint, PACKET *pkt, uint32_t omega)
  777. {
  778. size_t coeff_index = 0, k = hint->num_poly;
  779. const uint8_t *in, *limits;
  780. POLY *p = hint->poly, *end = p + k;
  781. if (!PACKET_get_bytes(pkt, &in, omega)
  782. || !PACKET_get_bytes(pkt, &limits, k))
  783. return 0;
  784. vector_zero(hint); /* Set all coefficients to zero */
  785. do {
  786. const uint32_t limit = *limits++;
  787. int last = -1;
  788. if (limit < coeff_index || limit > omega)
  789. return 0;
  790. while (coeff_index < limit) {
  791. int byte = in[coeff_index++];
  792. if (last >= 0 && byte <= last)
  793. return 0;
  794. last = byte;
  795. p->coeff[byte] = 1;
  796. }
  797. } while (++p < end);
  798. for (; coeff_index < omega; coeff_index++)
  799. if (in[coeff_index] != 0)
  800. return 0;
  801. return 1;
  802. }
  803. /*
  804. * @brief Encode a ML_DSA signature as an array of bytes.
  805. * See FIPS 204, Algorithm 26, sigEncode().
  806. *
  807. * @param
  808. * @param
  809. * @returns 1 if the signature was encoded successfully or 0 otherwise.
  810. */
  811. int ossl_ml_dsa_sig_encode(const ML_DSA_SIG *sig, const ML_DSA_PARAMS *params,
  812. uint8_t *out)
  813. {
  814. int ret = 0;
  815. size_t i;
  816. ENCODE_FN *encode_fn;
  817. WPACKET pkt;
  818. if (out == NULL)
  819. return 0;
  820. if (params->gamma1 == ML_DSA_GAMMA1_TWO_POWER_19)
  821. encode_fn = poly_encode_signed_two_to_power_19;
  822. else
  823. encode_fn = poly_encode_signed_two_to_power_17;
  824. if (!WPACKET_init_static_len(&pkt, out, params->sig_len, 0)
  825. || !WPACKET_memcpy(&pkt, sig->c_tilde, sig->c_tilde_len))
  826. goto err;
  827. for (i = 0; i < sig->z.num_poly; ++i)
  828. if (!encode_fn(sig->z.poly + i, &pkt))
  829. goto err;
  830. if (!hint_bits_encode(&sig->hint, &pkt, params->omega))
  831. goto err;
  832. ret = 1;
  833. err:
  834. WPACKET_finish(&pkt);
  835. return ret;
  836. }
  837. /*
  838. * @param sig is a initialized signature object to decode into.
  839. * @param in An encoded signature
  840. * @param in_len The size of |in|
  841. * @param params contains constants for an ML-DSA algorithm (such as gamma1)
  842. * @returns 1 if the signature was successfully decoded or 0 otherwise.
  843. */
  844. int ossl_ml_dsa_sig_decode(ML_DSA_SIG *sig, const uint8_t *in, size_t in_len,
  845. const ML_DSA_PARAMS *params)
  846. {
  847. int ret = 0;
  848. size_t i;
  849. DECODE_FN *decode_fn;
  850. PACKET pkt;
  851. if (params->gamma1 == ML_DSA_GAMMA1_TWO_POWER_19)
  852. decode_fn = poly_decode_signed_two_to_power_19;
  853. else
  854. decode_fn = poly_decode_signed_two_to_power_17;
  855. if (!PACKET_buf_init(&pkt, in, in_len)
  856. || !PACKET_copy_bytes(&pkt, sig->c_tilde, sig->c_tilde_len))
  857. goto err;
  858. for (i = 0; i < sig->z.num_poly; ++i)
  859. if (!decode_fn(sig->z.poly + i, &pkt))
  860. goto err;
  861. if (!hint_bits_decode(&sig->hint, &pkt, params->omega)
  862. || PACKET_remaining(&pkt) != 0)
  863. goto err;
  864. ret = 1;
  865. err:
  866. return ret;
  867. }
  868. int ossl_ml_dsa_poly_decode_expand_mask(POLY *out,
  869. const uint8_t *in, size_t in_len,
  870. uint32_t gamma1)
  871. {
  872. PACKET pkt;
  873. if (!PACKET_buf_init(&pkt, in, in_len))
  874. return 0;
  875. if (gamma1 == ML_DSA_GAMMA1_TWO_POWER_19)
  876. return poly_decode_signed_two_to_power_19(out, &pkt);
  877. else
  878. return poly_decode_signed_two_to_power_17(out, &pkt);
  879. }
  880. /*
  881. * @brief Encode a polynomial vector as an array of bytes.
  882. * Where the polynomial coefficients have a range of [0..15] or [0..43]
  883. * depending on the value of gamma2.
  884. *
  885. * See FIPS 204, Algorithm 28, w1Encode().
  886. *
  887. * @param w1 The vector to convert to bytes
  888. * @param gamma2 either ML_DSA_GAMMA2_Q_MINUS1_DIV32 or ML_DSA_GAMMA2_Q_MINUS1_DIV88
  889. * @returns 1 if the signature was encoded successfully or 0 otherwise.
  890. */
  891. int ossl_ml_dsa_w1_encode(const VECTOR *w1, uint32_t gamma2,
  892. uint8_t *out, size_t out_len)
  893. {
  894. WPACKET pkt;
  895. ENCODE_FN *encode_fn;
  896. int ret = 0;
  897. size_t i;
  898. if (!WPACKET_init_static_len(&pkt, out, out_len, 0))
  899. return 0;
  900. if (gamma2 == ML_DSA_GAMMA2_Q_MINUS1_DIV32)
  901. encode_fn = poly_encode_4_bits;
  902. else
  903. encode_fn = poly_encode_6_bits;
  904. for (i = 0; i < w1->num_poly; ++i)
  905. if (!encode_fn(w1->poly + i, &pkt))
  906. goto err;
  907. ret = 1;
  908. err:
  909. WPACKET_finish(&pkt);
  910. return ret;
  911. }