pq_crypto 0.6.3 → 0.6.5

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 (94) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +149 -17
  3. data/CHANGELOG.md +73 -0
  4. data/GET_STARTED.md +1 -1
  5. data/README.md +7 -2
  6. data/ext/pqcrypto/extconf.rb +264 -24
  7. data/ext/pqcrypto/pqcrypto_version.h +1 -1
  8. data/ext/pqcrypto/vendor/.vendored +4 -4
  9. data/ext/pqcrypto/vendor/mlkem-native/README.md +2 -4
  10. data/ext/pqcrypto/vendor/mlkem-native/RELEASE.md +98 -0
  11. data/ext/pqcrypto/vendor/mlkem-native/mlkem/mlkem_native.c +8 -7
  12. data/ext/pqcrypto/vendor/mlkem-native/mlkem/mlkem_native.h +21 -1
  13. data/ext/pqcrypto/vendor/mlkem-native/mlkem/mlkem_native_asm.S +45 -44
  14. data/ext/pqcrypto/vendor/mlkem-native/mlkem/mlkem_native_config.h +36 -0
  15. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/common.h +13 -30
  16. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/compress.c +25 -5
  17. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/compress.h +14 -0
  18. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/context.h +42 -0
  19. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/fips202/native/aarch64/auto.h +20 -12
  20. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/fips202/native/aarch64/src/keccak_f1600_x1_scalar_aarch64_asm.S +5 -3
  21. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/fips202/native/aarch64/src/keccak_f1600_x1_v84a_aarch64_asm.S +5 -2
  22. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/fips202/native/aarch64/src/keccak_f1600_x2_v84a_aarch64_asm.S +5 -2
  23. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/fips202/native/aarch64/src/keccak_f1600_x4_v8a_scalar_hybrid_aarch64_asm.S +10 -7
  24. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/fips202/native/aarch64/src/keccak_f1600_x4_v8a_v84a_scalar_hybrid_aarch64_asm.S +10 -7
  25. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/fips202/native/aarch64/x1_v84a.h +2 -1
  26. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/fips202/native/aarch64/x2_v84a.h +2 -1
  27. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/fips202/native/aarch64/x4_v8a_scalar.h +5 -0
  28. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/fips202/native/aarch64/x4_v8a_v84a_scalar.h +2 -1
  29. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/fips202/native/armv81m/mve.h +5 -19
  30. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/fips202/native/armv81m/src/keccak_f1600_x4_mve.S +8 -5
  31. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/fips202/native/armv81m/src/{state_extract_bytes_x4_mve.S → keccak_f1600_x4_state_extract_bytes_mve.S} +14 -14
  32. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/fips202/native/armv81m/src/{state_xor_bytes_x4_mve.S → keccak_f1600_x4_state_xor_bytes_mve.S} +12 -12
  33. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/fips202/native/x86_64/src/keccak_f1600_x4_avx2_asm.S +36 -2
  34. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/indcpa.c +22 -0
  35. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/indcpa.h +6 -0
  36. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/kem.c +11 -0
  37. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/kem.h +25 -1
  38. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/aarch64/meta.h +44 -2
  39. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/aarch64/src/aarch64_zetas.c +2 -0
  40. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/aarch64/src/arith_native_aarch64.h +11 -10
  41. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/aarch64/src/{intt_aarch64_asm.S → mlkem_intt_aarch64_asm.S} +16 -9
  42. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/aarch64/src/{ntt_aarch64_asm.S → mlkem_ntt_aarch64_asm.S} +10 -7
  43. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/aarch64/src/{poly_mulcache_compute_aarch64_asm.S → mlkem_poly_mulcache_compute_aarch64_asm.S} +6 -3
  44. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/aarch64/src/{poly_reduce_aarch64_asm.S → mlkem_poly_reduce_aarch64_asm.S} +6 -3
  45. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/aarch64/src/{poly_tobytes_aarch64_asm.S → mlkem_poly_tobytes_aarch64_asm.S} +12 -5
  46. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/aarch64/src/{poly_tomont_aarch64_asm.S → mlkem_poly_tomont_aarch64_asm.S} +11 -5
  47. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/aarch64/src/{polyvec_basemul_acc_montgomery_cached_k2_aarch64_asm.S → mlkem_polyvec_basemul_acc_montgomery_cached_k2_aarch64_asm.S} +6 -3
  48. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/aarch64/src/{polyvec_basemul_acc_montgomery_cached_k3_aarch64_asm.S → mlkem_polyvec_basemul_acc_montgomery_cached_k3_aarch64_asm.S} +6 -3
  49. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/aarch64/src/{polyvec_basemul_acc_montgomery_cached_k4_aarch64_asm.S → mlkem_polyvec_basemul_acc_montgomery_cached_k4_aarch64_asm.S} +6 -3
  50. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/aarch64/src/{rej_uniform_aarch64_asm.S → mlkem_rej_uniform_aarch64_asm.S} +17 -17
  51. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/api.h +21 -8
  52. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/meta.h +1 -1
  53. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/ppc64le/meta.h +4 -0
  54. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/ppc64le/src/{intt_ppc_asm.S → mlkem_intt_ppc_asm.S} +29 -5
  55. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/ppc64le/src/{ntt_ppc_asm.S → mlkem_ntt_ppc_asm.S} +22 -1
  56. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/ppc64le/src/{poly_tomont_ppc_asm.S → mlkem_poly_tomont_ppc_asm.S} +25 -3
  57. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/ppc64le/src/{reduce_ppc_asm.S → mlkem_reduce_ppc_asm.S} +22 -1
  58. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/riscv64/meta.h +4 -0
  59. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/riscv64/src/arith_native_riscv64.h +4 -0
  60. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/riscv64/src/rv64v_poly.c +6 -2
  61. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/x86_64/meta.h +25 -5
  62. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/x86_64/src/arith_native_x86_64.h +20 -20
  63. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/x86_64/src/compress_consts.c +14 -3
  64. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/x86_64/src/compress_consts.h +8 -0
  65. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/x86_64/src/{intt_avx2_asm.S → mlkem_intt_avx2_asm.S} +27 -3
  66. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/x86_64/src/{ntt_avx2_asm.S → mlkem_ntt_avx2_asm.S} +23 -1
  67. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/x86_64/src/{nttfrombytes_avx2_asm.S → mlkem_nttfrombytes_avx2_asm.S} +27 -3
  68. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/x86_64/src/{ntttobytes_avx2_asm.S → mlkem_ntttobytes_avx2_asm.S} +27 -3
  69. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/x86_64/src/{nttunpack_avx2_asm.S → mlkem_nttunpack_avx2_asm.S} +17 -1
  70. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/x86_64/src/{poly_compress_d10_avx2_asm.S → mlkem_poly_compress_d10_avx2_asm.S} +34 -3
  71. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/x86_64/src/{poly_compress_d11_avx2_asm.S → mlkem_poly_compress_d11_avx2_asm.S} +33 -2
  72. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/x86_64/src/{poly_compress_d4_avx2_asm.S → mlkem_poly_compress_d4_avx2_asm.S} +34 -3
  73. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/x86_64/src/{poly_compress_d5_avx2_asm.S → mlkem_poly_compress_d5_avx2_asm.S} +33 -2
  74. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/x86_64/src/{poly_decompress_d10_avx2_asm.S → mlkem_poly_decompress_d10_avx2_asm.S} +32 -3
  75. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/x86_64/src/{poly_decompress_d11_avx2_asm.S → mlkem_poly_decompress_d11_avx2_asm.S} +32 -2
  76. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/x86_64/src/{poly_decompress_d4_avx2_asm.S → mlkem_poly_decompress_d4_avx2_asm.S} +32 -3
  77. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/x86_64/src/{poly_decompress_d5_avx2_asm.S → mlkem_poly_decompress_d5_avx2_asm.S} +32 -2
  78. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/x86_64/src/{poly_mulcache_compute_avx2_asm.S → mlkem_poly_mulcache_compute_avx2_asm.S} +29 -1
  79. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/x86_64/src/{polyvec_basemul_acc_montgomery_cached_k2_avx2_asm.S → mlkem_polyvec_basemul_acc_montgomery_cached_k2_avx2_asm.S} +35 -1
  80. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/x86_64/src/{polyvec_basemul_acc_montgomery_cached_k3_avx2_asm.S → mlkem_polyvec_basemul_acc_montgomery_cached_k3_avx2_asm.S} +35 -1
  81. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/x86_64/src/{polyvec_basemul_acc_montgomery_cached_k4_avx2_asm.S → mlkem_polyvec_basemul_acc_montgomery_cached_k4_avx2_asm.S} +35 -1
  82. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/x86_64/src/{reduce_avx2_asm.S → mlkem_reduce_avx2_asm.S} +17 -1
  83. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/x86_64/src/{rej_uniform_avx2_asm.S → mlkem_rej_uniform_avx2_asm.S} +40 -7
  84. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/native/x86_64/src/{tomont_avx2_asm.S → mlkem_tomont_avx2_asm.S} +20 -3
  85. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/poly.c +7 -2
  86. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/poly.h +6 -0
  87. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/poly_k.c +25 -4
  88. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/poly_k.h +33 -4
  89. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/sampling.c +4 -0
  90. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/sampling.h +4 -0
  91. data/ext/pqcrypto/vendor/mlkem-native/mlkem/src/sys.h +19 -1
  92. data/lib/pq_crypto/version.rb +1 -1
  93. data/script/vendor_libs.rb +3 -3
  94. metadata +41 -43
@@ -3,6 +3,8 @@
3
3
 
4
4
  require "mkmf"
5
5
  require "rbconfig"
6
+ require "rubygems/version"
7
+ require "shellwords"
6
8
  require_relative "../../lib/pq_crypto/version"
7
9
 
8
10
  def generate_version_header!
@@ -27,7 +29,14 @@ generate_version_header!
27
29
 
28
30
  $CFLAGS << " -std=c11 -Wall -Wextra -O3"
29
31
  $CFLAGS << " -fstack-protector-strong -D_FORTIFY_SOURCE=2"
30
- $LDFLAGS << " -Wl,-no_warn_duplicate_libraries" if RbConfig::CONFIG["host_os"] =~ /darwin/
32
+ if RbConfig::CONFIG["host_os"] =~ /darwin/
33
+ $DLDFLAGS = $DLDFLAGS.to_s
34
+ .gsub(/(?:\A|\s)-Wl,-multiply_defined,suppress(?=\s|\z)/, " ")
35
+ .gsub(/(?:\A|\s)-multiply_defined\s+suppress(?=\s|\z)/, " ")
36
+ .strip
37
+
38
+ $LDFLAGS << " -Wl,-no_warn_duplicate_libraries"
39
+ end
31
40
 
32
41
  VENDOR_ONLY_CFLAGS = "-Wno-unused-parameter -Wno-unused-function -Wno-strict-prototypes -Wno-pedantic -Wno-c23-extensions -Wno-undef"
33
42
 
@@ -94,30 +103,245 @@ if ENV["PQCRYPTO_NATIVE_TUNE"] == "1"
94
103
  VENDOR_ASM_ARCH_FLAGS << " -march=native -mtune=native"
95
104
  end
96
105
 
106
+ def openssl_library_dirs(prefix)
107
+ dirs = Dir.glob(File.join(prefix, "lib", "*-linux-gnu"))
108
+ dirs.concat([File.join(prefix, "lib64"), File.join(prefix, "lib")])
109
+ dirs.select { |dir| File.directory?(dir) }.uniq
110
+ end
111
+
112
+ def openssl_library_file(dir, name)
113
+ candidates = [
114
+ File.join(dir, "lib#{name}.so.3"),
115
+ *Dir.glob(File.join(dir, "lib#{name}.so.3.*")).sort,
116
+ File.join(dir, "lib#{name}.so"),
117
+ File.join(dir, "lib#{name}.3.dylib"),
118
+ *Dir.glob(File.join(dir, "lib#{name}.3.*.dylib")).sort,
119
+ File.join(dir, "lib#{name}.dylib"),
120
+ File.join(dir, "lib#{name}.a"),
121
+ File.join(dir, "lib#{name}.dll.a"),
122
+ File.join(dir, "#{name}.lib")
123
+ ]
124
+
125
+ path = candidates.find { |candidate| File.file?(candidate) }
126
+ path && File.realpath(path)
127
+ rescue Errno::ENOENT
128
+ nil
129
+ end
130
+
131
+ def openssl_library_present?(dir, name)
132
+ !openssl_library_file(dir, name).nil?
133
+ end
134
+
135
+ def openssl_prefix_usable?(prefix)
136
+ return false if prefix.nil?
137
+
138
+ prefix = prefix.strip
139
+ return false if prefix.empty?
140
+ return false unless File.exist?(File.join(prefix, "include", "openssl", "opensslv.h"))
141
+
142
+ openssl_library_dirs(prefix).any? do |dir|
143
+ openssl_library_present?(dir, "crypto")
144
+ end
145
+ end
146
+
147
+ def explicit_openssl_prefix
148
+ %w[OPENSSL_ROOT_DIR OPENSSL_DIR].each do |var|
149
+ value = ENV[var]
150
+ next if value.nil? || value.strip.empty?
151
+
152
+ prefix = File.expand_path(value.strip)
153
+ abort <<~MSG unless openssl_prefix_usable?(prefix)
154
+ #{var}=#{value.inspect} does not point to a complete OpenSSL installation.
155
+
156
+ Expected OpenSSL headers under:
157
+ #{File.join(prefix, "include", "openssl")}
158
+
159
+ And libcrypto under lib, lib64, or a Linux multiarch lib directory.
160
+ MSG
161
+
162
+ return prefix
163
+ end
164
+
165
+ nil
166
+ end
167
+
168
+ def resolve_openssl_prefix
169
+ explicit = explicit_openssl_prefix
170
+ return explicit if explicit
171
+
172
+ candidates = []
173
+ if find_executable("brew")
174
+ %w[openssl@3 openssl].each do |formula|
175
+ prefix = `brew --prefix #{formula} 2>/dev/null`.strip
176
+ candidates << prefix unless prefix.empty?
177
+ end
178
+ end
179
+ candidates.concat(["/opt/homebrew/opt/openssl@3", "/usr/local/opt/openssl@3"])
180
+ candidates.uniq.find { |prefix| openssl_prefix_usable?(prefix) }
181
+ end
182
+
183
+ def pkg_config_value(variable)
184
+ value = `pkg-config --variable=#{variable} openssl 2>/dev/null`.strip
185
+ return nil unless $?.success?
186
+ return nil if value.empty?
187
+
188
+ File.expand_path(value)
189
+ end
190
+
191
+ def openssl_pkg_config
192
+ return nil unless find_executable("pkg-config")
193
+
194
+ version = `pkg-config --modversion openssl 2>/dev/null`.strip
195
+ return nil unless $?.success?
196
+ return nil if version.empty?
197
+ return { version: version } unless openssl_version_at_least_3?(version)
198
+
199
+ incdir = pkg_config_value("includedir")
200
+ libdir = pkg_config_value("libdir")
201
+ return { version: version } unless incdir && libdir
202
+ return { version: version } unless File.exist?(File.join(incdir, "openssl", "opensslv.h"))
203
+ crypto_lib = openssl_library_file(libdir, "crypto")
204
+ return { version: version } unless crypto_lib
205
+
206
+ { version: version, incdir: incdir, libdir: libdir, crypto_lib: crypto_lib }
207
+ end
208
+
209
+ def openssl_version_at_least_3?(version)
210
+ Gem::Version.new(version) >= Gem::Version.new("3.0.0")
211
+ rescue ArgumentError
212
+ false
213
+ end
214
+
215
+ def normalize_existing_path(path)
216
+ File.realpath(path)
217
+ rescue Errno::ENOENT
218
+ File.expand_path(path)
219
+ end
220
+
221
+ def include_paths_from_flags(flags)
222
+ tokens = Shellwords.split(flags.to_s)
223
+ paths = []
224
+ index = 0
225
+
226
+ while index < tokens.length
227
+ token = tokens[index]
228
+
229
+ case token
230
+ when "-I", "-isystem"
231
+ paths << tokens[index + 1] if tokens[index + 1]
232
+ index += 2
233
+ next
234
+ when /\A-I(.+)\z/
235
+ paths << Regexp.last_match(1)
236
+ when /\A-isystem(.+)\z/
237
+ paths << Regexp.last_match(1)
238
+ end
239
+
240
+ index += 1
241
+ end
242
+
243
+ paths
244
+ rescue ArgumentError
245
+ []
246
+ end
247
+
248
+ def strip_include_path(flags, path)
249
+ escaped = Regexp.escape(path)
250
+
251
+ flags.to_s
252
+ .gsub(/(?:\A|\s)-I\s*#{escaped}(?=\s|\z)/, " ")
253
+ .gsub(/(?:\A|\s)-isystem\s*#{escaped}(?=\s|\z)/, " ")
254
+ .strip
255
+ end
256
+
257
+ def remove_competing_openssl_headers!(selected_incdir)
258
+ selected = normalize_existing_path(selected_incdir)
259
+ flag_values = [$INCFLAGS, $CPPFLAGS, $CFLAGS]
260
+
261
+ competing = flag_values
262
+ .flat_map { |flags| include_paths_from_flags(flags) }.uniq.select do |path|
263
+ next false unless File.file?(File.join(path, "openssl", "opensslv.h"))
264
+
265
+ normalize_existing_path(path) != selected
266
+ end
267
+
268
+ competing.each do |path|
269
+ $INCFLAGS = strip_include_path($INCFLAGS, path)
270
+ $CPPFLAGS = strip_include_path($CPPFLAGS, path)
271
+ $CFLAGS = strip_include_path($CFLAGS, path)
272
+ puts "Ignoring competing OpenSSL headers: #{path}"
273
+ end
274
+ end
275
+
276
+ def configure_openssl_paths(incdir, libdir, crypto_lib:)
277
+ if defined?($configure_args) && $configure_args
278
+ $configure_args["--with-openssl-dir"] = File.dirname(incdir)
279
+ $configure_args["--with-openssl-include"] = incdir
280
+ $configure_args["--with-openssl-lib"] = libdir
281
+ end
282
+
283
+ remove_competing_openssl_headers!(incdir)
284
+
285
+ $INCFLAGS = "-I#{incdir} #{$INCFLAGS}".strip
286
+ $CPPFLAGS = "-I#{incdir} #{$CPPFLAGS}".strip
287
+ $LIBPATH.unshift(libdir) unless $LIBPATH.include?(libdir)
288
+
289
+ selected_libs = [crypto_lib].map { |path| Shellwords.escape(path) }.join(" ")
290
+ $LOCAL_LIBS = "#{selected_libs} #{$LOCAL_LIBS}".strip
291
+
292
+ unless host_os =~ /mswin|mingw|cygwin/i || libdir.start_with?("/usr/lib")
293
+ $LDFLAGS = "-Wl,-rpath,#{Shellwords.escape(libdir)} #{$LDFLAGS}".strip
294
+ end
295
+ end
296
+
297
+ def configure_openssl_prefix(prefix, source:)
298
+ incdir = File.join(prefix, "include")
299
+ libdir = openssl_library_dirs(prefix).find do |dir|
300
+ openssl_library_present?(dir, "crypto")
301
+ end
302
+ crypto_lib = openssl_library_file(libdir, "crypto")
303
+
304
+ configure_openssl_paths(incdir, libdir, crypto_lib: crypto_lib)
305
+ puts "OpenSSL #{source}: #{prefix}"
306
+ puts "OpenSSL include dir: #{incdir}"
307
+ puts "OpenSSL library dir: #{libdir}"
308
+ puts "OpenSSL libcrypto: #{crypto_lib}"
309
+ end
310
+
97
311
  def configure_compiler_environment
98
- if RUBY_PLATFORM.include?("darwin")
99
- dir_config("homebrew", "/opt/homebrew")
100
- $CPPFLAGS << " -I/opt/homebrew/include"
101
- $LDFLAGS << " -L/opt/homebrew/lib"
312
+ prefix = resolve_openssl_prefix
313
+ if prefix
314
+ configure_openssl_prefix(prefix, source: "prefix")
102
315
  return
103
316
  end
104
317
 
105
- openssl_root = ENV["OPENSSL_ROOT_DIR"] || ENV["OPENSSL_DIR"]
106
- if openssl_root && !openssl_root.strip.empty? && File.directory?(openssl_root)
107
- $CPPFLAGS << " -I#{openssl_root}/include"
108
- %w[lib64 lib].each do |suffix|
109
- libdir = File.join(openssl_root, suffix)
110
- next unless File.directory?(libdir)
318
+ pkg = openssl_pkg_config
319
+ if pkg && pkg[:incdir] && pkg[:libdir]
320
+ configure_openssl_paths(pkg[:incdir], pkg[:libdir], crypto_lib: pkg[:crypto_lib])
321
+ puts "OpenSSL pkg-config: #{pkg[:version]}"
322
+ puts "OpenSSL include dir: #{pkg[:incdir]}"
323
+ puts "OpenSSL library dir: #{pkg[:libdir]}"
324
+ puts "OpenSSL libcrypto: #{pkg[:crypto_lib]}"
325
+ return
326
+ end
111
327
 
112
- $LDFLAGS << " -L#{libdir} -Wl,-rpath,#{libdir}"
113
- break
328
+ if pkg && pkg[:version]
329
+ if openssl_version_at_least_3?(pkg[:version])
330
+ puts "Ignoring incomplete pkg-config OpenSSL #{pkg[:version]}; headers or libraries were not found"
331
+ else
332
+ puts "Ignoring pkg-config OpenSSL #{pkg[:version]}; OpenSSL 3.0 or later is required"
114
333
  end
115
- elsif find_executable("pkg-config")
116
- cflags = `pkg-config --cflags openssl 2>/dev/null`.strip
117
- libs = `pkg-config --libs-only-L openssl 2>/dev/null`.strip
118
- $CPPFLAGS << " #{cflags}" unless cflags.empty?
119
- $LDFLAGS << " #{libs}" unless libs.empty?
334
+ else
335
+ puts "OpenSSL pkg-config: unavailable"
120
336
  end
337
+
338
+ conventional = ["/usr/local", "/usr"].find { |candidate| openssl_prefix_usable?(candidate) }
339
+ if conventional
340
+ configure_openssl_prefix(conventional, source: "system prefix")
341
+ return
342
+ end
343
+
344
+ puts "OpenSSL prefix: (none resolved; using compiler defaults)"
121
345
  end
122
346
 
123
347
  def native_vendor_sources_for(vendor_dir)
@@ -196,8 +420,6 @@ end
196
420
  def configure_openssl!
197
421
  configure_compiler_environment
198
422
 
199
- abort "OpenSSL libcrypto is required" unless have_library("crypto")
200
- abort "OpenSSL libssl is required" unless have_library("ssl")
201
423
  abort "openssl/evp.h is required" unless have_header("openssl/evp.h")
202
424
  abort "openssl/rand.h is required" unless have_header("openssl/rand.h")
203
425
  abort "openssl/crypto.h is required" unless have_header("openssl/crypto.h")
@@ -205,13 +427,31 @@ def configure_openssl!
205
427
  abort "openssl/pkcs12.h is required" unless have_header("openssl/pkcs12.h")
206
428
 
207
429
  version_check = <<~SRC
430
+ #include <openssl/crypto.h>
208
431
  #include <openssl/opensslv.h>
209
432
  #if OPENSSL_VERSION_NUMBER < 0x30000000L
210
433
  #error "OpenSSL 3.0 or later is required"
211
434
  #endif
212
- int main(void) { return 0; }
435
+ int main(void) {
436
+ return (int)OPENSSL_version_major();
437
+ }
213
438
  SRC
214
- abort "OpenSSL 3.0 or later is required" unless try_compile(version_check)
439
+ abort <<~MSG unless try_link(version_check)
440
+ OpenSSL 3.0 or later is required, but the compiler and linker did not find
441
+ a consistent OpenSSL 3 headers + libcrypto pair. See mkmf.log for the exact
442
+ include paths, library paths, and linker error.
443
+
444
+ macOS with Homebrew:
445
+ brew install openssl@3
446
+ OPENSSL_ROOT_DIR="$(brew --prefix openssl@3)" bundle exec rake clean compile
447
+
448
+ Debian/Ubuntu:
449
+ sudo apt-get install libssl-dev pkg-config
450
+ pkg-config --modversion openssl # must report 3.x
451
+
452
+ If an old Ruby toolchain injects OpenSSL 1.1 through CPPFLAGS or
453
+ PKG_CONFIG_PATH, inspect mkmf.log and point the build at OpenSSL 3.
454
+ MSG
215
455
 
216
456
  sha3_check = <<~SRC
217
457
  #include <openssl/evp.h>
@@ -220,7 +460,7 @@ def configure_openssl!
220
460
  return md == NULL ? 1 : 0;
221
461
  }
222
462
  SRC
223
- abort "OpenSSL SHA3-256 is required (X-Wing combiner)" unless try_compile(sha3_check)
463
+ abort "OpenSSL SHA3-256 is required (X-Wing combiner)" unless try_link(sha3_check)
224
464
 
225
465
  shake_check = <<~SRC
226
466
  #include <openssl/evp.h>
@@ -229,7 +469,7 @@ def configure_openssl!
229
469
  return md == NULL ? 1 : 0;
230
470
  }
231
471
  SRC
232
- abort "OpenSSL SHAKE256 is required (X-Wing key expansion / ML-DSA streaming mu)" unless try_compile(shake_check)
472
+ abort "OpenSSL SHAKE256 is required (X-Wing key expansion / ML-DSA streaming mu)" unless try_link(shake_check)
233
473
 
234
474
  $CFLAGS << " -DHAVE_OPENSSL_EVP_H -DHAVE_OPENSSL_RAND_H"
235
475
  end
@@ -2,6 +2,6 @@
2
2
  #ifndef PQCRYPTO_VERSION_H
3
3
  #define PQCRYPTO_VERSION_H
4
4
 
5
- #define PQCRYPTO_VERSION "0.6.3"
5
+ #define PQCRYPTO_VERSION "0.6.5"
6
6
 
7
7
  #endif
@@ -2,11 +2,11 @@
2
2
  backend=PQ Code Package native only
3
3
  pqclean=removed
4
4
  mlkem_native_repo=https://github.com/pq-code-package/mlkem-native.git
5
- mlkem_native_ref=v1.2.0
6
- mlkem_native_commit=0ba906cb14b1c241476134d7403a811b382ca498
7
- mlkem_native_tree_sha256=cc78ed199b8c65abe68635b23a13b294d5a8deb20c8bc7b4d76590c00976bb2d
5
+ mlkem_native_ref=v1.3.0
6
+ mlkem_native_commit=398050c877ff4353c96305c6434b63528accfc37
7
+ mlkem_native_tree_sha256=3cd7af93cde256f73ce5ffde3ac3accd31e4361616e275f1bf1c39d462c2149e
8
8
  mldsa_native_repo=https://github.com/pq-code-package/mldsa-native.git
9
9
  mldsa_native_ref=v1.0.0-beta2
10
10
  mldsa_native_commit=9b0ee84f4cf399043eca59eca4e5f8531ca1d61b
11
11
  mldsa_native_tree_sha256=2887f59926c18a877e8c5a5e30727e84497c357032093d00d7135aedf53f011e
12
- manifest_sha256=011e9d7d1160c7d612869695d950e17f9e330dac6bf782883639593f96fee951
12
+ manifest_sha256=6fc387662d86d42905f6cbed29c92bc83abf18e8678a21500eb27fce14a89c7d
@@ -2,9 +2,7 @@
2
2
 
3
3
  # mlkem-native
4
4
 
5
- ![Base tests](https://github.com/pq-code-package/mlkem-native/actions/workflows/base.yml/badge.svg)
6
- ![Extended tests](https://github.com/pq-code-package/mlkem-native/actions/workflows/ci.yml/badge.svg)
7
- ![Proof: CBMC](https://github.com/pq-code-package/mlkem-native/actions/workflows/cbmc.yml/badge.svg)
5
+ ![CI](https://github.com/pq-code-package/mlkem-native/actions/workflows/all.yml/badge.svg)
8
6
  ![Proof: HOL-Light](https://github.com/pq-code-package/mlkem-native/actions/workflows/hol_light.yml/badge.svg)
9
7
  ![Benchmarks](https://github.com/pq-code-package/mlkem-native/actions/workflows/bench.yml/badge.svg)
10
8
  ![C90](https://img.shields.io/badge/language-C90-blue.svg)
@@ -102,7 +100,7 @@ mlkem-native currently offers the following backends:
102
100
  If you'd like contribute new backends, please reach out or just open a PR.
103
101
 
104
102
  Our AArch64 assembly is developed using the [SLOTHY](https://github.com/slothy-optimizer/slothy) superoptimizer, following the approach described in the SLOTHY paper[^SLOTHY_Paper]:
105
- We write 'clean' assembly by hand and automate micro-optimizations (e.g. see the [clean](dev/aarch64_clean/src/ntt_aarch64_asm.S) vs [optimized](dev/aarch64_opt/src/ntt_aarch64_asm.S) AArch64 NTT).
103
+ We write 'clean' assembly by hand and automate micro-optimizations (e.g. see the [clean](dev/aarch64_clean/src/mlkem_ntt_aarch64_asm.S) vs [optimized](dev/aarch64_opt/src/mlkem_ntt_aarch64_asm.S) AArch64 NTT).
106
104
  See [dev/README.md](dev/README.md) for more details.
107
105
 
108
106
  ## Test Vectors
@@ -1,5 +1,103 @@
1
1
  [//]: # (SPDX-License-Identifier: CC-BY-4.0)
2
2
 
3
+ mlkem-native v1.3.0
4
+ ===================
5
+
6
+ Release notes
7
+ -------------
8
+
9
+ mlkem-native v1.3.0 adds configuration options to control which KEM operations
10
+ are included in a build. It also improves AArch64 feature detection and runtime
11
+ dispatch, and introduces ABI compliance checks for assembly backends. Embedded
12
+ testing now uses Zephyr across a broader range of Arm targets, while assembly
13
+ namespacing and source naming improve integration with projects such as AWS-LC.
14
+
15
+ See the full change log here:
16
+ https://github.com/pq-code-package/mlkem-native/compare/v1.2.0...v1.3.0
17
+
18
+ What's next? mlkem-native v2
19
+ ----------------------------
20
+
21
+ This is expected to be the last release prior to mlkem-native v2. Between
22
+ v1.3.0 and v2, breaking changes to the `main` branch will be made.
23
+
24
+ Long-Term Support
25
+ -----------------
26
+
27
+ `release/v1.3` will act as a support branch until 6 months after
28
+ mlkem-native v2 is established. It will receive bugfixes, but no new features.
29
+ We do currently not plan to offer long-term support for mlkem-native v1.x
30
+ beyond that timeframe.
31
+
32
+ If you are deploying mlkem-native v1.3 and expect to be unable to upgrade to
33
+ mlkem-native v2 within 6 months of its release, please contact us to discuss
34
+ a potential extension of the support schedule.
35
+
36
+ What's New
37
+ ----------
38
+
39
+ ### Configuration / API
40
+
41
+ - Add `MLK_CONFIG_NO_KEYPAIR_API`, `MLK_CONFIG_NO_ENCAPS_API`, and
42
+ `MLK_CONFIG_NO_DECAPS_API`, allowing unused KEM operations and their internal
43
+ dependencies to be excluded. All non-empty API combinations are covered in
44
+ CI. ([#1787](https://github.com/pq-code-package/mlkem-native/pull/1787))
45
+ - Gate the AArch64 arithmetic and FIPS-202 backends on compile-time NEON
46
+ availability and the new `MLK_SYS_CAP_NEON` runtime capability. Integrators
47
+ can now fall back to portable C on AArch64 systems without usable NEON.
48
+ ([#1805](https://github.com/pq-code-package/mlkem-native/pull/1805),
49
+ [#1809](https://github.com/pq-code-package/mlkem-native/pull/1809))
50
+ - Add `MLK_SYS_AARCH64_FAST_SHA3` to select the pure-Neon Armv8.4-A SHA3
51
+ implementation on CPUs with sufficient SHA3 execution capacity, including
52
+ Graviton5. ([#1784](https://github.com/pq-code-package/mlkem-native/pull/1784))
53
+
54
+ ### Assurance / Testing
55
+
56
+ - Fix deterministic-only builds using `MLK_CONFIG_NO_RANDOMIZED_API`, including
57
+ test, example, and stack-measurement coverage.
58
+ ([#1816](https://github.com/pq-code-package/mlkem-native/pull/1816))
59
+ - Upgrade CBMC to v6.10.0, the newest release of CBMC including the fix
60
+ [cbmc/#9011](https://github.com/diffblue/cbmc/pull/9011) to the Z3 soundness
61
+ issue [z3/#9550](https://github.com/Z3Prover/z3/issues/9550). mlkem-native v1.2
62
+ had pinned CBMC to an unstable version between v6.9 and v6.10 which already
63
+ included that fix.
64
+ ([#1762](https://github.com/pq-code-package/mlkem-native/pull/1762))
65
+ - Add assembly ABI checkers for AArch64, x86_64 SysV, ppc64le ELFv2, and
66
+ Armv8.1-M MVE. The checkers verify preservation of callee-saved registers and
67
+ run as part of the standard test suite.
68
+ ([#1135](https://github.com/pq-code-package/mlkem-native/pull/1135))
69
+ - Add Zephyr-based testing for QEMU Cortex-M3, M4, M7, M33, and M55 targets,
70
+ replacing the previous custom MPS baremetal platforms. Add test and benchmark
71
+ support for the NUCLEO-N657X0-Q board.
72
+ ([#1750](https://github.com/pq-code-package/mlkem-native/pull/1750),
73
+ [#1547](https://github.com/pq-code-package/mlkem-native/pull/1547))
74
+ - Strengthen HOL Light tooling with cross-architecture proof execution and
75
+ checks that every expected theorem is present
76
+ ([#1634](https://github.com/pq-code-package/mlkem-native/pull/1634))
77
+ - Strengthen Wycheproof validation by checking newly specified fields, rejecting
78
+ unknown schema fields, and tracking upstream vector changes.
79
+ ([#1801](https://github.com/pq-code-package/mlkem-native/pull/1801))
80
+ - Extend Windows MSVC coverage to allocation-failure, RNG-failure, and
81
+ Wycheproof tests ([#1738](https://github.com/pq-code-package/mlkem-native/pull/1738))
82
+ - Add emulated testing on x86_64 without AVX2.
83
+ ([#1753](https://github.com/pq-code-package/mlkem-native/pull/1753))
84
+ - Correct decapsulation stack measurements, which previously returned before
85
+ the full operation and understated peak stack use by around 10%.
86
+ ([#1823](https://github.com/pq-code-package/mlkem-native/pull/1823))
87
+
88
+ ### Integration / Upgrade Notes
89
+
90
+ - Namespace assembly-local labels with an `mlk_` prefix, preventing collisions
91
+ when mlkem-native and other projects are combined into one assembly unit.
92
+ ([#1813](https://github.com/pq-code-package/mlkem-native/pull/1813))
93
+ - Rename backend assembly files to be self-identifying. Arithmetic assembly
94
+ filenames now use an `mlkem_` prefix. Downstream build systems with explicit
95
+ source lists must update those paths.
96
+ ([#1821](https://github.com/pq-code-package/mlkem-native/pull/1821))
97
+ - Move context-parameter support into the new `mlkem/src/context.h`; downstream
98
+ source manifests must include this file.
99
+ ([#1768](https://github.com/pq-code-package/mlkem-native/pull/1768))
100
+
3
101
  mlkem-native v1.2.0
4
102
  ===================
5
103
 
@@ -202,11 +202,6 @@
202
202
  #undef MLK_COMMON_H
203
203
  #undef MLK_CONCAT
204
204
  #undef MLK_CONCAT_
205
- #undef MLK_CONTEXT_PARAMETERS_0
206
- #undef MLK_CONTEXT_PARAMETERS_1
207
- #undef MLK_CONTEXT_PARAMETERS_2
208
- #undef MLK_CONTEXT_PARAMETERS_3
209
- #undef MLK_CONTEXT_PARAMETERS_4
210
205
  #undef MLK_EMPTY_CU
211
206
  #undef MLK_ERR_FAIL
212
207
  #undef MLK_ERR_OUT_OF_MEMORY
@@ -311,6 +306,13 @@
311
306
  #undef mlk_poly_frommsg
312
307
  #undef mlk_poly_tobytes
313
308
  #undef mlk_poly_tomsg
309
+ /* mlkem/src/context.h */
310
+ #undef MLK_CONTEXT_H
311
+ #undef MLK_CONTEXT_PARAMETERS_0
312
+ #undef MLK_CONTEXT_PARAMETERS_1
313
+ #undef MLK_CONTEXT_PARAMETERS_2
314
+ #undef MLK_CONTEXT_PARAMETERS_3
315
+ #undef MLK_CONTEXT_PARAMETERS_4
314
316
  /* mlkem/src/debug.h */
315
317
  #undef MLK_DEBUG_H
316
318
  #undef mlk_assert
@@ -377,6 +379,7 @@
377
379
  #undef MLK_SYSV_ABI_SUPPORTED
378
380
  #undef MLK_SYS_AARCH64
379
381
  #undef MLK_SYS_AARCH64_EB
382
+ #undef MLK_SYS_AARCH64_NEON
380
383
  #undef MLK_SYS_APPLE
381
384
  #undef MLK_SYS_ARMV81M_MVE
382
385
  #undef MLK_SYS_BIG_ENDIAN
@@ -508,8 +511,6 @@
508
511
  #undef MLK_USE_FIPS202_X4_NATIVE
509
512
  #undef MLK_USE_FIPS202_X4_XOR_BYTES_NATIVE
510
513
  #undef mlk_keccak_f1600_x4_native_impl
511
- #undef mlk_keccak_f1600_x4_state_extract_bytes
512
- #undef mlk_keccak_f1600_x4_state_xor_bytes
513
514
  /* mlkem/src/fips202/native/armv81m/src/fips202_native_armv81m.h */
514
515
  #undef MLK_FIPS202_NATIVE_ARMV81M_SRC_FIPS202_NATIVE_ARMV81M_H
515
516
  #undef mlk_keccak_f1600_x4_mve_asm
@@ -191,6 +191,7 @@ extern "C"
191
191
  {
192
192
  #endif
193
193
 
194
+ #if !defined(MLK_CONFIG_NO_KEYPAIR_API)
194
195
  /**
195
196
  * Generate a public/private keypair for the ML-KEM key encapsulation mechanism.
196
197
  *
@@ -255,7 +256,9 @@ int MLK_API_NAMESPACE(keypair)(
255
256
  #endif
256
257
  );
257
258
  #endif /* !MLK_CONFIG_NO_RANDOMIZED_API */
259
+ #endif /* !MLK_CONFIG_NO_KEYPAIR_API */
258
260
 
261
+ #if !defined(MLK_CONFIG_NO_ENCAPS_API)
259
262
  /**
260
263
  * Generate ciphertext and shared secret for a given public key.
261
264
  *
@@ -324,7 +327,9 @@ int MLK_API_NAMESPACE(enc)(
324
327
  #endif
325
328
  );
326
329
  #endif /* !MLK_CONFIG_NO_RANDOMIZED_API */
330
+ #endif /* !MLK_CONFIG_NO_ENCAPS_API */
327
331
 
332
+ #if !defined(MLK_CONFIG_NO_DECAPS_API)
328
333
  /**
329
334
  * Generate shared secret for a given ciphertext and private key.
330
335
  *
@@ -356,6 +361,7 @@ int MLK_API_NAMESPACE(dec)(
356
361
  MLK_CONFIG_CONTEXT_PARAMETER_TYPE context
357
362
  #endif
358
363
  );
364
+ #endif /* !MLK_CONFIG_NO_DECAPS_API */
359
365
 
360
366
 
361
367
  /**
@@ -375,6 +381,7 @@ int MLK_API_NAMESPACE(dec)(
375
381
  * @retval MLK_ERR_OUT_OF_MEMORY MLK_CONFIG_CUSTOM_ALLOC_FREE was used and
376
382
  * MLK_CUSTOM_ALLOC returned NULL.
377
383
  */
384
+ #if !defined(MLK_CONFIG_NO_ENCAPS_API)
378
385
  MLK_API_QUALIFIER
379
386
  MLK_API_MUST_CHECK_RETURN_VALUE
380
387
  int MLK_API_NAMESPACE(check_pk)(
@@ -384,6 +391,7 @@ int MLK_API_NAMESPACE(check_pk)(
384
391
  MLK_CONFIG_CONTEXT_PARAMETER_TYPE context
385
392
  #endif
386
393
  );
394
+ #endif /* !MLK_CONFIG_NO_ENCAPS_API */
387
395
 
388
396
  /**
389
397
  * Implements public key hash check mandated by FIPS 203, i.e., ensures that
@@ -402,6 +410,7 @@ int MLK_API_NAMESPACE(check_pk)(
402
410
  * @retval MLK_ERR_OUT_OF_MEMORY MLK_CONFIG_CUSTOM_ALLOC_FREE was used and
403
411
  * MLK_CUSTOM_ALLOC returned NULL.
404
412
  */
413
+ #if !defined(MLK_CONFIG_NO_DECAPS_API)
405
414
  MLK_API_QUALIFIER
406
415
  MLK_API_MUST_CHECK_RETURN_VALUE
407
416
  int MLK_API_NAMESPACE(check_sk)(
@@ -411,6 +420,7 @@ int MLK_API_NAMESPACE(check_sk)(
411
420
  MLK_CONFIG_CONTEXT_PARAMETER_TYPE context
412
421
  #endif
413
422
  );
423
+ #endif /* !MLK_CONFIG_NO_DECAPS_API */
414
424
 
415
425
  #ifdef __cplusplus
416
426
  }
@@ -427,13 +437,23 @@ int MLK_API_NAMESPACE(check_sk)(
427
437
  #define CRYPTO_SYMBYTES MLKEM_SYMBYTES
428
438
  #define CRYPTO_BYTES MLKEM_BYTES
429
439
 
440
+ #if !defined(MLK_CONFIG_NO_KEYPAIR_API)
430
441
  #define crypto_kem_keypair_derand MLK_API_NAMESPACE(keypair_derand)
442
+ #if !defined(MLK_CONFIG_NO_RANDOMIZED_API)
431
443
  #define crypto_kem_keypair MLK_API_NAMESPACE(keypair)
444
+ #endif
445
+ #endif /* !MLK_CONFIG_NO_KEYPAIR_API */
446
+ #if !defined(MLK_CONFIG_NO_ENCAPS_API)
432
447
  #define crypto_kem_enc_derand MLK_API_NAMESPACE(enc_derand)
448
+ #if !defined(MLK_CONFIG_NO_RANDOMIZED_API)
433
449
  #define crypto_kem_enc MLK_API_NAMESPACE(enc)
434
- #define crypto_kem_dec MLK_API_NAMESPACE(dec)
450
+ #endif
435
451
  #define crypto_kem_check_pk MLK_API_NAMESPACE(check_pk)
452
+ #endif /* !MLK_CONFIG_NO_ENCAPS_API */
453
+ #if !defined(MLK_CONFIG_NO_DECAPS_API)
454
+ #define crypto_kem_dec MLK_API_NAMESPACE(dec)
436
455
  #define crypto_kem_check_sk MLK_API_NAMESPACE(check_sk)
456
+ #endif
437
457
 
438
458
  #else /* !MLK_CONFIG_API_NO_SUPERCOP */
439
459