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 +4 -4
- data/.github/workflows/ci.yml +1 -1
- data/CHANGELOG.md +19 -0
- data/GET_STARTED.md +5 -1
- data/README.md +3 -1
- data/ext/pqcrypto/extconf.rb +7 -0
- data/ext/pqcrypto/pqcrypto_ruby_secure.c +30 -22
- data/ext/pqcrypto/pqcrypto_version.h +1 -1
- data/lib/pq_crypto/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: '0911b99fec80d68a6dff827829bbd77a28951d70c4a85f4fc68bc8c03bdffdda'
|
|
4
|
+
data.tar.gz: fb7f9e92387316b6641b191dc1d1f5c469f5297d866301a21d44d4eb789185e6
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 0a614e2b3a645332a3543062efd754421a4a002f08b7b2b71463ee2817f5008a14e65745c66d0c24b5b11a1ecb020f4fe9d479ff59676ddf770186d8d286e26a
|
|
7
|
+
data.tar.gz: ef7bd96e717b4a99b74346dfd2c98c4787bc3b09b3a1199acfe01b0a22ea2f26cfd594499f3948241abf207dab9d5602f21aaa0a21c66742710637ce53f1a07f
|
data/.github/workflows/ci.yml
CHANGED
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
|
|
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.
|
|
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`
|
data/ext/pqcrypto/extconf.rb
CHANGED
|
@@ -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
|
|
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;
|
|
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;
|
|
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 =
|
|
276
|
-
|
|
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
|
-
|
|
283
|
-
|
|
284
|
-
|
|
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
|
-
|
|
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,
|
|
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,
|
|
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 =
|
|
1432
|
-
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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);
|
data/lib/pq_crypto/version.rb
CHANGED
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.
|
|
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.
|
|
338
|
+
version: '3.1'
|
|
339
339
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
340
340
|
requirements:
|
|
341
341
|
- - ">="
|