pq_crypto 0.5.2 → 0.5.3

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2274795113da1599b664af11b1393a86d68f1886f3536e0a65385b04b8ce03fe
4
- data.tar.gz: 386fe1093ba0b28a910195a40d7698e0cef91f9f57fc90b3a1aaac3eec4451a5
3
+ metadata.gz: '0911b99fec80d68a6dff827829bbd77a28951d70c4a85f4fc68bc8c03bdffdda'
4
+ data.tar.gz: fb7f9e92387316b6641b191dc1d1f5c469f5297d866301a21d44d4eb789185e6
5
5
  SHA512:
6
- metadata.gz: f9f73a9d575d9931020e1674f96adafe08816a1f7183b0b948194fcd2fb4da106afb854525ef544409b47bde34c987ac0eae6ce54440b7562f70faf5807446c3
7
- data.tar.gz: c5e54b45ab8461bd1edd2b3e4e14f0092267232bc3bf1436841488fa7a604fdf66056dfd160767ec2d47b0a4afe37cb660a46a54466677994a3c1d73269959d1
6
+ metadata.gz: 0a614e2b3a645332a3543062efd754421a4a002f08b7b2b71463ee2817f5008a14e65745c66d0c24b5b11a1ecb020f4fe9d479ff59676ddf770186d8d286e26a
7
+ data.tar.gz: ef7bd96e717b4a99b74346dfd2c98c4787bc3b09b3a1199acfe01b0a22ea2f26cfd594499f3948241abf207dab9d5602f21aaa0a21c66742710637ce53f1a07f
@@ -31,7 +31,7 @@ jobs:
31
31
  fail-fast: false
32
32
  matrix:
33
33
  os: [ubuntu-latest, macos-latest]
34
- ruby: ["3.4", "4.0"]
34
+ ruby: ["3.1", "3.4", "4.0"]
35
35
 
36
36
  steps:
37
37
  - name: Checkout
data/CHANGELOG.md CHANGED
@@ -1,5 +1,24 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.5.3] - 2026-05-08
4
+
5
+ ### Compatibility
6
+
7
+ - Lowered the minimum supported Ruby version from `>= 3.4.0` to `>= 3.1`.
8
+ - Kept the Ruby 3.4+ optimized `rb_nogvl(..., RB_NOGVL_OFFLOAD_SAFE)` path intact.
9
+ - Added explicit native build probes for `ruby/thread.h`, `rb_thread_call_without_gvl`, and `rb_nogvl`.
10
+ - Ruby 3.1-3.3 now build the same selected `rb_nogvl` calls with a local `PQ_RB_NOGVL_OFFLOAD_SAFE` fallback of `0`, preserving ordinary no-GVL behavior without claiming scheduler offload guarantees.
11
+
12
+ ### CI
13
+
14
+ - Added Ruby 3.1-3.3 compatibility coverage as compile + smoke checks while keeping full test coverage on Ruby 3.4 and 4.0.
15
+ - Scoped the strict Async/Fiber Scheduler integration assertion to Ruby 3.4+ so compatibility runtimes do not claim `RB_NOGVL_OFFLOAD_SAFE` behavior.
16
+ - Pinned the test-only `async` dependency to the Ruby 3.1-compatible `2.21.x` line, which still contains the worker-pool support needed for the Ruby 3.4+ offload test.
17
+
18
+ ### Documentation
19
+
20
+ - Documented the Ruby 3.1+ support policy and the difference between compatibility no-GVL behavior and Ruby 3.4+ scheduler-aware offload.
21
+
3
22
  ## [0.5.2] - 2026-05-06
4
23
 
5
24
  ### Build
data/GET_STARTED.md CHANGED
@@ -379,11 +379,15 @@ PQCRYPTO_NATIVE_ASM=1 bundle exec rake compile
379
379
 
380
380
  ## 14. Async / Fiber scheduler behavior
381
381
 
382
- On Ruby 3.4, signing and verification use Ruby's scheduler-aware
382
+ On Ruby 3.4 and later, signing and verification keep Ruby's scheduler-aware
383
383
  `rb_nogvl(..., RB_NOGVL_OFFLOAD_SAFE)` path automatically. With a scheduler
384
384
  that implements `blocking_operation_wait`, blocking native work can be moved
385
385
  off the event loop.
386
386
 
387
+ Ruby 3.1-3.3 are supported as a compatibility path: native operations still
388
+ release the GVL, but `RB_NOGVL_OFFLOAD_SAFE` is not available there, so the gem
389
+ does not claim Fiber Scheduler offload guarantees on those runtimes.
390
+
387
391
  ## 15. Test-only deterministic helpers
388
392
 
389
393
  `PQCrypto::Testing` exposes deterministic helpers for regression tests:
data/README.md CHANGED
@@ -63,7 +63,9 @@ original algorithms:
63
63
 
64
64
  ## Requirements
65
65
 
66
- - Ruby 3.4 or later
66
+ - Ruby 3.1 or later
67
+ - Ruby 3.4+ keeps the optimized Fiber Scheduler offload path via `RB_NOGVL_OFFLOAD_SAFE`
68
+ - Ruby 3.1-3.3 use the compatibility no-GVL path without scheduler offload guarantees
67
69
  - a C toolchain with C11 support
68
70
  - OpenSSL 3.0 or later with SHA3-256 and SHAKE256 available
69
71
  - vendored minimal PQ Code Package native snapshot in `ext/pqcrypto/vendor`
@@ -187,6 +187,12 @@ def find_vendor_dir
187
187
  candidates.find { |path| native_vendor_ready?(path) }
188
188
  end
189
189
 
190
+ def configure_ruby_c_api!
191
+ abort "ruby/thread.h is required" unless have_header("ruby/thread.h")
192
+ abort "rb_thread_call_without_gvl is required" unless have_func("rb_thread_call_without_gvl", "ruby/thread.h")
193
+ abort "rb_nogvl is required" unless have_func("rb_nogvl", "ruby/thread.h")
194
+ end
195
+
190
196
  def configure_openssl!
191
197
  configure_compiler_environment
192
198
 
@@ -349,6 +355,7 @@ vendor_dir = find_vendor_dir
349
355
 
350
356
  puts
351
357
  puts "=== PQCrypto build configuration ==="
358
+ configure_ruby_c_api!
352
359
  configure_openssl!
353
360
  native_config = native_vendor_config(vendor_dir)
354
361
  puts "OpenSSL: system"
@@ -1,6 +1,13 @@
1
+ #if defined(__clang__) || defined(__GNUC__)
2
+ #pragma GCC diagnostic push
3
+ #pragma GCC diagnostic ignored "-Wunused-parameter"
4
+ #endif
1
5
  #include <ruby.h>
2
6
  #include <ruby/thread.h>
3
7
  #include <ruby/encoding.h>
8
+ #if defined(__clang__) || defined(__GNUC__)
9
+ #pragma GCC diagnostic pop
10
+ #endif
4
11
  #include <stdlib.h>
5
12
  #include <string.h>
6
13
 
@@ -10,7 +17,9 @@
10
17
  #include "pqcrypto_secure.h"
11
18
 
12
19
  #ifndef RB_NOGVL_OFFLOAD_SAFE
13
- #define RB_NOGVL_OFFLOAD_SAFE 0
20
+ #define PQ_RB_NOGVL_OFFLOAD_SAFE 0
21
+ #else
22
+ #define PQ_RB_NOGVL_OFFLOAD_SAFE RB_NOGVL_OFFLOAD_SAFE
14
23
  #endif
15
24
 
16
25
  #define PQ_MU_ABSORB_NOGVL_MIN_BYTES 16384
@@ -154,8 +163,8 @@ static void pq_init_algorithm_ids(void) {
154
163
  static const char *pq_algorithm_symbol_to_cstr(VALUE algorithm) {
155
164
  if (SYMBOL_P(algorithm)) {
156
165
  ID id = SYM2ID(algorithm);
157
- for (size_t i = 0; i < sizeof(PQC_CONTAINER_ALGORITHMS) / sizeof(PQC_CONTAINER_ALGORITHMS[0]);
158
- ++i) {
166
+ for (size_t i = 0;
167
+ i < sizeof(PQC_CONTAINER_ALGORITHMS) / sizeof(PQC_CONTAINER_ALGORITHMS[0]); ++i) {
159
168
  if (id == pqc_container_algorithm_ids[i]) {
160
169
  return PQC_CONTAINER_ALGORITHMS[i];
161
170
  }
@@ -164,8 +173,8 @@ static const char *pq_algorithm_symbol_to_cstr(VALUE algorithm) {
164
173
  VALUE str = StringValue(algorithm);
165
174
  const char *ptr = RSTRING_PTR(str);
166
175
  size_t len = (size_t)RSTRING_LEN(str);
167
- for (size_t i = 0; i < sizeof(PQC_CONTAINER_ALGORITHMS) / sizeof(PQC_CONTAINER_ALGORITHMS[0]);
168
- ++i) {
176
+ for (size_t i = 0;
177
+ i < sizeof(PQC_CONTAINER_ALGORITHMS) / sizeof(PQC_CONTAINER_ALGORITHMS[0]); ++i) {
169
178
  size_t algorithm_len = strlen(PQC_CONTAINER_ALGORITHMS[i]);
170
179
  if (len == algorithm_len && memcmp(ptr, PQC_CONTAINER_ALGORITHMS[i], len) == 0) {
171
180
  return PQC_CONTAINER_ALGORITHMS[i];
@@ -272,16 +281,16 @@ static void *pq_hybrid_kem_decapsulate_nogvl(void *arg) {
272
281
 
273
282
  static void *pq_hybrid_kem_decapsulate_expanded_nogvl(void *arg) {
274
283
  kem_decapsulate_call_t *call = (kem_decapsulate_call_t *)arg;
275
- call->result = pq_hybrid_kem_decapsulate_expanded(call->shared_secret, call->ciphertext,
276
- call->secret_key);
284
+ call->result =
285
+ pq_hybrid_kem_decapsulate_expanded(call->shared_secret, call->ciphertext, call->secret_key);
277
286
  return NULL;
278
287
  }
279
288
 
280
289
  static void *pq_hybrid_kem_decapsulate_expanded_pkey_nogvl(void *arg) {
281
- hybrid_decapsulate_expanded_pkey_call_t *call =
282
- (hybrid_decapsulate_expanded_pkey_call_t *)arg;
283
- call->result = pq_hybrid_kem_decapsulate_expanded_pkey(
284
- call->shared_secret, call->ciphertext, call->expanded_secret_key, call->x25519_private_pkey);
290
+ hybrid_decapsulate_expanded_pkey_call_t *call = (hybrid_decapsulate_expanded_pkey_call_t *)arg;
291
+ call->result = pq_hybrid_kem_decapsulate_expanded_pkey(call->shared_secret, call->ciphertext,
292
+ call->expanded_secret_key,
293
+ call->x25519_private_pkey);
285
294
  return NULL;
286
295
  }
287
296
 
@@ -815,12 +824,11 @@ static VALUE pqcrypto_hybrid_kem_decapsulate_expanded(VALUE self, VALUE cipherte
815
824
  (void)self;
816
825
  return pq_run_kem_decapsulate(pq_hybrid_kem_decapsulate_expanded_nogvl, ciphertext,
817
826
  PQ_HYBRID_CIPHERTEXTBYTES, expanded_secret_key,
818
- PQ_HYBRID_EXPANDED_SECRETKEYBYTES,
819
- PQ_HYBRID_SHAREDSECRETBYTES);
827
+ PQ_HYBRID_EXPANDED_SECRETKEYBYTES, PQ_HYBRID_SHAREDSECRETBYTES);
820
828
  }
821
829
 
822
830
  static VALUE pqcrypto_hybrid_kem_decapsulate_expanded_object(VALUE self, VALUE ciphertext,
823
- VALUE expanded_secret_key_obj) {
831
+ VALUE expanded_secret_key_obj) {
824
832
  (void)self;
825
833
  hybrid_expanded_key_wrapper_t *wrapper = hybrid_expanded_key_unwrap(expanded_secret_key_obj);
826
834
  hybrid_decapsulate_expanded_pkey_call_t call = {0};
@@ -1184,7 +1192,7 @@ static VALUE pq_run_sign(void *(*nogvl)(void *), VALUE message, VALUE secret_key
1184
1192
  call.signature = pq_alloc_buffer(signature_len_expected);
1185
1193
  call.message = pq_copy_ruby_string(message, &call.message_len);
1186
1194
 
1187
- rb_nogvl(nogvl, &call, NULL, NULL, RB_NOGVL_OFFLOAD_SAFE);
1195
+ rb_nogvl(nogvl, &call, NULL, NULL, PQ_RB_NOGVL_OFFLOAD_SAFE);
1188
1196
 
1189
1197
  pq_free_buffer(call.message);
1190
1198
  pq_wipe_and_free((uint8_t *)call.secret_key, secret_key_len);
@@ -1224,7 +1232,7 @@ static VALUE pq_run_verify(void *(*nogvl)(void *), VALUE message, VALUE signatur
1224
1232
  call.signature_len = signature_len;
1225
1233
  call.message = pq_copy_ruby_string(message, &call.message_len);
1226
1234
 
1227
- rb_nogvl(nogvl, &call, NULL, NULL, RB_NOGVL_OFFLOAD_SAFE);
1235
+ rb_nogvl(nogvl, &call, NULL, NULL, PQ_RB_NOGVL_OFFLOAD_SAFE);
1228
1236
 
1229
1237
  pq_free_buffer(call.message);
1230
1238
  pq_free_buffer((uint8_t *)call.public_key);
@@ -1428,8 +1436,8 @@ static VALUE pqcrypto__native_mldsa_mu_builder_update(VALUE self, VALUE builder_
1428
1436
  }
1429
1437
 
1430
1438
  if (chunk_len < PQ_MU_ABSORB_NOGVL_MIN_BYTES) {
1431
- int rc = pq_mu_builder_absorb(wrapper->builder, (const uint8_t *)RSTRING_PTR(chunk),
1432
- chunk_len);
1439
+ int rc =
1440
+ pq_mu_builder_absorb(wrapper->builder, (const uint8_t *)RSTRING_PTR(chunk), chunk_len);
1433
1441
  if (rc != PQ_SUCCESS) {
1434
1442
  pq_raise_general_error(rc);
1435
1443
  }
@@ -1444,7 +1452,7 @@ static VALUE pqcrypto__native_mldsa_mu_builder_update(VALUE self, VALUE builder_
1444
1452
  call.chunk = copy;
1445
1453
  call.chunk_len = chunk_len;
1446
1454
 
1447
- rb_nogvl(pq_mu_absorb_nogvl, &call, NULL, NULL, RB_NOGVL_OFFLOAD_SAFE);
1455
+ rb_nogvl(pq_mu_absorb_nogvl, &call, NULL, NULL, PQ_RB_NOGVL_OFFLOAD_SAFE);
1448
1456
  free(copy);
1449
1457
 
1450
1458
  if (call.result != PQ_SUCCESS) {
@@ -1469,7 +1477,7 @@ static VALUE pqcrypto__native_mldsa_mu_builder_finalize(VALUE self, VALUE builde
1469
1477
  call.builder = wrapper->builder;
1470
1478
  call.mu_out = mu;
1471
1479
 
1472
- rb_nogvl(pq_mu_finalize_nogvl, &call, NULL, NULL, RB_NOGVL_OFFLOAD_SAFE);
1480
+ rb_nogvl(pq_mu_finalize_nogvl, &call, NULL, NULL, PQ_RB_NOGVL_OFFLOAD_SAFE);
1473
1481
 
1474
1482
  wrapper->builder = NULL;
1475
1483
 
@@ -1516,7 +1524,7 @@ static VALUE pqcrypto__native_mldsa_sign_mu(VALUE self, VALUE mu, VALUE secret_k
1516
1524
  call.signature_len = PQ_MLDSA_BYTES;
1517
1525
  call.signature = pq_alloc_buffer(PQ_MLDSA_BYTES);
1518
1526
 
1519
- rb_nogvl(pq_sign_mu_nogvl, &call, NULL, NULL, RB_NOGVL_OFFLOAD_SAFE);
1527
+ rb_nogvl(pq_sign_mu_nogvl, &call, NULL, NULL, PQ_RB_NOGVL_OFFLOAD_SAFE);
1520
1528
 
1521
1529
  pq_wipe_and_free(mu_copy, mu_len);
1522
1530
  pq_wipe_and_free(sk_copy, secret_key_len);
@@ -1557,7 +1565,7 @@ static VALUE pqcrypto__native_mldsa_verify_mu(VALUE self, VALUE mu, VALUE signat
1557
1565
  call.signature = sig_copy;
1558
1566
  call.signature_len = signature_len;
1559
1567
 
1560
- rb_nogvl(pq_verify_mu_nogvl, &call, NULL, NULL, RB_NOGVL_OFFLOAD_SAFE);
1568
+ rb_nogvl(pq_verify_mu_nogvl, &call, NULL, NULL, PQ_RB_NOGVL_OFFLOAD_SAFE);
1561
1569
  pq_wipe_and_free(mu_copy, mu_len);
1562
1570
  pq_free_buffer(pk_copy);
1563
1571
  pq_free_buffer(sig_copy);
@@ -2,6 +2,6 @@
2
2
  #ifndef PQCRYPTO_VERSION_H
3
3
  #define PQCRYPTO_VERSION_H
4
4
 
5
- #define PQCRYPTO_VERSION "0.5.2"
5
+ #define PQCRYPTO_VERSION "0.5.3"
6
6
 
7
7
  #endif
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module PQCrypto
4
- VERSION = "0.5.2"
4
+ VERSION = "0.5.3"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pq_crypto
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.2
4
+ version: 0.5.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Roman Haydarov
@@ -335,7 +335,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
335
335
  requirements:
336
336
  - - ">="
337
337
  - !ruby/object:Gem::Version
338
- version: 3.4.0
338
+ version: '3.1'
339
339
  required_rubygems_version: !ruby/object:Gem::Requirement
340
340
  requirements:
341
341
  - - ">="