pq_crypto 0.6.1 → 0.6.2

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 (141) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +5 -0
  3. data/SECURITY.md +7 -0
  4. data/ext/pqcrypto/pqcrypto_version.h +1 -1
  5. data/ext/pqcrypto/vendor/.vendored +4 -4
  6. data/ext/pqcrypto/vendor/mldsa-native/README.md +23 -10
  7. data/ext/pqcrypto/vendor/mldsa-native/mldsa/README.md +23 -0
  8. data/ext/pqcrypto/vendor/mldsa-native/mldsa/mldsa_native.c +114 -58
  9. data/ext/pqcrypto/vendor/mldsa-native/mldsa/mldsa_native.h +498 -461
  10. data/ext/pqcrypto/vendor/mldsa-native/mldsa/mldsa_native_asm.S +145 -85
  11. data/ext/pqcrypto/vendor/mldsa-native/mldsa/mldsa_native_config.h +456 -422
  12. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/cbmc.h +47 -25
  13. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/common.h +26 -14
  14. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/ct.h +56 -81
  15. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/debug.h +17 -24
  16. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/fips202.c +33 -40
  17. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/fips202.h +67 -87
  18. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/fips202x4.c +19 -14
  19. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/fips202x4.h +13 -5
  20. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/keccakf1600.c +84 -10
  21. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/keccakf1600.h +10 -5
  22. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/aarch64/auto.h +6 -0
  23. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/aarch64/src/fips202_native_aarch64.h +22 -15
  24. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/aarch64/src/keccak_f1600_x1_scalar_aarch64_asm.S +376 -0
  25. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/aarch64/src/keccak_f1600_x1_v84a_aarch64_asm.S +204 -0
  26. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/aarch64/src/keccak_f1600_x2_v84a_aarch64_asm.S +259 -0
  27. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/aarch64/src/keccak_f1600_x4_v8a_scalar_hybrid_aarch64_asm.S +1077 -0
  28. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/aarch64/src/keccak_f1600_x4_v8a_v84a_scalar_hybrid_aarch64_asm.S +987 -0
  29. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/aarch64/src/keccakf1600_round_constants.c +16 -10
  30. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/aarch64/x1_scalar.h +2 -1
  31. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/aarch64/x1_v84a.h +1 -1
  32. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/aarch64/x2_v84a.h +4 -2
  33. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/aarch64/x4_v8a_scalar.h +2 -2
  34. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/aarch64/x4_v8a_v84a_scalar.h +1 -1
  35. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/api.h +60 -0
  36. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/armv81m/mve.h +48 -0
  37. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/armv81m/src/fips202_native_armv81m.h +18 -1
  38. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/armv81m/src/keccak_f1600_x4_mve.S +658 -582
  39. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/armv81m/src/keccak_f1600_x4_mve.c +5 -100
  40. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/armv81m/src/keccakf1600_round_constants.c +26 -25
  41. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/armv81m/src/state_extract_bytes_x4_mve.S +334 -0
  42. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/armv81m/src/state_xor_bytes_x4_mve.S +355 -0
  43. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/auto.h +8 -3
  44. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/x86_64/{xkcp.h → keccak_f1600_x4_avx2.h} +11 -8
  45. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/x86_64/src/fips202_native_x86_64.h +44 -0
  46. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/x86_64/src/keccak_f1600_x4_avx2_asm.S +454 -0
  47. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/x86_64/src/keccakf1600_constants.c +52 -0
  48. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/meta.h +37 -28
  49. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/aarch64_zetas.c +213 -196
  50. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/arith_native_aarch64.h +248 -64
  51. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/intt_aarch64_asm.S +753 -0
  52. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/mld_polyvecl_pointwise_acc_montgomery_l4_aarch64_asm.S +129 -0
  53. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/mld_polyvecl_pointwise_acc_montgomery_l5_aarch64_asm.S +145 -0
  54. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/mld_polyvecl_pointwise_acc_montgomery_l7_aarch64_asm.S +177 -0
  55. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/ntt_aarch64_asm.S +653 -0
  56. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/pointwise_montgomery_aarch64_asm.S +84 -0
  57. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/poly_caddq_aarch64_asm.S +53 -0
  58. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/poly_chknorm_aarch64_asm.S +55 -0
  59. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/poly_decompose_32_aarch64_asm.S +86 -0
  60. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/poly_decompose_88_aarch64_asm.S +86 -0
  61. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/poly_use_hint_32_aarch64_asm.S +103 -0
  62. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/poly_use_hint_88_aarch64_asm.S +111 -0
  63. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/polyz_unpack_17_aarch64_asm.S +75 -0
  64. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/polyz_unpack_19_aarch64_asm.S +72 -0
  65. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/polyz_unpack_table.c +23 -11
  66. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/rej_uniform_aarch64_asm.S +189 -0
  67. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/rej_uniform_eta2_aarch64_asm.S +137 -0
  68. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/rej_uniform_eta4_aarch64_asm.S +130 -0
  69. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/rej_uniform_eta_table.c +520 -516
  70. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/rej_uniform_table.c +34 -33
  71. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/api.h +202 -242
  72. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/x86_64/meta.h +25 -17
  73. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/x86_64/src/arith_native_x86_64.h +112 -28
  74. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/x86_64/src/consts.c +1 -1
  75. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/x86_64/src/consts.h +1 -1
  76. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/x86_64/src/intt_avx2_asm.S +2311 -0
  77. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/x86_64/src/ntt_avx2_asm.S +2383 -0
  78. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/x86_64/src/nttunpack_avx2_asm.S +238 -0
  79. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/x86_64/src/pointwise_acc_l4_avx2_asm.S +139 -0
  80. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/x86_64/src/pointwise_acc_l5_avx2_asm.S +155 -0
  81. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/x86_64/src/pointwise_acc_l7_avx2_asm.S +187 -0
  82. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/x86_64/src/pointwise_avx2_asm.S +130 -0
  83. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/x86_64/src/poly_caddq_avx2_asm.S +190 -0
  84. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/x86_64/src/poly_decompose_32_avx2.c +6 -4
  85. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/x86_64/src/poly_decompose_88_avx2.c +6 -4
  86. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/x86_64/src/poly_use_hint_32_avx2.c +9 -8
  87. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/x86_64/src/poly_use_hint_88_avx2.c +10 -9
  88. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/x86_64/src/polyz_unpack_17_avx2.c +8 -5
  89. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/x86_64/src/polyz_unpack_19_avx2.c +8 -5
  90. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/x86_64/src/rej_uniform_eta2_avx2.c +6 -4
  91. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/x86_64/src/rej_uniform_eta4_avx2.c +6 -4
  92. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/x86_64/src/rej_uniform_table.c +130 -129
  93. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/packing.c +109 -180
  94. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/packing.h +169 -150
  95. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/poly.c +56 -40
  96. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/poly.h +149 -164
  97. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/poly_kl.c +52 -57
  98. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/poly_kl.h +132 -167
  99. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/polyvec.c +57 -424
  100. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/polyvec.h +167 -474
  101. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/polyvec_lazy.c +308 -0
  102. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/polyvec_lazy.h +653 -0
  103. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/reduce.h +22 -29
  104. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/rounding.h +37 -43
  105. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/sign.c +511 -367
  106. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/sign.h +456 -417
  107. data/lib/pq_crypto/version.rb +1 -1
  108. data/script/vendor_libs.rb +3 -3
  109. metadata +41 -35
  110. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/aarch64/src/keccak_f1600_x1_scalar_asm.S +0 -376
  111. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/aarch64/src/keccak_f1600_x1_v84a_asm.S +0 -204
  112. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/aarch64/src/keccak_f1600_x2_v84a_asm.S +0 -259
  113. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/aarch64/src/keccak_f1600_x4_v8a_scalar_hybrid_asm.S +0 -1077
  114. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/aarch64/src/keccak_f1600_x4_v8a_v84a_scalar_hybrid_asm.S +0 -987
  115. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/x86_64/src/KeccakP_1600_times4_SIMD256.c +0 -488
  116. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/x86_64/src/KeccakP_1600_times4_SIMD256.h +0 -16
  117. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/intt.S +0 -753
  118. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/mld_polyvecl_pointwise_acc_montgomery_l4.S +0 -129
  119. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/mld_polyvecl_pointwise_acc_montgomery_l5.S +0 -145
  120. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/mld_polyvecl_pointwise_acc_montgomery_l7.S +0 -177
  121. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/ntt.S +0 -653
  122. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/pointwise_montgomery.S +0 -79
  123. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/poly_caddq_asm.S +0 -53
  124. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/poly_chknorm_asm.S +0 -55
  125. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/poly_decompose_32_asm.S +0 -85
  126. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/poly_decompose_88_asm.S +0 -85
  127. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/poly_use_hint_32_asm.S +0 -102
  128. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/poly_use_hint_88_asm.S +0 -110
  129. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/polyz_unpack_17_asm.S +0 -72
  130. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/polyz_unpack_19_asm.S +0 -69
  131. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/rej_uniform_asm.S +0 -189
  132. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/rej_uniform_eta2_asm.S +0 -135
  133. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/rej_uniform_eta4_asm.S +0 -128
  134. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/x86_64/src/intt.S +0 -2311
  135. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/x86_64/src/ntt.S +0 -2383
  136. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/x86_64/src/nttunpack.S +0 -239
  137. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/x86_64/src/pointwise.S +0 -131
  138. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/x86_64/src/pointwise_acc_l4.S +0 -139
  139. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/x86_64/src/pointwise_acc_l5.S +0 -155
  140. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/x86_64/src/pointwise_acc_l7.S +0 -187
  141. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/x86_64/src/poly_caddq_avx2.c +0 -61
@@ -48,39 +48,43 @@
48
48
  #define mld_compute_pack_z MLD_ADD_PARAM_SET(mld_compute_pack_z)
49
49
  #define mld_attempt_signature_generation \
50
50
  MLD_ADD_PARAM_SET(mld_attempt_signature_generation) MLD_CONTEXT_PARAMETERS_8
51
- #define mld_compute_t0_t1_tr_from_sk_components \
52
- MLD_ADD_PARAM_SET(mld_compute_t0_t1_tr_from_sk_components) \
53
- MLD_CONTEXT_PARAMETERS_7
54
- /* End of parameter set namespacing */
55
-
51
+ #define mld_compute_pack_t0_t1 \
52
+ MLD_ADD_PARAM_SET(mld_compute_pack_t0_t1) MLD_CONTEXT_PARAMETERS_5
53
+ #define mld_get_max_signing_attempts \
54
+ MLD_ADD_PARAM_SET(mld_get_max_signing_attempts)
56
55
 
56
+ #if !defined(MLD_CONFIG_NO_KEYPAIR_API)
57
57
  static int mld_check_pct(uint8_t const pk[MLDSA_CRYPTO_PUBLICKEYBYTES],
58
58
  uint8_t const sk[MLDSA_CRYPTO_SECRETKEYBYTES],
59
59
  MLD_CONFIG_CONTEXT_PARAMETER_TYPE context)
60
60
  __contract__(
61
61
  requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES))
62
62
  requires(memory_no_alias(sk, MLDSA_CRYPTO_SECRETKEYBYTES))
63
- ensures(return_value == 0
64
- || return_value == MLD_ERR_FAIL
65
- || return_value == MLD_ERR_OUT_OF_MEMORY
66
- || return_value == MLD_ERR_RNG_FAIL)
63
+ ensures(return_value == 0 || MLD_ANY_ERROR(return_value))
67
64
  );
68
65
 
69
66
  #if defined(MLD_CONFIG_KEYGEN_PCT)
70
- /*************************************************
71
- * @[FIPS140_3_IG]
72
- * (https://csrc.nist.gov/csrc/media/Projects/cryptographic-module-validation-program/documents/fips%20140-3/FIPS%20140-3%20IG.pdf)
67
+ /**
68
+ * Pair-wise Consistency Test (PCT) for DSA keypairs.
69
+ *
70
+ * @[FIPS140_3_IG] TE10.35.02
71
+ * (https://csrc.nist.gov/csrc/media/Projects/cryptographic-module-validation-program/documents/fips%20140-3/FIPS%20140-3%20IG.pdf).
72
+ *
73
+ * Validates that a generated public/private key pair can correctly sign and
74
+ * verify data. Performs signature generation using the private key (sk),
75
+ * followed by signature verification using the public key (pk).
73
76
  *
74
- * TE10.35.02: Pair-wise Consistency Test (PCT) for DSA keypairs
77
+ * @note @[FIPS204] requires that public/private key pairs are to be used
78
+ * only for the calculation and/or verification of digital signatures.
75
79
  *
76
- * Purpose: Validates that a generated public/private key pair can correctly
77
- * sign and verify data. Test performs signature generation using the private
78
- * key (sk), followed by signature verification using the public key (pk).
79
- * Returns 0 if the signature was successfully verified, non-zero if it cannot.
80
+ * @param[in] pk Public key.
81
+ * @param[in] sk Secret key.
82
+ * @param context Application context. Only present when
83
+ * MLD_CONFIG_CONTEXT_PARAMETER is defined; type set by
84
+ * MLD_CONFIG_CONTEXT_PARAMETER_TYPE.
80
85
  *
81
- * Note: @[FIPS204] requires that public/private key pairs are to be used only
82
- * for the calculation and/of verification of digital signatures.
83
- **************************************************/
86
+ * @return 0 if the signature was successfully verified, non-zero otherwise.
87
+ */
84
88
  static int mld_check_pct(uint8_t const pk[MLDSA_CRYPTO_PUBLICKEYBYTES],
85
89
  uint8_t const sk[MLDSA_CRYPTO_SECRETKEYBYTES],
86
90
  MLD_CONFIG_CONTEXT_PARAMETER_TYPE context)
@@ -195,52 +199,56 @@ __contract__(
195
199
  #endif /* !MLD_CONFIG_SERIAL_FIPS202_ONLY */
196
200
  }
197
201
 
198
- /*************************************************
199
- * Name: mld_compute_t0_t1_tr_from_sk_components
202
+ /**
203
+ * Compute t = A*s1hat + s2 row by row, decompose each row into t0[k] and
204
+ * t1[k] via power2round, and bit-pack t1[k] into pk_t1 and t0[k] into the
205
+ * t0_packed buffer. Used by both keygen and pk_from_sk.
200
206
  *
201
- * Description: Computes t0, t1, tr, and pk from secret key components
202
- * rho, s1, s2. This is the shared computation used by
203
- * both keygen and generating the public key from the
204
- * secret key.
207
+ * @param[out] pk_t1 Output buffer for packed t1 (size
208
+ * MLDSA_K * MLDSA_POLYT1_PACKEDBYTES; i.e. the t1
209
+ * region of pk).
210
+ * @param[out] t0_packed Output buffer for packed t0 (size
211
+ * MLDSA_K * MLDSA_POLYT0_PACKEDBYTES).
212
+ * @param[in] s1hat s1 in NTT domain.
213
+ * @param[in] s2 s2.
214
+ * @param[in] rho Byte array containing seed rho.
215
+ * @param context Application context. Only present when
216
+ * MLD_CONFIG_CONTEXT_PARAMETER is defined; type set by
217
+ * MLD_CONFIG_CONTEXT_PARAMETER_TYPE.
205
218
  *
206
- * Arguments: - mld_polyveck *t0: output t0
207
- * - mld_polyveck *t1: output t1
208
- * - uint8_t tr[MLDSA_TRBYTES]: output tr
209
- * - uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES]: output public key
210
- * - const uint8_t rho[MLDSA_SEEDBYTES]: input rho
211
- * - const mld_polyvecl *s1: input s1
212
- * - const mld_polyveck *s2: input s2
213
- **************************************************/
219
+ * @return - 0: Success.
220
+ * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is used and
221
+ * an allocation via MLD_CUSTOM_ALLOC returned NULL.
222
+ */
214
223
  MLD_MUST_CHECK_RETURN_VALUE
215
- static int mld_compute_t0_t1_tr_from_sk_components(
216
- mld_polyveck *t0, mld_polyveck *t1, uint8_t tr[MLDSA_TRBYTES],
217
- uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES], const uint8_t rho[MLDSA_SEEDBYTES],
218
- const mld_polyvecl *s1, const mld_polyveck *s2,
224
+ static int mld_compute_pack_t0_t1(
225
+ uint8_t pk_t1[MLDSA_K * MLDSA_POLYT1_PACKEDBYTES],
226
+ uint8_t t0_packed[MLDSA_K * MLDSA_POLYT0_PACKEDBYTES],
227
+ const mld_polyvecl *s1hat, const mld_polyveck *s2,
228
+ const uint8_t rho[MLDSA_SEEDBYTES],
219
229
  MLD_CONFIG_CONTEXT_PARAMETER_TYPE context)
220
230
  __contract__(
221
- requires(memory_no_alias(t0, sizeof(mld_polyveck)))
222
- requires(memory_no_alias(t1, sizeof(mld_polyveck)))
223
- requires(memory_no_alias(tr, MLDSA_TRBYTES))
224
- requires(memory_no_alias(pk, MLDSA_CRYPTO_PUBLICKEYBYTES))
225
- requires(memory_no_alias(rho, MLDSA_SEEDBYTES))
226
- requires(memory_no_alias(s1, sizeof(mld_polyvecl)))
231
+ requires(memory_no_alias(pk_t1, MLDSA_K * MLDSA_POLYT1_PACKEDBYTES))
232
+ requires(memory_no_alias(t0_packed, MLDSA_K * MLDSA_POLYT0_PACKEDBYTES))
233
+ requires(memory_no_alias(s1hat, sizeof(mld_polyvecl)))
227
234
  requires(memory_no_alias(s2, sizeof(mld_polyveck)))
228
- requires(forall(l0, 0, MLDSA_L, array_bound(s1->vec[l0].coeffs, 0, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, MLDSA_ETA + 1)))
229
- requires(forall(k0, 0, MLDSA_K, array_bound(s2->vec[k0].coeffs, 0, MLDSA_N, MLD_POLYETA_UNPACK_LOWER_BOUND, MLDSA_ETA + 1)))
230
- assigns(memory_slice(t0, sizeof(mld_polyveck)))
231
- assigns(memory_slice(t1, sizeof(mld_polyveck)))
232
- assigns(memory_slice(tr, MLDSA_TRBYTES))
233
- assigns(memory_slice(pk, MLDSA_CRYPTO_PUBLICKEYBYTES))
234
- ensures(forall(k1, 0, MLDSA_K, array_bound(t0->vec[k1].coeffs, 0, MLDSA_N, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1)))
235
- ensures(forall(k2, 0, MLDSA_K, array_bound(t1->vec[k2].coeffs, 0, MLDSA_N, 0, 1 << 10)))
235
+ requires(memory_no_alias(rho, MLDSA_SEEDBYTES))
236
+ requires(forall(l1, 0, MLDSA_L,
237
+ array_abs_bound(s1hat->vec[l1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND)))
238
+ requires(forall(k2, 0, MLDSA_K,
239
+ array_bound(s2->vec[k2].coeffs, 0, MLDSA_N,
240
+ MLD_POLYETA_UNPACK_LOWER_BOUND, MLDSA_ETA + 1)))
241
+ assigns(memory_slice(pk_t1, MLDSA_K * MLDSA_POLYT1_PACKEDBYTES))
242
+ assigns(memory_slice(t0_packed, MLDSA_K * MLDSA_POLYT0_PACKEDBYTES))
236
243
  ensures(return_value == 0 || return_value == MLD_ERR_OUT_OF_MEMORY))
237
244
  {
245
+ unsigned int k;
238
246
  int ret;
239
247
  MLD_ALLOC(mat, mld_polymat, 1, context);
240
- MLD_ALLOC(s1hat, mld_polyvecl, 1, context);
241
- MLD_ALLOC(t, mld_polyveck, 1, context);
248
+ MLD_ALLOC(t0k, mld_poly, 1, context);
249
+ MLD_ALLOC(t1k, mld_poly, 1, context);
242
250
 
243
- if (mat == NULL || s1hat == NULL || t == NULL)
251
+ if (mat == NULL || t0k == NULL || t1k == NULL)
244
252
  {
245
253
  ret = MLD_ERR_OUT_OF_MEMORY;
246
254
  goto cleanup;
@@ -249,40 +257,52 @@ __contract__(
249
257
  /* Expand matrix */
250
258
  mld_polyvec_matrix_expand(mat, rho);
251
259
 
252
- /* Matrix-vector multiplication */
253
- *s1hat = *s1;
254
- mld_polyvecl_ntt(s1hat);
255
- mld_polyvec_matrix_pointwise_montgomery(t, mat, s1hat);
256
- mld_polyveck_invntt_tomont(t);
257
-
258
- /* Add error vector s2 */
259
- mld_polyveck_add(t, s2);
260
-
261
- /* Reference: The following reduction is not present in the reference
262
- * implementation. Omitting this reduction requires the output of
263
- * the invntt to be small enough such that the addition of s2 does
264
- * not result in absolute values >= MLDSA_Q. While our C, x86_64,
265
- * and AArch64 invntt implementations produce small enough
266
- * values for this to work out, it complicates the bounds
267
- * reasoning. We instead add an additional reduction, and can
268
- * consequently, relax the bounds requirements for the invntt.
269
- */
270
- mld_polyveck_reduce(t);
271
-
272
- /* Decompose to get t1, t0 */
273
- mld_polyveck_caddq(t);
274
- mld_polyveck_power2round(t1, t0, t);
275
-
276
- /* Pack public key and compute tr */
277
- mld_pack_pk(pk, rho, t1);
278
- mld_shake256(tr, MLDSA_TRBYTES, pk, MLDSA_CRYPTO_PUBLICKEYBYTES);
260
+ for (k = 0; k < MLDSA_K; k++)
261
+ __loop__(
262
+ assigns(k, memory_slice(pk_t1, MLDSA_K * MLDSA_POLYT1_PACKEDBYTES),
263
+ memory_slice(t0_packed, MLDSA_K * MLDSA_POLYT0_PACKEDBYTES),
264
+ memory_slice(t0k, sizeof(mld_poly)),
265
+ memory_slice(t1k, sizeof(mld_poly))
266
+ MLD_IF_REDUCE_RAM(, memory_slice(mat, sizeof(mld_polymat))))
267
+ invariant(k <= MLDSA_K)
268
+ decreases(MLDSA_K - k)
269
+ )
270
+ {
271
+ /* t0k = (A * s1hat)_k in NTT domain */
272
+ mld_polyvec_matrix_pointwise_montgomery_row(t0k, mat, s1hat, k);
273
+
274
+ /* t0k = invNTT(t0k) */
275
+ mld_poly_invntt_tomont(t0k);
276
+
277
+ /* t0k += s2[k] */
278
+ mld_poly_add(t0k, &s2->vec[k]);
279
+
280
+ /* Reference: The following reduction is not present in the reference
281
+ * implementation. Omitting this reduction requires the output
282
+ * of the invntt to be small enough such that the addition of
283
+ * s2 does not result in absolute values >= MLDSA_Q. While our
284
+ * C, x86_64, and AArch64 invntt implementations produce small
285
+ * enough values for this to work out, it complicates the
286
+ * bounds reasoning. We instead add an additional reduction,
287
+ * and can consequently, relax the bounds requirements for the
288
+ * invntt.
289
+ */
290
+ mld_poly_reduce(t0k);
291
+
292
+ /* Decompose into t1[k] and t0[k] (in place into t0k). */
293
+ mld_poly_caddq(t0k);
294
+ mld_poly_power2round(t1k, t0k, t0k);
295
+
296
+ /* Pack t1[k] into pk and t0[k] into the t0 output buffer. */
297
+ mld_polyt1_pack(pk_t1 + k * MLDSA_POLYT1_PACKEDBYTES, t1k);
298
+ mld_polyt0_pack(t0_packed + k * MLDSA_POLYT0_PACKEDBYTES, t0k);
299
+ }
279
300
 
280
301
  ret = 0;
281
-
282
302
  cleanup:
283
303
  /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */
284
- MLD_FREE(t, mld_polyveck, 1, context);
285
- MLD_FREE(s1hat, mld_polyvecl, 1, context);
304
+ MLD_FREE(t1k, mld_poly, 1, context);
305
+ MLD_FREE(t0k, mld_poly, 1, context);
286
306
  MLD_FREE(mat, mld_polymat, 1, context);
287
307
  return ret;
288
308
  }
@@ -296,16 +316,15 @@ int mld_sign_keypair_internal(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES],
296
316
  {
297
317
  int ret;
298
318
  const uint8_t *rho, *rhoprime, *key;
319
+
299
320
  MLD_ALLOC(seedbuf, uint8_t, 2 * MLDSA_SEEDBYTES + MLDSA_CRHBYTES, context);
300
321
  MLD_ALLOC(inbuf, uint8_t, MLDSA_SEEDBYTES + 2, context);
301
322
  MLD_ALLOC(tr, uint8_t, MLDSA_TRBYTES, context);
302
323
  MLD_ALLOC(s1, mld_polyvecl, 1, context);
303
324
  MLD_ALLOC(s2, mld_polyveck, 1, context);
304
- MLD_ALLOC(t1, mld_polyveck, 1, context);
305
- MLD_ALLOC(t0, mld_polyveck, 1, context);
306
325
 
307
326
  if (seedbuf == NULL || inbuf == NULL || tr == NULL || s1 == NULL ||
308
- s2 == NULL || t1 == NULL || t0 == NULL)
327
+ s2 == NULL)
309
328
  {
310
329
  ret = MLD_ERR_OUT_OF_MEMORY;
311
330
  goto cleanup;
@@ -327,24 +346,38 @@ int mld_sign_keypair_internal(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES],
327
346
  /* Sample s1 and s2 */
328
347
  mld_sample_s1_s2(s1, s2, rhoprime);
329
348
 
330
- /* Compute t0, t1, tr, and pk from rho, s1, s2 */
331
- ret = mld_compute_t0_t1_tr_from_sk_components(t0, t1, tr, pk, rho, s1, s2,
332
- context);
349
+ /* Pack s1 into sk before NTT */
350
+ mld_pack_sk_s1(sk, s1);
351
+
352
+ /* NTT s1 in place to use as s1hat */
353
+ mld_polyvecl_ntt(s1);
354
+
355
+ /* Pack rho into pk */
356
+ mld_memcpy(pk, rho, MLDSA_SEEDBYTES);
357
+
358
+ /* Compute t = A*s1hat + s2 row by row, decompose into t1/t0, and pack
359
+ * t1 into pk and t0 directly into the t0 region of sk. */
360
+ ret = mld_compute_pack_t0_t1(pk + MLDSA_SEEDBYTES,
361
+ sk + 2 * MLDSA_SEEDBYTES + MLDSA_TRBYTES +
362
+ MLDSA_L * MLDSA_POLYETA_PACKEDBYTES +
363
+ MLDSA_K * MLDSA_POLYETA_PACKEDBYTES,
364
+ s1, s2, rho, context);
333
365
  if (ret != 0)
334
366
  {
335
367
  goto cleanup;
336
368
  }
337
369
 
338
- /* Pack secret key */
339
- mld_pack_sk(sk, rho, tr, key, t0, s1, s2);
370
+ /* Compute tr = H(pk) */
371
+ mld_shake256(tr, MLDSA_TRBYTES, pk, MLDSA_CRYPTO_PUBLICKEYBYTES);
372
+
373
+ /* Pack remaining secret key components (s1 and t0 already packed) */
374
+ mld_pack_sk_rho_key_tr_s2(sk, rho, tr, key, s2);
340
375
 
341
376
  /* Constant time: pk is the public key, inherently public data */
342
377
  MLD_CT_TESTING_DECLASSIFY(pk, MLDSA_CRYPTO_PUBLICKEYBYTES);
343
378
 
344
379
  cleanup:
345
380
  /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */
346
- MLD_FREE(t0, mld_polyveck, 1, context);
347
- MLD_FREE(t1, mld_polyveck, 1, context);
348
381
  MLD_FREE(s2, mld_polyveck, 1, context);
349
382
  MLD_FREE(s1, mld_polyvecl, 1, context);
350
383
  MLD_FREE(tr, uint8_t, MLDSA_TRBYTES, context);
@@ -361,6 +394,7 @@ cleanup:
361
394
  return mld_check_pct(pk, sk, context);
362
395
  }
363
396
 
397
+ #if !defined(MLD_CONFIG_CORE_API_ONLY)
364
398
  #if !defined(MLD_CONFIG_NO_RANDOMIZED_API)
365
399
  MLD_MUST_CHECK_RETURN_VALUE
366
400
  MLD_EXTERNAL_API
@@ -368,45 +402,48 @@ int mld_sign_keypair(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES],
368
402
  uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES],
369
403
  MLD_CONFIG_CONTEXT_PARAMETER_TYPE context)
370
404
  {
371
- MLD_ALIGN uint8_t seed[MLDSA_SEEDBYTES];
372
405
  int ret;
406
+ MLD_ALLOC(seed, uint8_t, MLDSA_SEEDBYTES, context);
407
+
408
+ if (seed == NULL)
409
+ {
410
+ ret = MLD_ERR_OUT_OF_MEMORY;
411
+ goto cleanup;
412
+ }
413
+
373
414
  if (mld_randombytes(seed, MLDSA_SEEDBYTES) != 0)
374
415
  {
375
416
  ret = MLD_ERR_RNG_FAIL;
376
417
  goto cleanup;
377
418
  }
378
- MLD_CT_TESTING_SECRET(seed, sizeof(seed));
419
+ MLD_CT_TESTING_SECRET(seed, MLDSA_SEEDBYTES);
379
420
  ret = mld_sign_keypair_internal(pk, sk, seed, context);
380
421
 
381
422
  cleanup:
382
423
  /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */
383
- mld_zeroize(seed, sizeof(seed));
424
+ MLD_FREE(seed, uint8_t, MLDSA_SEEDBYTES, context);
384
425
  return ret;
385
426
  }
386
427
  #endif /* !MLD_CONFIG_NO_RANDOMIZED_API */
428
+ #endif /* !MLD_CONFIG_CORE_API_ONLY */
429
+ #endif /* !MLD_CONFIG_NO_KEYPAIR_API */
387
430
 
388
- /*************************************************
389
- * Name: mld_H
390
- *
391
- * Description: Abstracts application of SHAKE256 to
392
- * one, two or three blocks of data,
393
- * yielding a user-requested size of
394
- * output.
431
+ #if !defined(MLD_CONFIG_NO_SIGN_API) || !defined(MLD_CONFIG_NO_VERIFY_API)
432
+ /**
433
+ * Abstracts application of SHAKE256 to one, two or three blocks of data,
434
+ * yielding a user-requested size of output.
395
435
  *
396
- * Arguments: - uint8_t *out: pointer to output
397
- * - size_t outlen: requested output length in bytes
398
- * - const uint8_t *in1: pointer to input block 1
399
- * Must NOT be NULL
400
- * - size_t in1len: length of input in1 bytes
401
- * - const uint8_t *in2: pointer to input block 2
402
- * May be NULL if in2len=0, in which case
403
- * this block is ignored
404
- * - size_t in2len: length of input in2 bytes
405
- * - const uint8_t *in3: pointer to input block 3
406
- * May be NULL if in3len=0, in which case
407
- * this block is ignored
408
- * - size_t in3len: length of input in3 bytes
409
- **************************************************/
436
+ * @param[out] out Pointer to output.
437
+ * @param outlen Requested output length in bytes.
438
+ * @param[in] in1 Pointer to input block 1. Must NOT be NULL.
439
+ * @param in1len Length of input in1 in bytes.
440
+ * @param[in] in2 Pointer to input block 2. May be NULL if in2len == 0,
441
+ * in which case this block is ignored.
442
+ * @param in2len Length of input in2 in bytes.
443
+ * @param[in] in3 Pointer to input block 3. May be NULL if in3len == 0,
444
+ * in which case this block is ignored.
445
+ * @param in3len Length of input in3 in bytes.
446
+ */
410
447
  static void mld_H(uint8_t *out, size_t outlen, const uint8_t *in1,
411
448
  size_t in1len, const uint8_t *in2, size_t in2len,
412
449
  const uint8_t *in3, size_t in3len)
@@ -440,44 +477,62 @@ __contract__(
440
477
  /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */
441
478
  mld_zeroize(&state, sizeof(state));
442
479
  }
480
+ #endif /* !MLD_CONFIG_NO_SIGN_API || !MLD_CONFIG_NO_VERIFY_API */
443
481
 
444
- /*************************************************
445
- * Name: mld_compute_pack_z
446
- *
447
- * Description: Computes z = y + s1*c, checks that z has coefficients smaller
448
- * than MLDSA_GAMMA1 - MLDSA_BETA, and packs z into the
449
- * signature buffer.
482
+ #if !defined(MLD_CONFIG_NO_SIGN_API)
483
+ /* Reference: The reference implementation does not explicitly check the
484
+ * maximum nonce value, but instead loops indefinitely (even when the nonce
485
+ * would overflow). Internally, sampling of y uses
486
+ * (nonce*L), (nonce*L+1), ..., (nonce*L + L - 1).
487
+ * Hence, there are no overflows if nonce < (UINT16_MAX - L)/L.
488
+ * Explicitly checking for this explicitly allows us to prove type-safety. */
489
+ #define MLD_NONCE_UB ((UINT16_MAX - MLDSA_L) / MLDSA_L)
490
+
491
+ /**
492
+ * Compute z = y + s1*c, check that z has coefficients smaller than
493
+ * MLDSA_GAMMA1 - MLDSA_BETA, and pack z into the signature buffer.
450
494
  *
451
- * Arguments: - uint8_t *sig: output signature
452
- * - const mld_poly *cp: challenge polynomial
453
- * - const polyvecl *s1: secret vector s1
454
- * - const polyvecl *y: masking vector y
495
+ * @reference{This function is inlined into mld_sign_signature in the
496
+ * reference implementation.}
455
497
  *
456
- * Returns: - 0: Success (z has coefficients smaller than
457
- * MLDSA_GAMMA1 - MLDSA_BETA,)
458
- * - MLD_ERR_FAIL: z rejected (norm check failed)
459
- * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is
460
- * used and an allocation via MLD_CUSTOM_ALLOC returned NULL.
498
+ * @param[in,out] sig Output signature.
499
+ * @param[in] cp Challenge polynomial.
500
+ * @param[in] s1hat Secret vector s1 in NTT domain.
501
+ * @param[in] y Masking vector y (or seed in REDUCE_RAM mode).
502
+ * @param[out] z Scratch polynomial for z computation.
503
+ * @param[out] tmp Scratch polynomial.
461
504
  *
462
- * Reference: This function is inlined into mld_sign_signature in the
463
- * reference implementation.
464
- **************************************************/
505
+ * @return - 0: Success (z has coefficients smaller than
506
+ * MLDSA_GAMMA1 - MLDSA_BETA).
507
+ * - MLD_ERR_FAIL: z rejected (norm check failed).
508
+ * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is used and
509
+ * an allocation via MLD_CUSTOM_ALLOC returned NULL.
510
+ */
465
511
  MLD_MUST_CHECK_RETURN_VALUE
466
512
  static int mld_compute_pack_z(uint8_t sig[MLDSA_CRYPTO_BYTES],
467
- const mld_poly *cp, const mld_polyvecl *s1,
468
- const mld_polyvecl *y, mld_poly *z)
513
+ const mld_poly *cp, const mld_sk_s1hat *s1hat,
514
+ const mld_yvec *y, mld_poly *z, mld_poly *tmp)
469
515
  __contract__(
470
516
  requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES))
471
517
  requires(memory_no_alias(cp, sizeof(mld_poly)))
472
- requires(memory_no_alias(s1, sizeof(mld_polyvecl)))
473
- requires(memory_no_alias(y, sizeof(mld_polyvecl)))
518
+ requires(memory_no_alias(s1hat, sizeof(mld_sk_s1hat)))
519
+ requires(memory_no_alias(y, sizeof(mld_yvec)))
474
520
  requires(memory_no_alias(z, sizeof(mld_poly)))
521
+ requires(memory_no_alias(tmp, sizeof(mld_poly)))
475
522
  requires(array_abs_bound(cp->coeffs, 0, MLDSA_N, MLD_NTT_BOUND))
476
- requires(forall(k0, 0, MLDSA_L,
477
- array_bound(y->vec[k0].coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)))
478
- requires(forall(k1, 0, MLDSA_L, array_abs_bound(s1->vec[k1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND)))
523
+ MLD_IF_NOT_REDUCE_RAM(
524
+ requires(forall(k0, 0, MLDSA_L,
525
+ array_bound(y->vec.vec[k0].coeffs, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1)))
526
+ requires(forall(k1, 0, MLDSA_L, array_abs_bound(s1hat->vec.vec[k1].coeffs, 0, MLDSA_N, MLD_NTT_BOUND)))
527
+ )
528
+ MLD_IF_REDUCE_RAM(
529
+ requires(memory_no_alias(s1hat->packed, MLDSA_L * MLDSA_POLYETA_PACKEDBYTES))
530
+ requires(memory_no_alias(y->rhoprime, MLDSA_CRHBYTES))
531
+ requires(y->nonce <= MLD_NONCE_UB)
532
+ )
479
533
  assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES))
480
534
  assigns(memory_slice(z, sizeof(mld_poly)))
535
+ assigns(memory_slice(tmp, sizeof(mld_poly)))
481
536
  ensures(return_value == 0 || return_value == MLD_ERR_FAIL ||
482
537
  return_value == MLD_ERR_OUT_OF_MEMORY)
483
538
  )
@@ -486,14 +541,18 @@ __contract__(
486
541
  uint32_t z_invalid;
487
542
  for (i = 0; i < MLDSA_L; i++)
488
543
  __loop__(
489
- assigns(i, memory_slice(z, sizeof(mld_poly)), memory_slice(sig, MLDSA_CRYPTO_BYTES))
544
+ assigns(i, memory_slice(z, sizeof(mld_poly)),
545
+ memory_slice(tmp, sizeof(mld_poly)),
546
+ memory_slice(sig, MLDSA_CRYPTO_BYTES))
490
547
  invariant(i <= MLDSA_L)
491
548
  decreases(MLDSA_L - i)
492
549
  )
493
550
  {
494
- mld_poly_pointwise_montgomery(z, cp, &s1->vec[i]);
551
+ mld_sk_s1hat_get_poly(z, s1hat, i);
552
+ mld_poly_pointwise_montgomery(z, cp);
495
553
  mld_poly_invntt_tomont(z);
496
- mld_poly_add(z, &y->vec[i]);
554
+ mld_yvec_get_poly(tmp, y, i);
555
+ mld_poly_add(z, tmp);
497
556
  mld_poly_reduce(z);
498
557
 
499
558
  z_invalid = mld_poly_chknorm(z, MLDSA_GAMMA1 - MLDSA_BETA);
@@ -521,118 +580,133 @@ __contract__(
521
580
  return 0;
522
581
  }
523
582
 
524
- /* Reference: The reference implementation does not explicitly check the
525
- * maximum nonce value, but instead loops indefinitely (even when the nonce
526
- * would overflow). Internally, sampling of y uses
527
- * (nonceL), (nonceL+1), ... (nonce*L+L-1).
528
- * Hence, there are no overflows if nonce < (UINT16_MAX - L)/L.
529
- * Explicitly checking for this explicitly allows us to prove type-safety.
530
- * Note that FIPS204 explicitly allows an upper-bound this loop of
531
- * 814 (< (UINT16_MAX - L)/L) - see @[FIPS204, Appendix C]. */
532
- #define MLD_NONCE_UB ((UINT16_MAX - MLDSA_L) / MLDSA_L)
583
+ /* User-facing bound on signing attempts. See MLD_CONFIG_MAX_SIGNING_ATTEMPTS
584
+ * in mldsa_native_config.h. Default is chosen so that failure probability
585
+ * is < 2^{-256}, that is, signatures will practically always succeed. */
586
+ #ifndef MLD_CONFIG_MAX_SIGNING_ATTEMPTS
587
+ #define MLD_CONFIG_MAX_SIGNING_ATTEMPTS MLD_NONCE_UB
588
+ #endif
533
589
 
534
- /*************************************************
535
- * Name: attempt_signature_generation
536
- *
537
- * Description: Attempts to generate a single signature.
590
+ #if !defined(MLD_ALLOW_NONCOMPLIANT_SIGNING_BOUND) && \
591
+ MLD_CONFIG_MAX_SIGNING_ATTEMPTS < 814
592
+ #error Bad configuration: MLD_CONFIG_MAX_SIGNING_ATTEMPTS must be >= 814 for FIPS 204 compliance @[FIPS204, Appendix C]
593
+ #endif
594
+
595
+ #if MLD_CONFIG_MAX_SIGNING_ATTEMPTS < 1
596
+ #error Bad configuration: MLD_CONFIG_MAX_SIGNING_ATTEMPTS must be >= 1
597
+ #endif
598
+
599
+ #if MLD_CONFIG_MAX_SIGNING_ATTEMPTS > MLD_NONCE_UB
600
+ #error Bad configuration: MLD_CONFIG_MAX_SIGNING_ATTEMPTS exceeds the maximum allowed value.
601
+ #endif
602
+
603
+ MLD_MUST_CHECK_RETURN_VALUE
604
+ static MLD_INLINE uint16_t mld_get_max_signing_attempts(void)
605
+ __contract__(
606
+ ensures(return_value >= 1)
607
+ ensures(return_value <= MLD_NONCE_UB)
608
+ )
609
+ {
610
+ /* cassert(0) ensures CBMC uses the contract rather than inlining the body,
611
+ * keeping proofs agnostic of the configured value. */
612
+ cassert(0);
613
+ return MLD_CONFIG_MAX_SIGNING_ATTEMPTS;
614
+ }
615
+
616
+ /**
617
+ * Attempt to generate a single signature.
538
618
  *
539
- * Arguments: - uint8_t *sig: pointer to output signature
540
- * - const uint8_t *mu: pointer to message or hash
541
- * of exactly MLDSA_CRHBYTES bytes
542
- * - const uint8_t *rhoprime: pointer to randomness seed
543
- * - uint16_t nonce: current nonce value
544
- * - const mld_polymat *mat: expanded matrix
545
- * - const polyvecl *s1: secret vector s1
546
- * - const polyveck *s2: secret vector s2
547
- * - const polyveck *t0: vector t0
619
+ * @reference{This code differs from the reference implementation in that it
620
+ * factors out the core signature generation step into a distinct function
621
+ * here in order to improve efficiency of CBMC proof.}
548
622
  *
549
- * Returns: - 0: Signature generation succeeded
550
- * - MLD_ERR_FAIL: Signature rejected (norm check failed)
551
- * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is
552
- * used and an allocation via MLD_CUSTOM_ALLOC returned NULL.
623
+ * @param[out] sig Pointer to output signature.
624
+ * @param[in] mu Pointer to message or hash of exactly MLDSA_CRHBYTES
625
+ * bytes.
626
+ * @param[in] rhoprime Pointer to randomness seed.
627
+ * @param nonce Current nonce value.
628
+ * @param[in] mat Expanded matrix.
629
+ * @param[in] s1hat Secret vector s1 in NTT domain.
630
+ * @param[in] s2hat Secret vector s2 in NTT domain.
631
+ * @param[in] t0hat Vector t0 in NTT domain.
632
+ * @param context Application context. Only present when
633
+ * MLD_CONFIG_CONTEXT_PARAMETER is defined; type set by
634
+ * MLD_CONFIG_CONTEXT_PARAMETER_TYPE.
553
635
  *
554
- * Reference: This code differs from the reference implementation
555
- * in that it factors out the core signature generation
556
- * step into a distinct function here in order to improve
557
- * efficiency of CBMC proof.
558
- **************************************************/
636
+ * @return - 0: Signature generation succeeded.
637
+ * - MLD_ERR_FAIL: Signature rejected (norm check failed).
638
+ * - MLD_ERR_OUT_OF_MEMORY: If MLD_CONFIG_CUSTOM_ALLOC_FREE is used and
639
+ * an allocation via MLD_CUSTOM_ALLOC returned NULL.
640
+ */
559
641
  MLD_MUST_CHECK_RETURN_VALUE
560
642
  static int mld_attempt_signature_generation(
561
643
  uint8_t sig[MLDSA_CRYPTO_BYTES], const uint8_t *mu,
562
644
  const uint8_t rhoprime[MLDSA_CRHBYTES], uint16_t nonce, mld_polymat *mat,
563
- const mld_polyvecl *s1, const mld_polyveck *s2, const mld_polyveck *t0,
564
- MLD_CONFIG_CONTEXT_PARAMETER_TYPE context)
645
+ const mld_sk_s1hat *s1hat, const mld_sk_s2hat *s2hat,
646
+ const mld_sk_t0hat *t0hat, MLD_CONFIG_CONTEXT_PARAMETER_TYPE context)
565
647
  __contract__(
566
648
  requires(memory_no_alias(sig, MLDSA_CRYPTO_BYTES))
567
649
  requires(memory_no_alias(mu, MLDSA_CRHBYTES))
568
650
  requires(memory_no_alias(rhoprime, MLDSA_CRHBYTES))
569
651
  requires(memory_no_alias(mat, sizeof(mld_polymat)))
570
- requires(memory_no_alias(s1, sizeof(mld_polyvecl)))
571
- requires(memory_no_alias(s2, sizeof(mld_polyveck)))
572
- requires(memory_no_alias(t0, sizeof(mld_polyveck)))
652
+ requires(memory_no_alias(s1hat, sizeof(mld_sk_s1hat)))
653
+ requires(memory_no_alias(s2hat, sizeof(mld_sk_s2hat)))
654
+ requires(memory_no_alias(t0hat, sizeof(mld_sk_t0hat)))
573
655
  requires(nonce <= MLD_NONCE_UB)
574
- requires(forall(k1, 0, MLDSA_K, forall(l1, 0, MLDSA_L,
575
- array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q))))
576
- requires(forall(k2, 0, MLDSA_K, array_abs_bound(t0->vec[k2].coeffs, 0, MLDSA_N, MLD_NTT_BOUND)))
577
- requires(forall(k3, 0, MLDSA_L, array_abs_bound(s1->vec[k3].coeffs, 0, MLDSA_N, MLD_NTT_BOUND)))
578
- requires(forall(k4, 0, MLDSA_K, array_abs_bound(s2->vec[k4].coeffs, 0, MLDSA_N, MLD_NTT_BOUND)))
656
+ MLD_IF_NOT_REDUCE_RAM(
657
+ requires(forall(k1, 0, MLDSA_K, forall(l1, 0, MLDSA_L,
658
+ array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q))))
659
+ requires(forall(k2, 0, MLDSA_K, array_abs_bound(t0hat->vec.vec[k2].coeffs, 0, MLDSA_N, MLD_NTT_BOUND)))
660
+ requires(forall(k3, 0, MLDSA_L, array_abs_bound(s1hat->vec.vec[k3].coeffs, 0, MLDSA_N, MLD_NTT_BOUND)))
661
+ requires(forall(k4, 0, MLDSA_K, array_abs_bound(s2hat->vec.vec[k4].coeffs, 0, MLDSA_N, MLD_NTT_BOUND)))
662
+ )
663
+ MLD_IF_REDUCE_RAM(
664
+ requires(memory_no_alias(s1hat->packed, MLDSA_L * MLDSA_POLYETA_PACKEDBYTES))
665
+ requires(memory_no_alias(s2hat->packed, MLDSA_K * MLDSA_POLYETA_PACKEDBYTES))
666
+ requires(memory_no_alias(t0hat->packed, MLDSA_K * MLDSA_POLYT0_PACKEDBYTES))
667
+ )
579
668
  assigns(memory_slice(sig, MLDSA_CRYPTO_BYTES))
669
+ MLD_IF_REDUCE_RAM(
670
+ assigns(memory_slice(mat, sizeof(mld_polymat)))
671
+ )
580
672
  ensures(return_value == 0 || return_value == MLD_ERR_FAIL ||
581
673
  return_value == MLD_ERR_OUT_OF_MEMORY)
582
674
  )
583
675
  {
584
- unsigned int n;
676
+ unsigned int k;
585
677
  uint32_t w0_invalid, h_invalid;
586
678
  int ret;
587
- /* TODO: Remove the following workaround for
588
- * https://github.com/diffblue/cbmc/issues/8813 */
589
- typedef MLD_UNION_OR_STRUCT
590
- {
591
- mld_polyvecl y;
592
- mld_polyveck h;
593
- }
594
- yh_u;
595
- mld_polyvecl *y;
596
- mld_polyveck *h;
597
679
 
598
- /* TODO: Remove the following workaround for
599
- * https://github.com/diffblue/cbmc/issues/8813 */
600
- typedef MLD_UNION_OR_STRUCT
680
+ typedef union
601
681
  {
602
682
  mld_polyveck w1;
603
683
  mld_polyvecl tmp;
604
- }
605
- w1tmp_u;
684
+ } w1tmp_u;
606
685
  mld_polyveck *w1;
607
686
  mld_polyvecl *tmp;
608
687
 
609
688
  MLD_ALLOC(challenge_bytes, uint8_t, MLDSA_CTILDEBYTES, context);
610
- MLD_ALLOC(yh, yh_u, 1, context);
689
+ MLD_ALLOC(y, mld_yvec, 1, context);
611
690
  MLD_ALLOC(z, mld_poly, 1, context);
612
691
  MLD_ALLOC(w1tmp, w1tmp_u, 1, context);
613
692
  MLD_ALLOC(w0, mld_polyveck, 1, context);
614
693
  MLD_ALLOC(cp, mld_poly, 1, context);
615
694
  MLD_ALLOC(t, mld_poly, 1, context);
616
695
 
617
- if (challenge_bytes == NULL || yh == NULL || z == NULL || w1tmp == NULL ||
696
+ if (challenge_bytes == NULL || y == NULL || z == NULL || w1tmp == NULL ||
618
697
  w0 == NULL || cp == NULL || t == NULL)
619
698
  {
620
699
  ret = MLD_ERR_OUT_OF_MEMORY;
621
700
  goto cleanup;
622
701
  }
623
- y = &yh->y;
624
- h = &yh->h;
625
702
  w1 = &w1tmp->w1;
626
703
  tmp = &w1tmp->tmp;
627
704
 
628
- /* Sample intermediate vector y */
629
- mld_polyvecl_uniform_gamma1(y, rhoprime, nonce);
705
+ /* Sample/initialize intermediate vector y */
706
+ mld_yvec_init(y, rhoprime, nonce);
630
707
 
631
- /* Matrix-vector multiplication */
632
- *tmp = *y;
633
- mld_polyvecl_ntt(tmp);
634
- mld_polyvec_matrix_pointwise_montgomery(w0, mat, tmp);
635
- mld_polyveck_invntt_tomont(w0);
708
+ /* Matrix-vector multiplication, fused with y sampling in REDUCE_RAM mode */
709
+ mld_polyvec_matrix_pointwise_montgomery_yvec(w0, mat, y, tmp);
636
710
 
637
711
  /* Decompose w and call the random oracle */
638
712
  mld_polyveck_caddq(w0);
@@ -650,63 +724,84 @@ __contract__(
650
724
  mld_poly_ntt(cp);
651
725
 
652
726
  /* Compute z, reject if it reveals secret */
653
- ret = mld_compute_pack_z(sig, cp, s1, y, t);
654
- if (ret)
727
+ ret = mld_compute_pack_z(sig, cp, s1hat, y, t, z);
728
+ if (ret != 0)
655
729
  {
656
730
  goto cleanup;
657
731
  }
658
732
 
659
- /* Check that subtracting cs2 does not change high bits of w and low bits
660
- * do not reveal secret information */
661
- mld_polyveck_pointwise_poly_montgomery(h, cp, s2);
662
- mld_polyveck_invntt_tomont(h);
663
- mld_polyveck_sub(w0, h);
664
- mld_polyveck_reduce(w0);
665
-
666
- w0_invalid = mld_polyveck_chknorm(w0, MLDSA_GAMMA2 - MLDSA_BETA);
667
- /* Constant time: w0_invalid may be leaked - see comment for z_invalid. */
668
- MLD_CT_TESTING_DECLASSIFY(&w0_invalid, sizeof(uint32_t));
669
- if (w0_invalid)
733
+ /* Compute w0 - cs2 + ct0 per-component, checking norms incrementally.
734
+ * This avoids allocating a full polyveck for h. */
735
+ for (k = 0; k < MLDSA_K; k++)
736
+ __loop__(
737
+ assigns(k,
738
+ object_whole(z),
739
+ object_whole(w0))
740
+ invariant(k <= MLDSA_K)
741
+ invariant(forall(k0, k, MLDSA_K,
742
+ array_abs_bound(w0->vec[k0].coeffs, 0, MLDSA_N, MLDSA_GAMMA2 + 1)))
743
+ decreases(MLDSA_K - k)
744
+ )
670
745
  {
671
- ret = MLD_ERR_FAIL; /* reject */
672
- goto cleanup;
673
- }
746
+ /* Compute cs2[k] and subtract from w0[k] */
747
+ mld_sk_s2hat_get_poly(z, s2hat, k);
748
+ mld_poly_pointwise_montgomery(z, cp);
749
+ mld_poly_invntt_tomont(z);
674
750
 
675
- /* Compute hints for w1 */
676
- mld_polyveck_pointwise_poly_montgomery(h, cp, t0);
677
- mld_polyveck_invntt_tomont(h);
678
- mld_polyveck_reduce(h);
751
+ mld_poly_sub(&w0->vec[k], z);
752
+ mld_poly_reduce(&w0->vec[k]);
679
753
 
680
- h_invalid = mld_polyveck_chknorm(h, MLDSA_GAMMA2);
681
- /* Constant time: h_invalid may be leaked - see comment for z_invalid. */
682
- MLD_CT_TESTING_DECLASSIFY(&h_invalid, sizeof(uint32_t));
683
- if (h_invalid)
684
- {
685
- ret = MLD_ERR_FAIL; /* reject */
686
- goto cleanup;
687
- }
754
+ /* Check that subtracting cs2 does not change high bits of w and low bits
755
+ * do not reveal secret information */
756
+ w0_invalid = mld_poly_chknorm(&w0->vec[k], MLDSA_GAMMA2 - MLDSA_BETA);
757
+ /* Constant time: w0_invalid may be leaked - see comment for z_invalid. */
758
+ MLD_CT_TESTING_DECLASSIFY(&w0_invalid, sizeof(uint32_t));
759
+ if (w0_invalid)
760
+ {
761
+ ret = MLD_ERR_FAIL; /* reject */
762
+ goto cleanup;
763
+ }
688
764
 
689
- mld_polyveck_add(w0, h);
765
+ /* Compute ct0[k], check norm, and add to w0[k] */
766
+ mld_sk_t0hat_get_poly(z, t0hat, k);
767
+ mld_poly_pointwise_montgomery(z, cp);
768
+ mld_poly_invntt_tomont(z);
769
+ mld_poly_reduce(z);
770
+
771
+ h_invalid = mld_poly_chknorm(z, MLDSA_GAMMA2);
772
+ /* Constant time: h_invalid may be leaked - see comment for z_invalid. */
773
+ MLD_CT_TESTING_DECLASSIFY(&h_invalid, sizeof(uint32_t));
774
+ if (h_invalid)
775
+ {
776
+ ret = MLD_ERR_FAIL; /* reject */
777
+ goto cleanup;
778
+ }
779
+
780
+ mld_poly_add(&w0->vec[k], z);
781
+ }
690
782
 
691
783
  /* Constant time: At this point all norm checks have passed and we, hence,
692
784
  * know that the signature does not leak any secret information.
693
785
  * Consequently, any value that can be computed from the signature and public
694
786
  * key is considered public.
695
787
  * w0 and w1 are public as they can be computed from Az - ct = \alpha w1 + w0.
696
- * h=c*t0 is public as both c and t0 are public.
697
- * For a more detailed discussion, refer to https://eprint.iacr.org/2022/1406.
788
+ * h=c*t0 is public as both c and t0 are considered public.
789
+ * While t0 is not part of the public key, it can be reconstructed from
790
+ * a small number of signatures and need not be regarded as secret
791
+ * (see @[FIPS204, Section 6.1]).
698
792
  */
699
793
  MLD_CT_TESTING_DECLASSIFY(w0, sizeof(*w0));
700
794
  MLD_CT_TESTING_DECLASSIFY(w1, sizeof(*w1));
701
- n = mld_polyveck_make_hint(h, w0, w1);
702
- if (n > MLDSA_OMEGA)
795
+
796
+ /* Pack challenge bytes and hints. */
797
+ mld_pack_sig_c(sig, challenge_bytes);
798
+
799
+ ret = mld_pack_sig_h(sig, w0, w1);
800
+ if (ret != 0)
703
801
  {
704
- ret = MLD_ERR_FAIL; /* reject */
705
802
  goto cleanup;
706
803
  }
707
804
 
708
- /* All is well - write signature */
709
- mld_pack_sig_c_h(sig, challenge_bytes, h, n);
710
805
  /* Constant time: At this point it is clear that the signature is valid - it
711
806
  * can, hence, be considered public. */
712
807
  MLD_CT_TESTING_DECLASSIFY(sig, MLDSA_CRYPTO_BYTES);
@@ -719,7 +814,7 @@ cleanup:
719
814
  MLD_FREE(w0, mld_polyveck, 1, context);
720
815
  MLD_FREE(w1tmp, w1tmp_u, 1, context);
721
816
  MLD_FREE(z, mld_poly, 1, context);
722
- MLD_FREE(yh, yh_u, 1, context);
817
+ MLD_FREE(y, mld_yvec, 1, context);
723
818
  MLD_FREE(challenge_bytes, uint8_t, MLDSA_CTILDEBYTES, context);
724
819
 
725
820
  return ret;
@@ -737,14 +832,16 @@ int mld_sign_signature_internal(uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen,
737
832
  int ret;
738
833
  uint8_t *rho, *tr, *key, *mu, *rhoprime;
739
834
  uint16_t nonce = 0;
835
+ const uint16_t nonce_limit = mld_get_max_signing_attempts();
740
836
  MLD_ALLOC(seedbuf, uint8_t,
741
837
  2 * MLDSA_SEEDBYTES + MLDSA_TRBYTES + 2 * MLDSA_CRHBYTES, context);
742
838
  MLD_ALLOC(mat, mld_polymat, 1, context);
743
- MLD_ALLOC(s1, mld_polyvecl, 1, context);
744
- MLD_ALLOC(t0, mld_polyveck, 1, context);
745
- MLD_ALLOC(s2, mld_polyveck, 1, context);
839
+ MLD_ALLOC(s1hat, mld_sk_s1hat, 1, context);
840
+ MLD_ALLOC(t0hat, mld_sk_t0hat, 1, context);
841
+ MLD_ALLOC(s2hat, mld_sk_s2hat, 1, context);
746
842
 
747
- if (seedbuf == NULL || mat == NULL || s1 == NULL || t0 == NULL || s2 == NULL)
843
+ if (seedbuf == NULL || mat == NULL || s1hat == NULL || t0hat == NULL ||
844
+ s2hat == NULL)
748
845
  {
749
846
  ret = MLD_ERR_OUT_OF_MEMORY;
750
847
  goto cleanup;
@@ -755,7 +852,7 @@ int mld_sign_signature_internal(uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen,
755
852
  key = tr + MLDSA_TRBYTES;
756
853
  mu = key + MLDSA_SEEDBYTES;
757
854
  rhoprime = mu + MLDSA_CRHBYTES;
758
- mld_unpack_sk(rho, tr, key, t0, s1, s2, sk);
855
+ mld_unpack_sk(rho, tr, key, t0hat, s1hat, s2hat, sk);
759
856
 
760
857
  if (!externalmu)
761
858
  {
@@ -776,47 +873,46 @@ int mld_sign_signature_internal(uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen,
776
873
  MLD_CT_TESTING_DECLASSIFY(rho, MLDSA_SEEDBYTES);
777
874
  /* Expand matrix and transform vectors */
778
875
  mld_polyvec_matrix_expand(mat, rho);
779
- mld_polyvecl_ntt(s1);
780
- mld_polyveck_ntt(s2);
781
- mld_polyveck_ntt(t0);
782
-
783
- /* By default, return failure. Flip to success and write output
784
- * once signature generation succeeds. */
785
- ret = MLD_ERR_FAIL;
786
876
 
787
877
  /* Reference: This code is re-structured using a while(1), */
788
878
  /* with explicit "continue" statements (rather than "goto") */
789
879
  /* to implement rejection of invalid signatures. */
790
880
  while (1)
791
881
  __loop__(
792
- assigns(nonce, ret, object_whole(siglen), memory_slice(sig, MLDSA_CRYPTO_BYTES))
793
- invariant(nonce <= MLD_NONCE_UB)
882
+ MLD_IF_NOT_REDUCE_RAM(
883
+ assigns(nonce, ret, object_whole(siglen), memory_slice(sig, MLDSA_CRYPTO_BYTES))
884
+ )
885
+ MLD_IF_REDUCE_RAM(
886
+ assigns(nonce, ret, object_whole(siglen), memory_slice(sig, MLDSA_CRYPTO_BYTES),
887
+ memory_slice(mat, sizeof(mld_polymat)))
888
+ )
889
+ invariant(nonce <= nonce_limit)
794
890
 
795
891
  /* t0, s1, s2, and mat are initialized above and are NOT changed by this */
796
892
  /* loop. We can therefore re-assert their bounds here as part of the */
797
893
  /* loop invariant. This makes proof noticeably faster with CBMC */
798
- invariant(forall(k1, 0, MLDSA_K, forall(l1, 0, MLDSA_L,
799
- array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q))))
800
- invariant(forall(k2, 0, MLDSA_K, array_abs_bound(t0->vec[k2].coeffs, 0, MLDSA_N, MLD_NTT_BOUND)))
801
- invariant(forall(k3, 0, MLDSA_L, array_abs_bound(s1->vec[k3].coeffs, 0, MLDSA_N, MLD_NTT_BOUND)))
802
- invariant(forall(k4, 0, MLDSA_K, array_abs_bound(s2->vec[k4].coeffs, 0, MLDSA_N, MLD_NTT_BOUND)))
803
- invariant(ret == MLD_ERR_FAIL)
804
- decreases(MLD_NONCE_UB - nonce)
894
+ MLD_IF_NOT_REDUCE_RAM(
895
+ invariant(forall(k1, 0, MLDSA_K, forall(l1, 0, MLDSA_L,
896
+ array_bound(mat->vec[k1].vec[l1].coeffs, 0, MLDSA_N, 0, MLDSA_Q))))
897
+ invariant(forall(k2, 0, MLDSA_K, array_abs_bound(t0hat->vec.vec[k2].coeffs, 0, MLDSA_N, MLD_NTT_BOUND)))
898
+ invariant(forall(k3, 0, MLDSA_L, array_abs_bound(s1hat->vec.vec[k3].coeffs, 0, MLDSA_N, MLD_NTT_BOUND)))
899
+ invariant(forall(k4, 0, MLDSA_K, array_abs_bound(s2hat->vec.vec[k4].coeffs, 0, MLDSA_N, MLD_NTT_BOUND)))
900
+ )
901
+ decreases(nonce_limit - nonce)
805
902
  )
806
903
  {
807
- /* Reference: this code explicitly checks for exhaustion of nonce */
808
- /* values to provide predictable termination and results in that case */
809
- /* Checking here also means that incrementing nonce below can also */
810
- /* be proven to be type-safe. */
811
- if (nonce == MLD_NONCE_UB)
904
+ /* Reference: this code explicitly checks for exhaustion of signing */
905
+ /* attempts to provide predictable termination and results in that */
906
+ /* case. Checking here also means that incrementing nonce below can */
907
+ /* be proven to be type-safe. */
908
+ if (nonce == nonce_limit)
812
909
  {
813
- /* Note that ret == MLD_ERR_FAIL by default, so we
814
- * don't need to set it here. */
910
+ ret = MLD_ERR_SIGN_ATTEMPTS_EXHAUSTED;
815
911
  break;
816
912
  }
817
913
 
818
- ret = mld_attempt_signature_generation(sig, mu, rhoprime, nonce, mat, s1,
819
- s2, t0, context);
914
+ ret = mld_attempt_signature_generation(sig, mu, rhoprime, nonce, mat, s1hat,
915
+ s2hat, t0hat, context);
820
916
  nonce++;
821
917
  if (ret == 0)
822
918
  {
@@ -842,15 +938,16 @@ cleanup:
842
938
  }
843
939
 
844
940
  /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */
845
- MLD_FREE(s2, mld_polyveck, 1, context);
846
- MLD_FREE(t0, mld_polyveck, 1, context);
847
- MLD_FREE(s1, mld_polyvecl, 1, context);
941
+ MLD_FREE(s2hat, mld_sk_s2hat, 1, context);
942
+ MLD_FREE(t0hat, mld_sk_t0hat, 1, context);
943
+ MLD_FREE(s1hat, mld_sk_s1hat, 1, context);
848
944
  MLD_FREE(mat, mld_polymat, 1, context);
849
945
  MLD_FREE(seedbuf, uint8_t,
850
946
  2 * MLDSA_SEEDBYTES + MLDSA_TRBYTES + 2 * MLDSA_CRHBYTES, context);
851
947
  return ret;
852
948
  }
853
949
 
950
+ #if !defined(MLD_CONFIG_CORE_API_ONLY)
854
951
  #if !defined(MLD_CONFIG_NO_RANDOMIZED_API)
855
952
  MLD_MUST_CHECK_RETURN_VALUE
856
953
  MLD_EXTERNAL_API
@@ -887,7 +984,7 @@ int mld_sign_signature(uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen,
887
984
  ret = MLD_ERR_RNG_FAIL;
888
985
  goto cleanup;
889
986
  }
890
- MLD_CT_TESTING_SECRET(rnd, sizeof(rnd));
987
+ MLD_CT_TESTING_SECRET(rnd, MLDSA_RNDBYTES);
891
988
 
892
989
  ret = mld_sign_signature_internal(sig, siglen, m, mlen, pre, pre_len, rnd, sk,
893
990
  0, context);
@@ -921,8 +1018,15 @@ int mld_sign_signature_extmu(uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen,
921
1018
  const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES],
922
1019
  MLD_CONFIG_CONTEXT_PARAMETER_TYPE context)
923
1020
  {
924
- MLD_ALIGN uint8_t rnd[MLDSA_RNDBYTES];
925
1021
  int ret;
1022
+ MLD_ALLOC(rnd, uint8_t, MLDSA_RNDBYTES, context);
1023
+
1024
+ if (rnd == NULL)
1025
+ {
1026
+ *siglen = 0;
1027
+ ret = MLD_ERR_OUT_OF_MEMORY;
1028
+ goto cleanup;
1029
+ }
926
1030
 
927
1031
  /* Randomized variant of ML-DSA. If you need the deterministic variant,
928
1032
  * call mld_sign_signature_internal directly with all-zero rnd. */
@@ -932,14 +1036,14 @@ int mld_sign_signature_extmu(uint8_t sig[MLDSA_CRYPTO_BYTES], size_t *siglen,
932
1036
  ret = MLD_ERR_RNG_FAIL;
933
1037
  goto cleanup;
934
1038
  }
935
- MLD_CT_TESTING_SECRET(rnd, sizeof(rnd));
1039
+ MLD_CT_TESTING_SECRET(rnd, MLDSA_RNDBYTES);
936
1040
 
937
1041
  ret = mld_sign_signature_internal(sig, siglen, mu, MLDSA_CRHBYTES, NULL, 0,
938
1042
  rnd, sk, 1, context);
939
1043
 
940
1044
  cleanup:
941
1045
  /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */
942
- mld_zeroize(rnd, sizeof(rnd));
1046
+ MLD_FREE(rnd, uint8_t, MLDSA_RNDBYTES, context);
943
1047
 
944
1048
  return ret;
945
1049
  }
@@ -967,11 +1071,17 @@ int mld_sign(uint8_t *sm, size_t *smlen, const uint8_t *m, size_t mlen,
967
1071
  }
968
1072
  ret = mld_sign_signature(sm, smlen, sm + MLDSA_CRYPTO_BYTES, mlen, ctx,
969
1073
  ctxlen, sk, context);
970
- *smlen += mlen;
1074
+ if (ret == 0)
1075
+ {
1076
+ *smlen += mlen;
1077
+ }
971
1078
  return ret;
972
1079
  }
973
1080
  #endif /* !MLD_CONFIG_NO_RANDOMIZED_API */
1081
+ #endif /* !MLD_CONFIG_CORE_API_ONLY */
1082
+ #endif /* !MLD_CONFIG_NO_SIGN_API */
974
1083
 
1084
+ #if !defined(MLD_CONFIG_NO_VERIFY_API)
975
1085
  MLD_MUST_CHECK_RETURN_VALUE
976
1086
  MLD_EXTERNAL_API
977
1087
  int mld_sign_verify_internal(const uint8_t *sig, size_t siglen,
@@ -982,39 +1092,24 @@ int mld_sign_verify_internal(const uint8_t *sig, size_t siglen,
982
1092
  MLD_CONFIG_CONTEXT_PARAMETER_TYPE context)
983
1093
  {
984
1094
  int ret, cmp;
985
-
986
- /* TODO: Remove the following workaround for
987
- * https://github.com/diffblue/cbmc/issues/8813 */
988
- typedef MLD_UNION_OR_STRUCT
989
- {
990
- mld_polyveck t1;
991
- mld_polyveck w1;
992
- }
993
- t1w1_u;
994
- mld_polyveck *t1;
995
- mld_polyveck *w1;
1095
+ unsigned int i;
996
1096
 
997
1097
  MLD_ALLOC(buf, uint8_t, (MLDSA_K * MLDSA_POLYW1_PACKEDBYTES), context);
998
- MLD_ALLOC(rho, uint8_t, MLDSA_SEEDBYTES, context);
999
1098
  MLD_ALLOC(mu, uint8_t, MLDSA_CRHBYTES, context);
1000
1099
  MLD_ALLOC(c, uint8_t, MLDSA_CTILDEBYTES, context);
1001
1100
  MLD_ALLOC(c2, uint8_t, MLDSA_CTILDEBYTES, context);
1101
+ MLD_ALLOC(z, mld_polyvecl, 1, context);
1002
1102
  MLD_ALLOC(cp, mld_poly, 1, context);
1003
1103
  MLD_ALLOC(mat, mld_polymat, 1, context);
1004
- MLD_ALLOC(z, mld_polyvecl, 1, context);
1005
- MLD_ALLOC(t1w1, t1w1_u, 1, context);
1006
- MLD_ALLOC(tmp, mld_polyveck, 1, context);
1007
- MLD_ALLOC(h, mld_polyveck, 1, context);
1104
+ MLD_ALLOC(w1, mld_poly, 1, context);
1105
+ MLD_ALLOC(tmp, mld_poly, 1, context);
1008
1106
 
1009
- if (buf == NULL || rho == NULL || mu == NULL || c == NULL || c2 == NULL ||
1010
- cp == NULL || mat == NULL || z == NULL || t1w1 == NULL || tmp == NULL ||
1011
- h == NULL)
1107
+ if (buf == NULL || mu == NULL || c == NULL || c2 == NULL || z == NULL ||
1108
+ cp == NULL || mat == NULL || w1 == NULL || tmp == NULL)
1012
1109
  {
1013
1110
  ret = MLD_ERR_OUT_OF_MEMORY;
1014
1111
  goto cleanup;
1015
1112
  }
1016
- t1 = &t1w1->t1;
1017
- w1 = &t1w1->w1;
1018
1113
 
1019
1114
  if (siglen != MLDSA_CRYPTO_BYTES)
1020
1115
  {
@@ -1022,16 +1117,11 @@ int mld_sign_verify_internal(const uint8_t *sig, size_t siglen,
1022
1117
  goto cleanup;
1023
1118
  }
1024
1119
 
1025
- mld_unpack_pk(rho, t1, pk);
1120
+ mld_memcpy(c, sig, MLDSA_CTILDEBYTES);
1121
+ mld_polyvecl_unpack_z(z, sig + MLDSA_CTILDEBYTES);
1026
1122
 
1027
- /* mld_unpack_sig and mld_polyvecl_chknorm signal failure through a
1028
- * single non-zero error code that's not yet aligned with MLD_ERR_XXX.
1029
- * Map it to MLD_ERR_FAIL explicitly. */
1030
- if (mld_unpack_sig(c, z, h, sig))
1031
- {
1032
- ret = MLD_ERR_FAIL;
1033
- goto cleanup;
1034
- }
1123
+ /* mld_polyvecl_chknorm signals failure through a single non-zero error code
1124
+ * that's not yet aligned with MLD_ERR_XXX. Map it to MLD_ERR_FAIL. */
1035
1125
  if (mld_polyvecl_chknorm(z, MLDSA_GAMMA1 - MLDSA_BETA))
1036
1126
  {
1037
1127
  ret = MLD_ERR_FAIL;
@@ -1055,24 +1145,51 @@ int mld_sign_verify_internal(const uint8_t *sig, size_t siglen,
1055
1145
  mld_memcpy(mu, m, MLDSA_CRHBYTES);
1056
1146
  }
1057
1147
 
1058
- /* Matrix-vector multiplication; compute Az - c2^dt1 */
1148
+ /* Matrix-vector multiplication and per-row reconstruction of w1. */
1149
+ mld_polyvecl_ntt(z);
1150
+ mld_polyvec_matrix_expand(mat, pk);
1059
1151
  mld_poly_challenge(cp, c);
1060
1152
  mld_poly_ntt(cp);
1061
- mld_polyveck_shiftl(t1);
1062
- mld_polyveck_ntt(t1);
1063
- mld_polyveck_pointwise_poly_montgomery(tmp, cp, t1);
1064
1153
 
1065
- mld_polyvec_matrix_expand(mat, rho);
1066
- mld_polyvecl_ntt(z);
1067
- mld_polyvec_matrix_pointwise_montgomery(w1, mat, z);
1068
- mld_polyveck_sub(w1, tmp);
1069
- mld_polyveck_reduce(w1);
1070
- mld_polyveck_invntt_tomont(w1);
1071
-
1072
- /* Reconstruct w1 */
1073
- mld_polyveck_caddq(w1);
1074
- mld_polyveck_use_hint(tmp, w1, h);
1075
- mld_polyveck_pack_w1(buf, tmp);
1154
+ for (i = 0; i < MLDSA_K; ++i)
1155
+ __loop__(
1156
+ assigns(MLD_IF_REDUCE_RAM(memory_slice(mat, sizeof(mld_polymat)),)
1157
+ i, ret,
1158
+ memory_slice(w1, sizeof(mld_poly)),
1159
+ memory_slice(tmp, sizeof(mld_poly)),
1160
+ memory_slice(buf, MLDSA_K * MLDSA_POLYW1_PACKEDBYTES)
1161
+ )
1162
+ invariant(i <= MLDSA_K)
1163
+ decreases(MLDSA_K - i)
1164
+ )
1165
+ {
1166
+ /* w1 = (A * z)_i in NTT domain */
1167
+ mld_polyvec_matrix_pointwise_montgomery_row(w1, mat, z, i);
1168
+
1169
+ /* tmp = c * t1_i * 2^d in NTT domain */
1170
+ mld_unpack_pk_t1(tmp, pk, i);
1171
+ mld_poly_shiftl(tmp);
1172
+ mld_poly_ntt(tmp);
1173
+ mld_poly_pointwise_montgomery(tmp, cp);
1174
+
1175
+ /* w1 = invNTT(w1 - c * t1_i * 2^d) */
1176
+ mld_poly_sub(w1, tmp);
1177
+ mld_poly_reduce(w1);
1178
+ mld_poly_invntt_tomont(w1);
1179
+ mld_poly_caddq(w1);
1180
+
1181
+ /* tmp = h_i (decoded and validated from signature) */
1182
+ ret = mld_sig_unpack_hints(tmp, sig, i);
1183
+ if (ret != 0)
1184
+ {
1185
+ goto cleanup;
1186
+ }
1187
+
1188
+ /* w1 = use_hint(w1, tmp), then pack into buf[i] */
1189
+ mld_poly_use_hint(w1, tmp);
1190
+ mld_polyw1_pack(buf + i * MLDSA_POLYW1_PACKEDBYTES, w1);
1191
+ }
1192
+
1076
1193
  /* Call random oracle and verify challenge */
1077
1194
  mld_H(c2, MLDSA_CTILDEBYTES, mu, MLDSA_CRHBYTES, buf,
1078
1195
  MLDSA_K * MLDSA_POLYW1_PACKEDBYTES, NULL, 0);
@@ -1086,20 +1203,19 @@ int mld_sign_verify_internal(const uint8_t *sig, size_t siglen,
1086
1203
 
1087
1204
  cleanup:
1088
1205
  /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */
1089
- MLD_FREE(h, mld_polyveck, 1, context);
1090
- MLD_FREE(tmp, mld_polyveck, 1, context);
1091
- MLD_FREE(t1w1, t1w1_u, 1, context);
1092
- MLD_FREE(z, mld_polyvecl, 1, context);
1206
+ MLD_FREE(tmp, mld_poly, 1, context);
1207
+ MLD_FREE(w1, mld_poly, 1, context);
1093
1208
  MLD_FREE(mat, mld_polymat, 1, context);
1094
1209
  MLD_FREE(cp, mld_poly, 1, context);
1210
+ MLD_FREE(z, mld_polyvecl, 1, context);
1095
1211
  MLD_FREE(c2, uint8_t, MLDSA_CTILDEBYTES, context);
1096
1212
  MLD_FREE(c, uint8_t, MLDSA_CTILDEBYTES, context);
1097
1213
  MLD_FREE(mu, uint8_t, MLDSA_CRHBYTES, context);
1098
- MLD_FREE(rho, uint8_t, MLDSA_SEEDBYTES, context);
1099
1214
  MLD_FREE(buf, uint8_t, (MLDSA_K * MLDSA_POLYW1_PACKEDBYTES), context);
1100
1215
  return ret;
1101
1216
  }
1102
1217
 
1218
+ #if !defined(MLD_CONFIG_CORE_API_ONLY)
1103
1219
  MLD_MUST_CHECK_RETURN_VALUE
1104
1220
  MLD_EXTERNAL_API
1105
1221
  int mld_sign_verify(const uint8_t *sig, size_t siglen, const uint8_t *m,
@@ -1184,8 +1300,11 @@ cleanup:
1184
1300
 
1185
1301
  return ret;
1186
1302
  }
1303
+ #endif /* !MLD_CONFIG_CORE_API_ONLY */
1304
+ #endif /* !MLD_CONFIG_NO_VERIFY_API */
1187
1305
 
1188
-
1306
+ #if !defined(MLD_CONFIG_CORE_API_ONLY)
1307
+ #if !defined(MLD_CONFIG_NO_SIGN_API)
1189
1308
  MLD_MUST_CHECK_RETURN_VALUE
1190
1309
  MLD_EXTERNAL_API
1191
1310
  int mld_sign_signature_pre_hash_internal(
@@ -1226,7 +1345,9 @@ cleanup:
1226
1345
  mld_zeroize(pre, sizeof(pre));
1227
1346
  return ret;
1228
1347
  }
1348
+ #endif /* !MLD_CONFIG_NO_SIGN_API */
1229
1349
 
1350
+ #if !defined(MLD_CONFIG_NO_VERIFY_API)
1230
1351
  MLD_MUST_CHECK_RETURN_VALUE
1231
1352
  MLD_EXTERNAL_API
1232
1353
  int mld_sign_verify_pre_hash_internal(
@@ -1255,7 +1376,9 @@ cleanup:
1255
1376
  mld_zeroize(pre, sizeof(pre));
1256
1377
  return ret;
1257
1378
  }
1379
+ #endif /* !MLD_CONFIG_NO_VERIFY_API */
1258
1380
 
1381
+ #if !defined(MLD_CONFIG_NO_SIGN_API)
1259
1382
  MLD_MUST_CHECK_RETURN_VALUE
1260
1383
  MLD_EXTERNAL_API
1261
1384
  int mld_sign_signature_pre_hash_shake256(
@@ -1275,7 +1398,9 @@ int mld_sign_signature_pre_hash_shake256(
1275
1398
  mld_zeroize(ph, sizeof(ph));
1276
1399
  return ret;
1277
1400
  }
1401
+ #endif /* !MLD_CONFIG_NO_SIGN_API */
1278
1402
 
1403
+ #if !defined(MLD_CONFIG_NO_VERIFY_API)
1279
1404
  MLD_MUST_CHECK_RETURN_VALUE
1280
1405
  MLD_EXTERNAL_API
1281
1406
  int mld_sign_verify_pre_hash_shake256(
@@ -1294,19 +1419,17 @@ int mld_sign_verify_pre_hash_shake256(
1294
1419
  mld_zeroize(ph, sizeof(ph));
1295
1420
  return ret;
1296
1421
  }
1422
+ #endif /* !MLD_CONFIG_NO_VERIFY_API */
1297
1423
 
1298
-
1424
+ #if !defined(MLD_CONFIG_NO_SIGN_API) || !defined(MLD_CONFIG_NO_VERIFY_API)
1299
1425
  #define MLD_PRE_HASH_OID_LEN 11
1300
1426
 
1301
- /*************************************************
1302
- * Name: mld_get_hash_oid
1303
- *
1304
- * Description: Returns the OID of a given SHA-2/SHA-3 hash function.
1427
+ /**
1428
+ * Return the OID of a given SHA-2/SHA-3 hash function.
1305
1429
  *
1306
- * Arguments: - uint8_t oid[11]: pointer to output oid
1307
- * - int hashalg: hash algorithm constant (MLD_PREHASH_*)
1308
- *
1309
- ***************************************************/
1430
+ * @param[out] oid Pointer to output OID.
1431
+ * @param hashalg Hash algorithm constant (MLD_PREHASH_*).
1432
+ */
1310
1433
  static void mld_get_hash_oid(uint8_t oid[MLD_PRE_HASH_OID_LEN], int hashalg)
1311
1434
  {
1312
1435
  unsigned int i;
@@ -1421,7 +1544,9 @@ size_t mld_prepare_domain_separation_prefix(
1421
1544
  mld_memcpy(prefix + 2 + ctxlen + MLD_PRE_HASH_OID_LEN, ph, phlen);
1422
1545
  return 2 + ctxlen + MLD_PRE_HASH_OID_LEN + phlen;
1423
1546
  }
1547
+ #endif /* !MLD_CONFIG_NO_SIGN_API || !MLD_CONFIG_NO_VERIFY_API */
1424
1548
 
1549
+ #if !defined(MLD_CONFIG_NO_KEYPAIR_API)
1425
1550
  MLD_EXTERNAL_API
1426
1551
  int mld_sign_pk_from_sk(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES],
1427
1552
  const uint8_t sk[MLDSA_CRYPTO_SECRETKEYBYTES],
@@ -1435,36 +1560,53 @@ int mld_sign_pk_from_sk(uint8_t pk[MLDSA_CRYPTO_PUBLICKEYBYTES],
1435
1560
  MLD_ALLOC(key, uint8_t, MLDSA_SEEDBYTES, context);
1436
1561
  MLD_ALLOC(s1, mld_polyvecl, 1, context);
1437
1562
  MLD_ALLOC(s2, mld_polyveck, 1, context);
1438
- MLD_ALLOC(t0, mld_polyveck, 1, context);
1439
- MLD_ALLOC(t0_computed, mld_polyveck, 1, context);
1440
- MLD_ALLOC(t1, mld_polyveck, 1, context);
1563
+ MLD_ALLOC(t0_packed, uint8_t, MLDSA_K *MLDSA_POLYT0_PACKEDBYTES, context);
1441
1564
 
1442
1565
  if (rho == NULL || tr == NULL || tr_computed == NULL || key == NULL ||
1443
- s1 == NULL || s2 == NULL || t0 == NULL || t0_computed == NULL ||
1444
- t1 == NULL)
1566
+ s1 == NULL || s2 == NULL || t0_packed == NULL)
1445
1567
  {
1446
1568
  ret = MLD_ERR_OUT_OF_MEMORY;
1447
1569
  goto cleanup;
1448
1570
  }
1449
1571
 
1450
- /* Unpack secret key */
1451
- mld_unpack_sk(rho, tr, key, t0, s1, s2, sk);
1572
+ /* Inline unpack_sk: mld_unpack_sk uses lazy types for s1/s2/t0 which
1573
+ * we cannot use here. t0 stays in packed form -- we compare it against
1574
+ * the recomputed value below. */
1575
+ mld_memcpy(rho, sk, MLDSA_SEEDBYTES);
1576
+ mld_memcpy(key, sk + MLDSA_SEEDBYTES, MLDSA_SEEDBYTES);
1577
+ mld_memcpy(tr, sk + 2 * MLDSA_SEEDBYTES, MLDSA_TRBYTES);
1578
+ mld_polyvecl_unpack_eta(s1, sk + 2 * MLDSA_SEEDBYTES + MLDSA_TRBYTES);
1579
+ mld_polyveck_unpack_eta(s2, sk + 2 * MLDSA_SEEDBYTES + MLDSA_TRBYTES +
1580
+ MLDSA_L * MLDSA_POLYETA_PACKEDBYTES);
1452
1581
 
1453
1582
  /* Validate s1 and s2 coefficients are within [-MLDSA_ETA, MLDSA_ETA] */
1454
1583
  chk1 = mld_polyvecl_chknorm(s1, MLDSA_ETA + 1) & 0xFF;
1455
1584
  chk2 = mld_polyveck_chknorm(s2, MLDSA_ETA + 1) & 0xFF;
1456
1585
 
1457
- /* Recompute t0, t1, tr, and pk from rho, s1, s2 */
1458
- ret = mld_compute_t0_t1_tr_from_sk_components(t0_computed, t1, tr_computed,
1459
- pk, rho, s1, s2, context);
1586
+ /* NTT s1 in place to use as s1hat */
1587
+ mld_polyvecl_ntt(s1);
1588
+
1589
+ /* Pack rho into pk */
1590
+ mld_memcpy(pk, rho, MLDSA_SEEDBYTES);
1591
+
1592
+ /* Recompute t row by row, decompose, and pack t1 into pk and t0 into
1593
+ * t0_packed. */
1594
+ ret = mld_compute_pack_t0_t1(pk + MLDSA_SEEDBYTES, t0_packed, s1, s2, rho,
1595
+ context);
1460
1596
  if (ret != 0)
1461
1597
  {
1462
1598
  goto cleanup;
1463
1599
  }
1464
1600
 
1465
- /* Validate t0 and tr using constant-time comparisons */
1466
- cmp0 = mld_ct_memcmp((const uint8_t *)t0, (const uint8_t *)t0_computed,
1467
- sizeof(mld_polyveck));
1601
+ /* Compare recomputed packed t0 against the t0 region of sk. */
1602
+ cmp0 = mld_ct_memcmp(t0_packed,
1603
+ sk + 2 * MLDSA_SEEDBYTES + MLDSA_TRBYTES +
1604
+ MLDSA_L * MLDSA_POLYETA_PACKEDBYTES +
1605
+ MLDSA_K * MLDSA_POLYETA_PACKEDBYTES,
1606
+ MLDSA_K * MLDSA_POLYT0_PACKEDBYTES);
1607
+
1608
+ /* Compute tr_computed = H(pk) and compare to the stored tr */
1609
+ mld_shake256(tr_computed, MLDSA_TRBYTES, pk, MLDSA_CRYPTO_PUBLICKEYBYTES);
1468
1610
  cmp1 = mld_ct_memcmp((const uint8_t *)tr, (const uint8_t *)tr_computed,
1469
1611
  MLDSA_TRBYTES);
1470
1612
  check = mld_value_barrier_u8(cmp0 | cmp1 | chk1 | chk2);
@@ -1484,9 +1626,7 @@ cleanup:
1484
1626
  MLD_CT_TESTING_DECLASSIFY(pk, MLDSA_CRYPTO_PUBLICKEYBYTES);
1485
1627
 
1486
1628
  /* @[FIPS204, Section 3.6.3] Destruction of intermediate values. */
1487
- MLD_FREE(t1, mld_polyveck, 1, context);
1488
- MLD_FREE(t0_computed, mld_polyveck, 1, context);
1489
- MLD_FREE(t0, mld_polyveck, 1, context);
1629
+ MLD_FREE(t0_packed, uint8_t, MLDSA_K *MLDSA_POLYT0_PACKEDBYTES, context);
1490
1630
  MLD_FREE(s2, mld_polyveck, 1, context);
1491
1631
  MLD_FREE(s1, mld_polyvecl, 1, context);
1492
1632
  MLD_FREE(key, uint8_t, MLDSA_SEEDBYTES, context);
@@ -1496,6 +1636,8 @@ cleanup:
1496
1636
 
1497
1637
  return ret;
1498
1638
  }
1639
+ #endif /* !MLD_CONFIG_NO_KEYPAIR_API */
1640
+ #endif /* !MLD_CONFIG_CORE_API_ONLY */
1499
1641
 
1500
1642
  /* To facilitate single-compilation-unit (SCU) builds, undefine all macros.
1501
1643
  * Don't modify by hand -- this is auto-generated by scripts/autogen. */
@@ -1506,6 +1648,8 @@ cleanup:
1506
1648
  #undef mld_H
1507
1649
  #undef mld_compute_pack_z
1508
1650
  #undef mld_attempt_signature_generation
1509
- #undef mld_compute_t0_t1_tr_from_sk_components
1651
+ #undef mld_compute_pack_t0_t1
1652
+ #undef mld_get_max_signing_attempts
1510
1653
  #undef MLD_NONCE_UB
1654
+ #undef MLD_CONFIG_MAX_SIGNING_ATTEMPTS
1511
1655
  #undef MLD_PRE_HASH_OID_LEN