pq_crypto 0.5.2 → 0.6.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 +1 -1
- data/CHANGELOG.md +30 -0
- data/GET_STARTED.md +75 -10
- data/README.md +14 -7
- data/ext/pqcrypto/extconf.rb +7 -0
- data/ext/pqcrypto/pq_externalmu.c +23 -18
- data/ext/pqcrypto/pqcrypto_native_api.h +10 -0
- data/ext/pqcrypto/pqcrypto_ruby_secure.c +242 -70
- data/ext/pqcrypto/pqcrypto_secure.c +83 -84
- data/ext/pqcrypto/pqcrypto_secure.h +15 -10
- data/ext/pqcrypto/pqcrypto_version.h +1 -1
- data/lib/pq_crypto/hybrid_kem.rb +1 -0
- data/lib/pq_crypto/kem.rb +71 -29
- data/lib/pq_crypto/key.rb +90 -0
- data/lib/pq_crypto/pkcs8.rb +184 -10
- data/lib/pq_crypto/signature.rb +74 -37
- data/lib/pq_crypto/version.rb +1 -1
- data/lib/pq_crypto.rb +6 -4
- metadata +8 -4
|
@@ -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
|
|
@@ -72,6 +81,8 @@ typedef struct {
|
|
|
72
81
|
size_t signature_len;
|
|
73
82
|
uint8_t *message;
|
|
74
83
|
size_t message_len;
|
|
84
|
+
uint8_t *context;
|
|
85
|
+
size_t context_len;
|
|
75
86
|
const uint8_t *secret_key;
|
|
76
87
|
const uint8_t *seed;
|
|
77
88
|
size_t seed_len;
|
|
@@ -83,6 +94,8 @@ typedef struct {
|
|
|
83
94
|
size_t signature_len;
|
|
84
95
|
uint8_t *message;
|
|
85
96
|
size_t message_len;
|
|
97
|
+
uint8_t *context;
|
|
98
|
+
size_t context_len;
|
|
86
99
|
const uint8_t *public_key;
|
|
87
100
|
} verify_call_t;
|
|
88
101
|
|
|
@@ -144,6 +157,52 @@ static const char *const PQC_CONTAINER_ALGORITHMS[] = {
|
|
|
144
157
|
static ID pqc_container_algorithm_ids[sizeof(PQC_CONTAINER_ALGORITHMS) /
|
|
145
158
|
sizeof(PQC_CONTAINER_ALGORITHMS[0])];
|
|
146
159
|
|
|
160
|
+
typedef int (*pq_mldsa_pk_from_sk_fn)(uint8_t *, const uint8_t *);
|
|
161
|
+
typedef int (*pq_mldsa_signature_extmu_fn)(uint8_t *, size_t *, const uint8_t *, const uint8_t *);
|
|
162
|
+
typedef int (*pq_mldsa_verify_extmu_fn)(const uint8_t *, size_t, const uint8_t *, const uint8_t *);
|
|
163
|
+
|
|
164
|
+
typedef struct {
|
|
165
|
+
const char *name;
|
|
166
|
+
size_t public_key_len;
|
|
167
|
+
size_t secret_key_len;
|
|
168
|
+
size_t signature_len;
|
|
169
|
+
pq_mldsa_pk_from_sk_fn pk_from_sk;
|
|
170
|
+
pq_mldsa_signature_extmu_fn signature_extmu;
|
|
171
|
+
pq_mldsa_verify_extmu_fn verify_extmu;
|
|
172
|
+
} pq_mldsa_profile_t;
|
|
173
|
+
|
|
174
|
+
static const pq_mldsa_profile_t MLDSA_PROFILES[] = {
|
|
175
|
+
{"ml_dsa_44", MLDSA44_PUBLICKEYBYTES, MLDSA44_SECRETKEYBYTES, MLDSA44_BYTES,
|
|
176
|
+
pqcr_mldsa44_pk_from_sk, pqcr_mldsa44_signature_extmu, pqcr_mldsa44_verify_extmu},
|
|
177
|
+
{"ml_dsa_65", MLDSA65_PUBLICKEYBYTES, MLDSA65_SECRETKEYBYTES, MLDSA65_BYTES,
|
|
178
|
+
pqcr_mldsa65_pk_from_sk, pqcr_mldsa65_signature_extmu, pqcr_mldsa65_verify_extmu},
|
|
179
|
+
{"ml_dsa_87", MLDSA87_PUBLICKEYBYTES, MLDSA87_SECRETKEYBYTES, MLDSA87_BYTES,
|
|
180
|
+
pqcr_mldsa87_pk_from_sk, pqcr_mldsa87_signature_extmu, pqcr_mldsa87_verify_extmu},
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
static const pq_mldsa_profile_t *pq_mldsa_profile_from_value(VALUE algorithm) {
|
|
184
|
+
ID id;
|
|
185
|
+
const char *name;
|
|
186
|
+
|
|
187
|
+
if (!SYMBOL_P(algorithm)) {
|
|
188
|
+
rb_raise(rb_eArgError, "ML-DSA algorithm must be a Symbol");
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
id = SYM2ID(algorithm);
|
|
192
|
+
name = rb_id2name(id);
|
|
193
|
+
if (!name) {
|
|
194
|
+
rb_raise(rb_eArgError, "Invalid ML-DSA algorithm symbol");
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
for (size_t i = 0; i < sizeof(MLDSA_PROFILES) / sizeof(MLDSA_PROFILES[0]); ++i) {
|
|
198
|
+
if (strcmp(name, MLDSA_PROFILES[i].name) == 0) {
|
|
199
|
+
return &MLDSA_PROFILES[i];
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
rb_raise(ePQCryptoError, "Unsupported ML-DSA algorithm: %s", name);
|
|
204
|
+
}
|
|
205
|
+
|
|
147
206
|
static void pq_init_algorithm_ids(void) {
|
|
148
207
|
for (size_t i = 0; i < sizeof(PQC_CONTAINER_ALGORITHMS) / sizeof(PQC_CONTAINER_ALGORITHMS[0]);
|
|
149
208
|
++i) {
|
|
@@ -154,8 +213,8 @@ static void pq_init_algorithm_ids(void) {
|
|
|
154
213
|
static const char *pq_algorithm_symbol_to_cstr(VALUE algorithm) {
|
|
155
214
|
if (SYMBOL_P(algorithm)) {
|
|
156
215
|
ID id = SYM2ID(algorithm);
|
|
157
|
-
for (size_t i = 0;
|
|
158
|
-
++i) {
|
|
216
|
+
for (size_t i = 0;
|
|
217
|
+
i < sizeof(PQC_CONTAINER_ALGORITHMS) / sizeof(PQC_CONTAINER_ALGORITHMS[0]); ++i) {
|
|
159
218
|
if (id == pqc_container_algorithm_ids[i]) {
|
|
160
219
|
return PQC_CONTAINER_ALGORITHMS[i];
|
|
161
220
|
}
|
|
@@ -164,8 +223,8 @@ static const char *pq_algorithm_symbol_to_cstr(VALUE algorithm) {
|
|
|
164
223
|
VALUE str = StringValue(algorithm);
|
|
165
224
|
const char *ptr = RSTRING_PTR(str);
|
|
166
225
|
size_t len = (size_t)RSTRING_LEN(str);
|
|
167
|
-
for (size_t i = 0;
|
|
168
|
-
++i) {
|
|
226
|
+
for (size_t i = 0;
|
|
227
|
+
i < sizeof(PQC_CONTAINER_ALGORITHMS) / sizeof(PQC_CONTAINER_ALGORITHMS[0]); ++i) {
|
|
169
228
|
size_t algorithm_len = strlen(PQC_CONTAINER_ALGORITHMS[i]);
|
|
170
229
|
if (len == algorithm_len && memcmp(ptr, PQC_CONTAINER_ALGORITHMS[i], len) == 0) {
|
|
171
230
|
return PQC_CONTAINER_ALGORITHMS[i];
|
|
@@ -272,16 +331,16 @@ static void *pq_hybrid_kem_decapsulate_nogvl(void *arg) {
|
|
|
272
331
|
|
|
273
332
|
static void *pq_hybrid_kem_decapsulate_expanded_nogvl(void *arg) {
|
|
274
333
|
kem_decapsulate_call_t *call = (kem_decapsulate_call_t *)arg;
|
|
275
|
-
call->result =
|
|
276
|
-
|
|
334
|
+
call->result =
|
|
335
|
+
pq_hybrid_kem_decapsulate_expanded(call->shared_secret, call->ciphertext, call->secret_key);
|
|
277
336
|
return NULL;
|
|
278
337
|
}
|
|
279
338
|
|
|
280
339
|
static void *pq_hybrid_kem_decapsulate_expanded_pkey_nogvl(void *arg) {
|
|
281
|
-
hybrid_decapsulate_expanded_pkey_call_t *call =
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
340
|
+
hybrid_decapsulate_expanded_pkey_call_t *call = (hybrid_decapsulate_expanded_pkey_call_t *)arg;
|
|
341
|
+
call->result = pq_hybrid_kem_decapsulate_expanded_pkey(call->shared_secret, call->ciphertext,
|
|
342
|
+
call->expanded_secret_key,
|
|
343
|
+
call->x25519_private_pkey);
|
|
285
344
|
return NULL;
|
|
286
345
|
}
|
|
287
346
|
|
|
@@ -311,12 +370,13 @@ PQ_DEFINE_SIGN_KEYPAIR_FROM_SEED_NOGVL(mldsa_87_keypair_from_seed, pq_mldsa87_ke
|
|
|
311
370
|
|
|
312
371
|
#undef PQ_DEFINE_SIGN_KEYPAIR_FROM_SEED_NOGVL
|
|
313
372
|
|
|
314
|
-
#define PQ_DEFINE_SIGN_NOGVL(rb_name, c_call)
|
|
315
|
-
static void *pq_##rb_name##_nogvl(void *arg) {
|
|
316
|
-
sign_call_t *call = (sign_call_t *)arg;
|
|
317
|
-
call->result =
|
|
318
|
-
|
|
319
|
-
|
|
373
|
+
#define PQ_DEFINE_SIGN_NOGVL(rb_name, c_call) \
|
|
374
|
+
static void *pq_##rb_name##_nogvl(void *arg) { \
|
|
375
|
+
sign_call_t *call = (sign_call_t *)arg; \
|
|
376
|
+
call->result = \
|
|
377
|
+
c_call(call->signature, &call->signature_len, call->message, call->message_len, \
|
|
378
|
+
call->context, call->context_len, call->secret_key); \
|
|
379
|
+
return NULL; \
|
|
320
380
|
}
|
|
321
381
|
|
|
322
382
|
PQ_DEFINE_SIGN_NOGVL(sign, pq_sign)
|
|
@@ -364,12 +424,13 @@ PQ_DEFINE_TESTING_SIGN_FROM_SEED(mldsa_87, pq_testing_mldsa87_sign_from_seed)
|
|
|
364
424
|
#undef PQ_DEFINE_TESTING_KEYPAIR_FROM_SEED
|
|
365
425
|
#undef PQ_DEFINE_TESTING_SIGN_FROM_SEED
|
|
366
426
|
|
|
367
|
-
#define PQ_DEFINE_VERIFY_NOGVL(rb_name, c_call)
|
|
368
|
-
static void *pq_##rb_name##_nogvl(void *arg) {
|
|
369
|
-
verify_call_t *call = (verify_call_t *)arg;
|
|
370
|
-
call->result =
|
|
371
|
-
|
|
372
|
-
|
|
427
|
+
#define PQ_DEFINE_VERIFY_NOGVL(rb_name, c_call) \
|
|
428
|
+
static void *pq_##rb_name##_nogvl(void *arg) { \
|
|
429
|
+
verify_call_t *call = (verify_call_t *)arg; \
|
|
430
|
+
call->result = \
|
|
431
|
+
c_call(call->signature, call->signature_len, call->message, call->message_len, \
|
|
432
|
+
call->context, call->context_len, call->public_key); \
|
|
433
|
+
return NULL; \
|
|
373
434
|
}
|
|
374
435
|
|
|
375
436
|
PQ_DEFINE_VERIFY_NOGVL(verify, pq_verify)
|
|
@@ -803,6 +864,26 @@ static VALUE pqcrypto_hybrid_kem_expand_secret_key_object(VALUE self, VALUE secr
|
|
|
803
864
|
return obj;
|
|
804
865
|
}
|
|
805
866
|
|
|
867
|
+
static VALUE pqcrypto_hybrid_kem_expanded_secret_key_wipe(VALUE self,
|
|
868
|
+
VALUE expanded_secret_key_obj) {
|
|
869
|
+
(void)self;
|
|
870
|
+
hybrid_expanded_key_wrapper_t *wrapper;
|
|
871
|
+
|
|
872
|
+
TypedData_Get_Struct(expanded_secret_key_obj, hybrid_expanded_key_wrapper_t,
|
|
873
|
+
&hybrid_expanded_key_data_type, wrapper);
|
|
874
|
+
if (!wrapper) {
|
|
875
|
+
return Qnil;
|
|
876
|
+
}
|
|
877
|
+
|
|
878
|
+
pq_secure_wipe(wrapper->expanded_secret_key, sizeof(wrapper->expanded_secret_key));
|
|
879
|
+
if (wrapper->x25519_private_pkey) {
|
|
880
|
+
EVP_PKEY_free(wrapper->x25519_private_pkey);
|
|
881
|
+
wrapper->x25519_private_pkey = NULL;
|
|
882
|
+
}
|
|
883
|
+
|
|
884
|
+
return Qnil;
|
|
885
|
+
}
|
|
886
|
+
|
|
806
887
|
static VALUE pqcrypto_hybrid_kem_decapsulate(VALUE self, VALUE ciphertext, VALUE secret_key) {
|
|
807
888
|
(void)self;
|
|
808
889
|
return pq_run_kem_decapsulate(pq_hybrid_kem_decapsulate_nogvl, ciphertext,
|
|
@@ -815,12 +896,11 @@ static VALUE pqcrypto_hybrid_kem_decapsulate_expanded(VALUE self, VALUE cipherte
|
|
|
815
896
|
(void)self;
|
|
816
897
|
return pq_run_kem_decapsulate(pq_hybrid_kem_decapsulate_expanded_nogvl, ciphertext,
|
|
817
898
|
PQ_HYBRID_CIPHERTEXTBYTES, expanded_secret_key,
|
|
818
|
-
PQ_HYBRID_EXPANDED_SECRETKEYBYTES,
|
|
819
|
-
PQ_HYBRID_SHAREDSECRETBYTES);
|
|
899
|
+
PQ_HYBRID_EXPANDED_SECRETKEYBYTES, PQ_HYBRID_SHAREDSECRETBYTES);
|
|
820
900
|
}
|
|
821
901
|
|
|
822
902
|
static VALUE pqcrypto_hybrid_kem_decapsulate_expanded_object(VALUE self, VALUE ciphertext,
|
|
823
|
-
|
|
903
|
+
VALUE expanded_secret_key_obj) {
|
|
824
904
|
(void)self;
|
|
825
905
|
hybrid_expanded_key_wrapper_t *wrapper = hybrid_expanded_key_unwrap(expanded_secret_key_obj);
|
|
826
906
|
hybrid_decapsulate_expanded_pkey_call_t call = {0};
|
|
@@ -1173,20 +1253,28 @@ PQ_DEFINE_RUBY_MLDSA_KEYPAIR(ml_dsa_87_keypair, mldsa_87_sign_keypair, MLDSA87_P
|
|
|
1173
1253
|
|
|
1174
1254
|
#undef PQ_DEFINE_RUBY_MLDSA_KEYPAIR
|
|
1175
1255
|
|
|
1176
|
-
static VALUE pq_run_sign(void *(*nogvl)(void *), VALUE message, VALUE secret_key,
|
|
1256
|
+
static VALUE pq_run_sign(void *(*nogvl)(void *), VALUE message, VALUE secret_key, VALUE context,
|
|
1177
1257
|
size_t secret_key_len_expected, size_t signature_len_expected) {
|
|
1178
1258
|
pq_validate_bytes_argument(secret_key, secret_key_len_expected, "secret key");
|
|
1259
|
+
StringValue(context);
|
|
1260
|
+
if (RSTRING_LEN(context) > 255) {
|
|
1261
|
+
rb_raise(rb_eArgError, "ML-DSA context length must be <= 255 bytes");
|
|
1262
|
+
}
|
|
1179
1263
|
|
|
1180
1264
|
sign_call_t call = {0};
|
|
1181
1265
|
size_t secret_key_len = 0;
|
|
1266
|
+
size_t context_len = 0;
|
|
1182
1267
|
call.secret_key = pq_copy_ruby_string(secret_key, &secret_key_len);
|
|
1183
1268
|
call.signature_len = signature_len_expected;
|
|
1184
1269
|
call.signature = pq_alloc_buffer(signature_len_expected);
|
|
1185
1270
|
call.message = pq_copy_ruby_string(message, &call.message_len);
|
|
1271
|
+
call.context = pq_copy_ruby_string(context, &context_len);
|
|
1272
|
+
call.context_len = context_len;
|
|
1186
1273
|
|
|
1187
|
-
rb_nogvl(nogvl, &call, NULL, NULL,
|
|
1274
|
+
rb_nogvl(nogvl, &call, NULL, NULL, PQ_RB_NOGVL_OFFLOAD_SAFE);
|
|
1188
1275
|
|
|
1189
1276
|
pq_free_buffer(call.message);
|
|
1277
|
+
pq_free_buffer(call.context);
|
|
1190
1278
|
pq_wipe_and_free((uint8_t *)call.secret_key, secret_key_len);
|
|
1191
1279
|
|
|
1192
1280
|
if (call.result != PQ_SUCCESS) {
|
|
@@ -1199,10 +1287,16 @@ static VALUE pq_run_sign(void *(*nogvl)(void *), VALUE message, VALUE secret_key
|
|
|
1199
1287
|
return result;
|
|
1200
1288
|
}
|
|
1201
1289
|
|
|
1202
|
-
#define PQ_DEFINE_RUBY_MLDSA_SIGN(rb_name, nogvl_stem, sk_bytes, sig_bytes)
|
|
1203
|
-
static VALUE pqcrypto_##rb_name(
|
|
1204
|
-
(void)self;
|
|
1205
|
-
|
|
1290
|
+
#define PQ_DEFINE_RUBY_MLDSA_SIGN(rb_name, nogvl_stem, sk_bytes, sig_bytes) \
|
|
1291
|
+
static VALUE pqcrypto_##rb_name(int argc, VALUE *argv, VALUE self) { \
|
|
1292
|
+
(void)self; \
|
|
1293
|
+
VALUE message, secret_key, context; \
|
|
1294
|
+
rb_scan_args(argc, argv, "21", &message, &secret_key, &context); \
|
|
1295
|
+
if (NIL_P(context)) { \
|
|
1296
|
+
context = rb_str_new("", 0); \
|
|
1297
|
+
} \
|
|
1298
|
+
return pq_run_sign(pq_##nogvl_stem##_nogvl, message, secret_key, context, sk_bytes, \
|
|
1299
|
+
sig_bytes); \
|
|
1206
1300
|
}
|
|
1207
1301
|
|
|
1208
1302
|
PQ_DEFINE_RUBY_MLDSA_SIGN(sign, sign, PQ_MLDSA_SECRETKEYBYTES, PQ_MLDSA_BYTES)
|
|
@@ -1212,21 +1306,29 @@ PQ_DEFINE_RUBY_MLDSA_SIGN(ml_dsa_87_sign, mldsa_87_sign, MLDSA87_SECRETKEYBYTES,
|
|
|
1212
1306
|
#undef PQ_DEFINE_RUBY_MLDSA_SIGN
|
|
1213
1307
|
|
|
1214
1308
|
static VALUE pq_run_verify(void *(*nogvl)(void *), VALUE message, VALUE signature, VALUE public_key,
|
|
1215
|
-
size_t public_key_len_expected) {
|
|
1309
|
+
VALUE context, size_t public_key_len_expected) {
|
|
1216
1310
|
StringValue(signature);
|
|
1217
1311
|
pq_validate_bytes_argument(public_key, public_key_len_expected, "public key");
|
|
1312
|
+
StringValue(context);
|
|
1313
|
+
if (RSTRING_LEN(context) > 255) {
|
|
1314
|
+
rb_raise(rb_eArgError, "ML-DSA context length must be <= 255 bytes");
|
|
1315
|
+
}
|
|
1218
1316
|
|
|
1219
1317
|
verify_call_t call = {0};
|
|
1220
1318
|
size_t public_key_len = 0;
|
|
1221
1319
|
size_t signature_len = 0;
|
|
1320
|
+
size_t context_len = 0;
|
|
1222
1321
|
call.public_key = pq_copy_ruby_string(public_key, &public_key_len);
|
|
1223
1322
|
call.signature = pq_copy_ruby_string(signature, &signature_len);
|
|
1224
1323
|
call.signature_len = signature_len;
|
|
1225
1324
|
call.message = pq_copy_ruby_string(message, &call.message_len);
|
|
1325
|
+
call.context = pq_copy_ruby_string(context, &context_len);
|
|
1326
|
+
call.context_len = context_len;
|
|
1226
1327
|
|
|
1227
|
-
rb_nogvl(nogvl, &call, NULL, NULL,
|
|
1328
|
+
rb_nogvl(nogvl, &call, NULL, NULL, PQ_RB_NOGVL_OFFLOAD_SAFE);
|
|
1228
1329
|
|
|
1229
1330
|
pq_free_buffer(call.message);
|
|
1331
|
+
pq_free_buffer(call.context);
|
|
1230
1332
|
pq_free_buffer((uint8_t *)call.public_key);
|
|
1231
1333
|
pq_free_buffer((uint8_t *)call.signature);
|
|
1232
1334
|
|
|
@@ -1239,11 +1341,16 @@ static VALUE pq_run_verify(void *(*nogvl)(void *), VALUE message, VALUE signatur
|
|
|
1239
1341
|
pq_raise_general_error(call.result);
|
|
1240
1342
|
}
|
|
1241
1343
|
|
|
1242
|
-
#define PQ_DEFINE_RUBY_MLDSA_VERIFY(rb_name, nogvl_stem, pk_bytes)
|
|
1243
|
-
static VALUE pqcrypto_##rb_name(
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1344
|
+
#define PQ_DEFINE_RUBY_MLDSA_VERIFY(rb_name, nogvl_stem, pk_bytes) \
|
|
1345
|
+
static VALUE pqcrypto_##rb_name(int argc, VALUE *argv, VALUE self) { \
|
|
1346
|
+
(void)self; \
|
|
1347
|
+
VALUE message, signature, public_key, context; \
|
|
1348
|
+
rb_scan_args(argc, argv, "31", &message, &signature, &public_key, &context); \
|
|
1349
|
+
if (NIL_P(context)) { \
|
|
1350
|
+
context = rb_str_new("", 0); \
|
|
1351
|
+
} \
|
|
1352
|
+
return pq_run_verify(pq_##nogvl_stem##_nogvl, message, signature, public_key, context, \
|
|
1353
|
+
pk_bytes); \
|
|
1247
1354
|
}
|
|
1248
1355
|
|
|
1249
1356
|
PQ_DEFINE_RUBY_MLDSA_VERIFY(verify, verify, PQ_MLDSA_PUBLICKEYBYTES)
|
|
@@ -1304,6 +1411,7 @@ typedef struct {
|
|
|
1304
1411
|
size_t signature_len;
|
|
1305
1412
|
const uint8_t *mu;
|
|
1306
1413
|
const uint8_t *secret_key;
|
|
1414
|
+
pq_mldsa_signature_extmu_fn signature_extmu;
|
|
1307
1415
|
} sign_mu_call_t;
|
|
1308
1416
|
|
|
1309
1417
|
typedef struct {
|
|
@@ -1312,6 +1420,8 @@ typedef struct {
|
|
|
1312
1420
|
size_t signature_len;
|
|
1313
1421
|
const uint8_t *mu;
|
|
1314
1422
|
const uint8_t *public_key;
|
|
1423
|
+
size_t expected_signature_len;
|
|
1424
|
+
pq_mldsa_verify_extmu_fn verify_extmu;
|
|
1315
1425
|
} verify_mu_call_t;
|
|
1316
1426
|
|
|
1317
1427
|
static void mu_builder_wrapper_free(void *ptr) {
|
|
@@ -1355,12 +1465,25 @@ static mu_builder_wrapper_t *mu_builder_unwrap(VALUE obj) {
|
|
|
1355
1465
|
return wrapper;
|
|
1356
1466
|
}
|
|
1357
1467
|
|
|
1358
|
-
static VALUE pqcrypto__native_mldsa_extract_tr(VALUE
|
|
1468
|
+
static VALUE pqcrypto__native_mldsa_extract_tr(int argc, VALUE *argv, VALUE self) {
|
|
1359
1469
|
(void)self;
|
|
1360
|
-
|
|
1470
|
+
VALUE algorithm = ID2SYM(rb_intern("ml_dsa_65"));
|
|
1471
|
+
VALUE secret_key;
|
|
1472
|
+
if (argc == 1) {
|
|
1473
|
+
secret_key = argv[0];
|
|
1474
|
+
} else if (argc == 2) {
|
|
1475
|
+
algorithm = argv[0];
|
|
1476
|
+
secret_key = argv[1];
|
|
1477
|
+
} else {
|
|
1478
|
+
rb_raise(rb_eArgError, "wrong number of arguments (given %d, expected 1..2)", argc);
|
|
1479
|
+
}
|
|
1480
|
+
|
|
1481
|
+
const pq_mldsa_profile_t *profile = pq_mldsa_profile_from_value(algorithm);
|
|
1482
|
+
pq_validate_bytes_argument(secret_key, profile->secret_key_len, "secret key");
|
|
1361
1483
|
|
|
1362
1484
|
uint8_t tr[PQ_MLDSA_TRBYTES];
|
|
1363
|
-
int rc = pq_mldsa_extract_tr_from_secret_key(tr, (const uint8_t *)RSTRING_PTR(secret_key)
|
|
1485
|
+
int rc = pq_mldsa_extract_tr_from_secret_key(tr, (const uint8_t *)RSTRING_PTR(secret_key),
|
|
1486
|
+
profile->public_key_len, profile->pk_from_sk);
|
|
1364
1487
|
if (rc != PQ_SUCCESS) {
|
|
1365
1488
|
pq_secure_wipe(tr, sizeof(tr));
|
|
1366
1489
|
pq_raise_general_error(rc);
|
|
@@ -1370,12 +1493,25 @@ static VALUE pqcrypto__native_mldsa_extract_tr(VALUE self, VALUE secret_key) {
|
|
|
1370
1493
|
return result;
|
|
1371
1494
|
}
|
|
1372
1495
|
|
|
1373
|
-
static VALUE pqcrypto__native_mldsa_compute_tr(VALUE
|
|
1496
|
+
static VALUE pqcrypto__native_mldsa_compute_tr(int argc, VALUE *argv, VALUE self) {
|
|
1374
1497
|
(void)self;
|
|
1375
|
-
|
|
1498
|
+
VALUE algorithm = ID2SYM(rb_intern("ml_dsa_65"));
|
|
1499
|
+
VALUE public_key;
|
|
1500
|
+
if (argc == 1) {
|
|
1501
|
+
public_key = argv[0];
|
|
1502
|
+
} else if (argc == 2) {
|
|
1503
|
+
algorithm = argv[0];
|
|
1504
|
+
public_key = argv[1];
|
|
1505
|
+
} else {
|
|
1506
|
+
rb_raise(rb_eArgError, "wrong number of arguments (given %d, expected 1..2)", argc);
|
|
1507
|
+
}
|
|
1508
|
+
|
|
1509
|
+
const pq_mldsa_profile_t *profile = pq_mldsa_profile_from_value(algorithm);
|
|
1510
|
+
pq_validate_bytes_argument(public_key, profile->public_key_len, "public key");
|
|
1376
1511
|
|
|
1377
1512
|
uint8_t tr[PQ_MLDSA_TRBYTES];
|
|
1378
|
-
int rc = pq_mldsa_compute_tr_from_public_key(tr, (const uint8_t *)RSTRING_PTR(public_key)
|
|
1513
|
+
int rc = pq_mldsa_compute_tr_from_public_key(tr, (const uint8_t *)RSTRING_PTR(public_key),
|
|
1514
|
+
profile->public_key_len);
|
|
1379
1515
|
if (rc != PQ_SUCCESS) {
|
|
1380
1516
|
pq_raise_general_error(rc);
|
|
1381
1517
|
}
|
|
@@ -1428,8 +1564,8 @@ static VALUE pqcrypto__native_mldsa_mu_builder_update(VALUE self, VALUE builder_
|
|
|
1428
1564
|
}
|
|
1429
1565
|
|
|
1430
1566
|
if (chunk_len < PQ_MU_ABSORB_NOGVL_MIN_BYTES) {
|
|
1431
|
-
int rc =
|
|
1432
|
-
|
|
1567
|
+
int rc =
|
|
1568
|
+
pq_mu_builder_absorb(wrapper->builder, (const uint8_t *)RSTRING_PTR(chunk), chunk_len);
|
|
1433
1569
|
if (rc != PQ_SUCCESS) {
|
|
1434
1570
|
pq_raise_general_error(rc);
|
|
1435
1571
|
}
|
|
@@ -1444,7 +1580,7 @@ static VALUE pqcrypto__native_mldsa_mu_builder_update(VALUE self, VALUE builder_
|
|
|
1444
1580
|
call.chunk = copy;
|
|
1445
1581
|
call.chunk_len = chunk_len;
|
|
1446
1582
|
|
|
1447
|
-
rb_nogvl(pq_mu_absorb_nogvl, &call, NULL, NULL,
|
|
1583
|
+
rb_nogvl(pq_mu_absorb_nogvl, &call, NULL, NULL, PQ_RB_NOGVL_OFFLOAD_SAFE);
|
|
1448
1584
|
free(copy);
|
|
1449
1585
|
|
|
1450
1586
|
if (call.result != PQ_SUCCESS) {
|
|
@@ -1469,7 +1605,7 @@ static VALUE pqcrypto__native_mldsa_mu_builder_finalize(VALUE self, VALUE builde
|
|
|
1469
1605
|
call.builder = wrapper->builder;
|
|
1470
1606
|
call.mu_out = mu;
|
|
1471
1607
|
|
|
1472
|
-
rb_nogvl(pq_mu_finalize_nogvl, &call, NULL, NULL,
|
|
1608
|
+
rb_nogvl(pq_mu_finalize_nogvl, &call, NULL, NULL, PQ_RB_NOGVL_OFFLOAD_SAFE);
|
|
1473
1609
|
|
|
1474
1610
|
wrapper->builder = NULL;
|
|
1475
1611
|
|
|
@@ -1496,14 +1632,29 @@ static VALUE pqcrypto__native_mldsa_mu_builder_release(VALUE self, VALUE builder
|
|
|
1496
1632
|
|
|
1497
1633
|
static void *pq_sign_mu_nogvl(void *arg) {
|
|
1498
1634
|
sign_mu_call_t *call = (sign_mu_call_t *)arg;
|
|
1499
|
-
call->result = pq_sign_mu(call->signature, &call->signature_len, call->mu, call->secret_key
|
|
1635
|
+
call->result = pq_sign_mu(call->signature, &call->signature_len, call->mu, call->secret_key,
|
|
1636
|
+
call->signature_extmu);
|
|
1500
1637
|
return NULL;
|
|
1501
1638
|
}
|
|
1502
1639
|
|
|
1503
|
-
static VALUE pqcrypto__native_mldsa_sign_mu(
|
|
1640
|
+
static VALUE pqcrypto__native_mldsa_sign_mu(int argc, VALUE *argv, VALUE self) {
|
|
1504
1641
|
(void)self;
|
|
1642
|
+
VALUE algorithm = ID2SYM(rb_intern("ml_dsa_65"));
|
|
1643
|
+
VALUE mu, secret_key;
|
|
1644
|
+
if (argc == 2) {
|
|
1645
|
+
mu = argv[0];
|
|
1646
|
+
secret_key = argv[1];
|
|
1647
|
+
} else if (argc == 3) {
|
|
1648
|
+
algorithm = argv[0];
|
|
1649
|
+
mu = argv[1];
|
|
1650
|
+
secret_key = argv[2];
|
|
1651
|
+
} else {
|
|
1652
|
+
rb_raise(rb_eArgError, "wrong number of arguments (given %d, expected 2..3)", argc);
|
|
1653
|
+
}
|
|
1654
|
+
|
|
1655
|
+
const pq_mldsa_profile_t *profile = pq_mldsa_profile_from_value(algorithm);
|
|
1505
1656
|
pq_validate_bytes_argument(mu, PQ_MLDSA_MUBYTES, "mu");
|
|
1506
|
-
pq_validate_bytes_argument(secret_key,
|
|
1657
|
+
pq_validate_bytes_argument(secret_key, profile->secret_key_len, "secret key");
|
|
1507
1658
|
|
|
1508
1659
|
sign_mu_call_t call = {0};
|
|
1509
1660
|
size_t secret_key_len = 0;
|
|
@@ -1513,10 +1664,11 @@ static VALUE pqcrypto__native_mldsa_sign_mu(VALUE self, VALUE mu, VALUE secret_k
|
|
|
1513
1664
|
|
|
1514
1665
|
call.mu = mu_copy;
|
|
1515
1666
|
call.secret_key = sk_copy;
|
|
1516
|
-
call.
|
|
1517
|
-
call.
|
|
1667
|
+
call.signature_extmu = profile->signature_extmu;
|
|
1668
|
+
call.signature_len = profile->signature_len;
|
|
1669
|
+
call.signature = pq_alloc_buffer(profile->signature_len);
|
|
1518
1670
|
|
|
1519
|
-
rb_nogvl(pq_sign_mu_nogvl, &call, NULL, NULL,
|
|
1671
|
+
rb_nogvl(pq_sign_mu_nogvl, &call, NULL, NULL, PQ_RB_NOGVL_OFFLOAD_SAFE);
|
|
1520
1672
|
|
|
1521
1673
|
pq_wipe_and_free(mu_copy, mu_len);
|
|
1522
1674
|
pq_wipe_and_free(sk_copy, secret_key_len);
|
|
@@ -1533,16 +1685,32 @@ static VALUE pqcrypto__native_mldsa_sign_mu(VALUE self, VALUE mu, VALUE secret_k
|
|
|
1533
1685
|
|
|
1534
1686
|
static void *pq_verify_mu_nogvl(void *arg) {
|
|
1535
1687
|
verify_mu_call_t *call = (verify_mu_call_t *)arg;
|
|
1536
|
-
call->result = pq_verify_mu(call->signature, call->signature_len, call->mu, call->public_key
|
|
1688
|
+
call->result = pq_verify_mu(call->signature, call->signature_len, call->mu, call->public_key,
|
|
1689
|
+
call->expected_signature_len, call->verify_extmu);
|
|
1537
1690
|
return NULL;
|
|
1538
1691
|
}
|
|
1539
1692
|
|
|
1540
|
-
static VALUE pqcrypto__native_mldsa_verify_mu(
|
|
1541
|
-
VALUE public_key) {
|
|
1693
|
+
static VALUE pqcrypto__native_mldsa_verify_mu(int argc, VALUE *argv, VALUE self) {
|
|
1542
1694
|
(void)self;
|
|
1695
|
+
VALUE algorithm = ID2SYM(rb_intern("ml_dsa_65"));
|
|
1696
|
+
VALUE mu, signature, public_key;
|
|
1697
|
+
if (argc == 3) {
|
|
1698
|
+
mu = argv[0];
|
|
1699
|
+
signature = argv[1];
|
|
1700
|
+
public_key = argv[2];
|
|
1701
|
+
} else if (argc == 4) {
|
|
1702
|
+
algorithm = argv[0];
|
|
1703
|
+
mu = argv[1];
|
|
1704
|
+
signature = argv[2];
|
|
1705
|
+
public_key = argv[3];
|
|
1706
|
+
} else {
|
|
1707
|
+
rb_raise(rb_eArgError, "wrong number of arguments (given %d, expected 3..4)", argc);
|
|
1708
|
+
}
|
|
1709
|
+
|
|
1710
|
+
const pq_mldsa_profile_t *profile = pq_mldsa_profile_from_value(algorithm);
|
|
1543
1711
|
StringValue(signature);
|
|
1544
1712
|
pq_validate_bytes_argument(mu, PQ_MLDSA_MUBYTES, "mu");
|
|
1545
|
-
pq_validate_bytes_argument(public_key,
|
|
1713
|
+
pq_validate_bytes_argument(public_key, profile->public_key_len, "public key");
|
|
1546
1714
|
|
|
1547
1715
|
verify_mu_call_t call = {0};
|
|
1548
1716
|
size_t public_key_len = 0;
|
|
@@ -1556,8 +1724,10 @@ static VALUE pqcrypto__native_mldsa_verify_mu(VALUE self, VALUE mu, VALUE signat
|
|
|
1556
1724
|
call.public_key = pk_copy;
|
|
1557
1725
|
call.signature = sig_copy;
|
|
1558
1726
|
call.signature_len = signature_len;
|
|
1727
|
+
call.expected_signature_len = profile->signature_len;
|
|
1728
|
+
call.verify_extmu = profile->verify_extmu;
|
|
1559
1729
|
|
|
1560
|
-
rb_nogvl(pq_verify_mu_nogvl, &call, NULL, NULL,
|
|
1730
|
+
rb_nogvl(pq_verify_mu_nogvl, &call, NULL, NULL, PQ_RB_NOGVL_OFFLOAD_SAFE);
|
|
1561
1731
|
pq_wipe_and_free(mu_copy, mu_len);
|
|
1562
1732
|
pq_free_buffer(pk_copy);
|
|
1563
1733
|
pq_free_buffer(sig_copy);
|
|
@@ -1699,6 +1869,8 @@ void Init_pqcrypto_secure(void) {
|
|
|
1699
1869
|
pqcrypto_hybrid_kem_expand_secret_key, 1);
|
|
1700
1870
|
rb_define_module_function(mPQCrypto, "hybrid_kem_expand_secret_key_object",
|
|
1701
1871
|
pqcrypto_hybrid_kem_expand_secret_key_object, 1);
|
|
1872
|
+
rb_define_module_function(mPQCrypto, "hybrid_kem_expanded_secret_key_wipe",
|
|
1873
|
+
pqcrypto_hybrid_kem_expanded_secret_key_wipe, 1);
|
|
1702
1874
|
rb_define_module_function(mPQCrypto, "hybrid_kem_decapsulate", pqcrypto_hybrid_kem_decapsulate,
|
|
1703
1875
|
2);
|
|
1704
1876
|
rb_define_module_function(mPQCrypto, "hybrid_kem_decapsulate_expanded",
|
|
@@ -1706,20 +1878,20 @@ void Init_pqcrypto_secure(void) {
|
|
|
1706
1878
|
rb_define_module_function(mPQCrypto, "hybrid_kem_decapsulate_expanded_object",
|
|
1707
1879
|
pqcrypto_hybrid_kem_decapsulate_expanded_object, 2);
|
|
1708
1880
|
rb_define_module_function(mPQCrypto, "sign_keypair", pqcrypto_sign_keypair, 0);
|
|
1709
|
-
rb_define_module_function(mPQCrypto, "sign", pqcrypto_sign,
|
|
1710
|
-
rb_define_module_function(mPQCrypto, "verify", pqcrypto_verify,
|
|
1881
|
+
rb_define_module_function(mPQCrypto, "sign", pqcrypto_sign, -1);
|
|
1882
|
+
rb_define_module_function(mPQCrypto, "verify", pqcrypto_verify, -1);
|
|
1711
1883
|
rb_define_module_function(mPQCrypto, "ml_dsa_44_keypair", pqcrypto_ml_dsa_44_keypair, 0);
|
|
1712
1884
|
rb_define_module_function(mPQCrypto, "ml_dsa_44_keypair_from_seed",
|
|
1713
1885
|
pqcrypto_ml_dsa_44_keypair_from_seed, 1);
|
|
1714
1886
|
rb_define_module_function(mPQCrypto, "ml_dsa_keypair_from_seed",
|
|
1715
1887
|
pqcrypto_ml_dsa_keypair_from_seed, 1);
|
|
1716
|
-
rb_define_module_function(mPQCrypto, "ml_dsa_44_sign", pqcrypto_ml_dsa_44_sign,
|
|
1717
|
-
rb_define_module_function(mPQCrypto, "ml_dsa_44_verify", pqcrypto_ml_dsa_44_verify,
|
|
1888
|
+
rb_define_module_function(mPQCrypto, "ml_dsa_44_sign", pqcrypto_ml_dsa_44_sign, -1);
|
|
1889
|
+
rb_define_module_function(mPQCrypto, "ml_dsa_44_verify", pqcrypto_ml_dsa_44_verify, -1);
|
|
1718
1890
|
rb_define_module_function(mPQCrypto, "ml_dsa_87_keypair", pqcrypto_ml_dsa_87_keypair, 0);
|
|
1719
1891
|
rb_define_module_function(mPQCrypto, "ml_dsa_87_keypair_from_seed",
|
|
1720
1892
|
pqcrypto_ml_dsa_87_keypair_from_seed, 1);
|
|
1721
|
-
rb_define_module_function(mPQCrypto, "ml_dsa_87_sign", pqcrypto_ml_dsa_87_sign,
|
|
1722
|
-
rb_define_module_function(mPQCrypto, "ml_dsa_87_verify", pqcrypto_ml_dsa_87_verify,
|
|
1893
|
+
rb_define_module_function(mPQCrypto, "ml_dsa_87_sign", pqcrypto_ml_dsa_87_sign, -1);
|
|
1894
|
+
rb_define_module_function(mPQCrypto, "ml_dsa_87_verify", pqcrypto_ml_dsa_87_verify, -1);
|
|
1723
1895
|
rb_define_module_function(mPQCrypto, "ct_equals", pqcrypto_ct_equals, 2);
|
|
1724
1896
|
rb_define_module_function(mPQCrypto, "secure_wipe", pqcrypto_secure_wipe, 1);
|
|
1725
1897
|
rb_define_module_function(mPQCrypto, "version", pqcrypto_version, 0);
|
|
@@ -1740,9 +1912,9 @@ void Init_pqcrypto_secure(void) {
|
|
|
1740
1912
|
rb_define_module_function(mPQCrypto, "secret_key_from_pqc_container_pem",
|
|
1741
1913
|
pqcrypto_secret_key_from_pqc_container_pem, 1);
|
|
1742
1914
|
rb_define_module_function(mPQCrypto, "_native_mldsa_extract_tr",
|
|
1743
|
-
pqcrypto__native_mldsa_extract_tr, 1);
|
|
1915
|
+
pqcrypto__native_mldsa_extract_tr, -1);
|
|
1744
1916
|
rb_define_module_function(mPQCrypto, "_native_mldsa_compute_tr",
|
|
1745
|
-
pqcrypto__native_mldsa_compute_tr, 1);
|
|
1917
|
+
pqcrypto__native_mldsa_compute_tr, -1);
|
|
1746
1918
|
rb_define_module_function(mPQCrypto, "_native_mldsa_mu_builder_new",
|
|
1747
1919
|
pqcrypto__native_mldsa_mu_builder_new, 2);
|
|
1748
1920
|
rb_define_module_function(mPQCrypto, "_native_mldsa_mu_builder_update",
|
|
@@ -1752,9 +1924,9 @@ void Init_pqcrypto_secure(void) {
|
|
|
1752
1924
|
rb_define_module_function(mPQCrypto, "_native_mldsa_mu_builder_release",
|
|
1753
1925
|
pqcrypto__native_mldsa_mu_builder_release, 1);
|
|
1754
1926
|
rb_define_module_function(mPQCrypto, "_native_mldsa_sign_mu", pqcrypto__native_mldsa_sign_mu,
|
|
1755
|
-
|
|
1927
|
+
-1);
|
|
1756
1928
|
rb_define_module_function(mPQCrypto, "_native_mldsa_verify_mu",
|
|
1757
|
-
pqcrypto__native_mldsa_verify_mu,
|
|
1929
|
+
pqcrypto__native_mldsa_verify_mu, -1);
|
|
1758
1930
|
|
|
1759
1931
|
define_constants();
|
|
1760
1932
|
}
|