pq_crypto 0.1.0 → 0.3.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 +102 -0
- data/GET_STARTED.md +16 -9
- data/README.md +117 -23
- data/SECURITY.md +72 -13
- data/ext/pqcrypto/extconf.rb +16 -11
- data/ext/pqcrypto/pq_randombytes.c +56 -0
- data/ext/pqcrypto/pqcrypto_ruby_secure.c +266 -320
- data/ext/pqcrypto/pqcrypto_secure.c +332 -607
- data/ext/pqcrypto/pqcrypto_secure.h +13 -2
- data/lib/pq_crypto/errors.rb +12 -6
- data/lib/pq_crypto/hybrid_kem.rb +2 -2
- data/lib/pq_crypto/kem.rb +16 -4
- data/lib/pq_crypto/serialization.rb +2 -2
- data/lib/pq_crypto/signature.rb +26 -18
- data/lib/pq_crypto/version.rb +1 -1
- data/lib/pq_crypto.rb +42 -73
- data/script/vendor_libs.rb +0 -1
- metadata +5 -24
- data/ext/pqcrypto/vendor/pqclean/common/keccak4x/Makefile +0 -8
- data/ext/pqcrypto/vendor/pqclean/crypto_kem/ml-kem-768/clean/Makefile +0 -19
- data/ext/pqcrypto/vendor/pqclean/crypto_sign/ml-dsa-65/clean/Makefile +0 -19
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
#include <stdlib.h>
|
|
5
5
|
#include <string.h>
|
|
6
6
|
|
|
7
|
+
#include <openssl/crypto.h>
|
|
8
|
+
|
|
7
9
|
#include "pqcrypto_secure.h"
|
|
8
10
|
|
|
9
11
|
typedef struct {
|
|
@@ -62,6 +64,8 @@ static VALUE mPQCrypto;
|
|
|
62
64
|
static VALUE ePQCryptoError;
|
|
63
65
|
static VALUE ePQCryptoVerificationError;
|
|
64
66
|
|
|
67
|
+
__attribute__((noreturn)) static void pq_raise_general_error(int err);
|
|
68
|
+
|
|
65
69
|
static const char *pq_algorithm_symbol_to_cstr(VALUE algorithm) {
|
|
66
70
|
ID id;
|
|
67
71
|
if (SYMBOL_P(algorithm)) {
|
|
@@ -72,8 +76,8 @@ static const char *pq_algorithm_symbol_to_cstr(VALUE algorithm) {
|
|
|
72
76
|
}
|
|
73
77
|
if (id == rb_intern("ml_kem_768"))
|
|
74
78
|
return "ml_kem_768";
|
|
75
|
-
if (id == rb_intern("
|
|
76
|
-
return "
|
|
79
|
+
if (id == rb_intern("ml_kem_768_x25519_xwing"))
|
|
80
|
+
return "ml_kem_768_x25519_xwing";
|
|
77
81
|
if (id == rb_intern("ml_dsa_65"))
|
|
78
82
|
return "ml_dsa_65";
|
|
79
83
|
rb_raise(rb_eArgError, "Unsupported serialization algorithm");
|
|
@@ -82,8 +86,8 @@ static const char *pq_algorithm_symbol_to_cstr(VALUE algorithm) {
|
|
|
82
86
|
static VALUE pq_algorithm_cstr_to_symbol(const char *algorithm) {
|
|
83
87
|
if (strcmp(algorithm, "ml_kem_768") == 0)
|
|
84
88
|
return ID2SYM(rb_intern("ml_kem_768"));
|
|
85
|
-
if (strcmp(algorithm, "
|
|
86
|
-
return ID2SYM(rb_intern("
|
|
89
|
+
if (strcmp(algorithm, "ml_kem_768_x25519_xwing") == 0)
|
|
90
|
+
return ID2SYM(rb_intern("ml_kem_768_x25519_xwing"));
|
|
87
91
|
if (strcmp(algorithm, "ml_dsa_65") == 0)
|
|
88
92
|
return ID2SYM(rb_intern("ml_dsa_65"));
|
|
89
93
|
rb_raise(rb_eArgError, "Unsupported serialization algorithm");
|
|
@@ -215,238 +219,292 @@ static void pq_wipe_and_free(uint8_t *buffer, size_t len) {
|
|
|
215
219
|
}
|
|
216
220
|
}
|
|
217
221
|
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
rb_raise(
|
|
222
|
-
break;
|
|
223
|
-
case PQ_ERROR_ENCAPSULATE:
|
|
224
|
-
rb_raise(ePQCryptoError, "Encapsulation failed");
|
|
225
|
-
break;
|
|
226
|
-
case PQ_ERROR_DECAPSULATE:
|
|
227
|
-
rb_raise(ePQCryptoError, "Decapsulation failed");
|
|
228
|
-
break;
|
|
229
|
-
case PQ_ERROR_SIGN:
|
|
230
|
-
rb_raise(ePQCryptoError, "Signing failed");
|
|
231
|
-
break;
|
|
232
|
-
case PQ_ERROR_VERIFY:
|
|
233
|
-
rb_raise(ePQCryptoError, "Verification failed");
|
|
234
|
-
break;
|
|
235
|
-
case PQ_ERROR_RANDOM:
|
|
236
|
-
rb_raise(ePQCryptoError, "Random number generation failed");
|
|
237
|
-
break;
|
|
238
|
-
case PQ_ERROR_KDF:
|
|
239
|
-
rb_raise(ePQCryptoError, "Key derivation failed");
|
|
240
|
-
break;
|
|
241
|
-
case PQ_ERROR_BUFFER:
|
|
242
|
-
rb_raise(ePQCryptoError, "Buffer error");
|
|
243
|
-
break;
|
|
244
|
-
case PQ_ERROR_NOMEM:
|
|
245
|
-
rb_raise(rb_eNoMemError, "Memory allocation failed");
|
|
246
|
-
break;
|
|
247
|
-
case PQ_ERROR_OPENSSL:
|
|
248
|
-
rb_raise(ePQCryptoError, "OpenSSL error");
|
|
249
|
-
break;
|
|
250
|
-
default:
|
|
251
|
-
rb_raise(ePQCryptoError, "Unknown error: %d", err);
|
|
252
|
-
break;
|
|
222
|
+
static void pq_validate_bytes_argument(VALUE value, size_t expected_len, const char *what) {
|
|
223
|
+
StringValue(value);
|
|
224
|
+
if ((size_t)RSTRING_LEN(value) != expected_len) {
|
|
225
|
+
rb_raise(rb_eArgError, "Invalid %s length", what);
|
|
253
226
|
}
|
|
254
227
|
}
|
|
255
228
|
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
pq_raise_general_error(err);
|
|
263
|
-
}
|
|
229
|
+
static VALUE pq_build_binary_pair(const uint8_t *first, size_t first_len, const uint8_t *second,
|
|
230
|
+
size_t second_len) {
|
|
231
|
+
VALUE result = rb_ary_new2(2);
|
|
232
|
+
rb_ary_push(result, pq_string_from_buffer(first, first_len));
|
|
233
|
+
rb_ary_push(result, pq_string_from_buffer(second, second_len));
|
|
234
|
+
return result;
|
|
264
235
|
}
|
|
265
236
|
|
|
266
|
-
static VALUE
|
|
267
|
-
|
|
237
|
+
static VALUE pq_build_algorithm_key_pair(const char *algorithm, const uint8_t *key,
|
|
238
|
+
size_t key_len) {
|
|
239
|
+
VALUE result = rb_ary_new2(2);
|
|
240
|
+
rb_ary_push(result, pq_algorithm_cstr_to_symbol(algorithm));
|
|
241
|
+
rb_ary_push(result, pq_string_from_buffer(key, key_len));
|
|
242
|
+
return result;
|
|
243
|
+
}
|
|
268
244
|
|
|
245
|
+
static VALUE pq_run_kem_keypair(void *(*nogvl)(void *), size_t public_key_len,
|
|
246
|
+
size_t secret_key_len) {
|
|
269
247
|
kem_keypair_call_t call = {0};
|
|
270
|
-
|
|
271
|
-
call.secret_key = pq_alloc_buffer(PQ_MLKEM_SECRETKEYBYTES);
|
|
248
|
+
VALUE result;
|
|
272
249
|
|
|
273
|
-
|
|
250
|
+
call.public_key = pq_alloc_buffer(public_key_len);
|
|
251
|
+
call.secret_key = pq_alloc_buffer(secret_key_len);
|
|
252
|
+
|
|
253
|
+
rb_thread_call_without_gvl(nogvl, &call, NULL, NULL);
|
|
274
254
|
|
|
275
255
|
if (call.result != PQ_SUCCESS) {
|
|
276
|
-
pq_wipe_and_free(call.secret_key,
|
|
256
|
+
pq_wipe_and_free(call.secret_key, secret_key_len);
|
|
277
257
|
free(call.public_key);
|
|
278
258
|
pq_raise_general_error(call.result);
|
|
279
259
|
}
|
|
280
260
|
|
|
281
|
-
|
|
282
|
-
rb_ary_push(result, pq_string_from_buffer(call.public_key, PQ_MLKEM_PUBLICKEYBYTES));
|
|
283
|
-
rb_ary_push(result, pq_string_from_buffer(call.secret_key, PQ_MLKEM_SECRETKEYBYTES));
|
|
284
|
-
|
|
261
|
+
result = pq_build_binary_pair(call.public_key, public_key_len, call.secret_key, secret_key_len);
|
|
285
262
|
free(call.public_key);
|
|
286
|
-
pq_wipe_and_free(call.secret_key,
|
|
263
|
+
pq_wipe_and_free(call.secret_key, secret_key_len);
|
|
287
264
|
return result;
|
|
288
265
|
}
|
|
289
266
|
|
|
290
|
-
static VALUE
|
|
291
|
-
|
|
292
|
-
|
|
267
|
+
static VALUE pq_run_kem_encapsulate(void *(*nogvl)(void *), VALUE public_key, size_t public_key_len,
|
|
268
|
+
size_t ciphertext_len, size_t shared_secret_len) {
|
|
269
|
+
kem_encapsulate_call_t call = {0};
|
|
270
|
+
VALUE result;
|
|
271
|
+
size_t copied_public_key_len = 0;
|
|
293
272
|
|
|
294
|
-
|
|
295
|
-
rb_raise(rb_eArgError, "Invalid public key length");
|
|
296
|
-
}
|
|
273
|
+
pq_validate_bytes_argument(public_key, public_key_len, "public key");
|
|
297
274
|
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
call.
|
|
301
|
-
call.ciphertext = pq_alloc_buffer(PQ_MLKEM_CIPHERTEXTBYTES);
|
|
302
|
-
call.shared_secret = pq_alloc_buffer(PQ_MLKEM_SHAREDSECRETBYTES);
|
|
275
|
+
call.public_key = pq_copy_ruby_string(public_key, &copied_public_key_len);
|
|
276
|
+
call.ciphertext = pq_alloc_buffer(ciphertext_len);
|
|
277
|
+
call.shared_secret = pq_alloc_buffer(shared_secret_len);
|
|
303
278
|
|
|
304
|
-
rb_thread_call_without_gvl(
|
|
305
|
-
pq_wipe_and_free((uint8_t *)call.public_key,
|
|
279
|
+
rb_thread_call_without_gvl(nogvl, &call, NULL, NULL);
|
|
280
|
+
pq_wipe_and_free((uint8_t *)call.public_key, copied_public_key_len);
|
|
306
281
|
|
|
307
282
|
if (call.result != PQ_SUCCESS) {
|
|
308
|
-
pq_wipe_and_free(call.shared_secret,
|
|
283
|
+
pq_wipe_and_free(call.shared_secret, shared_secret_len);
|
|
309
284
|
free(call.ciphertext);
|
|
310
285
|
pq_raise_general_error(call.result);
|
|
311
286
|
}
|
|
312
287
|
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
rb_ary_push(result, pq_string_from_buffer(call.shared_secret, PQ_MLKEM_SHAREDSECRETBYTES));
|
|
316
|
-
|
|
288
|
+
result = pq_build_binary_pair(call.ciphertext, ciphertext_len, call.shared_secret,
|
|
289
|
+
shared_secret_len);
|
|
317
290
|
free(call.ciphertext);
|
|
318
|
-
pq_wipe_and_free(call.shared_secret,
|
|
291
|
+
pq_wipe_and_free(call.shared_secret, shared_secret_len);
|
|
319
292
|
return result;
|
|
320
293
|
}
|
|
321
294
|
|
|
322
|
-
static VALUE
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
295
|
+
static VALUE pq_run_kem_decapsulate(void *(*nogvl)(void *), VALUE ciphertext, size_t ciphertext_len,
|
|
296
|
+
VALUE secret_key, size_t secret_key_len,
|
|
297
|
+
size_t shared_secret_len) {
|
|
298
|
+
kem_decapsulate_call_t call = {0};
|
|
299
|
+
VALUE result;
|
|
300
|
+
size_t copied_ciphertext_len = 0;
|
|
301
|
+
size_t copied_secret_key_len = 0;
|
|
326
302
|
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
}
|
|
330
|
-
if ((size_t)RSTRING_LEN(secret_key) != PQ_MLKEM_SECRETKEYBYTES) {
|
|
331
|
-
rb_raise(rb_eArgError, "Invalid secret key length");
|
|
332
|
-
}
|
|
303
|
+
pq_validate_bytes_argument(ciphertext, ciphertext_len, "ciphertext");
|
|
304
|
+
pq_validate_bytes_argument(secret_key, secret_key_len, "secret key");
|
|
333
305
|
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
call.ciphertext = pq_copy_ruby_string(ciphertext, &ciphertext_len);
|
|
338
|
-
call.secret_key = pq_copy_ruby_string(secret_key, &secret_key_len);
|
|
339
|
-
call.shared_secret = pq_alloc_buffer(PQ_MLKEM_SHAREDSECRETBYTES);
|
|
306
|
+
call.ciphertext = pq_copy_ruby_string(ciphertext, &copied_ciphertext_len);
|
|
307
|
+
call.secret_key = pq_copy_ruby_string(secret_key, &copied_secret_key_len);
|
|
308
|
+
call.shared_secret = pq_alloc_buffer(shared_secret_len);
|
|
340
309
|
|
|
341
|
-
rb_thread_call_without_gvl(
|
|
342
|
-
pq_wipe_and_free((uint8_t *)call.ciphertext,
|
|
343
|
-
pq_wipe_and_free((uint8_t *)call.secret_key,
|
|
310
|
+
rb_thread_call_without_gvl(nogvl, &call, NULL, NULL);
|
|
311
|
+
pq_wipe_and_free((uint8_t *)call.ciphertext, copied_ciphertext_len);
|
|
312
|
+
pq_wipe_and_free((uint8_t *)call.secret_key, copied_secret_key_len);
|
|
344
313
|
|
|
345
314
|
if (call.result != PQ_SUCCESS) {
|
|
346
|
-
pq_wipe_and_free(call.shared_secret,
|
|
315
|
+
pq_wipe_and_free(call.shared_secret, shared_secret_len);
|
|
347
316
|
pq_raise_general_error(call.result);
|
|
348
317
|
}
|
|
349
318
|
|
|
350
|
-
|
|
351
|
-
pq_wipe_and_free(call.shared_secret,
|
|
319
|
+
result = pq_string_from_buffer(call.shared_secret, shared_secret_len);
|
|
320
|
+
pq_wipe_and_free(call.shared_secret, shared_secret_len);
|
|
352
321
|
return result;
|
|
353
322
|
}
|
|
354
323
|
|
|
355
|
-
static VALUE
|
|
356
|
-
|
|
324
|
+
static VALUE pq_run_sign_keypair(void *(*nogvl)(void *), size_t public_key_len,
|
|
325
|
+
size_t secret_key_len) {
|
|
326
|
+
sign_keypair_call_t call = {0};
|
|
327
|
+
VALUE result;
|
|
357
328
|
|
|
358
|
-
|
|
359
|
-
call.
|
|
360
|
-
call.secret_key = pq_alloc_buffer(PQ_HYBRID_SECRETKEYBYTES);
|
|
329
|
+
call.public_key = pq_alloc_buffer(public_key_len);
|
|
330
|
+
call.secret_key = pq_alloc_buffer(secret_key_len);
|
|
361
331
|
|
|
362
|
-
rb_thread_call_without_gvl(
|
|
332
|
+
rb_thread_call_without_gvl(nogvl, &call, NULL, NULL);
|
|
363
333
|
|
|
364
334
|
if (call.result != PQ_SUCCESS) {
|
|
365
|
-
pq_wipe_and_free(call.secret_key,
|
|
335
|
+
pq_wipe_and_free(call.secret_key, secret_key_len);
|
|
366
336
|
free(call.public_key);
|
|
367
337
|
pq_raise_general_error(call.result);
|
|
368
338
|
}
|
|
369
339
|
|
|
370
|
-
|
|
371
|
-
rb_ary_push(result, pq_string_from_buffer(call.public_key, PQ_HYBRID_PUBLICKEYBYTES));
|
|
372
|
-
rb_ary_push(result, pq_string_from_buffer(call.secret_key, PQ_HYBRID_SECRETKEYBYTES));
|
|
373
|
-
|
|
340
|
+
result = pq_build_binary_pair(call.public_key, public_key_len, call.secret_key, secret_key_len);
|
|
374
341
|
free(call.public_key);
|
|
375
|
-
pq_wipe_and_free(call.secret_key,
|
|
342
|
+
pq_wipe_and_free(call.secret_key, secret_key_len);
|
|
376
343
|
return result;
|
|
377
344
|
}
|
|
378
345
|
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
346
|
+
typedef int (*pq_export_der_fn)(uint8_t **, size_t *, const uint8_t *, size_t, const char *);
|
|
347
|
+
typedef int (*pq_export_pem_fn)(char **, size_t *, const uint8_t *, size_t, const char *);
|
|
348
|
+
typedef int (*pq_import_der_fn)(char **, uint8_t **, size_t *, const uint8_t *, size_t);
|
|
349
|
+
typedef int (*pq_import_pem_fn)(char **, uint8_t **, size_t *, const char *, size_t);
|
|
382
350
|
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
351
|
+
static VALUE pq_export_container_der(VALUE algorithm, VALUE key_bytes, pq_export_der_fn fn) {
|
|
352
|
+
uint8_t *out = NULL;
|
|
353
|
+
size_t out_len = 0;
|
|
354
|
+
VALUE result;
|
|
355
|
+
int ret;
|
|
386
356
|
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
357
|
+
StringValue(key_bytes);
|
|
358
|
+
ret = fn(&out, &out_len, (const uint8_t *)RSTRING_PTR(key_bytes),
|
|
359
|
+
(size_t)RSTRING_LEN(key_bytes), pq_algorithm_symbol_to_cstr(algorithm));
|
|
360
|
+
if (ret != PQ_SUCCESS)
|
|
361
|
+
pq_raise_general_error(ret);
|
|
392
362
|
|
|
393
|
-
|
|
394
|
-
|
|
363
|
+
result = pq_string_from_buffer(out, out_len);
|
|
364
|
+
pq_secure_wipe(out, out_len);
|
|
365
|
+
free(out);
|
|
366
|
+
return result;
|
|
367
|
+
}
|
|
395
368
|
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
369
|
+
static VALUE pq_export_container_pem(VALUE algorithm, VALUE key_bytes, pq_export_pem_fn fn) {
|
|
370
|
+
char *out = NULL;
|
|
371
|
+
size_t out_len = 0;
|
|
372
|
+
VALUE result;
|
|
373
|
+
int ret;
|
|
401
374
|
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
375
|
+
StringValue(key_bytes);
|
|
376
|
+
ret = fn(&out, &out_len, (const uint8_t *)RSTRING_PTR(key_bytes),
|
|
377
|
+
(size_t)RSTRING_LEN(key_bytes), pq_algorithm_symbol_to_cstr(algorithm));
|
|
378
|
+
if (ret != PQ_SUCCESS)
|
|
379
|
+
pq_raise_general_error(ret);
|
|
405
380
|
|
|
406
|
-
|
|
407
|
-
|
|
381
|
+
result = rb_utf8_str_new(out, (long)out_len);
|
|
382
|
+
pq_secure_wipe(out, out_len);
|
|
383
|
+
free(out);
|
|
408
384
|
return result;
|
|
409
385
|
}
|
|
410
386
|
|
|
411
|
-
static VALUE
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
387
|
+
static VALUE pq_import_container_der(VALUE der, pq_import_der_fn fn) {
|
|
388
|
+
char *algorithm = NULL;
|
|
389
|
+
uint8_t *key = NULL;
|
|
390
|
+
size_t key_len = 0;
|
|
391
|
+
VALUE result;
|
|
392
|
+
int ret;
|
|
415
393
|
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
if (
|
|
420
|
-
|
|
421
|
-
}
|
|
394
|
+
StringValue(der);
|
|
395
|
+
ret =
|
|
396
|
+
fn(&algorithm, &key, &key_len, (const uint8_t *)RSTRING_PTR(der), (size_t)RSTRING_LEN(der));
|
|
397
|
+
if (ret != PQ_SUCCESS)
|
|
398
|
+
pq_raise_general_error(ret);
|
|
422
399
|
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
400
|
+
result = pq_build_algorithm_key_pair(algorithm, key, key_len);
|
|
401
|
+
free(algorithm);
|
|
402
|
+
pq_secure_wipe(key, key_len);
|
|
403
|
+
free(key);
|
|
404
|
+
return result;
|
|
405
|
+
}
|
|
429
406
|
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
407
|
+
static VALUE pq_import_container_pem(VALUE pem, pq_import_pem_fn fn) {
|
|
408
|
+
char *algorithm = NULL;
|
|
409
|
+
uint8_t *key = NULL;
|
|
410
|
+
size_t key_len = 0;
|
|
411
|
+
VALUE result;
|
|
412
|
+
int ret;
|
|
433
413
|
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
414
|
+
StringValue(pem);
|
|
415
|
+
ret = fn(&algorithm, &key, &key_len, RSTRING_PTR(pem), (size_t)RSTRING_LEN(pem));
|
|
416
|
+
if (ret != PQ_SUCCESS)
|
|
417
|
+
pq_raise_general_error(ret);
|
|
438
418
|
|
|
439
|
-
|
|
440
|
-
|
|
419
|
+
result = pq_build_algorithm_key_pair(algorithm, key, key_len);
|
|
420
|
+
free(algorithm);
|
|
421
|
+
pq_secure_wipe(key, key_len);
|
|
422
|
+
free(key);
|
|
441
423
|
return result;
|
|
442
424
|
}
|
|
443
425
|
|
|
426
|
+
__attribute__((noreturn)) static void pq_raise_general_error(int err) {
|
|
427
|
+
switch (err) {
|
|
428
|
+
case PQ_ERROR_KEYPAIR:
|
|
429
|
+
rb_raise(ePQCryptoError, "Keypair generation failed");
|
|
430
|
+
break;
|
|
431
|
+
case PQ_ERROR_ENCAPSULATE:
|
|
432
|
+
rb_raise(ePQCryptoError, "Encapsulation failed");
|
|
433
|
+
break;
|
|
434
|
+
case PQ_ERROR_DECAPSULATE:
|
|
435
|
+
rb_raise(ePQCryptoError, "Decapsulation failed");
|
|
436
|
+
break;
|
|
437
|
+
case PQ_ERROR_SIGN:
|
|
438
|
+
rb_raise(ePQCryptoError, "Signing failed");
|
|
439
|
+
break;
|
|
440
|
+
case PQ_ERROR_VERIFY:
|
|
441
|
+
rb_raise(ePQCryptoError, "Verification failed");
|
|
442
|
+
break;
|
|
443
|
+
case PQ_ERROR_RANDOM:
|
|
444
|
+
rb_raise(ePQCryptoError, "Random number generation failed");
|
|
445
|
+
break;
|
|
446
|
+
case PQ_ERROR_KDF:
|
|
447
|
+
rb_raise(ePQCryptoError, "Key derivation failed");
|
|
448
|
+
break;
|
|
449
|
+
case PQ_ERROR_BUFFER:
|
|
450
|
+
rb_raise(ePQCryptoError, "Buffer error");
|
|
451
|
+
break;
|
|
452
|
+
case PQ_ERROR_NOMEM:
|
|
453
|
+
rb_raise(rb_eNoMemError, "Memory allocation failed");
|
|
454
|
+
break;
|
|
455
|
+
case PQ_ERROR_OPENSSL:
|
|
456
|
+
rb_raise(ePQCryptoError, "OpenSSL error");
|
|
457
|
+
break;
|
|
458
|
+
default:
|
|
459
|
+
rb_raise(ePQCryptoError, "Unknown error: %d", err);
|
|
460
|
+
break;
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
static VALUE pqcrypto_ml_kem_keypair(VALUE self) {
|
|
465
|
+
(void)self;
|
|
466
|
+
return pq_run_kem_keypair(pq_ml_kem_keypair_nogvl, PQ_MLKEM_PUBLICKEYBYTES,
|
|
467
|
+
PQ_MLKEM_SECRETKEYBYTES);
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
static VALUE pqcrypto_ml_kem_encapsulate(VALUE self, VALUE public_key) {
|
|
471
|
+
(void)self;
|
|
472
|
+
return pq_run_kem_encapsulate(pq_ml_kem_encapsulate_nogvl, public_key, PQ_MLKEM_PUBLICKEYBYTES,
|
|
473
|
+
PQ_MLKEM_CIPHERTEXTBYTES, PQ_MLKEM_SHAREDSECRETBYTES);
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
static VALUE pqcrypto_ml_kem_decapsulate(VALUE self, VALUE ciphertext, VALUE secret_key) {
|
|
477
|
+
(void)self;
|
|
478
|
+
return pq_run_kem_decapsulate(pq_ml_kem_decapsulate_nogvl, ciphertext, PQ_MLKEM_CIPHERTEXTBYTES,
|
|
479
|
+
secret_key, PQ_MLKEM_SECRETKEYBYTES, PQ_MLKEM_SHAREDSECRETBYTES);
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
static VALUE pqcrypto_hybrid_kem_keypair(VALUE self) {
|
|
483
|
+
(void)self;
|
|
484
|
+
return pq_run_kem_keypair(pq_hybrid_kem_keypair_nogvl, PQ_HYBRID_PUBLICKEYBYTES,
|
|
485
|
+
PQ_HYBRID_SECRETKEYBYTES);
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
static VALUE pqcrypto_hybrid_kem_encapsulate(VALUE self, VALUE public_key) {
|
|
489
|
+
(void)self;
|
|
490
|
+
return pq_run_kem_encapsulate(pq_hybrid_kem_encapsulate_nogvl, public_key,
|
|
491
|
+
PQ_HYBRID_PUBLICKEYBYTES, PQ_HYBRID_CIPHERTEXTBYTES,
|
|
492
|
+
PQ_HYBRID_SHAREDSECRETBYTES);
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
static VALUE pqcrypto_hybrid_kem_decapsulate(VALUE self, VALUE ciphertext, VALUE secret_key) {
|
|
496
|
+
(void)self;
|
|
497
|
+
return pq_run_kem_decapsulate(pq_hybrid_kem_decapsulate_nogvl, ciphertext,
|
|
498
|
+
PQ_HYBRID_CIPHERTEXTBYTES, secret_key, PQ_HYBRID_SECRETKEYBYTES,
|
|
499
|
+
PQ_HYBRID_SHAREDSECRETBYTES);
|
|
500
|
+
}
|
|
501
|
+
|
|
444
502
|
static VALUE pqcrypto__test_ml_kem_keypair_from_seed(VALUE self, VALUE seed) {
|
|
445
503
|
(void)self;
|
|
446
504
|
StringValue(seed);
|
|
447
505
|
|
|
448
|
-
if ((size_t)RSTRING_LEN(seed) !=
|
|
449
|
-
rb_raise(rb_eArgError, "Deterministic ML-KEM test seed must be
|
|
506
|
+
if ((size_t)RSTRING_LEN(seed) != 64) {
|
|
507
|
+
rb_raise(rb_eArgError, "Deterministic ML-KEM test seed must be 64 bytes (FIPS 203 d||z)");
|
|
450
508
|
}
|
|
451
509
|
|
|
452
510
|
kem_keypair_call_t call = {0};
|
|
@@ -476,12 +534,9 @@ static VALUE pqcrypto__test_ml_kem_keypair_from_seed(VALUE self, VALUE seed) {
|
|
|
476
534
|
|
|
477
535
|
static VALUE pqcrypto__test_ml_kem_encapsulate_from_seed(VALUE self, VALUE public_key, VALUE seed) {
|
|
478
536
|
(void)self;
|
|
479
|
-
|
|
537
|
+
pq_validate_bytes_argument(public_key, PQ_MLKEM_PUBLICKEYBYTES, "public key");
|
|
480
538
|
StringValue(seed);
|
|
481
539
|
|
|
482
|
-
if ((size_t)RSTRING_LEN(public_key) != PQ_MLKEM_PUBLICKEYBYTES) {
|
|
483
|
-
rb_raise(rb_eArgError, "Invalid public key length");
|
|
484
|
-
}
|
|
485
540
|
if ((size_t)RSTRING_LEN(seed) != 32) {
|
|
486
541
|
rb_raise(rb_eArgError, "Deterministic test seed must be 32 bytes");
|
|
487
542
|
}
|
|
@@ -550,12 +605,9 @@ static VALUE pqcrypto__test_sign_keypair_from_seed(VALUE self, VALUE seed) {
|
|
|
550
605
|
static VALUE pqcrypto__test_sign_from_seed(VALUE self, VALUE message, VALUE secret_key,
|
|
551
606
|
VALUE seed) {
|
|
552
607
|
(void)self;
|
|
553
|
-
|
|
608
|
+
pq_validate_bytes_argument(secret_key, PQ_MLDSA_SECRETKEYBYTES, "secret key");
|
|
554
609
|
StringValue(seed);
|
|
555
610
|
|
|
556
|
-
if ((size_t)RSTRING_LEN(secret_key) != PQ_MLDSA_SECRETKEYBYTES) {
|
|
557
|
-
rb_raise(rb_eArgError, "Invalid secret key length");
|
|
558
|
-
}
|
|
559
611
|
if ((size_t)RSTRING_LEN(seed) != 32) {
|
|
560
612
|
rb_raise(rb_eArgError, "Deterministic test seed must be 32 bytes");
|
|
561
613
|
}
|
|
@@ -588,35 +640,13 @@ static VALUE pqcrypto__test_sign_from_seed(VALUE self, VALUE message, VALUE secr
|
|
|
588
640
|
|
|
589
641
|
static VALUE pqcrypto_sign_keypair(VALUE self) {
|
|
590
642
|
(void)self;
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
call.public_key = pq_alloc_buffer(PQ_MLDSA_PUBLICKEYBYTES);
|
|
594
|
-
call.secret_key = pq_alloc_buffer(PQ_MLDSA_SECRETKEYBYTES);
|
|
595
|
-
|
|
596
|
-
rb_thread_call_without_gvl(pq_sign_keypair_nogvl, &call, NULL, NULL);
|
|
597
|
-
|
|
598
|
-
if (call.result != PQ_SUCCESS) {
|
|
599
|
-
pq_wipe_and_free(call.secret_key, PQ_MLDSA_SECRETKEYBYTES);
|
|
600
|
-
free(call.public_key);
|
|
601
|
-
pq_raise_general_error(call.result);
|
|
602
|
-
}
|
|
603
|
-
|
|
604
|
-
VALUE result = rb_ary_new2(2);
|
|
605
|
-
rb_ary_push(result, pq_string_from_buffer(call.public_key, PQ_MLDSA_PUBLICKEYBYTES));
|
|
606
|
-
rb_ary_push(result, pq_string_from_buffer(call.secret_key, PQ_MLDSA_SECRETKEYBYTES));
|
|
607
|
-
|
|
608
|
-
free(call.public_key);
|
|
609
|
-
pq_wipe_and_free(call.secret_key, PQ_MLDSA_SECRETKEYBYTES);
|
|
610
|
-
return result;
|
|
643
|
+
return pq_run_sign_keypair(pq_sign_keypair_nogvl, PQ_MLDSA_PUBLICKEYBYTES,
|
|
644
|
+
PQ_MLDSA_SECRETKEYBYTES);
|
|
611
645
|
}
|
|
612
646
|
|
|
613
647
|
static VALUE pqcrypto_sign(VALUE self, VALUE message, VALUE secret_key) {
|
|
614
648
|
(void)self;
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
if ((size_t)RSTRING_LEN(secret_key) != PQ_MLDSA_SECRETKEYBYTES) {
|
|
618
|
-
rb_raise(rb_eArgError, "Invalid secret key length");
|
|
619
|
-
}
|
|
649
|
+
pq_validate_bytes_argument(secret_key, PQ_MLDSA_SECRETKEYBYTES, "secret key");
|
|
620
650
|
|
|
621
651
|
sign_call_t call = {0};
|
|
622
652
|
size_t secret_key_len = 0;
|
|
@@ -625,7 +655,7 @@ static VALUE pqcrypto_sign(VALUE self, VALUE message, VALUE secret_key) {
|
|
|
625
655
|
call.signature = pq_alloc_buffer(PQ_MLDSA_BYTES);
|
|
626
656
|
call.message = pq_copy_ruby_string(message, &call.message_len);
|
|
627
657
|
|
|
628
|
-
|
|
658
|
+
rb_nogvl(pq_sign_nogvl, &call, NULL, NULL, RB_NOGVL_OFFLOAD_SAFE);
|
|
629
659
|
|
|
630
660
|
pq_wipe_and_free(call.message, call.message_len);
|
|
631
661
|
pq_wipe_and_free((uint8_t *)call.secret_key, secret_key_len);
|
|
@@ -643,11 +673,7 @@ static VALUE pqcrypto_sign(VALUE self, VALUE message, VALUE secret_key) {
|
|
|
643
673
|
static VALUE pqcrypto_verify(VALUE self, VALUE message, VALUE signature, VALUE public_key) {
|
|
644
674
|
(void)self;
|
|
645
675
|
StringValue(signature);
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
if ((size_t)RSTRING_LEN(public_key) != PQ_MLDSA_PUBLICKEYBYTES) {
|
|
649
|
-
rb_raise(rb_eArgError, "Invalid public key length");
|
|
650
|
-
}
|
|
676
|
+
pq_validate_bytes_argument(public_key, PQ_MLDSA_PUBLICKEYBYTES, "public key");
|
|
651
677
|
|
|
652
678
|
verify_call_t call = {0};
|
|
653
679
|
size_t public_key_len = 0;
|
|
@@ -657,17 +683,35 @@ static VALUE pqcrypto_verify(VALUE self, VALUE message, VALUE signature, VALUE p
|
|
|
657
683
|
call.signature_len = signature_len;
|
|
658
684
|
call.message = pq_copy_ruby_string(message, &call.message_len);
|
|
659
685
|
|
|
660
|
-
|
|
686
|
+
rb_nogvl(pq_verify_nogvl, &call, NULL, NULL, RB_NOGVL_OFFLOAD_SAFE);
|
|
661
687
|
|
|
662
688
|
pq_wipe_and_free(call.message, call.message_len);
|
|
663
689
|
pq_wipe_and_free((uint8_t *)call.public_key, public_key_len);
|
|
664
690
|
pq_wipe_and_free((uint8_t *)call.signature, signature_len);
|
|
665
691
|
|
|
666
|
-
if (call.result
|
|
667
|
-
|
|
692
|
+
if (call.result == PQ_SUCCESS) {
|
|
693
|
+
return Qtrue;
|
|
694
|
+
}
|
|
695
|
+
if (call.result == PQ_ERROR_VERIFY) {
|
|
696
|
+
return Qfalse;
|
|
668
697
|
}
|
|
698
|
+
pq_raise_general_error(call.result);
|
|
699
|
+
}
|
|
669
700
|
|
|
670
|
-
|
|
701
|
+
static VALUE pqcrypto_ct_equals(VALUE self, VALUE a, VALUE b) {
|
|
702
|
+
(void)self;
|
|
703
|
+
StringValue(a);
|
|
704
|
+
StringValue(b);
|
|
705
|
+
if (RSTRING_LEN(a) != RSTRING_LEN(b)) {
|
|
706
|
+
return Qfalse;
|
|
707
|
+
}
|
|
708
|
+
if (RSTRING_LEN(a) == 0) {
|
|
709
|
+
return Qtrue;
|
|
710
|
+
}
|
|
711
|
+
if (CRYPTO_memcmp(RSTRING_PTR(a), RSTRING_PTR(b), (size_t)RSTRING_LEN(a)) == 0) {
|
|
712
|
+
return Qtrue;
|
|
713
|
+
}
|
|
714
|
+
return Qfalse;
|
|
671
715
|
}
|
|
672
716
|
|
|
673
717
|
static VALUE pqcrypto_secure_wipe(VALUE self, VALUE str) {
|
|
@@ -700,151 +744,52 @@ static void define_constants(void) {
|
|
|
700
744
|
|
|
701
745
|
static VALUE pqcrypto_public_key_to_pqc_container_der(VALUE self, VALUE algorithm,
|
|
702
746
|
VALUE key_bytes) {
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
VALUE result;
|
|
706
|
-
StringValue(key_bytes);
|
|
707
|
-
int ret = pq_public_key_to_pqc_container_der(
|
|
708
|
-
&out, &out_len, (const uint8_t *)RSTRING_PTR(key_bytes), (size_t)RSTRING_LEN(key_bytes),
|
|
709
|
-
pq_algorithm_symbol_to_cstr(algorithm));
|
|
710
|
-
if (ret != PQ_SUCCESS)
|
|
711
|
-
pq_raise_general_error(ret);
|
|
712
|
-
result = pq_string_from_buffer(out, out_len);
|
|
713
|
-
pq_secure_wipe(out, out_len);
|
|
714
|
-
free(out);
|
|
715
|
-
return result;
|
|
747
|
+
(void)self;
|
|
748
|
+
return pq_export_container_der(algorithm, key_bytes, pq_public_key_to_pqc_container_der);
|
|
716
749
|
}
|
|
717
750
|
|
|
718
751
|
static VALUE pqcrypto_public_key_to_pqc_container_pem(VALUE self, VALUE algorithm,
|
|
719
752
|
VALUE key_bytes) {
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
VALUE result;
|
|
723
|
-
StringValue(key_bytes);
|
|
724
|
-
int ret = pq_public_key_to_pqc_container_pem(
|
|
725
|
-
&out, &out_len, (const uint8_t *)RSTRING_PTR(key_bytes), (size_t)RSTRING_LEN(key_bytes),
|
|
726
|
-
pq_algorithm_symbol_to_cstr(algorithm));
|
|
727
|
-
if (ret != PQ_SUCCESS)
|
|
728
|
-
pq_raise_general_error(ret);
|
|
729
|
-
result = rb_utf8_str_new(out, (long)out_len);
|
|
730
|
-
pq_secure_wipe(out, out_len);
|
|
731
|
-
free(out);
|
|
732
|
-
return result;
|
|
753
|
+
(void)self;
|
|
754
|
+
return pq_export_container_pem(algorithm, key_bytes, pq_public_key_to_pqc_container_pem);
|
|
733
755
|
}
|
|
734
756
|
|
|
735
757
|
static VALUE pqcrypto_secret_key_to_pqc_container_der(VALUE self, VALUE algorithm,
|
|
736
758
|
VALUE key_bytes) {
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
VALUE result;
|
|
740
|
-
StringValue(key_bytes);
|
|
741
|
-
int ret = pq_secret_key_to_pqc_container_der(
|
|
742
|
-
&out, &out_len, (const uint8_t *)RSTRING_PTR(key_bytes), (size_t)RSTRING_LEN(key_bytes),
|
|
743
|
-
pq_algorithm_symbol_to_cstr(algorithm));
|
|
744
|
-
if (ret != PQ_SUCCESS)
|
|
745
|
-
pq_raise_general_error(ret);
|
|
746
|
-
result = pq_string_from_buffer(out, out_len);
|
|
747
|
-
pq_secure_wipe(out, out_len);
|
|
748
|
-
free(out);
|
|
749
|
-
return result;
|
|
759
|
+
(void)self;
|
|
760
|
+
return pq_export_container_der(algorithm, key_bytes, pq_secret_key_to_pqc_container_der);
|
|
750
761
|
}
|
|
751
762
|
|
|
752
763
|
static VALUE pqcrypto_secret_key_to_pqc_container_pem(VALUE self, VALUE algorithm,
|
|
753
764
|
VALUE key_bytes) {
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
VALUE result;
|
|
757
|
-
StringValue(key_bytes);
|
|
758
|
-
int ret = pq_secret_key_to_pqc_container_pem(
|
|
759
|
-
&out, &out_len, (const uint8_t *)RSTRING_PTR(key_bytes), (size_t)RSTRING_LEN(key_bytes),
|
|
760
|
-
pq_algorithm_symbol_to_cstr(algorithm));
|
|
761
|
-
if (ret != PQ_SUCCESS)
|
|
762
|
-
pq_raise_general_error(ret);
|
|
763
|
-
result = rb_utf8_str_new(out, (long)out_len);
|
|
764
|
-
pq_secure_wipe(out, out_len);
|
|
765
|
-
free(out);
|
|
766
|
-
return result;
|
|
765
|
+
(void)self;
|
|
766
|
+
return pq_export_container_pem(algorithm, key_bytes, pq_secret_key_to_pqc_container_pem);
|
|
767
767
|
}
|
|
768
768
|
|
|
769
769
|
static VALUE pqcrypto_public_key_from_pqc_container_der(VALUE self, VALUE der) {
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
size_t key_len = 0;
|
|
773
|
-
VALUE ary;
|
|
774
|
-
StringValue(der);
|
|
775
|
-
int ret = pq_public_key_from_pqc_container_der(
|
|
776
|
-
&algorithm, &key, &key_len, (const uint8_t *)RSTRING_PTR(der), (size_t)RSTRING_LEN(der));
|
|
777
|
-
if (ret != PQ_SUCCESS)
|
|
778
|
-
pq_raise_general_error(ret);
|
|
779
|
-
ary = rb_ary_new_capa(2);
|
|
780
|
-
rb_ary_push(ary, pq_algorithm_cstr_to_symbol(algorithm));
|
|
781
|
-
rb_ary_push(ary, pq_string_from_buffer(key, key_len));
|
|
782
|
-
free(algorithm);
|
|
783
|
-
pq_secure_wipe(key, key_len);
|
|
784
|
-
free(key);
|
|
785
|
-
return ary;
|
|
770
|
+
(void)self;
|
|
771
|
+
return pq_import_container_der(der, pq_public_key_from_pqc_container_der);
|
|
786
772
|
}
|
|
787
773
|
|
|
788
774
|
static VALUE pqcrypto_public_key_from_pqc_container_pem(VALUE self, VALUE pem) {
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
size_t key_len = 0;
|
|
792
|
-
VALUE ary;
|
|
793
|
-
StringValue(pem);
|
|
794
|
-
int ret = pq_public_key_from_pqc_container_pem(&algorithm, &key, &key_len, RSTRING_PTR(pem),
|
|
795
|
-
(size_t)RSTRING_LEN(pem));
|
|
796
|
-
if (ret != PQ_SUCCESS)
|
|
797
|
-
pq_raise_general_error(ret);
|
|
798
|
-
ary = rb_ary_new_capa(2);
|
|
799
|
-
rb_ary_push(ary, pq_algorithm_cstr_to_symbol(algorithm));
|
|
800
|
-
rb_ary_push(ary, pq_string_from_buffer(key, key_len));
|
|
801
|
-
free(algorithm);
|
|
802
|
-
pq_secure_wipe(key, key_len);
|
|
803
|
-
free(key);
|
|
804
|
-
return ary;
|
|
775
|
+
(void)self;
|
|
776
|
+
return pq_import_container_pem(pem, pq_public_key_from_pqc_container_pem);
|
|
805
777
|
}
|
|
806
778
|
|
|
807
779
|
static VALUE pqcrypto_secret_key_from_pqc_container_der(VALUE self, VALUE der) {
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
size_t key_len = 0;
|
|
811
|
-
VALUE ary;
|
|
812
|
-
StringValue(der);
|
|
813
|
-
int ret = pq_secret_key_from_pqc_container_der(
|
|
814
|
-
&algorithm, &key, &key_len, (const uint8_t *)RSTRING_PTR(der), (size_t)RSTRING_LEN(der));
|
|
815
|
-
if (ret != PQ_SUCCESS)
|
|
816
|
-
pq_raise_general_error(ret);
|
|
817
|
-
ary = rb_ary_new_capa(2);
|
|
818
|
-
rb_ary_push(ary, pq_algorithm_cstr_to_symbol(algorithm));
|
|
819
|
-
rb_ary_push(ary, pq_string_from_buffer(key, key_len));
|
|
820
|
-
free(algorithm);
|
|
821
|
-
pq_secure_wipe(key, key_len);
|
|
822
|
-
free(key);
|
|
823
|
-
return ary;
|
|
780
|
+
(void)self;
|
|
781
|
+
return pq_import_container_der(der, pq_secret_key_from_pqc_container_der);
|
|
824
782
|
}
|
|
825
783
|
|
|
826
784
|
static VALUE pqcrypto_secret_key_from_pqc_container_pem(VALUE self, VALUE pem) {
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
size_t key_len = 0;
|
|
830
|
-
VALUE ary;
|
|
831
|
-
StringValue(pem);
|
|
832
|
-
int ret = pq_secret_key_from_pqc_container_pem(&algorithm, &key, &key_len, RSTRING_PTR(pem),
|
|
833
|
-
(size_t)RSTRING_LEN(pem));
|
|
834
|
-
if (ret != PQ_SUCCESS)
|
|
835
|
-
pq_raise_general_error(ret);
|
|
836
|
-
ary = rb_ary_new_capa(2);
|
|
837
|
-
rb_ary_push(ary, pq_algorithm_cstr_to_symbol(algorithm));
|
|
838
|
-
rb_ary_push(ary, pq_string_from_buffer(key, key_len));
|
|
839
|
-
free(algorithm);
|
|
840
|
-
pq_secure_wipe(key, key_len);
|
|
841
|
-
free(key);
|
|
842
|
-
return ary;
|
|
785
|
+
(void)self;
|
|
786
|
+
return pq_import_container_pem(pem, pq_secret_key_from_pqc_container_pem);
|
|
843
787
|
}
|
|
844
788
|
|
|
845
789
|
void Init_pqcrypto_secure(void) {
|
|
846
790
|
mPQCrypto = rb_define_module("PQCrypto");
|
|
847
791
|
ePQCryptoError = rb_define_class_under(mPQCrypto, "Error", rb_eStandardError);
|
|
792
|
+
|
|
848
793
|
ePQCryptoVerificationError =
|
|
849
794
|
rb_define_class_under(mPQCrypto, "VerificationError", ePQCryptoError);
|
|
850
795
|
|
|
@@ -866,6 +811,7 @@ void Init_pqcrypto_secure(void) {
|
|
|
866
811
|
rb_define_module_function(mPQCrypto, "sign_keypair", pqcrypto_sign_keypair, 0);
|
|
867
812
|
rb_define_module_function(mPQCrypto, "sign", pqcrypto_sign, 2);
|
|
868
813
|
rb_define_module_function(mPQCrypto, "verify", pqcrypto_verify, 3);
|
|
814
|
+
rb_define_module_function(mPQCrypto, "ct_equals", pqcrypto_ct_equals, 2);
|
|
869
815
|
rb_define_module_function(mPQCrypto, "secure_wipe", pqcrypto_secure_wipe, 1);
|
|
870
816
|
rb_define_module_function(mPQCrypto, "version", pqcrypto_version, 0);
|
|
871
817
|
rb_define_module_function(mPQCrypto, "public_key_to_pqc_container_der",
|