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.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +56 -0
- data/CHANGELOG.md +62 -0
- data/GET_STARTED.md +366 -40
- data/README.md +76 -233
- data/SECURITY.md +107 -82
- data/ext/pqcrypto/extconf.rb +169 -87
- data/ext/pqcrypto/mldsa_api.h +1 -48
- data/ext/pqcrypto/mlkem_api.h +1 -18
- data/ext/pqcrypto/pq_externalmu.c +89 -204
- data/ext/pqcrypto/pqcrypto_native_api.h +129 -0
- data/ext/pqcrypto/pqcrypto_ruby_secure.c +484 -84
- data/ext/pqcrypto/pqcrypto_secure.c +203 -78
- data/ext/pqcrypto/pqcrypto_secure.h +53 -14
- data/ext/pqcrypto/pqcrypto_version.h +7 -0
- data/ext/pqcrypto/randombytes.h +9 -0
- data/ext/pqcrypto/vendor/.vendored +10 -5
- data/ext/pqcrypto/vendor/mldsa-native/BUILDING.md +105 -0
- data/ext/pqcrypto/vendor/mldsa-native/LICENSE +286 -0
- data/ext/pqcrypto/vendor/mldsa-native/META.yml +24 -0
- data/ext/pqcrypto/vendor/mldsa-native/README.md +221 -0
- data/ext/pqcrypto/vendor/mldsa-native/SECURITY.md +8 -0
- data/ext/pqcrypto/vendor/mldsa-native/mldsa/mldsa_native.c +721 -0
- data/ext/pqcrypto/vendor/mldsa-native/mldsa/mldsa_native.h +975 -0
- data/ext/pqcrypto/vendor/mldsa-native/mldsa/mldsa_native_asm.S +724 -0
- data/ext/pqcrypto/vendor/mldsa-native/mldsa/mldsa_native_config.h +723 -0
- data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/cbmc.h +166 -0
- data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/common.h +321 -0
- data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/ct.c +21 -0
- data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/ct.h +385 -0
- data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/debug.c +73 -0
- data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/debug.h +130 -0
- data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/fips202.c +277 -0
- data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/fips202.h +244 -0
- data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/fips202x4.c +182 -0
- data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/fips202x4.h +117 -0
- data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/keccakf1600.c +438 -0
- data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/keccakf1600.h +105 -0
- data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/aarch64/auto.h +71 -0
- data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/aarch64/src/fips202_native_aarch64.h +62 -0
- data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/aarch64/src/keccak_f1600_x1_scalar_asm.S +376 -0
- data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/aarch64/src/keccak_f1600_x1_v84a_asm.S +204 -0
- data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/aarch64/src/keccak_f1600_x2_v84a_asm.S +259 -0
- data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/aarch64/src/keccak_f1600_x4_v8a_scalar_hybrid_asm.S +1077 -0
- data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/aarch64/src/keccak_f1600_x4_v8a_v84a_scalar_hybrid_asm.S +987 -0
- data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/aarch64/src/keccakf1600_round_constants.c +41 -0
- data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/aarch64/x1_scalar.h +26 -0
- data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/aarch64/x1_v84a.h +35 -0
- data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/aarch64/x2_v84a.h +37 -0
- data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/aarch64/x4_v8a_scalar.h +27 -0
- data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/aarch64/x4_v8a_v84a_scalar.h +36 -0
- data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/api.h +69 -0
- data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/armv81m/README.md +10 -0
- data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/armv81m/mve.h +32 -0
- data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/armv81m/src/fips202_native_armv81m.h +20 -0
- data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/armv81m/src/keccak_f1600_x4_mve.S +638 -0
- data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/armv81m/src/keccak_f1600_x4_mve.c +136 -0
- data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/armv81m/src/keccakf1600_round_constants.c +52 -0
- data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/auto.h +29 -0
- data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/x86_64/src/KeccakP_1600_times4_SIMD256.c +488 -0
- data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/x86_64/src/KeccakP_1600_times4_SIMD256.h +16 -0
- data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/fips202/native/x86_64/xkcp.h +31 -0
- data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/meta.h +247 -0
- data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/aarch64_zetas.c +231 -0
- data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/arith_native_aarch64.h +150 -0
- data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/intt.S +753 -0
- data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/mld_polyvecl_pointwise_acc_montgomery_l4.S +129 -0
- data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/mld_polyvecl_pointwise_acc_montgomery_l5.S +145 -0
- data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/mld_polyvecl_pointwise_acc_montgomery_l7.S +177 -0
- data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/ntt.S +653 -0
- data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/pointwise_montgomery.S +79 -0
- data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/poly_caddq_asm.S +53 -0
- data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/poly_chknorm_asm.S +55 -0
- data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/poly_decompose_32_asm.S +85 -0
- data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/poly_decompose_88_asm.S +85 -0
- data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/poly_use_hint_32_asm.S +102 -0
- data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/poly_use_hint_88_asm.S +110 -0
- data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/polyz_unpack_17_asm.S +72 -0
- data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/polyz_unpack_19_asm.S +69 -0
- data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/polyz_unpack_table.c +40 -0
- data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/rej_uniform_asm.S +189 -0
- data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/rej_uniform_eta2_asm.S +135 -0
- data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/rej_uniform_eta4_asm.S +128 -0
- data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/rej_uniform_eta_table.c +543 -0
- data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/aarch64/src/rej_uniform_table.c +62 -0
- data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/api.h +649 -0
- data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/meta.h +23 -0
- data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/x86_64/meta.h +315 -0
- data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/x86_64/src/arith_native_x86_64.h +124 -0
- data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/x86_64/src/consts.c +157 -0
- data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/x86_64/src/consts.h +27 -0
- data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/x86_64/src/intt.S +2311 -0
- data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/x86_64/src/ntt.S +2383 -0
- data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/x86_64/src/nttunpack.S +239 -0
- data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/x86_64/src/pointwise.S +131 -0
- data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/x86_64/src/pointwise_acc_l4.S +139 -0
- data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/x86_64/src/pointwise_acc_l5.S +155 -0
- data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/x86_64/src/pointwise_acc_l7.S +187 -0
- data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/x86_64/src/poly_caddq_avx2.c +61 -0
- data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/x86_64/src/poly_chknorm_avx2.c +52 -0
- data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/x86_64/src/poly_decompose_32_avx2.c +155 -0
- data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/x86_64/src/poly_decompose_88_avx2.c +155 -0
- data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/x86_64/src/poly_use_hint_32_avx2.c +102 -0
- data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/x86_64/src/poly_use_hint_88_avx2.c +104 -0
- data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/x86_64/src/polyz_unpack_17_avx2.c +91 -0
- data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/x86_64/src/polyz_unpack_19_avx2.c +93 -0
- data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/x86_64/src/rej_uniform_avx2.c +126 -0
- data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/x86_64/src/rej_uniform_eta2_avx2.c +155 -0
- data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/x86_64/src/rej_uniform_eta4_avx2.c +139 -0
- data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/native/x86_64/src/rej_uniform_table.c +160 -0
- data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/packing.c +293 -0
- data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/packing.h +224 -0
- data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/params.h +77 -0
- data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/poly.c +991 -0
- data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/poly.h +393 -0
- data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/poly_kl.c +946 -0
- data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/poly_kl.h +360 -0
- data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/polyvec.c +877 -0
- data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/polyvec.h +725 -0
- data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/randombytes.h +26 -0
- data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/reduce.h +139 -0
- data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/rounding.h +249 -0
- data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/sign.c +1511 -0
- data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/sign.h +806 -0
- data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/symmetric.h +68 -0
- data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/sys.h +268 -0
- data/ext/pqcrypto/vendor/mldsa-native/mldsa/src/zetas.inc +55 -0
- data/ext/pqcrypto/vendor/mlkem-native/BUILDING.md +104 -0
- data/ext/pqcrypto/vendor/mlkem-native/LICENSE +294 -0
- data/ext/pqcrypto/vendor/mlkem-native/META.yml +30 -0
- data/ext/pqcrypto/vendor/mlkem-native/README.md +223 -0
- data/ext/pqcrypto/vendor/mlkem-native/RELEASE.md +86 -0
- data/ext/pqcrypto/vendor/mlkem-native/SECURITY.md +8 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/README.md +23 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/mlkem_native.c +660 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/mlkem_native.h +538 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/mlkem_native_asm.S +681 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/mlkem_native_config.h +709 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/cbmc.h +174 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/common.h +274 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/compress.c +717 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/compress.h +688 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/debug.c +64 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/debug.h +128 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/fips202/fips202.c +251 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/fips202/fips202.h +158 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/fips202/fips202x4.c +208 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/fips202/fips202x4.h +80 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/fips202/keccakf1600.c +463 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/fips202/keccakf1600.h +98 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/fips202/native/aarch64/auto.h +70 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/fips202/native/aarch64/src/fips202_native_aarch64.h +69 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/fips202/native/aarch64/src/keccak_f1600_x1_scalar_asm.S +375 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/fips202/native/aarch64/src/keccak_f1600_x1_v84a_asm.S +203 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/fips202/native/aarch64/src/keccak_f1600_x2_v84a_asm.S +258 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/fips202/native/aarch64/src/keccak_f1600_x4_v8a_scalar_hybrid_asm.S +1076 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/fips202/native/aarch64/src/keccak_f1600_x4_v8a_v84a_scalar_hybrid_asm.S +986 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/fips202/native/aarch64/src/keccakf1600_round_constants.c +46 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/fips202/native/aarch64/x1_scalar.h +25 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/fips202/native/aarch64/x1_v84a.h +34 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/fips202/native/aarch64/x2_v84a.h +35 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/fips202/native/aarch64/x4_v8a_scalar.h +26 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/fips202/native/aarch64/x4_v8a_v84a_scalar.h +35 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/fips202/native/api.h +117 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/fips202/native/armv81m/README.md +10 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/fips202/native/armv81m/mve.h +79 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/fips202/native/armv81m/src/fips202_native_armv81m.h +35 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/fips202/native/armv81m/src/keccak_f1600_x4_mve.S +667 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/fips202/native/armv81m/src/keccak_f1600_x4_mve.c +40 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/fips202/native/armv81m/src/keccakf1600_round_constants.c +51 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/fips202/native/armv81m/src/state_extract_bytes_x4_mve.S +290 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/fips202/native/armv81m/src/state_xor_bytes_x4_mve.S +314 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/fips202/native/auto.h +28 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/fips202/native/x86_64/keccak_f1600_x4_avx2.h +33 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/fips202/native/x86_64/src/fips202_native_x86_64.h +41 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/fips202/native/x86_64/src/keccak_f1600_x4_avx2.S +451 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/fips202/native/x86_64/src/keccakf1600_constants.c +51 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/indcpa.c +622 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/indcpa.h +156 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/kem.c +446 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/kem.h +326 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/aarch64/README.md +16 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/aarch64/meta.h +122 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/aarch64/src/aarch64_zetas.c +174 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/aarch64/src/arith_native_aarch64.h +177 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/aarch64/src/intt.S +628 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/aarch64/src/ntt.S +562 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/aarch64/src/poly_mulcache_compute_asm.S +127 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/aarch64/src/poly_reduce_asm.S +150 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/aarch64/src/poly_tobytes_asm.S +117 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/aarch64/src/poly_tomont_asm.S +98 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/aarch64/src/polyvec_basemul_acc_montgomery_cached_asm_k2.S +261 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/aarch64/src/polyvec_basemul_acc_montgomery_cached_asm_k3.S +314 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/aarch64/src/polyvec_basemul_acc_montgomery_cached_asm_k4.S +368 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/aarch64/src/rej_uniform_asm.S +226 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/aarch64/src/rej_uniform_table.c +542 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/api.h +637 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/meta.h +25 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/riscv64/README.md +11 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/riscv64/meta.h +128 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/riscv64/src/arith_native_riscv64.h +45 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/riscv64/src/rv64v_debug.c +81 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/riscv64/src/rv64v_debug.h +145 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/riscv64/src/rv64v_izetas.inc +27 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/riscv64/src/rv64v_poly.c +805 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/riscv64/src/rv64v_zetas.inc +27 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/riscv64/src/rv64v_zetas_basemul.inc +39 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/x86_64/README.md +4 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/x86_64/meta.h +304 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/x86_64/src/arith_native_x86_64.h +309 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/x86_64/src/compress_consts.c +94 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/x86_64/src/compress_consts.h +45 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/x86_64/src/consts.c +102 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/x86_64/src/consts.h +25 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/x86_64/src/intt.S +719 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/x86_64/src/mulcache_compute.S +90 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/x86_64/src/ntt.S +639 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/x86_64/src/nttfrombytes.S +193 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/x86_64/src/ntttobytes.S +181 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/x86_64/src/nttunpack.S +174 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/x86_64/src/poly_compress_d10.S +382 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/x86_64/src/poly_compress_d11.S +448 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/x86_64/src/poly_compress_d4.S +163 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/x86_64/src/poly_compress_d5.S +220 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/x86_64/src/poly_decompress_d10.S +228 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/x86_64/src/poly_decompress_d11.S +277 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/x86_64/src/poly_decompress_d4.S +180 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/x86_64/src/poly_decompress_d5.S +192 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/x86_64/src/polyvec_basemul_acc_montgomery_cached_asm_k2.S +502 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/x86_64/src/polyvec_basemul_acc_montgomery_cached_asm_k3.S +750 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/x86_64/src/polyvec_basemul_acc_montgomery_cached_asm_k4.S +998 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/x86_64/src/reduce.S +218 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/x86_64/src/rej_uniform_asm.S +103 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/x86_64/src/rej_uniform_table.c +544 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/x86_64/src/tomont.S +155 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/params.h +76 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/poly.c +572 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/poly.h +317 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/poly_k.c +502 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/poly_k.h +668 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/randombytes.h +60 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/sampling.c +362 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/sampling.h +118 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/symmetric.h +70 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/sys.h +260 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/verify.c +20 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/verify.h +464 -0
- data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/zetas.inc +30 -0
- data/lib/pq_crypto/algorithm_registry.rb +200 -0
- data/lib/pq_crypto/hybrid_kem.rb +1 -12
- data/lib/pq_crypto/kem.rb +104 -13
- data/lib/pq_crypto/pkcs8.rb +387 -0
- data/lib/pq_crypto/serialization.rb +1 -14
- data/lib/pq_crypto/signature.rb +123 -17
- data/lib/pq_crypto/spki.rb +131 -0
- data/lib/pq_crypto/version.rb +1 -1
- data/lib/pq_crypto.rb +79 -20
- data/script/vendor_libs.rb +88 -155
- metadata +241 -73
- data/ext/pqcrypto/vendor/pqclean/common/aes.c +0 -639
- data/ext/pqcrypto/vendor/pqclean/common/aes.h +0 -64
- data/ext/pqcrypto/vendor/pqclean/common/compat.h +0 -73
- data/ext/pqcrypto/vendor/pqclean/common/crypto_declassify.h +0 -7
- data/ext/pqcrypto/vendor/pqclean/common/fips202.c +0 -928
- data/ext/pqcrypto/vendor/pqclean/common/fips202.h +0 -166
- data/ext/pqcrypto/vendor/pqclean/common/keccak2x/feat.S +0 -168
- data/ext/pqcrypto/vendor/pqclean/common/keccak2x/fips202x2.c +0 -684
- data/ext/pqcrypto/vendor/pqclean/common/keccak2x/fips202x2.h +0 -60
- data/ext/pqcrypto/vendor/pqclean/common/keccak4x/KeccakP-1600-times4-SIMD256.c +0 -1028
- data/ext/pqcrypto/vendor/pqclean/common/keccak4x/KeccakP-1600-times4-SnP.h +0 -50
- data/ext/pqcrypto/vendor/pqclean/common/keccak4x/KeccakP-1600-unrolling.macros +0 -198
- data/ext/pqcrypto/vendor/pqclean/common/keccak4x/Makefile +0 -8
- data/ext/pqcrypto/vendor/pqclean/common/keccak4x/Makefile.Microsoft_nmake +0 -8
- data/ext/pqcrypto/vendor/pqclean/common/keccak4x/SIMD256-config.h +0 -3
- data/ext/pqcrypto/vendor/pqclean/common/keccak4x/align.h +0 -34
- data/ext/pqcrypto/vendor/pqclean/common/keccak4x/brg_endian.h +0 -142
- data/ext/pqcrypto/vendor/pqclean/common/nistseedexpander.c +0 -101
- data/ext/pqcrypto/vendor/pqclean/common/nistseedexpander.h +0 -39
- data/ext/pqcrypto/vendor/pqclean/common/randombytes.c +0 -355
- data/ext/pqcrypto/vendor/pqclean/common/randombytes.h +0 -27
- data/ext/pqcrypto/vendor/pqclean/common/sha2.c +0 -769
- data/ext/pqcrypto/vendor/pqclean/common/sha2.h +0 -173
- data/ext/pqcrypto/vendor/pqclean/common/sp800-185.c +0 -156
- data/ext/pqcrypto/vendor/pqclean/common/sp800-185.h +0 -27
- data/ext/pqcrypto/vendor/pqclean/crypto_kem/ml-kem-768/clean/LICENSE +0 -5
- data/ext/pqcrypto/vendor/pqclean/crypto_kem/ml-kem-768/clean/Makefile +0 -19
- data/ext/pqcrypto/vendor/pqclean/crypto_kem/ml-kem-768/clean/Makefile.Microsoft_nmake +0 -23
- data/ext/pqcrypto/vendor/pqclean/crypto_kem/ml-kem-768/clean/api.h +0 -18
- data/ext/pqcrypto/vendor/pqclean/crypto_kem/ml-kem-768/clean/cbd.c +0 -83
- data/ext/pqcrypto/vendor/pqclean/crypto_kem/ml-kem-768/clean/cbd.h +0 -11
- data/ext/pqcrypto/vendor/pqclean/crypto_kem/ml-kem-768/clean/indcpa.c +0 -327
- data/ext/pqcrypto/vendor/pqclean/crypto_kem/ml-kem-768/clean/indcpa.h +0 -22
- data/ext/pqcrypto/vendor/pqclean/crypto_kem/ml-kem-768/clean/kem.c +0 -164
- data/ext/pqcrypto/vendor/pqclean/crypto_kem/ml-kem-768/clean/kem.h +0 -23
- data/ext/pqcrypto/vendor/pqclean/crypto_kem/ml-kem-768/clean/ntt.c +0 -146
- data/ext/pqcrypto/vendor/pqclean/crypto_kem/ml-kem-768/clean/ntt.h +0 -14
- data/ext/pqcrypto/vendor/pqclean/crypto_kem/ml-kem-768/clean/params.h +0 -36
- data/ext/pqcrypto/vendor/pqclean/crypto_kem/ml-kem-768/clean/poly.c +0 -299
- data/ext/pqcrypto/vendor/pqclean/crypto_kem/ml-kem-768/clean/poly.h +0 -37
- data/ext/pqcrypto/vendor/pqclean/crypto_kem/ml-kem-768/clean/polyvec.c +0 -188
- data/ext/pqcrypto/vendor/pqclean/crypto_kem/ml-kem-768/clean/polyvec.h +0 -26
- data/ext/pqcrypto/vendor/pqclean/crypto_kem/ml-kem-768/clean/reduce.c +0 -41
- data/ext/pqcrypto/vendor/pqclean/crypto_kem/ml-kem-768/clean/reduce.h +0 -13
- data/ext/pqcrypto/vendor/pqclean/crypto_kem/ml-kem-768/clean/symmetric-shake.c +0 -71
- data/ext/pqcrypto/vendor/pqclean/crypto_kem/ml-kem-768/clean/symmetric.h +0 -30
- data/ext/pqcrypto/vendor/pqclean/crypto_kem/ml-kem-768/clean/verify.c +0 -67
- data/ext/pqcrypto/vendor/pqclean/crypto_kem/ml-kem-768/clean/verify.h +0 -13
- data/ext/pqcrypto/vendor/pqclean/crypto_sign/ml-dsa-65/clean/LICENSE +0 -5
- data/ext/pqcrypto/vendor/pqclean/crypto_sign/ml-dsa-65/clean/Makefile +0 -19
- data/ext/pqcrypto/vendor/pqclean/crypto_sign/ml-dsa-65/clean/Makefile.Microsoft_nmake +0 -23
- data/ext/pqcrypto/vendor/pqclean/crypto_sign/ml-dsa-65/clean/api.h +0 -50
- data/ext/pqcrypto/vendor/pqclean/crypto_sign/ml-dsa-65/clean/ntt.c +0 -98
- data/ext/pqcrypto/vendor/pqclean/crypto_sign/ml-dsa-65/clean/ntt.h +0 -10
- data/ext/pqcrypto/vendor/pqclean/crypto_sign/ml-dsa-65/clean/packing.c +0 -261
- data/ext/pqcrypto/vendor/pqclean/crypto_sign/ml-dsa-65/clean/packing.h +0 -31
- data/ext/pqcrypto/vendor/pqclean/crypto_sign/ml-dsa-65/clean/params.h +0 -44
- data/ext/pqcrypto/vendor/pqclean/crypto_sign/ml-dsa-65/clean/poly.c +0 -799
- data/ext/pqcrypto/vendor/pqclean/crypto_sign/ml-dsa-65/clean/poly.h +0 -52
- data/ext/pqcrypto/vendor/pqclean/crypto_sign/ml-dsa-65/clean/polyvec.c +0 -415
- data/ext/pqcrypto/vendor/pqclean/crypto_sign/ml-dsa-65/clean/polyvec.h +0 -65
- data/ext/pqcrypto/vendor/pqclean/crypto_sign/ml-dsa-65/clean/reduce.c +0 -69
- data/ext/pqcrypto/vendor/pqclean/crypto_sign/ml-dsa-65/clean/reduce.h +0 -17
- data/ext/pqcrypto/vendor/pqclean/crypto_sign/ml-dsa-65/clean/rounding.c +0 -92
- data/ext/pqcrypto/vendor/pqclean/crypto_sign/ml-dsa-65/clean/rounding.h +0 -14
- data/ext/pqcrypto/vendor/pqclean/crypto_sign/ml-dsa-65/clean/sign.c +0 -407
- data/ext/pqcrypto/vendor/pqclean/crypto_sign/ml-dsa-65/clean/sign.h +0 -47
- data/ext/pqcrypto/vendor/pqclean/crypto_sign/ml-dsa-65/clean/symmetric-shake.c +0 -26
- data/ext/pqcrypto/vendor/pqclean/crypto_sign/ml-dsa-65/clean/symmetric.h +0 -34
data/README.md
CHANGED
|
@@ -1,284 +1,127 @@
|
|
|
1
1
|
# pq_crypto
|
|
2
2
|
|
|
3
3
|
`pq_crypto` is a primitive-first Ruby gem for post-quantum cryptography.
|
|
4
|
+
It provides small Ruby APIs for ML-KEM, ML-DSA, and one hybrid X-Wing KEM,
|
|
5
|
+
with standard key serialization where available.
|
|
4
6
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
- `PQCrypto::Signature` — `ML-DSA-65` (FIPS 204)
|
|
9
|
-
- `PQCrypto::HybridKEM` — `ML-KEM-768 + X25519` combined via the
|
|
10
|
-
[X-Wing](https://datatracker.ietf.org/doc/draft-connolly-cfrg-xwing-kem/)
|
|
11
|
-
SHA3-256 combiner
|
|
12
|
-
|
|
13
|
-
The gem is backed by vendored `PQClean` sources for `ML-KEM-768` /
|
|
14
|
-
`ML-DSA-65` and by OpenSSL for `X25519` and `SHA3-256`. Every piece of
|
|
15
|
-
conventional-crypto functionality goes through standard library calls
|
|
16
|
-
(`EVP_*`, `RAND_bytes`, `CRYPTO_memcmp`, `BIO_f_base64`) — nothing
|
|
17
|
-
roll-your-own where a library primitive exists.
|
|
18
|
-
|
|
19
|
-
## Status
|
|
20
|
-
|
|
21
|
-
- primitive-first API only
|
|
22
|
-
- no protocol/session helpers in the public surface
|
|
23
|
-
- streaming ML-DSA signing/verification is available for large IO inputs
|
|
24
|
-
- serialization uses pq_crypto-specific `pqc_container_*` wrappers
|
|
25
|
-
- not audited
|
|
26
|
-
- not yet positioned as production-ready
|
|
7
|
+
The gem intentionally stays close to cryptographic primitives. It does not
|
|
8
|
+
provide protocol, session, transport, certificate-chain, or application-level
|
|
9
|
+
handshake helpers.
|
|
27
10
|
|
|
28
11
|
## Installation
|
|
29
12
|
|
|
30
|
-
Add the gem to your
|
|
13
|
+
Add the gem to your `Gemfile`:
|
|
31
14
|
|
|
32
15
|
```ruby
|
|
33
16
|
# Gemfile
|
|
34
17
|
gem "pq_crypto"
|
|
35
18
|
```
|
|
36
19
|
|
|
20
|
+
Then install it:
|
|
21
|
+
|
|
37
22
|
```bash
|
|
38
23
|
bundle install
|
|
39
|
-
bundle exec rake compile
|
|
40
24
|
```
|
|
41
25
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
- Ruby 3.4.x
|
|
45
|
-
- a C toolchain with C11 support (for `_Static_assert` / `_Thread_local`)
|
|
46
|
-
- OpenSSL **3.0 or later** with SHA3-256 and SHAKE256 available (default provider)
|
|
47
|
-
|
|
48
|
-
### Build-time Keccak backend
|
|
49
|
-
|
|
50
|
-
The default build uses PQClean's scalar `common/fips202.c` backend:
|
|
26
|
+
When working from a source checkout, compile the native extension before
|
|
27
|
+
running tests or examples:
|
|
51
28
|
|
|
52
29
|
```bash
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
`PQCRYPTO_KECCAK_BACKEND=xkcp` is reserved for a separately vendored,
|
|
57
|
-
reviewed, `fips202.h`-compatible XKCP adapter. If requested without that
|
|
58
|
-
adapter, the build aborts instead of silently falling back to `clean`.
|
|
59
|
-
This avoids mixing OpenSSL EVP SHAKE state with PQClean SHAKE state and
|
|
60
|
-
keeps output-byte compatibility explicit.
|
|
61
|
-
|
|
62
|
-
## Async / Fiber scheduler support
|
|
63
|
-
|
|
64
|
-
`pq_crypto` does not require any gem-specific Async configuration. On
|
|
65
|
-
Ruby 3.4, `sign` and `verify` use Ruby's scheduler-aware
|
|
66
|
-
`rb_nogvl(..., RB_NOGVL_OFFLOAD_SAFE)` path automatically.
|
|
67
|
-
|
|
68
|
-
That means:
|
|
69
|
-
|
|
70
|
-
- without a Fiber scheduler, these methods fall back to the ordinary
|
|
71
|
-
no-GVL behavior;
|
|
72
|
-
- with a scheduler that implements `blocking_operation_wait` (for
|
|
73
|
-
example `Async` with a worker pool), the blocking native work can
|
|
74
|
-
be moved off the event loop.
|
|
75
|
-
|
|
76
|
-
This integration is intentionally limited to `sign` and `verify`; the
|
|
77
|
-
faster primitive operations keep the lower-overhead path.
|
|
78
|
-
|
|
79
|
-
Example with `Async`:
|
|
80
|
-
|
|
81
|
-
```ruby
|
|
82
|
-
require "async"
|
|
83
|
-
require "pq_crypto"
|
|
84
|
-
|
|
85
|
-
keypair = PQCrypto::Signature.generate(:ml_dsa_65)
|
|
86
|
-
message = "hello" * 100_000
|
|
87
|
-
|
|
88
|
-
reactor = Async::Reactor.new(worker_pool: true)
|
|
89
|
-
root = reactor.async do |task|
|
|
90
|
-
task.async do
|
|
91
|
-
signature = keypair.secret_key.sign(message)
|
|
92
|
-
keypair.public_key.verify(message, signature)
|
|
93
|
-
end
|
|
94
|
-
|
|
95
|
-
task.async do
|
|
96
|
-
sleep 0.01
|
|
97
|
-
puts "event loop stayed responsive"
|
|
98
|
-
end
|
|
99
|
-
end
|
|
100
|
-
|
|
101
|
-
reactor.run
|
|
102
|
-
root.wait
|
|
103
|
-
reactor.close
|
|
104
|
-
```
|
|
105
|
-
|
|
106
|
-
## Primitive API
|
|
107
|
-
|
|
108
|
-
### ML-KEM-768
|
|
109
|
-
|
|
110
|
-
```ruby
|
|
111
|
-
keypair = PQCrypto::KEM.generate(:ml_kem_768)
|
|
112
|
-
result = keypair.public_key.encapsulate
|
|
113
|
-
shared_secret = keypair.secret_key.decapsulate(result.ciphertext)
|
|
114
|
-
```
|
|
115
|
-
|
|
116
|
-
### ML-DSA-65
|
|
117
|
-
|
|
118
|
-
One-shot signing keeps the existing API:
|
|
119
|
-
|
|
120
|
-
```ruby
|
|
121
|
-
keypair = PQCrypto::Signature.generate(:ml_dsa_65)
|
|
122
|
-
signature = keypair.secret_key.sign("hello")
|
|
123
|
-
|
|
124
|
-
keypair.public_key.verify("hello", signature) # => true / false
|
|
125
|
-
keypair.public_key.verify!("hello", signature) # raises on mismatch
|
|
126
|
-
```
|
|
127
|
-
|
|
128
|
-
For large inputs, use streaming IO so the message does not need to be
|
|
129
|
-
materialized as one Ruby string:
|
|
130
|
-
|
|
131
|
-
```ruby
|
|
132
|
-
signature = File.open("document.bin", "rb") do |io|
|
|
133
|
-
keypair.secret_key.sign_io(io, chunk_size: 1 << 20)
|
|
134
|
-
end
|
|
135
|
-
|
|
136
|
-
ok = File.open("document.bin", "rb") do |io|
|
|
137
|
-
keypair.public_key.verify_io(io, signature, chunk_size: 1 << 20)
|
|
138
|
-
end
|
|
30
|
+
bundle exec rake compile
|
|
31
|
+
bundle exec rake test
|
|
139
32
|
```
|
|
140
33
|
|
|
141
|
-
|
|
142
|
-
ExternalMu flow. They are not HashML-DSA/prehash shortcuts and do not
|
|
143
|
-
expose public `sign_mu` / `verify_mu` APIs. With the default empty
|
|
144
|
-
context, streaming signatures verify with `verify(message, signature)`
|
|
145
|
-
and one-shot signatures verify with `verify_io(io, signature)`.
|
|
34
|
+
## What this gem provides
|
|
146
35
|
|
|
147
|
-
|
|
36
|
+
| Area | Capabilities |
|
|
37
|
+
| --- | --- |
|
|
38
|
+
| ML-KEM | Key generation, encapsulation, decapsulation, raw key import/export, SPKI public keys, PKCS#8 private keys. |
|
|
39
|
+
| ML-DSA | Key generation, signing, verification, streaming signing/verification for large inputs, raw key import/export, SPKI public keys, PKCS#8 private keys. |
|
|
40
|
+
| Hybrid KEM | ML-KEM-768 + X25519 using the X-Wing combiner. |
|
|
41
|
+
| Serialization | Standard SPKI / PKCS#8 for NIST PQC keys, plus frozen `pqc_container_*` compatibility formats for the original algorithms. |
|
|
42
|
+
| Safety helpers | Best-effort secret wiping and constant-time equality for key comparisons. |
|
|
43
|
+
| Introspection | Supported algorithm lists, algorithm metadata, backend/version helpers. |
|
|
148
44
|
|
|
149
|
-
|
|
150
|
-
ctx = "invoice-v1".b
|
|
151
|
-
signature = File.open("document.bin", "rb") { |io| keypair.secret_key.sign_io(io, context: ctx) }
|
|
152
|
-
ok = File.open("document.bin", "rb") { |io| keypair.public_key.verify_io(io, signature, context: ctx) }
|
|
153
|
-
```
|
|
45
|
+
## Supported algorithms
|
|
154
46
|
|
|
155
|
-
|
|
156
|
-
|
|
47
|
+
| Family | Algorithms | Notes |
|
|
48
|
+
| --- | --- | --- |
|
|
49
|
+
| KEM | `:ml_kem_512`, `:ml_kem_768`, `:ml_kem_1024` | FIPS 203 ML-KEM. Standard SPKI public keys and PKCS#8 private keys. |
|
|
50
|
+
| Signature | `:ml_dsa_44`, `:ml_dsa_65`, `:ml_dsa_87` | FIPS 204 ML-DSA. Standard SPKI public keys and PKCS#8 private keys. |
|
|
51
|
+
| Hybrid KEM | `:ml_kem_768_x25519_xwing` | ML-KEM-768 + X25519 hybrid KEM using the X-Wing construction. |
|
|
157
52
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
match.
|
|
53
|
+
Standard encodings use RFC 9935 OIDs for ML-KEM and RFC 9881 OIDs for
|
|
54
|
+
ML-DSA. `AlgorithmIdentifier.parameters` are omitted, not encoded as `NULL`.
|
|
161
55
|
|
|
162
|
-
|
|
56
|
+
The `pqc_container_*` format is project-local and kept only for backward
|
|
57
|
+
compatibility. It is not ASN.1, SPKI, or PKCS#8. It remains limited to the
|
|
58
|
+
original algorithms:
|
|
163
59
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
shared_secret = keypair.secret_key.decapsulate(result.ciphertext)
|
|
168
|
-
```
|
|
169
|
-
|
|
170
|
-
The implementation follows draft-10 key expansion: the X-Wing secret
|
|
171
|
-
decapsulation key is a 32-byte seed expanded with SHAKE256 into ML-KEM
|
|
172
|
-
and X25519 private material. The combiner is exactly:
|
|
60
|
+
- `:ml_kem_768`
|
|
61
|
+
- `:ml_dsa_65`
|
|
62
|
+
- `:ml_kem_768_x25519_xwing`
|
|
173
63
|
|
|
174
|
-
|
|
175
|
-
ss = SHA3-256( ss_M || ss_X || ct_X || pk_X || "\.//^\" )
|
|
176
|
-
```
|
|
64
|
+
## Requirements
|
|
177
65
|
|
|
178
|
-
|
|
179
|
-
|
|
66
|
+
- Ruby 3.4 or later
|
|
67
|
+
- a C toolchain with C11 support
|
|
68
|
+
- OpenSSL 3.0 or later with SHA3-256 and SHAKE256 available
|
|
69
|
+
- vendored minimal PQ Code Package native snapshot in `ext/pqcrypto/vendor`
|
|
180
70
|
|
|
181
|
-
##
|
|
71
|
+
## Native backend
|
|
182
72
|
|
|
183
|
-
|
|
73
|
+
Version `0.5.0` moves ML-KEM and ML-DSA to PQ Code Package
|
|
74
|
+
`mlkem-native` / `mldsa-native` sources. PQClean is no longer built and there
|
|
75
|
+
is no runtime or build-time PQClean fallback. The repository and source gem
|
|
76
|
+
ship a minimal vendor snapshot containing only the `mlkem/` and `mldsa/` source
|
|
77
|
+
trees plus license/docs; upstream examples, tests, proofs, `.git` directories,
|
|
78
|
+
and symlink-heavy trees are intentionally omitted. If the native vendor snapshot
|
|
79
|
+
is missing, the extension build fails early.
|
|
184
80
|
|
|
185
|
-
|
|
186
|
-
- `to_pqc_container_pem`
|
|
187
|
-
- `*_from_pqc_container_der`
|
|
188
|
-
- `*_from_pqc_container_pem`
|
|
81
|
+
From a source checkout, refresh the native vendor snapshot before compiling:
|
|
189
82
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
keypair = PQCrypto::KEM.generate(:ml_kem_768)
|
|
194
|
-
der = keypair.public_key.to_pqc_container_der
|
|
195
|
-
imported = PQCrypto::KEM.public_key_from_pqc_container_der(der)
|
|
83
|
+
```bash
|
|
84
|
+
bundle exec rake vendor
|
|
85
|
+
bundle exec rake compile
|
|
196
86
|
```
|
|
197
87
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
not advertised as interoperable with external PKI tooling.
|
|
88
|
+
The default build uses the portable native source path. Upstream native assembly
|
|
89
|
+
can be tested explicitly with:
|
|
201
90
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
`PQCrypto.secure_wipe(str)` zeros the bytes of a mutable Ruby string
|
|
205
|
-
in place. Key objects hold a private copy of their bytes, so `wipe!`
|
|
206
|
-
on a `SecretKey` zeroes **only** that internal copy — any prior Ruby
|
|
207
|
-
string the caller holds is untouched. If you need to wipe the
|
|
208
|
-
caller-side buffer, do so explicitly:
|
|
209
|
-
|
|
210
|
-
```ruby
|
|
211
|
-
raw = File.binread(path)
|
|
212
|
-
key = PQCrypto::KEM.secret_key_from_bytes(:ml_kem_768, raw)
|
|
213
|
-
PQCrypto.secure_wipe(raw) # scrub the original input
|
|
214
|
-
# ... use key ...
|
|
215
|
-
key.wipe! # scrub the key's internal copy
|
|
91
|
+
```bash
|
|
92
|
+
PQCRYPTO_NATIVE_ASM=1 bundle exec rake compile
|
|
216
93
|
```
|
|
217
94
|
|
|
218
|
-
##
|
|
95
|
+
## Security status
|
|
219
96
|
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
97
|
+
`pq_crypto` is experimental and not audited. Treat it as a low-level primitive
|
|
98
|
+
library, not a complete security protocol. See [`SECURITY.md`](SECURITY.md) for
|
|
99
|
+
audit status, serialization caveats, hybrid-KEM notes, and interoperability
|
|
100
|
+
warnings.
|
|
223
101
|
|
|
224
|
-
|
|
225
|
-
objects do not expose a public `fingerprint` method. `wipe!` remains
|
|
226
|
-
best-effort only: it clears the current Ruby string buffer owned by the
|
|
227
|
-
key object, not every possible copy made by Ruby, OpenSSL, serialization,
|
|
228
|
-
logging, or the garbage collector.
|
|
229
|
-
|
|
230
|
-
## Introspection
|
|
102
|
+
## Useful entry points
|
|
231
103
|
|
|
232
104
|
```ruby
|
|
233
105
|
PQCrypto.version
|
|
234
106
|
PQCrypto.backend
|
|
235
107
|
PQCrypto.supported_kems
|
|
236
|
-
PQCrypto.supported_hybrid_kems
|
|
237
108
|
PQCrypto.supported_signatures
|
|
238
|
-
PQCrypto
|
|
239
|
-
PQCrypto::HybridKEM.details(:ml_kem_768_x25519_xwing)
|
|
240
|
-
PQCrypto::Signature.details(:ml_dsa_65)
|
|
241
|
-
```
|
|
242
|
-
|
|
243
|
-
## Testing helpers
|
|
244
|
-
|
|
245
|
-
Deterministic test hooks are exposed under `PQCrypto::Testing` for
|
|
246
|
-
regression coverage:
|
|
247
|
-
|
|
248
|
-
- `ml_kem_keypair_from_seed` — requires a 64-byte `d||z` seed (FIPS 203)
|
|
249
|
-
- `ml_kem_encapsulate_from_seed` — requires a 32-byte seed
|
|
250
|
-
- `ml_dsa_keypair_from_seed` — requires a 32-byte seed
|
|
251
|
-
- `ml_dsa_sign_from_seed` — requires a 32-byte seed
|
|
252
|
-
|
|
253
|
-
These helpers are intended for tests only. They work by installing a
|
|
254
|
-
thread-local seed-replay mode inside the gem's `randombytes()` for
|
|
255
|
-
the duration of the call, then call the stock PQClean entrypoints.
|
|
256
|
-
No internal PQClean algorithm logic is reimplemented in this gem.
|
|
257
|
-
|
|
258
|
-
## Development
|
|
259
|
-
|
|
260
|
-
Run the test suite with:
|
|
109
|
+
PQCrypto.supported_hybrid_kems
|
|
261
110
|
|
|
262
|
-
|
|
263
|
-
|
|
111
|
+
PQCrypto::KEM.generate(:ml_kem_768)
|
|
112
|
+
PQCrypto::Signature.generate(:ml_dsa_65)
|
|
113
|
+
PQCrypto::HybridKEM.generate(:ml_kem_768_x25519_xwing)
|
|
264
114
|
```
|
|
265
115
|
|
|
266
|
-
|
|
267
|
-
update the vendor snapshot. The refresh script has a safe pinned
|
|
268
|
-
default and records the exact vendored snapshot in
|
|
269
|
-
`ext/pqcrypto/vendor/.vendored`:
|
|
270
|
-
|
|
271
|
-
```bash
|
|
272
|
-
bundle exec ruby script/vendor_libs.rb
|
|
273
|
-
```
|
|
116
|
+
## More examples
|
|
274
117
|
|
|
275
|
-
|
|
276
|
-
pinning inputs together:
|
|
118
|
+
Detailed usage examples live in [`GET_STARTED.md`](GET_STARTED.md):
|
|
277
119
|
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
120
|
+
- generating keys
|
|
121
|
+
- ML-KEM encapsulation / decapsulation
|
|
122
|
+
- ML-DSA signing / verification
|
|
123
|
+
- streaming ML-DSA for large files
|
|
124
|
+
- SPKI and PKCS#8 serialization
|
|
125
|
+
- `pqc_container_*` compatibility serialization
|
|
126
|
+
- native backend / vendoring notes
|
|
127
|
+
- secure wiping and practical safety notes
|
data/SECURITY.md
CHANGED
|
@@ -4,125 +4,150 @@
|
|
|
4
4
|
|
|
5
5
|
`pq_crypto` exposes a primitive-first public surface:
|
|
6
6
|
|
|
7
|
-
- `PQCrypto::KEM`
|
|
8
|
-
- `PQCrypto::Signature`
|
|
9
|
-
- `PQCrypto::HybridKEM`
|
|
7
|
+
- `PQCrypto::KEM` — ML-KEM-512, ML-KEM-768, ML-KEM-1024
|
|
8
|
+
- `PQCrypto::Signature` — ML-DSA-44, ML-DSA-65, ML-DSA-87
|
|
9
|
+
- `PQCrypto::HybridKEM` — ML-KEM-768 + X25519 via the X-Wing combiner
|
|
10
10
|
- `PQCrypto.secure_wipe`
|
|
11
|
-
- `PQCrypto.ct_equals`
|
|
11
|
+
- `PQCrypto.ct_equals`
|
|
12
12
|
|
|
13
|
-
The gem does
|
|
14
|
-
|
|
13
|
+
The gem does not publish protocol/session helpers as part of the supported
|
|
14
|
+
public API.
|
|
15
15
|
|
|
16
16
|
## Audit status
|
|
17
17
|
|
|
18
18
|
This project has not been audited. Treat it as experimental software.
|
|
19
19
|
|
|
20
|
+
The test surface includes deterministic regression tests, NIST ACVP KAT test
|
|
21
|
+
infrastructure, and OpenSSL 3.5+ interoperability tests for standard SPKI /
|
|
22
|
+
PKCS#8 encodings where the linked OpenSSL exposes the corresponding ML-KEM /
|
|
23
|
+
ML-DSA EVP support. These tests improve compatibility coverage but are not a
|
|
24
|
+
substitute for a security audit.
|
|
25
|
+
|
|
20
26
|
## Algorithm notes
|
|
21
27
|
|
|
22
|
-
### ML-KEM
|
|
28
|
+
### ML-KEM / ML-DSA
|
|
23
29
|
|
|
24
|
-
|
|
25
|
-
and
|
|
26
|
-
|
|
27
|
-
gem.
|
|
30
|
+
As of `0.5.0`, the post-quantum primitives are backed by vendored PQ Code
|
|
31
|
+
Package `mlkem-native` and `mldsa-native` sources. PQClean is not built and
|
|
32
|
+
there is intentionally no PQClean fallback.
|
|
28
33
|
|
|
29
|
-
|
|
34
|
+
The gem calls the native package entrypoints for ML-KEM key generation,
|
|
35
|
+
encapsulation, decapsulation, ML-DSA key generation, signing, verification, and
|
|
36
|
+
test-only deterministic hooks. It does not reimplement ML-KEM, ML-DSA, SHAKE,
|
|
37
|
+
or Keccak.
|
|
30
38
|
|
|
31
|
-
|
|
32
|
-
[`draft-connolly-cfrg-xwing-kem-10`](https://datatracker.ietf.org/doc/draft-connolly-cfrg-xwing-kem/).
|
|
39
|
+
### HybridKEM
|
|
33
40
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
internally for decapsulation. The public key and ciphertext are the
|
|
37
|
-
fixed-length concatenations specified by the draft.
|
|
41
|
+
`PQCrypto::HybridKEM` implements the X-Wing construction from
|
|
42
|
+
`draft-connolly-cfrg-xwing-kem-10`.
|
|
38
43
|
|
|
39
|
-
|
|
44
|
+
The X-Wing secret decapsulation key is a 32-byte seed. It is expanded with
|
|
45
|
+
SHAKE256 into the ML-KEM-768 and X25519 private material used internally for
|
|
46
|
+
decapsulation. The public key and ciphertext are the fixed-length
|
|
47
|
+
concatenations specified by the draft.
|
|
40
48
|
|
|
41
|
-
|
|
49
|
+
```text
|
|
50
|
+
ss = SHA3-256( ss_M || ss_X || ct_X || pk_X || XWingLabel )
|
|
51
|
+
```
|
|
42
52
|
|
|
43
|
-
|
|
44
|
-
the strong Diffie-Hellman assumption for X25519 (in the ROM), and
|
|
45
|
-
post-quantum IND-CCA security in the standard model assuming ML-KEM-768
|
|
46
|
-
is IND-CCA secure and SHA3-256 behaves as a PRF.
|
|
53
|
+
where `XWingLabel = "\.//^\"`.
|
|
47
54
|
|
|
48
|
-
|
|
49
|
-
interoperability should still be verified against the reference
|
|
55
|
+
External interoperability should be verified against the reference
|
|
50
56
|
implementation before relying on it.
|
|
51
57
|
|
|
52
|
-
|
|
58
|
+
## Serialization formats
|
|
53
59
|
|
|
54
|
-
|
|
55
|
-
`crypto_sign_keypair` / `crypto_sign_signature` (for ML-DSA) and
|
|
56
|
-
`crypto_kem_keypair_derand` / `crypto_kem_enc_derand` (for ML-KEM)
|
|
57
|
-
against a caller-supplied seed. For ML-DSA, which has no derand API
|
|
58
|
-
upstream, the gem installs a thread-local seed-replay buffer inside
|
|
59
|
-
its `randombytes()` implementation; outside of a test call the same
|
|
60
|
-
`randombytes()` entry delegates directly to OpenSSL `RAND_bytes`. No
|
|
61
|
-
internal PQClean algorithm logic is reimplemented in this gem.
|
|
60
|
+
### pq_crypto-local `pqc_container_*`
|
|
62
61
|
|
|
63
|
-
|
|
62
|
+
`pqc_container_*` DER/PEM wrappers are pq_crypto-specific containers. They are:
|
|
64
63
|
|
|
65
|
-
|
|
64
|
+
- not ASN.1
|
|
65
|
+
- not SPKI
|
|
66
|
+
- not PKCS#8
|
|
67
|
+
- not advertised as interoperable with OpenSSL, Go, Java, or PKI tooling
|
|
66
68
|
|
|
67
|
-
|
|
69
|
+
This format is frozen for backward compatibility and remains limited to the
|
|
70
|
+
original three algorithms:
|
|
68
71
|
|
|
69
|
-
-
|
|
70
|
-
-
|
|
71
|
-
-
|
|
72
|
+
- `:ml_kem_768`
|
|
73
|
+
- `:ml_dsa_65`
|
|
74
|
+
- `:ml_kem_768_x25519_xwing`
|
|
75
|
+
|
|
76
|
+
### Standard SPKI / PKCS#8
|
|
77
|
+
|
|
78
|
+
ML-KEM and ML-DSA use standard SPKI public-key and PKCS#8 private-key encodings
|
|
79
|
+
for the NIST parameter sets. AlgorithmIdentifier parameters are absent, not
|
|
80
|
+
encoded as `NULL`.
|
|
81
|
+
|
|
82
|
+
| Algorithm | Standard OID | Reference |
|
|
83
|
+
| --- | --- | --- |
|
|
84
|
+
| ML-KEM-512 | `2.16.840.1.101.3.4.4.1` | RFC 9935 |
|
|
85
|
+
| ML-KEM-768 | `2.16.840.1.101.3.4.4.2` | RFC 9935 |
|
|
86
|
+
| ML-KEM-1024 | `2.16.840.1.101.3.4.4.3` | RFC 9935 |
|
|
87
|
+
| ML-DSA-44 | `2.16.840.1.101.3.4.3.17` | RFC 9881 |
|
|
88
|
+
| ML-DSA-65 | `2.16.840.1.101.3.4.3.18` | RFC 9881 |
|
|
89
|
+
| ML-DSA-87 | `2.16.840.1.101.3.4.3.19` | RFC 9881 |
|
|
90
|
+
|
|
91
|
+
`PQCrypto::KEM.details` / `PQCrypto::Signature.details` keep `:oid` as the
|
|
92
|
+
legacy `pqc_container_*` OID for backward compatibility. Use
|
|
93
|
+
`PQCrypto::AlgorithmRegistry.standard_oid` for the standard OID.
|
|
72
94
|
|
|
73
|
-
|
|
74
|
-
ML-DSA currently use project-local UUID-derived OIDs under `2.25.*`.
|
|
75
|
-
Hybrid X-Wing uses the draft X-Wing OID `1.3.6.1.4.1.62253.25722`.
|
|
95
|
+
## ML-DSA seed-format imports
|
|
76
96
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
97
|
+
ML-DSA seed and both-form PKCS#8 imports are disabled by default. To import
|
|
98
|
+
these encodings, callers must explicitly set:
|
|
99
|
+
|
|
100
|
+
```ruby
|
|
101
|
+
PQCrypto::PKCS8.allow_ml_dsa_seed_format = true
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
This opt-in remains explicit because seed and both-form imports are more
|
|
105
|
+
sensitive than expanded-key imports: the decoder expands the seed into an
|
|
106
|
+
expanded private key and, for `both` encodings, rejects the key if the
|
|
107
|
+
expandedKey half does not match the seed-derived key.
|
|
108
|
+
|
|
109
|
+
The expansion path uses the vendored `mldsa-native` deterministic keypair
|
|
110
|
+
entrypoints rather than a `randombytes()` seed-replay fallback.
|
|
111
|
+
|
|
112
|
+
## Deterministic test hooks
|
|
113
|
+
|
|
114
|
+
`PQCrypto::Testing` deterministic helpers drive the vendored PQ Code Package
|
|
115
|
+
native deterministic entrypoints against caller-supplied seeds. ML-DSA
|
|
116
|
+
deterministic signing passes the FIPS 204 pure-mode domain-separation prefix
|
|
117
|
+
into `mldsa-native` `signature_internal`; for an empty context this prefix is
|
|
118
|
+
`00 00`.
|
|
119
|
+
|
|
120
|
+
Outside of test-only deterministic calls, production randomness delegates
|
|
121
|
+
directly to OpenSSL `RAND_bytes`.
|
|
83
122
|
|
|
84
123
|
## Memory wiping
|
|
85
124
|
|
|
86
|
-
`PQCrypto.secure_wipe` clears mutable Ruby strings in place. Ruby key
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
125
|
+
`PQCrypto.secure_wipe` clears mutable Ruby strings in place. Ruby key objects
|
|
126
|
+
take a copy of the bytes passed into their constructor and expose `#wipe!` to
|
|
127
|
+
zero only that internal copy. Ruby garbage collection and prior derived copies
|
|
128
|
+
may still leave sensitive material elsewhere in process memory.
|
|
129
|
+
|
|
130
|
+
Secret key objects redact `inspect` output and intentionally do not expose a
|
|
131
|
+
public `fingerprint` method. This avoids accidental logging of raw secret bytes
|
|
132
|
+
or stable secret-derived identifiers.
|
|
92
133
|
|
|
93
134
|
## OpenSSL baseline
|
|
94
135
|
|
|
95
|
-
`pq_crypto` requires OpenSSL
|
|
136
|
+
`pq_crypto` requires OpenSSL 3.0 or later.
|
|
96
137
|
|
|
97
138
|
OpenSSL is used for:
|
|
98
139
|
|
|
99
|
-
-
|
|
100
|
-
-
|
|
101
|
-
-
|
|
102
|
-
-
|
|
103
|
-
- Base64 encode/decode for PEM
|
|
104
|
-
header/footer framing and trailing-garbage checks.
|
|
105
|
-
|
|
106
|
-
## Secret key display and wiping
|
|
107
|
-
|
|
108
|
-
Secret key objects redact `inspect` output and intentionally do not expose
|
|
109
|
-
a public `fingerprint` method. This avoids accidental logging of raw secret
|
|
110
|
-
bytes or stable secret-derived identifiers.
|
|
140
|
+
- X25519 key generation and key agreement
|
|
141
|
+
- SHA3-256 for the X-Wing combiner
|
|
142
|
+
- RAND_bytes as the production entropy source for `randombytes()`
|
|
143
|
+
- CRYPTO_memcmp for constant-time comparison
|
|
144
|
+
- Base64 encode/decode for PEM
|
|
111
145
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
OpenSSL, native wrapper buffers, serialization, logging, crash dumps, or
|
|
115
|
-
the garbage collector.
|
|
146
|
+
OpenSSL 3.5+ is additionally used in interop tests when ML-KEM / ML-DSA EVP
|
|
147
|
+
support is available.
|
|
116
148
|
|
|
117
149
|
## Threading
|
|
118
150
|
|
|
119
151
|
Concurrent read-only operations on primitive key objects are supported.
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
pinned in place.
|
|
123
|
-
|
|
124
|
-
The deterministic test hooks use a thread-local seed-replay mode
|
|
125
|
-
around `randombytes()`, so a test running on one thread does not
|
|
126
|
-
affect production callers on other threads. The deterministic helpers
|
|
127
|
-
remain test-only utilities and should not be relied on as a general
|
|
128
|
-
multi-threading contract.
|
|
152
|
+
Mutating operations such as `wipe!` must not race with other uses of the same
|
|
153
|
+
object.
|