pq_crypto 0.3.2 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (328) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +56 -0
  3. data/CHANGELOG.md +62 -0
  4. data/GET_STARTED.md +366 -40
  5. data/README.md +76 -233
  6. data/SECURITY.md +107 -82
  7. data/ext/pqcrypto/extconf.rb +169 -87
  8. data/ext/pqcrypto/mldsa_api.h +1 -48
  9. data/ext/pqcrypto/mlkem_api.h +1 -18
  10. data/ext/pqcrypto/pq_externalmu.c +89 -204
  11. data/ext/pqcrypto/pqcrypto_native_api.h +129 -0
  12. data/ext/pqcrypto/pqcrypto_ruby_secure.c +484 -84
  13. data/ext/pqcrypto/pqcrypto_secure.c +203 -78
  14. data/ext/pqcrypto/pqcrypto_secure.h +53 -14
  15. data/ext/pqcrypto/pqcrypto_version.h +7 -0
  16. data/ext/pqcrypto/randombytes.h +9 -0
  17. data/ext/pqcrypto/vendor/.vendored +10 -5
  18. data/ext/pqcrypto/vendor/mldsa-native/BUILDING.md +105 -0
  19. data/ext/pqcrypto/vendor/mldsa-native/LICENSE +286 -0
  20. data/ext/pqcrypto/vendor/mldsa-native/META.yml +24 -0
  21. data/ext/pqcrypto/vendor/mldsa-native/README.md +221 -0
  22. data/ext/pqcrypto/vendor/mldsa-native/SECURITY.md +8 -0
  23. data/ext/pqcrypto/vendor/mldsa-native/mldsa/mldsa_native.c +721 -0
  24. data/ext/pqcrypto/vendor/mldsa-native/mldsa/mldsa_native.h +975 -0
  25. data/ext/pqcrypto/vendor/mldsa-native/mldsa/mldsa_native_asm.S +724 -0
  26. data/ext/pqcrypto/vendor/mldsa-native/mldsa/mldsa_native_config.h +723 -0
  27. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/cbmc.h +166 -0
  28. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/common.h +321 -0
  29. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/ct.c +21 -0
  30. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/ct.h +385 -0
  31. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/debug.c +73 -0
  32. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/debug.h +130 -0
  33. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/fips202.c +277 -0
  34. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/fips202.h +244 -0
  35. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/fips202x4.c +182 -0
  36. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/fips202x4.h +117 -0
  37. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/keccakf1600.c +438 -0
  38. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/keccakf1600.h +105 -0
  39. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/aarch64/auto.h +71 -0
  40. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/aarch64/src/fips202_native_aarch64.h +62 -0
  41. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/aarch64/src/keccak_f1600_x1_scalar_asm.S +376 -0
  42. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/aarch64/src/keccak_f1600_x1_v84a_asm.S +204 -0
  43. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/aarch64/src/keccak_f1600_x2_v84a_asm.S +259 -0
  44. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/aarch64/src/keccak_f1600_x4_v8a_scalar_hybrid_asm.S +1077 -0
  45. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/aarch64/src/keccak_f1600_x4_v8a_v84a_scalar_hybrid_asm.S +987 -0
  46. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/aarch64/src/keccakf1600_round_constants.c +41 -0
  47. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/aarch64/x1_scalar.h +26 -0
  48. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/aarch64/x1_v84a.h +35 -0
  49. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/aarch64/x2_v84a.h +37 -0
  50. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/aarch64/x4_v8a_scalar.h +27 -0
  51. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/aarch64/x4_v8a_v84a_scalar.h +36 -0
  52. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/api.h +69 -0
  53. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/armv81m/README.md +10 -0
  54. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/armv81m/mve.h +32 -0
  55. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/armv81m/src/fips202_native_armv81m.h +20 -0
  56. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/armv81m/src/keccak_f1600_x4_mve.S +638 -0
  57. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/armv81m/src/keccak_f1600_x4_mve.c +136 -0
  58. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/armv81m/src/keccakf1600_round_constants.c +52 -0
  59. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/auto.h +29 -0
  60. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/x86_64/src/KeccakP_1600_times4_SIMD256.c +488 -0
  61. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/x86_64/src/KeccakP_1600_times4_SIMD256.h +16 -0
  62. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/x86_64/xkcp.h +31 -0
  63. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/meta.h +247 -0
  64. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/aarch64_zetas.c +231 -0
  65. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/arith_native_aarch64.h +150 -0
  66. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/intt.S +753 -0
  67. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/mld_polyvecl_pointwise_acc_montgomery_l4.S +129 -0
  68. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/mld_polyvecl_pointwise_acc_montgomery_l5.S +145 -0
  69. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/mld_polyvecl_pointwise_acc_montgomery_l7.S +177 -0
  70. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/ntt.S +653 -0
  71. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/pointwise_montgomery.S +79 -0
  72. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/poly_caddq_asm.S +53 -0
  73. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/poly_chknorm_asm.S +55 -0
  74. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/poly_decompose_32_asm.S +85 -0
  75. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/poly_decompose_88_asm.S +85 -0
  76. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/poly_use_hint_32_asm.S +102 -0
  77. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/poly_use_hint_88_asm.S +110 -0
  78. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/polyz_unpack_17_asm.S +72 -0
  79. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/polyz_unpack_19_asm.S +69 -0
  80. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/polyz_unpack_table.c +40 -0
  81. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/rej_uniform_asm.S +189 -0
  82. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/rej_uniform_eta2_asm.S +135 -0
  83. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/rej_uniform_eta4_asm.S +128 -0
  84. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/rej_uniform_eta_table.c +543 -0
  85. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/rej_uniform_table.c +62 -0
  86. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/api.h +649 -0
  87. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/meta.h +23 -0
  88. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/x86_64/meta.h +315 -0
  89. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/x86_64/src/arith_native_x86_64.h +124 -0
  90. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/x86_64/src/consts.c +157 -0
  91. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/x86_64/src/consts.h +27 -0
  92. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/x86_64/src/intt.S +2311 -0
  93. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/x86_64/src/ntt.S +2383 -0
  94. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/x86_64/src/nttunpack.S +239 -0
  95. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/x86_64/src/pointwise.S +131 -0
  96. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/x86_64/src/pointwise_acc_l4.S +139 -0
  97. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/x86_64/src/pointwise_acc_l5.S +155 -0
  98. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/x86_64/src/pointwise_acc_l7.S +187 -0
  99. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/x86_64/src/poly_caddq_avx2.c +61 -0
  100. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/x86_64/src/poly_chknorm_avx2.c +52 -0
  101. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/x86_64/src/poly_decompose_32_avx2.c +155 -0
  102. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/x86_64/src/poly_decompose_88_avx2.c +155 -0
  103. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/x86_64/src/poly_use_hint_32_avx2.c +102 -0
  104. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/x86_64/src/poly_use_hint_88_avx2.c +104 -0
  105. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/x86_64/src/polyz_unpack_17_avx2.c +91 -0
  106. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/x86_64/src/polyz_unpack_19_avx2.c +93 -0
  107. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/x86_64/src/rej_uniform_avx2.c +126 -0
  108. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/x86_64/src/rej_uniform_eta2_avx2.c +155 -0
  109. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/x86_64/src/rej_uniform_eta4_avx2.c +139 -0
  110. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/x86_64/src/rej_uniform_table.c +160 -0
  111. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/packing.c +293 -0
  112. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/packing.h +224 -0
  113. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/params.h +77 -0
  114. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/poly.c +991 -0
  115. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/poly.h +393 -0
  116. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/poly_kl.c +946 -0
  117. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/poly_kl.h +360 -0
  118. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/polyvec.c +877 -0
  119. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/polyvec.h +725 -0
  120. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/randombytes.h +26 -0
  121. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/reduce.h +139 -0
  122. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/rounding.h +249 -0
  123. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/sign.c +1511 -0
  124. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/sign.h +806 -0
  125. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/symmetric.h +68 -0
  126. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/sys.h +268 -0
  127. data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/zetas.inc +55 -0
  128. data/ext/pqcrypto/vendor/mlkem-native/BUILDING.md +104 -0
  129. data/ext/pqcrypto/vendor/mlkem-native/LICENSE +294 -0
  130. data/ext/pqcrypto/vendor/mlkem-native/META.yml +30 -0
  131. data/ext/pqcrypto/vendor/mlkem-native/README.md +223 -0
  132. data/ext/pqcrypto/vendor/mlkem-native/RELEASE.md +86 -0
  133. data/ext/pqcrypto/vendor/mlkem-native/SECURITY.md +8 -0
  134. data/ext/pqcrypto/vendor/mlkem-native/mlkem/README.md +23 -0
  135. data/ext/pqcrypto/vendor/mlkem-native/mlkem/mlkem_native.c +660 -0
  136. data/ext/pqcrypto/vendor/mlkem-native/mlkem/mlkem_native.h +538 -0
  137. data/ext/pqcrypto/vendor/mlkem-native/mlkem/mlkem_native_asm.S +681 -0
  138. data/ext/pqcrypto/vendor/mlkem-native/mlkem/mlkem_native_config.h +709 -0
  139. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/cbmc.h +174 -0
  140. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/common.h +274 -0
  141. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/compress.c +717 -0
  142. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/compress.h +688 -0
  143. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/debug.c +64 -0
  144. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/debug.h +128 -0
  145. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/fips202/fips202.c +251 -0
  146. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/fips202/fips202.h +158 -0
  147. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/fips202/fips202x4.c +208 -0
  148. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/fips202/fips202x4.h +80 -0
  149. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/fips202/keccakf1600.c +463 -0
  150. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/fips202/keccakf1600.h +98 -0
  151. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/fips202/native/aarch64/auto.h +70 -0
  152. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/fips202/native/aarch64/src/fips202_native_aarch64.h +69 -0
  153. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/fips202/native/aarch64/src/keccak_f1600_x1_scalar_asm.S +375 -0
  154. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/fips202/native/aarch64/src/keccak_f1600_x1_v84a_asm.S +203 -0
  155. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/fips202/native/aarch64/src/keccak_f1600_x2_v84a_asm.S +258 -0
  156. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/fips202/native/aarch64/src/keccak_f1600_x4_v8a_scalar_hybrid_asm.S +1076 -0
  157. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/fips202/native/aarch64/src/keccak_f1600_x4_v8a_v84a_scalar_hybrid_asm.S +986 -0
  158. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/fips202/native/aarch64/src/keccakf1600_round_constants.c +46 -0
  159. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/fips202/native/aarch64/x1_scalar.h +25 -0
  160. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/fips202/native/aarch64/x1_v84a.h +34 -0
  161. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/fips202/native/aarch64/x2_v84a.h +35 -0
  162. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/fips202/native/aarch64/x4_v8a_scalar.h +26 -0
  163. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/fips202/native/aarch64/x4_v8a_v84a_scalar.h +35 -0
  164. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/fips202/native/api.h +117 -0
  165. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/fips202/native/armv81m/README.md +10 -0
  166. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/fips202/native/armv81m/mve.h +79 -0
  167. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/fips202/native/armv81m/src/fips202_native_armv81m.h +35 -0
  168. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/fips202/native/armv81m/src/keccak_f1600_x4_mve.S +667 -0
  169. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/fips202/native/armv81m/src/keccak_f1600_x4_mve.c +40 -0
  170. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/fips202/native/armv81m/src/keccakf1600_round_constants.c +51 -0
  171. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/fips202/native/armv81m/src/state_extract_bytes_x4_mve.S +290 -0
  172. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/fips202/native/armv81m/src/state_xor_bytes_x4_mve.S +314 -0
  173. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/fips202/native/auto.h +28 -0
  174. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/fips202/native/x86_64/keccak_f1600_x4_avx2.h +33 -0
  175. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/fips202/native/x86_64/src/fips202_native_x86_64.h +41 -0
  176. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/fips202/native/x86_64/src/keccak_f1600_x4_avx2.S +451 -0
  177. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/fips202/native/x86_64/src/keccakf1600_constants.c +51 -0
  178. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/indcpa.c +622 -0
  179. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/indcpa.h +156 -0
  180. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/kem.c +446 -0
  181. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/kem.h +326 -0
  182. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/aarch64/README.md +16 -0
  183. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/aarch64/meta.h +122 -0
  184. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/aarch64/src/aarch64_zetas.c +174 -0
  185. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/aarch64/src/arith_native_aarch64.h +177 -0
  186. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/aarch64/src/intt.S +628 -0
  187. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/aarch64/src/ntt.S +562 -0
  188. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/aarch64/src/poly_mulcache_compute_asm.S +127 -0
  189. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/aarch64/src/poly_reduce_asm.S +150 -0
  190. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/aarch64/src/poly_tobytes_asm.S +117 -0
  191. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/aarch64/src/poly_tomont_asm.S +98 -0
  192. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/aarch64/src/polyvec_basemul_acc_montgomery_cached_asm_k2.S +261 -0
  193. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/aarch64/src/polyvec_basemul_acc_montgomery_cached_asm_k3.S +314 -0
  194. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/aarch64/src/polyvec_basemul_acc_montgomery_cached_asm_k4.S +368 -0
  195. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/aarch64/src/rej_uniform_asm.S +226 -0
  196. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/aarch64/src/rej_uniform_table.c +542 -0
  197. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/api.h +637 -0
  198. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/meta.h +25 -0
  199. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/riscv64/README.md +11 -0
  200. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/riscv64/meta.h +128 -0
  201. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/riscv64/src/arith_native_riscv64.h +45 -0
  202. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/riscv64/src/rv64v_debug.c +81 -0
  203. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/riscv64/src/rv64v_debug.h +145 -0
  204. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/riscv64/src/rv64v_izetas.inc +27 -0
  205. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/riscv64/src/rv64v_poly.c +805 -0
  206. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/riscv64/src/rv64v_zetas.inc +27 -0
  207. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/riscv64/src/rv64v_zetas_basemul.inc +39 -0
  208. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/x86_64/README.md +4 -0
  209. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/x86_64/meta.h +304 -0
  210. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/x86_64/src/arith_native_x86_64.h +309 -0
  211. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/x86_64/src/compress_consts.c +94 -0
  212. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/x86_64/src/compress_consts.h +45 -0
  213. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/x86_64/src/consts.c +102 -0
  214. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/x86_64/src/consts.h +25 -0
  215. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/x86_64/src/intt.S +719 -0
  216. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/x86_64/src/mulcache_compute.S +90 -0
  217. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/x86_64/src/ntt.S +639 -0
  218. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/x86_64/src/nttfrombytes.S +193 -0
  219. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/x86_64/src/ntttobytes.S +181 -0
  220. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/x86_64/src/nttunpack.S +174 -0
  221. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/x86_64/src/poly_compress_d10.S +382 -0
  222. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/x86_64/src/poly_compress_d11.S +448 -0
  223. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/x86_64/src/poly_compress_d4.S +163 -0
  224. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/x86_64/src/poly_compress_d5.S +220 -0
  225. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/x86_64/src/poly_decompress_d10.S +228 -0
  226. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/x86_64/src/poly_decompress_d11.S +277 -0
  227. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/x86_64/src/poly_decompress_d4.S +180 -0
  228. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/x86_64/src/poly_decompress_d5.S +192 -0
  229. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/x86_64/src/polyvec_basemul_acc_montgomery_cached_asm_k2.S +502 -0
  230. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/x86_64/src/polyvec_basemul_acc_montgomery_cached_asm_k3.S +750 -0
  231. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/x86_64/src/polyvec_basemul_acc_montgomery_cached_asm_k4.S +998 -0
  232. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/x86_64/src/reduce.S +218 -0
  233. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/x86_64/src/rej_uniform_asm.S +103 -0
  234. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/x86_64/src/rej_uniform_table.c +544 -0
  235. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/x86_64/src/tomont.S +155 -0
  236. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/params.h +76 -0
  237. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/poly.c +572 -0
  238. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/poly.h +317 -0
  239. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/poly_k.c +502 -0
  240. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/poly_k.h +668 -0
  241. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/randombytes.h +60 -0
  242. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/sampling.c +362 -0
  243. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/sampling.h +118 -0
  244. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/symmetric.h +70 -0
  245. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/sys.h +260 -0
  246. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/verify.c +20 -0
  247. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/verify.h +464 -0
  248. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/zetas.inc +30 -0
  249. data/lib/pq_crypto/algorithm_registry.rb +200 -0
  250. data/lib/pq_crypto/hybrid_kem.rb +1 -12
  251. data/lib/pq_crypto/kem.rb +104 -13
  252. data/lib/pq_crypto/pkcs8.rb +387 -0
  253. data/lib/pq_crypto/serialization.rb +1 -14
  254. data/lib/pq_crypto/signature.rb +123 -17
  255. data/lib/pq_crypto/spki.rb +131 -0
  256. data/lib/pq_crypto/version.rb +1 -1
  257. data/lib/pq_crypto.rb +79 -20
  258. data/script/vendor_libs.rb +88 -155
  259. metadata +241 -73
  260. data/ext/pqcrypto/vendor/pqclean/common/aes.c +0 -639
  261. data/ext/pqcrypto/vendor/pqclean/common/aes.h +0 -64
  262. data/ext/pqcrypto/vendor/pqclean/common/compat.h +0 -73
  263. data/ext/pqcrypto/vendor/pqclean/common/crypto_declassify.h +0 -7
  264. data/ext/pqcrypto/vendor/pqclean/common/fips202.c +0 -928
  265. data/ext/pqcrypto/vendor/pqclean/common/fips202.h +0 -166
  266. data/ext/pqcrypto/vendor/pqclean/common/keccak2x/feat.S +0 -168
  267. data/ext/pqcrypto/vendor/pqclean/common/keccak2x/fips202x2.c +0 -684
  268. data/ext/pqcrypto/vendor/pqclean/common/keccak2x/fips202x2.h +0 -60
  269. data/ext/pqcrypto/vendor/pqclean/common/keccak4x/KeccakP-1600-times4-SIMD256.c +0 -1028
  270. data/ext/pqcrypto/vendor/pqclean/common/keccak4x/KeccakP-1600-times4-SnP.h +0 -50
  271. data/ext/pqcrypto/vendor/pqclean/common/keccak4x/KeccakP-1600-unrolling.macros +0 -198
  272. data/ext/pqcrypto/vendor/pqclean/common/keccak4x/Makefile +0 -8
  273. data/ext/pqcrypto/vendor/pqclean/common/keccak4x/Makefile.Microsoft_nmake +0 -8
  274. data/ext/pqcrypto/vendor/pqclean/common/keccak4x/SIMD256-config.h +0 -3
  275. data/ext/pqcrypto/vendor/pqclean/common/keccak4x/align.h +0 -34
  276. data/ext/pqcrypto/vendor/pqclean/common/keccak4x/brg_endian.h +0 -142
  277. data/ext/pqcrypto/vendor/pqclean/common/nistseedexpander.c +0 -101
  278. data/ext/pqcrypto/vendor/pqclean/common/nistseedexpander.h +0 -39
  279. data/ext/pqcrypto/vendor/pqclean/common/randombytes.c +0 -355
  280. data/ext/pqcrypto/vendor/pqclean/common/randombytes.h +0 -27
  281. data/ext/pqcrypto/vendor/pqclean/common/sha2.c +0 -769
  282. data/ext/pqcrypto/vendor/pqclean/common/sha2.h +0 -173
  283. data/ext/pqcrypto/vendor/pqclean/common/sp800-185.c +0 -156
  284. data/ext/pqcrypto/vendor/pqclean/common/sp800-185.h +0 -27
  285. data/ext/pqcrypto/vendor/pqclean/crypto_kem/ml-kem-768/clean/LICENSE +0 -5
  286. data/ext/pqcrypto/vendor/pqclean/crypto_kem/ml-kem-768/clean/Makefile +0 -19
  287. data/ext/pqcrypto/vendor/pqclean/crypto_kem/ml-kem-768/clean/Makefile.Microsoft_nmake +0 -23
  288. data/ext/pqcrypto/vendor/pqclean/crypto_kem/ml-kem-768/clean/api.h +0 -18
  289. data/ext/pqcrypto/vendor/pqclean/crypto_kem/ml-kem-768/clean/cbd.c +0 -83
  290. data/ext/pqcrypto/vendor/pqclean/crypto_kem/ml-kem-768/clean/cbd.h +0 -11
  291. data/ext/pqcrypto/vendor/pqclean/crypto_kem/ml-kem-768/clean/indcpa.c +0 -327
  292. data/ext/pqcrypto/vendor/pqclean/crypto_kem/ml-kem-768/clean/indcpa.h +0 -22
  293. data/ext/pqcrypto/vendor/pqclean/crypto_kem/ml-kem-768/clean/kem.c +0 -164
  294. data/ext/pqcrypto/vendor/pqclean/crypto_kem/ml-kem-768/clean/kem.h +0 -23
  295. data/ext/pqcrypto/vendor/pqclean/crypto_kem/ml-kem-768/clean/ntt.c +0 -146
  296. data/ext/pqcrypto/vendor/pqclean/crypto_kem/ml-kem-768/clean/ntt.h +0 -14
  297. data/ext/pqcrypto/vendor/pqclean/crypto_kem/ml-kem-768/clean/params.h +0 -36
  298. data/ext/pqcrypto/vendor/pqclean/crypto_kem/ml-kem-768/clean/poly.c +0 -299
  299. data/ext/pqcrypto/vendor/pqclean/crypto_kem/ml-kem-768/clean/poly.h +0 -37
  300. data/ext/pqcrypto/vendor/pqclean/crypto_kem/ml-kem-768/clean/polyvec.c +0 -188
  301. data/ext/pqcrypto/vendor/pqclean/crypto_kem/ml-kem-768/clean/polyvec.h +0 -26
  302. data/ext/pqcrypto/vendor/pqclean/crypto_kem/ml-kem-768/clean/reduce.c +0 -41
  303. data/ext/pqcrypto/vendor/pqclean/crypto_kem/ml-kem-768/clean/reduce.h +0 -13
  304. data/ext/pqcrypto/vendor/pqclean/crypto_kem/ml-kem-768/clean/symmetric-shake.c +0 -71
  305. data/ext/pqcrypto/vendor/pqclean/crypto_kem/ml-kem-768/clean/symmetric.h +0 -30
  306. data/ext/pqcrypto/vendor/pqclean/crypto_kem/ml-kem-768/clean/verify.c +0 -67
  307. data/ext/pqcrypto/vendor/pqclean/crypto_kem/ml-kem-768/clean/verify.h +0 -13
  308. data/ext/pqcrypto/vendor/pqclean/crypto_sign/ml-dsa-65/clean/LICENSE +0 -5
  309. data/ext/pqcrypto/vendor/pqclean/crypto_sign/ml-dsa-65/clean/Makefile +0 -19
  310. data/ext/pqcrypto/vendor/pqclean/crypto_sign/ml-dsa-65/clean/Makefile.Microsoft_nmake +0 -23
  311. data/ext/pqcrypto/vendor/pqclean/crypto_sign/ml-dsa-65/clean/api.h +0 -50
  312. data/ext/pqcrypto/vendor/pqclean/crypto_sign/ml-dsa-65/clean/ntt.c +0 -98
  313. data/ext/pqcrypto/vendor/pqclean/crypto_sign/ml-dsa-65/clean/ntt.h +0 -10
  314. data/ext/pqcrypto/vendor/pqclean/crypto_sign/ml-dsa-65/clean/packing.c +0 -261
  315. data/ext/pqcrypto/vendor/pqclean/crypto_sign/ml-dsa-65/clean/packing.h +0 -31
  316. data/ext/pqcrypto/vendor/pqclean/crypto_sign/ml-dsa-65/clean/params.h +0 -44
  317. data/ext/pqcrypto/vendor/pqclean/crypto_sign/ml-dsa-65/clean/poly.c +0 -799
  318. data/ext/pqcrypto/vendor/pqclean/crypto_sign/ml-dsa-65/clean/poly.h +0 -52
  319. data/ext/pqcrypto/vendor/pqclean/crypto_sign/ml-dsa-65/clean/polyvec.c +0 -415
  320. data/ext/pqcrypto/vendor/pqclean/crypto_sign/ml-dsa-65/clean/polyvec.h +0 -65
  321. data/ext/pqcrypto/vendor/pqclean/crypto_sign/ml-dsa-65/clean/reduce.c +0 -69
  322. data/ext/pqcrypto/vendor/pqclean/crypto_sign/ml-dsa-65/clean/reduce.h +0 -17
  323. data/ext/pqcrypto/vendor/pqclean/crypto_sign/ml-dsa-65/clean/rounding.c +0 -92
  324. data/ext/pqcrypto/vendor/pqclean/crypto_sign/ml-dsa-65/clean/rounding.h +0 -14
  325. data/ext/pqcrypto/vendor/pqclean/crypto_sign/ml-dsa-65/clean/sign.c +0 -407
  326. data/ext/pqcrypto/vendor/pqclean/crypto_sign/ml-dsa-65/clean/sign.h +0 -47
  327. data/ext/pqcrypto/vendor/pqclean/crypto_sign/ml-dsa-65/clean/symmetric-shake.c +0 -26
  328. data/ext/pqcrypto/vendor/pqclean/crypto_sign/ml-dsa-65/clean/symmetric.h +0 -34
@@ -6,22 +6,33 @@ module PQCrypto
6
6
  module Signature
7
7
  CANONICAL_ALGORITHM = :ml_dsa_65
8
8
 
9
- DETAILS = {
10
- CANONICAL_ALGORITHM => {
11
- name: CANONICAL_ALGORITHM,
12
- family: Serialization.algorithm_to_family(CANONICAL_ALGORITHM),
13
- oid: Serialization.algorithm_to_oid(CANONICAL_ALGORITHM),
14
- public_key_bytes: SIGN_PUBLIC_KEY_BYTES,
15
- secret_key_bytes: SIGN_SECRET_KEY_BYTES,
16
- signature_bytes: SIGN_BYTES,
17
- description: "ML-DSA-65 signature primitive (FIPS 204).",
9
+ DETAILS = AlgorithmRegistry.details_for_family(:ml_dsa).freeze
10
+
11
+ NATIVE_DISPATCH = {
12
+ ml_dsa_44: {
13
+ keypair: :native_ml_dsa_44_keypair,
14
+ sign: :native_ml_dsa_44_sign,
15
+ verify: :native_ml_dsa_44_verify,
16
+ keypair_from_seed: :native_ml_dsa_44_keypair_from_seed,
17
+ }.freeze,
18
+ ml_dsa_65: {
19
+ keypair: :native_sign_keypair,
20
+ sign: :native_sign,
21
+ verify: :native_verify,
22
+ keypair_from_seed: :native_ml_dsa_keypair_from_seed,
23
+ }.freeze,
24
+ ml_dsa_87: {
25
+ keypair: :native_ml_dsa_87_keypair,
26
+ sign: :native_ml_dsa_87_sign,
27
+ verify: :native_ml_dsa_87_verify,
28
+ keypair_from_seed: :native_ml_dsa_87_keypair_from_seed,
18
29
  }.freeze,
19
30
  }.freeze
20
31
 
21
32
  class << self
22
33
  def generate(algorithm = CANONICAL_ALGORITHM)
23
- resolve_algorithm!(algorithm)
24
- public_key, secret_key = PQCrypto.__send__(:native_sign_keypair)
34
+ algorithm = resolve_algorithm!(algorithm)
35
+ public_key, secret_key = PQCrypto.__send__(native_method_for(algorithm, :keypair))
25
36
  Keypair.new(PublicKey.new(algorithm, public_key), SecretKey.new(algorithm, secret_key))
26
37
  end
27
38
 
@@ -59,6 +70,26 @@ module PQCrypto
59
70
  SecretKey.new(resolved_algorithm, bytes)
60
71
  end
61
72
 
73
+ def public_key_from_spki_der(der, algorithm: nil)
74
+ resolved_algorithm, bytes = SPKI.decode_der(der)
75
+ validate_algorithm_match!(algorithm, resolved_algorithm) if algorithm
76
+ PublicKey.new(resolve_algorithm!(resolved_algorithm), bytes)
77
+ end
78
+
79
+ def public_key_from_spki_pem(pem, algorithm: nil)
80
+ resolved_algorithm, bytes = SPKI.decode_pem(pem)
81
+ validate_algorithm_match!(algorithm, resolved_algorithm) if algorithm
82
+ PublicKey.new(resolve_algorithm!(resolved_algorithm), bytes)
83
+ end
84
+
85
+ def secret_key_from_pkcs8_der(der)
86
+ secret_key_from_decoded_pkcs8(*PKCS8.decode_der(der))
87
+ end
88
+
89
+ def secret_key_from_pkcs8_pem(pem)
90
+ secret_key_from_decoded_pkcs8(*PKCS8.decode_pem(pem))
91
+ end
92
+
62
93
  def details(algorithm)
63
94
  DETAILS.fetch(resolve_algorithm!(algorithm)).dup
64
95
  end
@@ -75,9 +106,43 @@ module PQCrypto
75
106
  raise UnsupportedAlgorithmError, "Unsupported signature algorithm: #{algorithm.inspect}"
76
107
  end
77
108
 
109
+ def secret_key_from_decoded_pkcs8(algorithm, format, material)
110
+ algorithm = resolve_algorithm!(algorithm)
111
+
112
+ case format
113
+ when :expanded
114
+ SecretKey.new(algorithm, material)
115
+ when :seed
116
+ _public_key, expanded = PQCrypto.__send__(native_method_for(algorithm, :keypair_from_seed), material)
117
+ SecretKey.new(algorithm, expanded)
118
+ when :both
119
+ _seed, expanded = material
120
+ SecretKey.new(algorithm, expanded)
121
+ else
122
+ raise SerializationError, "Unsupported ML-DSA PKCS#8 private key format: #{format.inspect}"
123
+ end
124
+ rescue ArgumentError => e
125
+ raise InvalidKeyError, e.message
126
+ end
127
+
128
+ def native_method_for(algorithm, operation)
129
+ NATIVE_DISPATCH.fetch(resolve_algorithm!(algorithm)).fetch(operation)
130
+ end
131
+
132
+ def validate_algorithm_match!(expected_algorithm, actual_algorithm)
133
+ expected = resolve_algorithm!(expected_algorithm)
134
+ return if expected == actual_algorithm
135
+
136
+ raise SerializationError,
137
+ "Expected #{expected.inspect}, got #{actual_algorithm.inspect} (SPKI key algorithm mismatch)"
138
+ rescue UnsupportedAlgorithmError => e
139
+ raise SerializationError, e.message
140
+ end
141
+
78
142
  def _streaming_sign(secret_key, io, chunk_size, context)
143
+ validate_streaming_algorithm!(secret_key.algorithm)
79
144
  validate_chunk_size!(chunk_size)
80
- validate_context!(context)
145
+ context = validate_context!(context)
81
146
  validate_io!(io)
82
147
 
83
148
  sk_bytes = secret_key.__send__(:bytes_for_native)
@@ -87,7 +152,7 @@ module PQCrypto
87
152
  raise InvalidKeyError, e.message
88
153
  end
89
154
 
90
- builder = PQCrypto.__send__(:_native_mldsa_mu_builder_new, tr, context.b)
155
+ builder = PQCrypto.__send__(:_native_mldsa_mu_builder_new, tr, context)
91
156
  builder_consumed = false
92
157
  mu = nil
93
158
  begin
@@ -103,8 +168,9 @@ module PQCrypto
103
168
  end
104
169
 
105
170
  def _streaming_verify(public_key, io, signature, chunk_size, context)
171
+ validate_streaming_algorithm!(public_key.algorithm)
106
172
  validate_chunk_size!(chunk_size)
107
- validate_context!(context)
173
+ context = validate_context!(context)
108
174
  validate_io!(io)
109
175
 
110
176
  pk_bytes = public_key.__send__(:bytes_for_native)
@@ -114,7 +180,7 @@ module PQCrypto
114
180
  raise InvalidKeyError, e.message
115
181
  end
116
182
 
117
- builder = PQCrypto.__send__(:_native_mldsa_mu_builder_new, tr, context.b)
183
+ builder = PQCrypto.__send__(:_native_mldsa_mu_builder_new, tr, context)
118
184
  builder_consumed = false
119
185
  mu = nil
120
186
  sig_bytes = String(signature).b
@@ -162,6 +228,14 @@ module PQCrypto
162
228
  if ctx.bytesize > 255
163
229
  raise ArgumentError, "context must be at most 255 bytes (FIPS 204)"
164
230
  end
231
+ ctx
232
+ end
233
+
234
+ def validate_streaming_algorithm!(algorithm)
235
+ return if resolve_algorithm!(algorithm) == CANONICAL_ALGORITHM
236
+
237
+ raise UnsupportedAlgorithmError,
238
+ "Streaming sign_io/verify_io currently supports only #{CANONICAL_ALGORITHM.inspect}"
165
239
  end
166
240
  end
167
241
 
@@ -203,8 +277,16 @@ module PQCrypto
203
277
  Serialization.public_key_to_pqc_container_pem(@algorithm, @bytes)
204
278
  end
205
279
 
280
+ def to_spki_der
281
+ SPKI.encode_der(@algorithm, @bytes)
282
+ end
283
+
284
+ def to_spki_pem
285
+ SPKI.encode_pem(@algorithm, @bytes)
286
+ end
287
+
206
288
  def verify(message, signature)
207
- PQCrypto.__send__(:native_verify, String(message).b, String(signature).b, @bytes)
289
+ PQCrypto.__send__(Signature.send(:native_method_for, @algorithm, :verify), String(message).b, String(signature).b, @bytes)
208
290
  rescue ArgumentError => e
209
291
  raise InvalidKeyError, e.message
210
292
  end
@@ -273,8 +355,32 @@ module PQCrypto
273
355
  Serialization.secret_key_to_pqc_container_pem(@algorithm, @bytes)
274
356
  end
275
357
 
358
+ def to_pkcs8_der(format: :expanded)
359
+ case format
360
+ when :expanded
361
+ PKCS8.encode_der(@algorithm, @bytes, format: :expanded)
362
+ when :seed, :both
363
+ raise SerializationError,
364
+ "ML-DSA seed/both PKCS#8 export requires original seed material; use PQCrypto::PKCS8.encode_der/encode_pem directly"
365
+ else
366
+ raise SerializationError, "Unsupported PKCS#8 private key format: #{format.inspect}"
367
+ end
368
+ end
369
+
370
+ def to_pkcs8_pem(format: :expanded)
371
+ case format
372
+ when :expanded
373
+ PKCS8.encode_pem(@algorithm, @bytes, format: :expanded)
374
+ when :seed, :both
375
+ raise SerializationError,
376
+ "ML-DSA seed/both PKCS#8 export requires original seed material; use PQCrypto::PKCS8.encode_der/encode_pem directly"
377
+ else
378
+ raise SerializationError, "Unsupported PKCS#8 private key format: #{format.inspect}"
379
+ end
380
+ end
381
+
276
382
  def sign(message)
277
- PQCrypto.__send__(:native_sign, String(message).b, @bytes)
383
+ PQCrypto.__send__(Signature.send(:native_method_for, @algorithm, :sign), String(message).b, @bytes)
278
384
  rescue ArgumentError => e
279
385
  raise InvalidKeyError, e.message
280
386
  end
@@ -0,0 +1,131 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "openssl"
4
+
5
+ module PQCrypto
6
+ module SPKI
7
+ PEM_LABEL = "PUBLIC KEY"
8
+ PEM_BEGIN = "-----BEGIN #{PEM_LABEL}-----"
9
+ PEM_END = "-----END #{PEM_LABEL}-----"
10
+
11
+ class << self
12
+ def encode_der(algorithm_symbol, public_key_bytes)
13
+ entry = AlgorithmRegistry.fetch(algorithm_symbol)
14
+ validate_public_key_algorithm!(algorithm_symbol, entry)
15
+
16
+ bytes = String(public_key_bytes).b
17
+ expected = entry.fetch(:public_key_bytes)
18
+ unless bytes.bytesize == expected
19
+ raise SerializationError,
20
+ "Invalid #{algorithm_symbol.inspect} public key length: expected #{expected}, got #{bytes.bytesize}"
21
+ end
22
+
23
+ OpenSSL::ASN1::Sequence.new([
24
+ OpenSSL::ASN1::Sequence.new([
25
+ OpenSSL::ASN1::ObjectId.new(AlgorithmRegistry.standard_oid(algorithm_symbol)),
26
+ ]),
27
+ OpenSSL::ASN1::BitString.new(bytes),
28
+ ]).to_der.b
29
+ rescue OpenSSL::ASN1::ASN1Error => e
30
+ raise SerializationError, e.message
31
+ end
32
+
33
+ def encode_pem(algorithm_symbol, public_key_bytes)
34
+ der = encode_der(algorithm_symbol, public_key_bytes)
35
+ body = encode_base64(der).scan(/.{1,64}/).join("\n")
36
+ "#{PEM_BEGIN}\n#{body}\n#{PEM_END}\n"
37
+ end
38
+
39
+ def decode_der(der)
40
+ input = String(der).b
41
+ outer = decode_asn1(input)
42
+ raise SerializationError, "SPKI DER contains trailing data" unless outer.to_der.b == input
43
+ raise SerializationError, "SPKI must be an ASN.1 SEQUENCE" unless outer.is_a?(OpenSSL::ASN1::Sequence)
44
+ raise SerializationError, "SPKI SEQUENCE must contain exactly 2 elements" unless outer.value.size == 2
45
+
46
+ algorithm_identifier, subject_public_key = outer.value
47
+ algorithm = decode_algorithm_identifier(algorithm_identifier)
48
+ entry = AlgorithmRegistry.fetch(algorithm)
49
+ validate_public_key_algorithm!(algorithm, entry)
50
+
51
+ unless subject_public_key.is_a?(OpenSSL::ASN1::BitString)
52
+ raise SerializationError, "SPKI subjectPublicKey must be a BIT STRING"
53
+ end
54
+ unless subject_public_key.unused_bits.zero?
55
+ raise SerializationError, "SPKI subjectPublicKey must have zero unused bits"
56
+ end
57
+
58
+ bytes = String(subject_public_key.value).b
59
+ expected = entry.fetch(:public_key_bytes)
60
+ unless bytes.bytesize == expected
61
+ raise SerializationError,
62
+ "Invalid #{algorithm.inspect} SPKI public key length: expected #{expected}, got #{bytes.bytesize}"
63
+ end
64
+
65
+ [algorithm, bytes]
66
+ end
67
+
68
+ def decode_pem(pem)
69
+ der = der_from_pem(pem)
70
+ decode_der(der)
71
+ end
72
+
73
+ private
74
+
75
+ def decode_asn1(der)
76
+ OpenSSL::ASN1.decode(der)
77
+ rescue OpenSSL::ASN1::ASN1Error => e
78
+ raise SerializationError, e.message
79
+ end
80
+
81
+ def decode_algorithm_identifier(value)
82
+ unless value.is_a?(OpenSSL::ASN1::Sequence)
83
+ raise SerializationError, "SPKI algorithm must be an AlgorithmIdentifier SEQUENCE"
84
+ end
85
+ unless value.value.size == 1
86
+ raise SerializationError, "SPKI AlgorithmIdentifier parameters must be absent"
87
+ end
88
+
89
+ oid = value.value.first
90
+ raise SerializationError, "SPKI AlgorithmIdentifier must contain an OBJECT IDENTIFIER" unless oid.is_a?(OpenSSL::ASN1::ObjectId)
91
+
92
+ algorithm = AlgorithmRegistry.by_standard_oid(oid.oid)
93
+ raise SerializationError, "Unsupported SPKI algorithm OID: #{oid.oid}" if algorithm.nil?
94
+
95
+ algorithm
96
+ end
97
+
98
+ def validate_public_key_algorithm!(algorithm_symbol, entry)
99
+ return if %i[ml_kem ml_dsa].include?(entry.fetch(:family))
100
+
101
+ raise SerializationError, "SPKI public key codec is not supported for #{algorithm_symbol.inspect}"
102
+ end
103
+
104
+ def encode_base64(bytes)
105
+ [String(bytes).b].pack("m0")
106
+ end
107
+
108
+ def decode_base64(body)
109
+ compact = body.gsub(/[\r\n]/, "")
110
+ unless compact.match?(/\A(?:[A-Za-z0-9+\/]{4})*(?:[A-Za-z0-9+\/]{2}==|[A-Za-z0-9+\/]{3}=)?\z/)
111
+ raise SerializationError, "Invalid SPKI PEM: invalid base64"
112
+ end
113
+
114
+ compact.unpack1("m0").b
115
+ rescue ArgumentError => e
116
+ raise SerializationError, e.message
117
+ end
118
+
119
+ def der_from_pem(pem)
120
+ text = String(pem)
121
+ match = text.match(/\A#{Regexp.escape(PEM_BEGIN)}\r?\n(?<body>[A-Za-z0-9+\/=\r\n]+)\r?\n#{Regexp.escape(PEM_END)}[ \t\r\n]*\z/)
122
+ raise SerializationError, "Invalid SPKI PEM: expected #{PEM_LABEL.inspect} label" unless match
123
+
124
+ body = match[:body]
125
+ raise SerializationError, "Invalid SPKI PEM: embedded NUL in body" if body.include?("\0")
126
+
127
+ decode_base64(body)
128
+ end
129
+ end
130
+ end
131
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module PQCrypto
4
- VERSION = "0.3.2"
4
+ VERSION = "0.5.0"
5
5
  end
data/lib/pq_crypto.rb CHANGED
@@ -1,12 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "rbconfig"
4
- require_relative "pq_crypto/version"
5
- require_relative "pq_crypto/errors"
6
-
7
3
  begin
8
- require "pqcrypto/pqcrypto_secure"
4
+ require "pqcrypto/pqcrypto_secure" # native extension first
9
5
  rescue LoadError => original_error
6
+ require "rbconfig"
7
+
10
8
  ext_dir = File.expand_path("pqcrypto", __dir__)
11
9
  extensions = [".#{RbConfig::CONFIG.fetch('DLEXT')}", ".bundle", ".so"].uniq
12
10
  search_dirs = [ext_dir, File.join(ext_dir, "pqcrypto")].uniq
@@ -30,13 +28,21 @@ rescue LoadError => original_error
30
28
  raise original_error unless loaded
31
29
  end
32
30
 
31
+ require_relative "pq_crypto/errors"
32
+ require_relative "pq_crypto/version"
33
+ require_relative "pq_crypto/algorithm_registry"
33
34
  require_relative "pq_crypto/serialization"
35
+ require_relative "pq_crypto/spki"
36
+ require_relative "pq_crypto/pkcs8"
37
+ require_relative "pq_crypto/kem"
38
+ require_relative "pq_crypto/signature"
39
+ require_relative "pq_crypto/hybrid_kem"
34
40
 
35
41
  module PQCrypto
36
42
  SUITES = {
37
- kem: [:ml_kem_768].freeze,
38
- hybrid_kem: [:ml_kem_768_x25519_xwing].freeze,
39
- signature: [:ml_dsa_65].freeze,
43
+ kem: AlgorithmRegistry.supported_kems,
44
+ hybrid_kem: AlgorithmRegistry.supported_hybrid_kems,
45
+ signature: AlgorithmRegistry.supported_signatures,
40
46
  }.freeze
41
47
 
42
48
  NATIVE_EXTENSION_LOADED = true
@@ -44,14 +50,32 @@ module PQCrypto
44
50
  module NativeBindings
45
51
  NATIVE_METHODS = %i[
46
52
  ml_kem_keypair
53
+ ml_kem_keypair_from_seed
47
54
  ml_kem_encapsulate
48
55
  ml_kem_decapsulate
56
+ ml_kem_512_keypair
57
+ ml_kem_512_keypair_from_seed
58
+ ml_kem_512_encapsulate
59
+ ml_kem_512_decapsulate
60
+ ml_kem_1024_keypair
61
+ ml_kem_1024_keypair_from_seed
62
+ ml_kem_1024_encapsulate
63
+ ml_kem_1024_decapsulate
49
64
  hybrid_kem_keypair
50
65
  hybrid_kem_encapsulate
51
66
  hybrid_kem_decapsulate
52
67
  sign_keypair
53
68
  sign
54
69
  verify
70
+ ml_dsa_44_keypair
71
+ ml_dsa_44_keypair_from_seed
72
+ ml_dsa_keypair_from_seed
73
+ ml_dsa_44_sign
74
+ ml_dsa_44_verify
75
+ ml_dsa_87_keypair
76
+ ml_dsa_87_keypair_from_seed
77
+ ml_dsa_87_sign
78
+ ml_dsa_87_verify
55
79
  ct_equals
56
80
  secure_wipe
57
81
  version
@@ -65,8 +89,14 @@ module PQCrypto
65
89
  secret_key_from_pqc_container_pem
66
90
  __test_ml_kem_keypair_from_seed
67
91
  __test_ml_kem_encapsulate_from_seed
92
+ __test_ml_kem_512_encapsulate_from_seed
93
+ __test_ml_kem_1024_encapsulate_from_seed
68
94
  __test_sign_keypair_from_seed
95
+ __test_ml_dsa_44_keypair_from_seed
96
+ __test_ml_dsa_87_keypair_from_seed
69
97
  __test_sign_from_seed
98
+ __test_ml_dsa_44_sign_from_seed
99
+ __test_ml_dsa_87_sign_from_seed
70
100
  ].freeze
71
101
 
72
102
  EXTERNAL_MU_METHODS = %i[
@@ -99,7 +129,7 @@ module PQCrypto
99
129
  end
100
130
 
101
131
  def backend
102
- :native_pqclean
132
+ :native_pq_code_package
103
133
  end
104
134
 
105
135
  def native_extension_loaded?
@@ -127,32 +157,61 @@ module PQCrypto
127
157
  end
128
158
 
129
159
  module Testing
130
- def self.ml_kem_keypair_from_seed(seed)
131
- PQCrypto.__send__(:native_test_ml_kem_keypair_from_seed, String(seed).b)
160
+ KEM_KEYPAIR_METHODS = {
161
+ ml_kem_512: :native_ml_kem_512_keypair_from_seed,
162
+ ml_kem_768: :native_ml_kem_keypair_from_seed,
163
+ ml_kem_1024: :native_ml_kem_1024_keypair_from_seed,
164
+ }.freeze
165
+
166
+ KEM_ENCAPSULATE_METHODS = {
167
+ ml_kem_512: :native_test_ml_kem_512_encapsulate_from_seed,
168
+ ml_kem_768: :native_test_ml_kem_encapsulate_from_seed,
169
+ ml_kem_1024: :native_test_ml_kem_1024_encapsulate_from_seed,
170
+ }.freeze
171
+
172
+ MLDSA_KEYPAIR_METHODS = {
173
+ ml_dsa_44: :native_test_ml_dsa_44_keypair_from_seed,
174
+ ml_dsa_65: :native_test_sign_keypair_from_seed,
175
+ ml_dsa_87: :native_test_ml_dsa_87_keypair_from_seed,
176
+ }.freeze
177
+
178
+ MLDSA_SIGN_METHODS = {
179
+ ml_dsa_44: :native_test_ml_dsa_44_sign_from_seed,
180
+ ml_dsa_65: :native_test_sign_from_seed,
181
+ ml_dsa_87: :native_test_ml_dsa_87_sign_from_seed,
182
+ }.freeze
183
+
184
+ def self.ml_kem_keypair_from_seed(seed, algorithm: :ml_kem_768)
185
+ PQCrypto.__send__(KEM_KEYPAIR_METHODS.fetch(algorithm), String(seed).b)
186
+ rescue KeyError
187
+ raise UnsupportedAlgorithmError, "Unsupported ML-KEM KAT algorithm: #{algorithm.inspect}"
132
188
  rescue ArgumentError => e
133
189
  raise InvalidKeyError, e.message
134
190
  end
135
191
 
136
- def self.ml_kem_encapsulate_from_seed(public_key, seed)
137
- PQCrypto.__send__(:native_test_ml_kem_encapsulate_from_seed, String(public_key).b, String(seed).b)
192
+ def self.ml_kem_encapsulate_from_seed(public_key, seed, algorithm: :ml_kem_768)
193
+ PQCrypto.__send__(KEM_ENCAPSULATE_METHODS.fetch(algorithm), String(public_key).b, String(seed).b)
194
+ rescue KeyError
195
+ raise UnsupportedAlgorithmError, "Unsupported ML-KEM KAT algorithm: #{algorithm.inspect}"
138
196
  rescue ArgumentError => e
139
197
  raise InvalidKeyError, e.message
140
198
  end
141
199
 
142
- def self.ml_dsa_keypair_from_seed(seed)
143
- PQCrypto.__send__(:native_test_sign_keypair_from_seed, String(seed).b)
200
+ def self.ml_dsa_keypair_from_seed(seed, algorithm: :ml_dsa_65)
201
+ PQCrypto.__send__(MLDSA_KEYPAIR_METHODS.fetch(algorithm), String(seed).b)
202
+ rescue KeyError
203
+ raise UnsupportedAlgorithmError, "Unsupported ML-DSA KAT algorithm: #{algorithm.inspect}"
144
204
  rescue ArgumentError => e
145
205
  raise InvalidKeyError, e.message
146
206
  end
147
207
 
148
- def self.ml_dsa_sign_from_seed(message, secret_key, seed)
149
- PQCrypto.__send__(:native_test_sign_from_seed, String(message).b, String(secret_key).b, String(seed).b)
208
+ def self.ml_dsa_sign_from_seed(message, secret_key, seed, algorithm: :ml_dsa_65)
209
+ PQCrypto.__send__(MLDSA_SIGN_METHODS.fetch(algorithm), String(message).b, String(secret_key).b, String(seed).b)
210
+ rescue KeyError
211
+ raise UnsupportedAlgorithmError, "Unsupported ML-DSA KAT algorithm: #{algorithm.inspect}"
150
212
  rescue ArgumentError => e
151
213
  raise InvalidKeyError, e.message
152
214
  end
153
215
  end
154
216
  end
155
217
 
156
- require_relative "pq_crypto/kem"
157
- require_relative "pq_crypto/hybrid_kem"
158
- require_relative "pq_crypto/signature"