pq_crypto 0.6.0 → 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 (154) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +12 -0
  3. data/SECURITY.md +7 -0
  4. data/ext/pqcrypto/extconf.rb +2 -0
  5. data/ext/pqcrypto/pqcrypto_ruby_secure.c +139 -0
  6. data/ext/pqcrypto/pqcrypto_secure.c +532 -0
  7. data/ext/pqcrypto/pqcrypto_secure.h +20 -0
  8. data/ext/pqcrypto/pqcrypto_version.h +1 -1
  9. data/ext/pqcrypto/vendor/.vendored +4 -4
  10. data/ext/pqcrypto/vendor/mldsa-native/README.md +23 -10
  11. data/ext/pqcrypto/vendor/mldsa-native/mldsa/README.md +23 -0
  12. data/ext/pqcrypto/vendor/mldsa-native/mldsa/mldsa_native.c +114 -58
  13. data/ext/pqcrypto/vendor/mldsa-native/mldsa/mldsa_native.h +498 -461
  14. data/ext/pqcrypto/vendor/mldsa-native/mldsa/mldsa_native_asm.S +145 -85
  15. data/ext/pqcrypto/vendor/mldsa-native/mldsa/mldsa_native_config.h +456 -422
  16. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/cbmc.h +47 -25
  17. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/common.h +26 -14
  18. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/ct.h +56 -81
  19. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/debug.h +17 -24
  20. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/fips202.c +33 -40
  21. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/fips202.h +67 -87
  22. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/fips202x4.c +19 -14
  23. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/fips202x4.h +13 -5
  24. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/keccakf1600.c +84 -10
  25. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/keccakf1600.h +10 -5
  26. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/aarch64/auto.h +6 -0
  27. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/aarch64/src/fips202_native_aarch64.h +22 -15
  28. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/aarch64/src/keccak_f1600_x1_scalar_aarch64_asm.S +376 -0
  29. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/aarch64/src/keccak_f1600_x1_v84a_aarch64_asm.S +204 -0
  30. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/aarch64/src/keccak_f1600_x2_v84a_aarch64_asm.S +259 -0
  31. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/aarch64/src/keccak_f1600_x4_v8a_scalar_hybrid_aarch64_asm.S +1077 -0
  32. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/aarch64/src/keccak_f1600_x4_v8a_v84a_scalar_hybrid_aarch64_asm.S +987 -0
  33. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/aarch64/src/keccakf1600_round_constants.c +16 -10
  34. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/aarch64/x1_scalar.h +2 -1
  35. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/aarch64/x1_v84a.h +1 -1
  36. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/aarch64/x2_v84a.h +4 -2
  37. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/aarch64/x4_v8a_scalar.h +2 -2
  38. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/aarch64/x4_v8a_v84a_scalar.h +1 -1
  39. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/api.h +60 -0
  40. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/armv81m/mve.h +48 -0
  41. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/armv81m/src/fips202_native_armv81m.h +18 -1
  42. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/armv81m/src/keccak_f1600_x4_mve.S +658 -582
  43. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/armv81m/src/keccak_f1600_x4_mve.c +5 -100
  44. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/armv81m/src/keccakf1600_round_constants.c +26 -25
  45. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/armv81m/src/state_extract_bytes_x4_mve.S +334 -0
  46. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/armv81m/src/state_xor_bytes_x4_mve.S +355 -0
  47. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/auto.h +8 -3
  48. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/x86_64/{xkcp.h → keccak_f1600_x4_avx2.h} +11 -8
  49. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/x86_64/src/fips202_native_x86_64.h +44 -0
  50. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/x86_64/src/keccak_f1600_x4_avx2_asm.S +454 -0
  51. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/x86_64/src/keccakf1600_constants.c +52 -0
  52. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/meta.h +37 -28
  53. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/aarch64_zetas.c +213 -196
  54. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/arith_native_aarch64.h +248 -64
  55. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/intt_aarch64_asm.S +753 -0
  56. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/mld_polyvecl_pointwise_acc_montgomery_l4_aarch64_asm.S +129 -0
  57. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/mld_polyvecl_pointwise_acc_montgomery_l5_aarch64_asm.S +145 -0
  58. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/mld_polyvecl_pointwise_acc_montgomery_l7_aarch64_asm.S +177 -0
  59. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/ntt_aarch64_asm.S +653 -0
  60. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/pointwise_montgomery_aarch64_asm.S +84 -0
  61. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/poly_caddq_aarch64_asm.S +53 -0
  62. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/poly_chknorm_aarch64_asm.S +55 -0
  63. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/poly_decompose_32_aarch64_asm.S +86 -0
  64. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/poly_decompose_88_aarch64_asm.S +86 -0
  65. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/poly_use_hint_32_aarch64_asm.S +103 -0
  66. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/poly_use_hint_88_aarch64_asm.S +111 -0
  67. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/polyz_unpack_17_aarch64_asm.S +75 -0
  68. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/polyz_unpack_19_aarch64_asm.S +72 -0
  69. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/polyz_unpack_table.c +23 -11
  70. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/rej_uniform_aarch64_asm.S +189 -0
  71. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/rej_uniform_eta2_aarch64_asm.S +137 -0
  72. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/rej_uniform_eta4_aarch64_asm.S +130 -0
  73. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/rej_uniform_eta_table.c +520 -516
  74. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/rej_uniform_table.c +34 -33
  75. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/api.h +202 -242
  76. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/x86_64/meta.h +25 -17
  77. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/x86_64/src/arith_native_x86_64.h +112 -28
  78. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/x86_64/src/consts.c +1 -1
  79. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/x86_64/src/consts.h +1 -1
  80. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/x86_64/src/intt_avx2_asm.S +2311 -0
  81. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/x86_64/src/ntt_avx2_asm.S +2383 -0
  82. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/x86_64/src/nttunpack_avx2_asm.S +238 -0
  83. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/x86_64/src/pointwise_acc_l4_avx2_asm.S +139 -0
  84. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/x86_64/src/pointwise_acc_l5_avx2_asm.S +155 -0
  85. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/x86_64/src/pointwise_acc_l7_avx2_asm.S +187 -0
  86. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/x86_64/src/pointwise_avx2_asm.S +130 -0
  87. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/x86_64/src/poly_caddq_avx2_asm.S +190 -0
  88. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/x86_64/src/poly_decompose_32_avx2.c +6 -4
  89. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/x86_64/src/poly_decompose_88_avx2.c +6 -4
  90. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/x86_64/src/poly_use_hint_32_avx2.c +9 -8
  91. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/x86_64/src/poly_use_hint_88_avx2.c +10 -9
  92. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/x86_64/src/polyz_unpack_17_avx2.c +8 -5
  93. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/x86_64/src/polyz_unpack_19_avx2.c +8 -5
  94. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/x86_64/src/rej_uniform_eta2_avx2.c +6 -4
  95. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/x86_64/src/rej_uniform_eta4_avx2.c +6 -4
  96. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/x86_64/src/rej_uniform_table.c +130 -129
  97. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/packing.c +109 -180
  98. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/packing.h +169 -150
  99. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/poly.c +56 -40
  100. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/poly.h +149 -164
  101. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/poly_kl.c +52 -57
  102. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/poly_kl.h +132 -167
  103. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/polyvec.c +57 -424
  104. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/polyvec.h +167 -474
  105. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/polyvec_lazy.c +308 -0
  106. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/polyvec_lazy.h +653 -0
  107. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/reduce.h +22 -29
  108. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/rounding.h +37 -43
  109. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/sign.c +511 -367
  110. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/sign.h +456 -417
  111. data/lib/pq_crypto/hybrid_kem.rb +1 -1
  112. data/lib/pq_crypto/internal.rb +23 -0
  113. data/lib/pq_crypto/kem.rb +27 -34
  114. data/lib/pq_crypto/pkcs8/der.rb +68 -0
  115. data/lib/pq_crypto/pkcs8/private_key_choice.rb +186 -0
  116. data/lib/pq_crypto/pkcs8.rb +51 -468
  117. data/lib/pq_crypto/serialization.rb +19 -29
  118. data/lib/pq_crypto/signature.rb +28 -35
  119. data/lib/pq_crypto/version.rb +1 -1
  120. data/lib/pq_crypto.rb +10 -0
  121. data/script/vendor_libs.rb +3 -3
  122. metadata +44 -35
  123. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/aarch64/src/keccak_f1600_x1_scalar_asm.S +0 -376
  124. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/aarch64/src/keccak_f1600_x1_v84a_asm.S +0 -204
  125. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/aarch64/src/keccak_f1600_x2_v84a_asm.S +0 -259
  126. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/aarch64/src/keccak_f1600_x4_v8a_scalar_hybrid_asm.S +0 -1077
  127. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/aarch64/src/keccak_f1600_x4_v8a_v84a_scalar_hybrid_asm.S +0 -987
  128. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/x86_64/src/KeccakP_1600_times4_SIMD256.c +0 -488
  129. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/x86_64/src/KeccakP_1600_times4_SIMD256.h +0 -16
  130. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/intt.S +0 -753
  131. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/mld_polyvecl_pointwise_acc_montgomery_l4.S +0 -129
  132. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/mld_polyvecl_pointwise_acc_montgomery_l5.S +0 -145
  133. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/mld_polyvecl_pointwise_acc_montgomery_l7.S +0 -177
  134. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/ntt.S +0 -653
  135. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/pointwise_montgomery.S +0 -79
  136. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/poly_caddq_asm.S +0 -53
  137. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/poly_chknorm_asm.S +0 -55
  138. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/poly_decompose_32_asm.S +0 -85
  139. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/poly_decompose_88_asm.S +0 -85
  140. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/poly_use_hint_32_asm.S +0 -102
  141. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/poly_use_hint_88_asm.S +0 -110
  142. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/polyz_unpack_17_asm.S +0 -72
  143. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/polyz_unpack_19_asm.S +0 -69
  144. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/rej_uniform_asm.S +0 -189
  145. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/rej_uniform_eta2_asm.S +0 -135
  146. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/rej_uniform_eta4_asm.S +0 -128
  147. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/x86_64/src/intt.S +0 -2311
  148. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/x86_64/src/ntt.S +0 -2383
  149. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/x86_64/src/nttunpack.S +0 -239
  150. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/x86_64/src/pointwise.S +0 -131
  151. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/x86_64/src/pointwise_acc_l4.S +0 -139
  152. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/x86_64/src/pointwise_acc_l5.S +0 -155
  153. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/x86_64/src/pointwise_acc_l7.S +0 -187
  154. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/x86_64/src/poly_caddq_avx2.c +0 -61
@@ -15,6 +15,9 @@
15
15
  #include <openssl/crypto.h>
16
16
  #include <openssl/evp.h>
17
17
  #include <openssl/rand.h>
18
+ #include <openssl/x509.h>
19
+ #include <openssl/pkcs12.h>
20
+ #include <openssl/objects.h>
18
21
 
19
22
  #if OPENSSL_VERSION_NUMBER < 0x30000000L
20
23
  #error "OpenSSL 3.0 or later is required for pq_crypto"
@@ -1159,6 +1162,535 @@ int pq_secret_key_from_pqc_container_pem(char **algorithm_out, uint8_t **key_out
1159
1162
  return ret;
1160
1163
  }
1161
1164
 
1165
+ #define PQ_PKCS8_PRIVATE_KEY_PEM_LABEL "PRIVATE KEY"
1166
+ #define PQ_PKCS8_ENCRYPTED_PRIVATE_KEY_PEM_LABEL "ENCRYPTED PRIVATE KEY"
1167
+
1168
+ static size_t pq_der_length_octets(size_t len) {
1169
+ size_t octets = 0;
1170
+ size_t v = len;
1171
+
1172
+ if (len < 0x80)
1173
+ return 1;
1174
+ do {
1175
+ octets++;
1176
+ v >>= 8;
1177
+ } while (v != 0);
1178
+ return 1 + octets;
1179
+ }
1180
+
1181
+ static int pq_der_write_length(uint8_t **cursor, size_t len) {
1182
+ uint8_t *p;
1183
+ size_t octets = 0;
1184
+ size_t v = len;
1185
+
1186
+ if (!cursor || !*cursor)
1187
+ return PQ_ERROR_BUFFER;
1188
+
1189
+ p = *cursor;
1190
+ if (len < 0x80) {
1191
+ *p++ = (uint8_t)len;
1192
+ *cursor = p;
1193
+ return PQ_SUCCESS;
1194
+ }
1195
+
1196
+ do {
1197
+ octets++;
1198
+ v >>= 8;
1199
+ } while (v != 0);
1200
+ if (octets > sizeof(size_t))
1201
+ return PQ_ERROR_BUFFER;
1202
+
1203
+ *p++ = (uint8_t)(0x80u | (uint8_t)octets);
1204
+ for (size_t i = 0; i < octets; ++i) {
1205
+ size_t shift = 8 * (octets - 1 - i);
1206
+ *p++ = (uint8_t)((len >> shift) & 0xffu);
1207
+ }
1208
+ *cursor = p;
1209
+ return PQ_SUCCESS;
1210
+ }
1211
+
1212
+ static int pq_der_read_length(const uint8_t *input, size_t input_len, size_t *offset,
1213
+ size_t *len_out) {
1214
+ uint8_t first;
1215
+ size_t len = 0;
1216
+ size_t length_octets;
1217
+
1218
+ if (!input || !offset || !len_out || *offset >= input_len)
1219
+ return PQ_ERROR_BUFFER;
1220
+
1221
+ first = input[(*offset)++];
1222
+ if (first < 0x80) {
1223
+ *len_out = (size_t)first;
1224
+ return PQ_SUCCESS;
1225
+ }
1226
+
1227
+ length_octets = (size_t)(first & 0x7fu);
1228
+ if (length_octets == 0 || length_octets > sizeof(size_t))
1229
+ return PQ_ERROR_BUFFER;
1230
+ if (input_len - *offset < length_octets)
1231
+ return PQ_ERROR_BUFFER;
1232
+ if (input[*offset] == 0)
1233
+ return PQ_ERROR_BUFFER;
1234
+
1235
+ for (size_t i = 0; i < length_octets; ++i) {
1236
+ if (len > (SIZE_MAX >> 8))
1237
+ return PQ_ERROR_BUFFER;
1238
+ len = (len << 8) | (size_t)input[*offset + i];
1239
+ }
1240
+ if (len < 0x80)
1241
+ return PQ_ERROR_BUFFER;
1242
+
1243
+ *offset += length_octets;
1244
+ *len_out = len;
1245
+ return PQ_SUCCESS;
1246
+ }
1247
+
1248
+ static int pq_der_expect_tlv(const uint8_t *input, size_t input_len, size_t *offset,
1249
+ uint8_t expected_tag, size_t *value_offset_out,
1250
+ size_t *value_len_out) {
1251
+ size_t value_len;
1252
+ size_t value_offset;
1253
+
1254
+ if (!input || !offset || !value_offset_out || !value_len_out || *offset >= input_len)
1255
+ return PQ_ERROR_BUFFER;
1256
+ if (input[(*offset)++] != expected_tag)
1257
+ return PQ_ERROR_BUFFER;
1258
+ if (pq_der_read_length(input, input_len, offset, &value_len) != PQ_SUCCESS)
1259
+ return PQ_ERROR_BUFFER;
1260
+ value_offset = *offset;
1261
+ if (input_len - value_offset < value_len)
1262
+ return PQ_ERROR_BUFFER;
1263
+ *offset = value_offset + value_len;
1264
+ *value_offset_out = value_offset;
1265
+ *value_len_out = value_len;
1266
+ return PQ_SUCCESS;
1267
+ }
1268
+
1269
+ static int pq_oid_text_to_der(const char *oid_text, uint8_t **oid_der_out,
1270
+ size_t *oid_der_len_out) {
1271
+ ASN1_OBJECT *obj = NULL;
1272
+ uint8_t *der = NULL;
1273
+ unsigned char *cursor;
1274
+ int der_len;
1275
+ int ret = PQ_ERROR_OPENSSL;
1276
+
1277
+ if (!oid_text || !oid_der_out || !oid_der_len_out)
1278
+ return PQ_ERROR_BUFFER;
1279
+ *oid_der_out = NULL;
1280
+ *oid_der_len_out = 0;
1281
+
1282
+ obj = OBJ_txt2obj(oid_text, 1);
1283
+ if (!obj)
1284
+ goto cleanup;
1285
+ der_len = i2d_ASN1_OBJECT(obj, NULL);
1286
+ if (der_len <= 0)
1287
+ goto cleanup;
1288
+ der = malloc((size_t)der_len);
1289
+ if (!der) {
1290
+ ret = PQ_ERROR_NOMEM;
1291
+ goto cleanup;
1292
+ }
1293
+ cursor = der;
1294
+ if (i2d_ASN1_OBJECT(obj, &cursor) != der_len || (size_t)(cursor - der) != (size_t)der_len)
1295
+ goto cleanup;
1296
+
1297
+ *oid_der_out = der;
1298
+ *oid_der_len_out = (size_t)der_len;
1299
+ der = NULL;
1300
+ ret = PQ_SUCCESS;
1301
+
1302
+ cleanup:
1303
+ if (der) {
1304
+ pq_secure_wipe(der, (size_t)(der_len > 0 ? der_len : 0));
1305
+ free(der);
1306
+ }
1307
+ if (obj)
1308
+ ASN1_OBJECT_free(obj);
1309
+ return ret;
1310
+ }
1311
+
1312
+ static int pq_oid_der_to_text(const uint8_t *oid_der, size_t oid_der_len, char **oid_text_out) {
1313
+ ASN1_OBJECT *obj = NULL;
1314
+ const unsigned char *cursor;
1315
+ char tmp[128];
1316
+ int text_len;
1317
+ char *copy = NULL;
1318
+ int ret = PQ_ERROR_OPENSSL;
1319
+
1320
+ if (!oid_der || oid_der_len == 0 || oid_der_len > (size_t)LONG_MAX || !oid_text_out)
1321
+ return PQ_ERROR_BUFFER;
1322
+ *oid_text_out = NULL;
1323
+
1324
+ cursor = oid_der;
1325
+ obj = d2i_ASN1_OBJECT(NULL, &cursor, (long)oid_der_len);
1326
+ if (!obj || cursor != oid_der + oid_der_len)
1327
+ goto cleanup;
1328
+ text_len = OBJ_obj2txt(tmp, sizeof(tmp), obj, 1);
1329
+ if (text_len <= 0 || (size_t)text_len >= sizeof(tmp))
1330
+ goto cleanup;
1331
+ copy = malloc((size_t)text_len + 1);
1332
+ if (!copy) {
1333
+ ret = PQ_ERROR_NOMEM;
1334
+ goto cleanup;
1335
+ }
1336
+ memcpy(copy, tmp, (size_t)text_len + 1);
1337
+ *oid_text_out = copy;
1338
+ copy = NULL;
1339
+ ret = PQ_SUCCESS;
1340
+
1341
+ cleanup:
1342
+ if (copy)
1343
+ free(copy);
1344
+ if (obj)
1345
+ ASN1_OBJECT_free(obj);
1346
+ return ret;
1347
+ }
1348
+
1349
+ int pq_pkcs8_private_key_info_to_der(uint8_t **output, size_t *output_len, const char *oid_text,
1350
+ const uint8_t *private_key, size_t private_key_len) {
1351
+ uint8_t *oid_der = NULL;
1352
+ size_t oid_der_len = 0;
1353
+ size_t alg_body_len, alg_len, priv_len, inner_len, total_len;
1354
+ uint8_t *buf = NULL;
1355
+ uint8_t *cur;
1356
+ int ret;
1357
+
1358
+ if (!output || !output_len || !oid_text || !private_key)
1359
+ return PQ_ERROR_BUFFER;
1360
+ *output = NULL;
1361
+ *output_len = 0;
1362
+
1363
+ ret = pq_oid_text_to_der(oid_text, &oid_der, &oid_der_len);
1364
+ if (ret != PQ_SUCCESS)
1365
+ return ret;
1366
+
1367
+ alg_body_len = oid_der_len;
1368
+ alg_len = 1 + pq_der_length_octets(alg_body_len) + alg_body_len;
1369
+ priv_len = 1 + pq_der_length_octets(private_key_len) + private_key_len;
1370
+ if (pq_size_add(3, alg_len, &inner_len) != PQ_SUCCESS ||
1371
+ pq_size_add(inner_len, priv_len, &inner_len) != PQ_SUCCESS) {
1372
+ ret = PQ_ERROR_BUFFER;
1373
+ goto cleanup;
1374
+ }
1375
+ if (pq_size_add(1 + pq_der_length_octets(inner_len), inner_len, &total_len) != PQ_SUCCESS) {
1376
+ ret = PQ_ERROR_BUFFER;
1377
+ goto cleanup;
1378
+ }
1379
+
1380
+ buf = malloc(total_len);
1381
+ if (!buf) {
1382
+ ret = PQ_ERROR_NOMEM;
1383
+ goto cleanup;
1384
+ }
1385
+
1386
+ cur = buf;
1387
+ *cur++ = 0x30;
1388
+ ret = pq_der_write_length(&cur, inner_len);
1389
+ if (ret != PQ_SUCCESS)
1390
+ goto cleanup;
1391
+ *cur++ = 0x02;
1392
+ *cur++ = 0x01;
1393
+ *cur++ = 0x00;
1394
+ *cur++ = 0x30;
1395
+ ret = pq_der_write_length(&cur, alg_body_len);
1396
+ if (ret != PQ_SUCCESS)
1397
+ goto cleanup;
1398
+ memcpy(cur, oid_der, oid_der_len);
1399
+ cur += oid_der_len;
1400
+ *cur++ = 0x04;
1401
+ ret = pq_der_write_length(&cur, private_key_len);
1402
+ if (ret != PQ_SUCCESS)
1403
+ goto cleanup;
1404
+ memcpy(cur, private_key, private_key_len);
1405
+ cur += private_key_len;
1406
+ if ((size_t)(cur - buf) != total_len) {
1407
+ ret = PQ_ERROR_BUFFER;
1408
+ goto cleanup;
1409
+ }
1410
+
1411
+ *output = buf;
1412
+ *output_len = total_len;
1413
+ buf = NULL;
1414
+ ret = PQ_SUCCESS;
1415
+
1416
+ cleanup:
1417
+ if (buf) {
1418
+ pq_secure_wipe(buf, total_len);
1419
+ free(buf);
1420
+ }
1421
+ if (oid_der) {
1422
+ pq_secure_wipe(oid_der, oid_der_len);
1423
+ free(oid_der);
1424
+ }
1425
+ return ret;
1426
+ }
1427
+
1428
+ int pq_pkcs8_private_key_info_from_der(char **oid_text_out, uint8_t **private_key_out,
1429
+ size_t *private_key_len_out, const uint8_t *input,
1430
+ size_t input_len) {
1431
+ size_t offset = 0;
1432
+ size_t outer_off = 0, outer_len = 0, outer_end;
1433
+ size_t alg_off = 0, alg_len = 0, alg_end;
1434
+ size_t oid_off = 0, oid_len = 0;
1435
+ size_t priv_off = 0, priv_len = 0;
1436
+ uint8_t *private_key = NULL;
1437
+ char *oid_text = NULL;
1438
+ int ret;
1439
+
1440
+ if (!oid_text_out || !private_key_out || !private_key_len_out || !input)
1441
+ return PQ_ERROR_BUFFER;
1442
+ *oid_text_out = NULL;
1443
+ *private_key_out = NULL;
1444
+ *private_key_len_out = 0;
1445
+
1446
+ ret = pq_der_expect_tlv(input, input_len, &offset, 0x30, &outer_off, &outer_len);
1447
+ if (ret != PQ_SUCCESS)
1448
+ return ret;
1449
+ outer_end = outer_off + outer_len;
1450
+ if (offset != input_len || outer_end != input_len)
1451
+ return PQ_ERROR_BUFFER;
1452
+
1453
+ offset = outer_off;
1454
+ {
1455
+ size_t version_off = 0, version_len = 0;
1456
+ ret = pq_der_expect_tlv(input, outer_end, &offset, 0x02, &version_off, &version_len);
1457
+ if (ret != PQ_SUCCESS)
1458
+ return ret;
1459
+ if (version_len != 1 || input[version_off] != 0x00)
1460
+ return PQ_ERROR_BUFFER;
1461
+ }
1462
+
1463
+ ret = pq_der_expect_tlv(input, outer_end, &offset, 0x30, &alg_off, &alg_len);
1464
+ if (ret != PQ_SUCCESS)
1465
+ return ret;
1466
+ alg_end = alg_off + alg_len;
1467
+ {
1468
+ size_t alg_cursor = alg_off;
1469
+ size_t oid_tlv_start = alg_cursor;
1470
+ ret = pq_der_expect_tlv(input, alg_end, &alg_cursor, 0x06, &oid_off, &oid_len);
1471
+ if (ret != PQ_SUCCESS)
1472
+ return ret;
1473
+ if (alg_cursor != alg_end)
1474
+ return PQ_ERROR_BUFFER;
1475
+ ret = pq_oid_der_to_text(input + oid_tlv_start, alg_cursor - oid_tlv_start, &oid_text);
1476
+ }
1477
+ if (ret != PQ_SUCCESS)
1478
+ return ret;
1479
+
1480
+ ret = pq_der_expect_tlv(input, outer_end, &offset, 0x04, &priv_off, &priv_len);
1481
+ if (ret != PQ_SUCCESS)
1482
+ goto cleanup;
1483
+ if (offset != outer_end) {
1484
+ ret = PQ_ERROR_BUFFER;
1485
+ goto cleanup;
1486
+ }
1487
+ private_key = malloc(priv_len ? priv_len : 1);
1488
+ if (!private_key) {
1489
+ ret = PQ_ERROR_NOMEM;
1490
+ goto cleanup;
1491
+ }
1492
+ if (priv_len)
1493
+ memcpy(private_key, input + priv_off, priv_len);
1494
+
1495
+ *oid_text_out = oid_text;
1496
+ *private_key_out = private_key;
1497
+ *private_key_len_out = priv_len;
1498
+ oid_text = NULL;
1499
+ private_key = NULL;
1500
+ ret = PQ_SUCCESS;
1501
+
1502
+ cleanup:
1503
+ if (oid_text)
1504
+ free(oid_text);
1505
+ if (private_key) {
1506
+ pq_secure_wipe(private_key, priv_len);
1507
+ free(private_key);
1508
+ }
1509
+ return ret;
1510
+ }
1511
+
1512
+ int pq_pkcs8_encrypt_private_key_info_der(uint8_t **output, size_t *output_len,
1513
+ const uint8_t *plain_der, size_t plain_der_len,
1514
+ const char *passphrase, size_t passphrase_len,
1515
+ int iterations) {
1516
+ const unsigned char *cursor;
1517
+ PKCS8_PRIV_KEY_INFO *p8 = NULL;
1518
+ X509_SIG *encrypted = NULL;
1519
+ unsigned char salt[16];
1520
+ unsigned char *der = NULL;
1521
+ unsigned char *der_cursor;
1522
+ int der_len;
1523
+ int ret = PQ_ERROR_OPENSSL;
1524
+
1525
+ if (!output || !output_len || !plain_der || !passphrase || iterations <= 0 ||
1526
+ passphrase_len > (size_t)INT_MAX || plain_der_len > (size_t)LONG_MAX)
1527
+ return PQ_ERROR_BUFFER;
1528
+ *output = NULL;
1529
+ *output_len = 0;
1530
+
1531
+ cursor = plain_der;
1532
+ p8 = d2i_PKCS8_PRIV_KEY_INFO(NULL, &cursor, (long)plain_der_len);
1533
+ if (!p8 || cursor != plain_der + plain_der_len)
1534
+ goto cleanup;
1535
+ if (RAND_bytes(salt, sizeof(salt)) != 1)
1536
+ goto cleanup;
1537
+
1538
+ encrypted = PKCS8_encrypt(-1, EVP_aes_256_cbc(), passphrase, (int)passphrase_len, salt,
1539
+ (int)sizeof(salt), iterations, p8);
1540
+ if (!encrypted)
1541
+ goto cleanup;
1542
+
1543
+ der_len = i2d_X509_SIG(encrypted, NULL);
1544
+ if (der_len <= 0) {
1545
+ ret = PQ_ERROR_OPENSSL;
1546
+ goto cleanup;
1547
+ }
1548
+ der = malloc((size_t)der_len);
1549
+ if (!der) {
1550
+ ret = PQ_ERROR_NOMEM;
1551
+ goto cleanup;
1552
+ }
1553
+ der_cursor = der;
1554
+ if (i2d_X509_SIG(encrypted, &der_cursor) != der_len ||
1555
+ (size_t)(der_cursor - der) != (size_t)der_len)
1556
+ goto cleanup;
1557
+
1558
+ *output = der;
1559
+ *output_len = (size_t)der_len;
1560
+ der = NULL;
1561
+ ret = PQ_SUCCESS;
1562
+
1563
+ cleanup:
1564
+ pq_secure_wipe(salt, sizeof(salt));
1565
+ if (der) {
1566
+ pq_secure_wipe(der, (size_t)(der_len > 0 ? der_len : 0));
1567
+ free(der);
1568
+ }
1569
+ if (encrypted)
1570
+ X509_SIG_free(encrypted);
1571
+ if (p8)
1572
+ PKCS8_PRIV_KEY_INFO_free(p8);
1573
+ return ret;
1574
+ }
1575
+
1576
+ int pq_pkcs8_decrypt_private_key_info_der(uint8_t **output, size_t *output_len,
1577
+ const uint8_t *encrypted_der, size_t encrypted_der_len,
1578
+ const char *passphrase, size_t passphrase_len) {
1579
+ const unsigned char *cursor;
1580
+ X509_SIG *encrypted = NULL;
1581
+ PKCS8_PRIV_KEY_INFO *p8 = NULL;
1582
+ unsigned char *der = NULL;
1583
+ unsigned char *der_cursor;
1584
+ int der_len;
1585
+ int ret = PQ_ERROR_OPENSSL;
1586
+
1587
+ if (!output || !output_len || !encrypted_der || !passphrase ||
1588
+ passphrase_len > (size_t)INT_MAX || encrypted_der_len > (size_t)LONG_MAX)
1589
+ return PQ_ERROR_BUFFER;
1590
+ *output = NULL;
1591
+ *output_len = 0;
1592
+
1593
+ cursor = encrypted_der;
1594
+ encrypted = d2i_X509_SIG(NULL, &cursor, (long)encrypted_der_len);
1595
+ if (!encrypted || cursor != encrypted_der + encrypted_der_len)
1596
+ goto cleanup;
1597
+ p8 = PKCS8_decrypt(encrypted, passphrase, (int)passphrase_len);
1598
+ if (!p8)
1599
+ goto cleanup;
1600
+
1601
+ der_len = i2d_PKCS8_PRIV_KEY_INFO(p8, NULL);
1602
+ if (der_len <= 0)
1603
+ goto cleanup;
1604
+ der = malloc((size_t)der_len);
1605
+ if (!der) {
1606
+ ret = PQ_ERROR_NOMEM;
1607
+ goto cleanup;
1608
+ }
1609
+ der_cursor = der;
1610
+ if (i2d_PKCS8_PRIV_KEY_INFO(p8, &der_cursor) != der_len ||
1611
+ (size_t)(der_cursor - der) != (size_t)der_len)
1612
+ goto cleanup;
1613
+
1614
+ *output = der;
1615
+ *output_len = (size_t)der_len;
1616
+ der = NULL;
1617
+ ret = PQ_SUCCESS;
1618
+
1619
+ cleanup:
1620
+ if (der) {
1621
+ pq_secure_wipe(der, (size_t)(der_len > 0 ? der_len : 0));
1622
+ free(der);
1623
+ }
1624
+ if (p8)
1625
+ PKCS8_PRIV_KEY_INFO_free(p8);
1626
+ if (encrypted)
1627
+ X509_SIG_free(encrypted);
1628
+ return ret;
1629
+ }
1630
+
1631
+ int pq_pkcs8_der_is_encrypted_private_key_info(const uint8_t *input, size_t input_len) {
1632
+ const unsigned char *cursor;
1633
+ X509_SIG *encrypted = NULL;
1634
+ const X509_ALGOR *alg = NULL;
1635
+ const ASN1_OCTET_STRING *digest = NULL;
1636
+ const ASN1_OBJECT *obj = NULL;
1637
+ int ptype = 0;
1638
+ const void *pval = NULL;
1639
+ int ret = 0;
1640
+
1641
+ if (!input || input_len > (size_t)LONG_MAX)
1642
+ return 0;
1643
+ cursor = input;
1644
+ encrypted = d2i_X509_SIG(NULL, &cursor, (long)input_len);
1645
+ if (!encrypted || cursor != input + input_len)
1646
+ goto cleanup;
1647
+ X509_SIG_get0(encrypted, &alg, &digest);
1648
+ if (!alg || !digest)
1649
+ goto cleanup;
1650
+ X509_ALGOR_get0(&obj, &ptype, &pval, alg);
1651
+ (void)ptype;
1652
+ (void)pval;
1653
+ if (obj && OBJ_obj2nid(obj) == NID_pbes2)
1654
+ ret = 1;
1655
+
1656
+ cleanup:
1657
+ if (encrypted)
1658
+ X509_SIG_free(encrypted);
1659
+ return ret;
1660
+ }
1661
+
1662
+ int pq_pkcs8_der_to_pem(char **output, size_t *output_len, const uint8_t *der, size_t der_len,
1663
+ int encrypted) {
1664
+ return pq_der_to_pem(encrypted ? PQ_PKCS8_ENCRYPTED_PRIVATE_KEY_PEM_LABEL
1665
+ : PQ_PKCS8_PRIVATE_KEY_PEM_LABEL,
1666
+ der, der_len, output, output_len);
1667
+ }
1668
+
1669
+ int pq_pkcs8_pem_to_der(uint8_t **der_out, size_t *der_len_out, int *encrypted_out,
1670
+ const char *input, size_t input_len) {
1671
+ int ret;
1672
+
1673
+ if (!der_out || !der_len_out || !encrypted_out || !input)
1674
+ return PQ_ERROR_BUFFER;
1675
+ *der_out = NULL;
1676
+ *der_len_out = 0;
1677
+ *encrypted_out = 0;
1678
+
1679
+ ret = pq_pem_to_der(PQ_PKCS8_PRIVATE_KEY_PEM_LABEL, input, input_len, der_out, der_len_out);
1680
+ if (ret == PQ_SUCCESS) {
1681
+ *encrypted_out = 0;
1682
+ return PQ_SUCCESS;
1683
+ }
1684
+
1685
+ ret = pq_pem_to_der(PQ_PKCS8_ENCRYPTED_PRIVATE_KEY_PEM_LABEL, input, input_len, der_out,
1686
+ der_len_out);
1687
+ if (ret == PQ_SUCCESS) {
1688
+ *encrypted_out = 1;
1689
+ return PQ_SUCCESS;
1690
+ }
1691
+ return PQ_ERROR_BUFFER;
1692
+ }
1693
+
1162
1694
  const char *pq_version(void) {
1163
1695
  return PQCRYPTO_VERSION;
1164
1696
  }
@@ -132,6 +132,26 @@ int pq_secret_key_from_pqc_container_pem(char **algorithm_out, uint8_t **key_out
132
132
  size_t *key_len_out, const char *input,
133
133
  size_t input_len);
134
134
 
135
+ int pq_pkcs8_private_key_info_to_der(uint8_t **output, size_t *output_len,
136
+ const char *oid_text, const uint8_t *private_key,
137
+ size_t private_key_len);
138
+ int pq_pkcs8_private_key_info_from_der(char **oid_text_out, uint8_t **private_key_out,
139
+ size_t *private_key_len_out, const uint8_t *input,
140
+ size_t input_len);
141
+ int pq_pkcs8_encrypt_private_key_info_der(uint8_t **output, size_t *output_len,
142
+ const uint8_t *plain_der, size_t plain_der_len,
143
+ const char *passphrase, size_t passphrase_len,
144
+ int iterations);
145
+ int pq_pkcs8_decrypt_private_key_info_der(uint8_t **output, size_t *output_len,
146
+ const uint8_t *encrypted_der,
147
+ size_t encrypted_der_len, const char *passphrase,
148
+ size_t passphrase_len);
149
+ int pq_pkcs8_der_is_encrypted_private_key_info(const uint8_t *input, size_t input_len);
150
+ int pq_pkcs8_der_to_pem(char **output, size_t *output_len, const uint8_t *der, size_t der_len,
151
+ int encrypted);
152
+ int pq_pkcs8_pem_to_der(uint8_t **der_out, size_t *der_len_out, int *encrypted_out,
153
+ const char *input, size_t input_len);
154
+
135
155
  int pq_testing_mlkem_keypair_from_seed(uint8_t *public_key, uint8_t *secret_key,
136
156
  const uint8_t *seed, size_t seed_len);
137
157
  int pq_testing_mlkem512_keypair_from_seed(uint8_t *public_key, uint8_t *secret_key,
@@ -2,6 +2,6 @@
2
2
  #ifndef PQCRYPTO_VERSION_H
3
3
  #define PQCRYPTO_VERSION_H
4
4
 
5
- #define PQCRYPTO_VERSION "0.6.0"
5
+ #define PQCRYPTO_VERSION "0.6.2"
6
6
 
7
7
  #endif
@@ -6,7 +6,7 @@ mlkem_native_ref=v1.1.0
6
6
  mlkem_native_commit=d2cae2be522a67bfae26100fdb520576f1b2ef90
7
7
  mlkem_native_tree_sha256=c225de87a69e6d6360cddc4b5839b03e65fa9d5a1112a5f19700c905b7e74512
8
8
  mldsa_native_repo=https://github.com/pq-code-package/mldsa-native.git
9
- mldsa_native_ref=v1.0.0-beta
10
- mldsa_native_commit=db65535319d9750d75d34c6d170677415f9d2c46
11
- mldsa_native_tree_sha256=3b2cb648dade4540191f08d606b422042bf781fb37b434934ab02b58a0121f5c
12
- manifest_sha256=aeb28860537e30f4da0d28dc2961ba6bb06e700195a56f1648e5caddf1b6e1be
9
+ mldsa_native_ref=v1.0.0-beta2
10
+ mldsa_native_commit=9b0ee84f4cf399043eca59eca4e5f8531ca1d61b
11
+ mldsa_native_tree_sha256=2887f59926c18a877e8c5a5e30727e84497c357032093d00d7135aedf53f011e
12
+ manifest_sha256=cfcf998232945760d5fd66cc3ec0af54925e13844e1758f559eeb1c7ecf16ffc
@@ -59,19 +59,14 @@ mldsa-native is used in
59
59
 
60
60
  We use the [C Bounded Model Checker (CBMC)](https://github.com/diffblue/cbmc) to prove absence of various classes of undefined behaviour in C, including out of bounds memory accesses and integer overflows. The proofs cover all C code in [mldsa/src/*](mldsa) and [mldsa/src/fips202/*](mldsa/src/fips202) involved in running mldsa-native with its C backend. See [proofs/cbmc](proofs/cbmc) for details.
61
61
 
62
- **Note:** The `MLD_CONFIG_REDUCE_RAM` configuration option is not currently covered by CBMC proofs.
63
-
64
- HOL-Light functional correctness proofs can be found in [proofs/hol_light](proofs/hol_light). So far, the following functions have been proven correct:
65
-
66
- - AArch64 poly_caddq [poly_caddq_asm.S](mldsa/src/native/aarch64/src/poly_caddq_asm.S)
67
- - x86_64 NTT [ntt.S](mldsa/src/native/x86_64/src/ntt.S)
68
-
69
- These proofs utilize the verification infrastructure in [s2n-bignum](https://github.com/awslabs/s2n-bignum).
62
+ HOL-Light functional correctness proofs can be found in [proofs/hol_light](proofs/hol_light). See the [HOL-Light README](proofs/hol_light/README.md) for the list of functions that have been proven correct. These proofs utilize the verification infrastructure in [s2n-bignum](https://github.com/awslabs/s2n-bignum).
70
63
 
71
64
  Finally, [proofs/isabelle](proofs/isabelle/compress) contains proofs in [Isabelle/HOL](https://isabelle.in.tum.de/) of the correctness of
72
65
  different approaches for computing the scalar decomposition routines used in ML-DSA. Those are still experimental and do not yet operate
73
66
  on the source level.
74
67
 
68
+ **NOTE:** Formal Verification is never absolute. See [SOUNDNESS.md](SOUNDNESS.md) for an analysis of the scope, assumptions and risks of the formal verification efforts around mldsa-native.
69
+
75
70
  ## Security
76
71
 
77
72
  All assembly in mldsa-native is constant-time in the sense that it is free of secret-dependent control flow, memory access,
@@ -81,6 +76,8 @@ timing side channels through suitable barriers and constant-time patterns.
81
76
  Absence of secret-dependent branches, memory-access patterns and variable-latency instructions is also tested using `valgrind`
82
77
  with various combinations of compilers and compilation options.
83
78
 
79
+ **Other attacks.** mldsa-native targets resistance against timing side-channels only. Other attack classes, such as power and electromagnetic side-channels, microarchitectural side-channels (e.g. speculative execution), or fault-injection attacks, are currently out of scope.
80
+
84
81
  ## Design
85
82
 
86
83
  mldsa-native is split into a _frontend_ and two _backends_ for arithmetic and FIPS202 / SHA3. The frontend is
@@ -98,9 +95,12 @@ mldsa-native currently offers the following backends:
98
95
 
99
96
  If you'd like contribute new backends, please reach out!
100
97
 
101
- ## ACVP Testing
98
+ ## Test Vectors
99
+
100
+ mldsa-native is tested against all official ACVP ML-DSA test vectors[^ACVP] and the
101
+ Wycheproof[^wycheproof] ML-DSA test vectors.
102
102
 
103
- mldsa-native is tested against all official ACVP ML-DSA test vectors[^ACVP].
103
+ ### ACVP
104
104
 
105
105
  You can run ACVP tests using the [`tests`](./scripts/tests) script or the [ACVP client](./test/acvp/acvp_client.py) directly:
106
106
 
@@ -122,6 +122,18 @@ python3 ./test/acvp/acvp_client.py \
122
122
  -e ./test/acvp/.acvp-data/v1.1.0.41/files/ML-DSA-sigVer-FIPS204/expectedResults.json
123
123
  ```
124
124
 
125
+ ### Wycheproof
126
+
127
+ You can run Wycheproof[^wycheproof] tests using the [`tests`](./scripts/tests) script or the [Wycheproof client](./test/wycheproof/wycheproof_client.py) directly:
128
+
129
+ ```bash
130
+ # Using the tests script
131
+ ./scripts/tests wycheproof
132
+
133
+ # Using the Wycheproof client directly
134
+ python3 ./test/wycheproof/wycheproof_client.py
135
+ ```
136
+
125
137
  ## Benchmarking
126
138
 
127
139
  You can measure performance, memory usage, and binary size using the [`tests`](./scripts/tests) script:
@@ -219,3 +231,4 @@ through the [PQCA Discord](https://discord.com/invite/xyVnwzfg5R). See also [CON
219
231
  [^NIST_FIPS204_SEC6]: National Institute of Standards and Technology: FIPS 204 Section 6 Guidance, [https://csrc.nist.gov/csrc/media/Projects/post-quantum-cryptography/documents/faq/fips204-sec6-03192025.pdf](https://csrc.nist.gov/csrc/media/Projects/post-quantum-cryptography/documents/faq/fips204-sec6-03192025.pdf)
220
232
  [^REF]: Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé: CRYSTALS-Dilithium reference implementation, [https://github.com/pq-crystals/dilithium/tree/master/ref](https://github.com/pq-crystals/dilithium/tree/master/ref)
221
233
  [^tiny_sha3]: Markku-Juhani O. Saarinen: tiny_sha3, [https://github.com/mjosaarinen/tiny_sha3](https://github.com/mjosaarinen/tiny_sha3)
234
+ [^wycheproof]: Community Cryptography Specification Project: Project Wycheproof, [https://github.com/C2SP/wycheproof](https://github.com/C2SP/wycheproof)
@@ -0,0 +1,23 @@
1
+ [//]: # (SPDX-License-Identifier: CC-BY-4.0)
2
+
3
+ # mldsa-native source tree
4
+
5
+ This is the main source tree of mldsa-native.
6
+
7
+ ## Building
8
+
9
+ To build mldsa-native for a fixed parameter set (ML-DSA-44/65/87), build the compilation units in `src/*` separately, and link to an RNG and your application. See [examples/basic](../examples/basic) for a simple example.
10
+
11
+ Alternatively, you can use the auto-generated helper files [mldsa_native.c](mldsa_native.c) and [mldsa_native_asm.S](mldsa_native_asm.S), which bundle all *.c and *.S files together. See [examples/monolithic_build](../examples/monolithic_build) and [examples/monolithic_build_native](../examples/monolithic_build_native) for examples with and without native code.
12
+
13
+ ## Configuration
14
+
15
+ The build is configured by [mldsa_native_config.h](mldsa_native_config.h), or by the file pointed to by `MLD_CONFIG_FILE`. Note in particular `MLD_CONFIG_PARAMETER_SET` and `MLD_CONFIG_NAMESPACE_PREFIX`, which set the parameter set and namespace prefix, respectively.
16
+
17
+ ## API
18
+
19
+ The public API is defined in [mldsa_native.h](mldsa_native.h).
20
+
21
+ ## Supporting multiple parameter sets
22
+
23
+ If you want to support multiple parameter sets, build the library once per parameter set you want to support. Set `MLD_CONFIG_MULTILEVEL_WITH_SHARED` for one of the builds, and `MLD_CONFIG_MULTILEVEL_NO_SHARED` for the others, to avoid duplicating shared functionality. Finally, link with RNG and your application as before. This is demonstrated in the examples [examples/multilevel_build](../examples/multilevel_build), [examples/multilevel_build_native](../examples/multilevel_build_native), [examples/monolithic_build_multilevel](../examples/monolithic_build_multilevel) and [examples/monolithic_build_multilevel_native](../examples/monolithic_build_multilevel_native).