pq_crypto 0.5.3 → 0.6.1
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/CHANGELOG.md +18 -0
- data/GET_STARTED.md +70 -9
- data/README.md +11 -6
- data/ext/pqcrypto/extconf.rb +2 -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 +351 -48
- data/ext/pqcrypto/pqcrypto_secure.c +615 -84
- data/ext/pqcrypto/pqcrypto_secure.h +35 -10
- data/ext/pqcrypto/pqcrypto_version.h +1 -1
- data/lib/pq_crypto/hybrid_kem.rb +2 -1
- data/lib/pq_crypto/internal.rb +23 -0
- data/lib/pq_crypto/kem.rb +79 -44
- data/lib/pq_crypto/key.rb +90 -0
- data/lib/pq_crypto/pkcs8/der.rb +68 -0
- data/lib/pq_crypto/pkcs8/private_key_choice.rb +186 -0
- data/lib/pq_crypto/pkcs8.rb +61 -304
- data/lib/pq_crypto/serialization.rb +19 -29
- data/lib/pq_crypto/signature.rb +81 -51
- data/lib/pq_crypto/version.rb +1 -1
- data/lib/pq_crypto.rb +16 -4
- metadata +10 -3
data/lib/pq_crypto/signature.rb
CHANGED
|
@@ -46,6 +46,10 @@ module PQCrypto
|
|
|
46
46
|
SecretKey.new(algorithm, bytes)
|
|
47
47
|
end
|
|
48
48
|
|
|
49
|
+
def secret_key_from_seed(algorithm, seed)
|
|
50
|
+
SecretKey.from_seed(resolve_algorithm!(algorithm), seed)
|
|
51
|
+
end
|
|
52
|
+
|
|
49
53
|
def public_key_from_pqc_container_der(der, algorithm = nil)
|
|
50
54
|
resolved_algorithm, bytes = Serialization.public_key_from_pqc_container_der(algorithm, der)
|
|
51
55
|
resolve_algorithm!(resolved_algorithm)
|
|
@@ -82,12 +86,12 @@ module PQCrypto
|
|
|
82
86
|
PublicKey.new(resolve_algorithm!(resolved_algorithm), bytes)
|
|
83
87
|
end
|
|
84
88
|
|
|
85
|
-
def secret_key_from_pkcs8_der(der)
|
|
86
|
-
secret_key_from_decoded_pkcs8(*PKCS8.decode_der(der))
|
|
89
|
+
def secret_key_from_pkcs8_der(der, passphrase: nil)
|
|
90
|
+
secret_key_from_decoded_pkcs8(*PKCS8.decode_der(der, passphrase: passphrase))
|
|
87
91
|
end
|
|
88
92
|
|
|
89
|
-
def secret_key_from_pkcs8_pem(pem)
|
|
90
|
-
secret_key_from_decoded_pkcs8(*PKCS8.decode_pem(pem))
|
|
93
|
+
def secret_key_from_pkcs8_pem(pem, passphrase: nil)
|
|
94
|
+
secret_key_from_decoded_pkcs8(*PKCS8.decode_pem(pem, passphrase: passphrase))
|
|
91
95
|
end
|
|
92
96
|
|
|
93
97
|
def details(algorithm)
|
|
@@ -114,10 +118,10 @@ module PQCrypto
|
|
|
114
118
|
SecretKey.new(algorithm, material)
|
|
115
119
|
when :seed
|
|
116
120
|
_public_key, expanded = PQCrypto.__send__(native_method_for(algorithm, :keypair_from_seed), material)
|
|
117
|
-
SecretKey.new(algorithm, expanded)
|
|
121
|
+
SecretKey.new(algorithm, expanded, seed: material)
|
|
118
122
|
when :both
|
|
119
123
|
_seed, expanded = material
|
|
120
|
-
SecretKey.new(algorithm, expanded)
|
|
124
|
+
SecretKey.new(algorithm, expanded, seed: _seed)
|
|
121
125
|
else
|
|
122
126
|
raise SerializationError, "Unsupported ML-DSA PKCS#8 private key format: #{format.inspect}"
|
|
123
127
|
end
|
|
@@ -145,9 +149,10 @@ module PQCrypto
|
|
|
145
149
|
context = validate_context!(context)
|
|
146
150
|
validate_io!(io)
|
|
147
151
|
|
|
152
|
+
algorithm = secret_key.algorithm
|
|
148
153
|
sk_bytes = secret_key.__send__(:bytes_for_native)
|
|
149
154
|
begin
|
|
150
|
-
tr = PQCrypto.__send__(:_native_mldsa_extract_tr, sk_bytes)
|
|
155
|
+
tr = PQCrypto.__send__(:_native_mldsa_extract_tr, algorithm, sk_bytes)
|
|
151
156
|
rescue ArgumentError => e
|
|
152
157
|
raise InvalidKeyError, e.message
|
|
153
158
|
end
|
|
@@ -159,7 +164,7 @@ module PQCrypto
|
|
|
159
164
|
_drain_io_into_builder(io, builder, chunk_size)
|
|
160
165
|
mu = PQCrypto.__send__(:_native_mldsa_mu_builder_finalize, builder)
|
|
161
166
|
builder_consumed = true
|
|
162
|
-
PQCrypto.__send__(:_native_mldsa_sign_mu, mu, sk_bytes)
|
|
167
|
+
PQCrypto.__send__(:_native_mldsa_sign_mu, algorithm, mu, sk_bytes)
|
|
163
168
|
ensure
|
|
164
169
|
PQCrypto.__send__(:_native_mldsa_mu_builder_release, builder) unless builder_consumed
|
|
165
170
|
PQCrypto.secure_wipe(tr) if tr && !tr.frozen?
|
|
@@ -173,9 +178,10 @@ module PQCrypto
|
|
|
173
178
|
context = validate_context!(context)
|
|
174
179
|
validate_io!(io)
|
|
175
180
|
|
|
181
|
+
algorithm = public_key.algorithm
|
|
176
182
|
pk_bytes = public_key.__send__(:bytes_for_native)
|
|
177
183
|
begin
|
|
178
|
-
tr = PQCrypto.__send__(:_native_mldsa_compute_tr, pk_bytes)
|
|
184
|
+
tr = PQCrypto.__send__(:_native_mldsa_compute_tr, algorithm, pk_bytes)
|
|
179
185
|
rescue ArgumentError => e
|
|
180
186
|
raise InvalidKeyError, e.message
|
|
181
187
|
end
|
|
@@ -183,12 +189,12 @@ module PQCrypto
|
|
|
183
189
|
builder = PQCrypto.__send__(:_native_mldsa_mu_builder_new, tr, context)
|
|
184
190
|
builder_consumed = false
|
|
185
191
|
mu = nil
|
|
186
|
-
sig_bytes =
|
|
192
|
+
sig_bytes = Internal.binary_string(signature)
|
|
187
193
|
begin
|
|
188
194
|
_drain_io_into_builder(io, builder, chunk_size)
|
|
189
195
|
mu = PQCrypto.__send__(:_native_mldsa_mu_builder_finalize, builder)
|
|
190
196
|
builder_consumed = true
|
|
191
|
-
PQCrypto.__send__(:_native_mldsa_verify_mu, mu, sig_bytes, pk_bytes)
|
|
197
|
+
PQCrypto.__send__(:_native_mldsa_verify_mu, algorithm, mu, sig_bytes, pk_bytes)
|
|
192
198
|
ensure
|
|
193
199
|
PQCrypto.__send__(:_native_mldsa_mu_builder_release, builder) unless builder_consumed
|
|
194
200
|
|
|
@@ -224,7 +230,7 @@ module PQCrypto
|
|
|
224
230
|
end
|
|
225
231
|
|
|
226
232
|
def validate_context!(context)
|
|
227
|
-
ctx =
|
|
233
|
+
ctx = Internal.binary_string(context)
|
|
228
234
|
if ctx.bytesize > 255
|
|
229
235
|
raise ArgumentError, "context must be at most 255 bytes (FIPS 204)"
|
|
230
236
|
end
|
|
@@ -232,10 +238,7 @@ module PQCrypto
|
|
|
232
238
|
end
|
|
233
239
|
|
|
234
240
|
def validate_streaming_algorithm!(algorithm)
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
raise UnsupportedAlgorithmError,
|
|
238
|
-
"Streaming sign_io/verify_io currently supports only #{CANONICAL_ALGORITHM.inspect}"
|
|
241
|
+
resolve_algorithm!(algorithm)
|
|
239
242
|
end
|
|
240
243
|
end
|
|
241
244
|
|
|
@@ -261,7 +264,7 @@ module PQCrypto
|
|
|
261
264
|
|
|
262
265
|
def initialize(algorithm, bytes)
|
|
263
266
|
@algorithm = algorithm
|
|
264
|
-
@bytes =
|
|
267
|
+
@bytes = Internal.binary_string(bytes)
|
|
265
268
|
validate_length!
|
|
266
269
|
end
|
|
267
270
|
|
|
@@ -285,14 +288,17 @@ module PQCrypto
|
|
|
285
288
|
SPKI.encode_pem(@algorithm, @bytes)
|
|
286
289
|
end
|
|
287
290
|
|
|
288
|
-
def verify(message, signature)
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
291
|
+
def verify(message, signature, context: "".b)
|
|
292
|
+
context = Signature.send(:validate_context!, context)
|
|
293
|
+
begin
|
|
294
|
+
PQCrypto.__send__(Signature.send(:native_method_for, @algorithm, :verify), Internal.binary_string(message), Internal.binary_string(signature), @bytes, context)
|
|
295
|
+
rescue ArgumentError => e
|
|
296
|
+
raise InvalidKeyError, e.message
|
|
297
|
+
end
|
|
292
298
|
end
|
|
293
299
|
|
|
294
|
-
def verify!(message, signature)
|
|
295
|
-
raise PQCrypto::VerificationError, "Verification failed" unless verify(message, signature)
|
|
300
|
+
def verify!(message, signature, context: "".b)
|
|
301
|
+
raise PQCrypto::VerificationError, "Verification failed" unless verify(message, signature, context: context)
|
|
296
302
|
true
|
|
297
303
|
end
|
|
298
304
|
|
|
@@ -309,7 +315,7 @@ module PQCrypto
|
|
|
309
315
|
|
|
310
316
|
def ==(other)
|
|
311
317
|
return false unless other.is_a?(PublicKey) && other.algorithm == algorithm
|
|
312
|
-
|
|
318
|
+
Internal.constant_time_equal?(other.send(:bytes_for_native), @bytes)
|
|
313
319
|
end
|
|
314
320
|
|
|
315
321
|
alias eql? ==
|
|
@@ -337,10 +343,20 @@ module PQCrypto
|
|
|
337
343
|
class SecretKey
|
|
338
344
|
attr_reader :algorithm
|
|
339
345
|
|
|
340
|
-
def initialize(algorithm, bytes)
|
|
346
|
+
def initialize(algorithm, bytes, seed: nil)
|
|
341
347
|
@algorithm = algorithm
|
|
342
|
-
@bytes =
|
|
348
|
+
@bytes = Internal.binary_string(bytes)
|
|
349
|
+
@seed = seed.nil? ? nil : Internal.binary_string(seed)
|
|
343
350
|
validate_length!
|
|
351
|
+
validate_seed_length! if @seed
|
|
352
|
+
end
|
|
353
|
+
|
|
354
|
+
def self.from_seed(algorithm, seed)
|
|
355
|
+
seed_bytes = Internal.binary_string(seed)
|
|
356
|
+
_public_key, expanded = PQCrypto.__send__(Signature.send(:native_method_for, algorithm, :keypair_from_seed), seed_bytes)
|
|
357
|
+
new(algorithm, expanded, seed: seed_bytes)
|
|
358
|
+
rescue ArgumentError => e
|
|
359
|
+
raise InvalidKeyError, e.message
|
|
344
360
|
end
|
|
345
361
|
|
|
346
362
|
def to_bytes
|
|
@@ -355,34 +371,21 @@ module PQCrypto
|
|
|
355
371
|
Serialization.secret_key_to_pqc_container_pem(@algorithm, @bytes)
|
|
356
372
|
end
|
|
357
373
|
|
|
358
|
-
def to_pkcs8_der(format: :expanded)
|
|
359
|
-
|
|
360
|
-
when :expanded
|
|
361
|
-
PKCS8.encode_der(@algorithm, @bytes, format: :expanded)
|
|
362
|
-
when :seed, :both
|
|
363
|
-
raise SerializationError,
|
|
364
|
-
"ML-DSA seed/both PKCS#8 export requires original seed material; use PQCrypto::PKCS8.encode_der/encode_pem directly"
|
|
365
|
-
else
|
|
366
|
-
raise SerializationError, "Unsupported PKCS#8 private key format: #{format.inspect}"
|
|
367
|
-
end
|
|
374
|
+
def to_pkcs8_der(format: :expanded, passphrase: nil, iterations: PKCS8::ENCRYPTED_PKCS8_DEFAULT_ITERATIONS)
|
|
375
|
+
PKCS8.encode_der(@algorithm, pkcs8_material(format), format: format, passphrase: passphrase, iterations: iterations)
|
|
368
376
|
end
|
|
369
377
|
|
|
370
|
-
def to_pkcs8_pem(format: :expanded)
|
|
371
|
-
|
|
372
|
-
when :expanded
|
|
373
|
-
PKCS8.encode_pem(@algorithm, @bytes, format: :expanded)
|
|
374
|
-
when :seed, :both
|
|
375
|
-
raise SerializationError,
|
|
376
|
-
"ML-DSA seed/both PKCS#8 export requires original seed material; use PQCrypto::PKCS8.encode_der/encode_pem directly"
|
|
377
|
-
else
|
|
378
|
-
raise SerializationError, "Unsupported PKCS#8 private key format: #{format.inspect}"
|
|
379
|
-
end
|
|
378
|
+
def to_pkcs8_pem(format: :expanded, passphrase: nil, iterations: PKCS8::ENCRYPTED_PKCS8_DEFAULT_ITERATIONS)
|
|
379
|
+
PKCS8.encode_pem(@algorithm, pkcs8_material(format), format: format, passphrase: passphrase, iterations: iterations)
|
|
380
380
|
end
|
|
381
381
|
|
|
382
|
-
def sign(message)
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
382
|
+
def sign(message, context: "".b)
|
|
383
|
+
context = Signature.send(:validate_context!, context)
|
|
384
|
+
begin
|
|
385
|
+
PQCrypto.__send__(Signature.send(:native_method_for, @algorithm, :sign), Internal.binary_string(message), @bytes, context)
|
|
386
|
+
rescue ArgumentError => e
|
|
387
|
+
raise InvalidKeyError, e.message
|
|
388
|
+
end
|
|
386
389
|
end
|
|
387
390
|
|
|
388
391
|
def sign_io(io, chunk_size: 1 << 20, context: "".b)
|
|
@@ -391,12 +394,13 @@ module PQCrypto
|
|
|
391
394
|
|
|
392
395
|
def wipe!
|
|
393
396
|
PQCrypto.secure_wipe(@bytes)
|
|
397
|
+
PQCrypto.secure_wipe(@seed) if @seed
|
|
394
398
|
self
|
|
395
399
|
end
|
|
396
400
|
|
|
397
401
|
def ==(other)
|
|
398
402
|
return false unless other.is_a?(SecretKey) && other.algorithm == algorithm
|
|
399
|
-
|
|
403
|
+
Internal.constant_time_equal?(other.send(:bytes_for_native), @bytes)
|
|
400
404
|
end
|
|
401
405
|
|
|
402
406
|
alias eql? ==
|
|
@@ -419,6 +423,32 @@ module PQCrypto
|
|
|
419
423
|
expected = Signature.details(@algorithm).fetch(:secret_key_bytes)
|
|
420
424
|
raise InvalidKeyError, "Invalid signature secret key length" unless @bytes.bytesize == expected
|
|
421
425
|
end
|
|
426
|
+
|
|
427
|
+
def pkcs8_material(format)
|
|
428
|
+
case format
|
|
429
|
+
when :expanded
|
|
430
|
+
@bytes
|
|
431
|
+
when :seed
|
|
432
|
+
ensure_seed_available!(format)
|
|
433
|
+
@seed
|
|
434
|
+
when :both
|
|
435
|
+
ensure_seed_available!(format)
|
|
436
|
+
[@seed, @bytes]
|
|
437
|
+
else
|
|
438
|
+
raise SerializationError, "Unsupported PKCS#8 private key format: #{format.inspect}"
|
|
439
|
+
end
|
|
440
|
+
end
|
|
441
|
+
|
|
442
|
+
def validate_seed_length!
|
|
443
|
+
expected = PKCS8::PrivateKeyChoice.seed_bytes(@algorithm)
|
|
444
|
+
raise InvalidKeyError, "Invalid signature seed length" unless @seed.bytesize == expected
|
|
445
|
+
end
|
|
446
|
+
|
|
447
|
+
def ensure_seed_available!(format)
|
|
448
|
+
return if @seed
|
|
449
|
+
|
|
450
|
+
raise SerializationError, "ML-DSA #{format.inspect} PKCS#8 export requires original seed material"
|
|
451
|
+
end
|
|
422
452
|
end
|
|
423
453
|
end
|
|
424
454
|
end
|
data/lib/pq_crypto/version.rb
CHANGED
data/lib/pq_crypto.rb
CHANGED
|
@@ -30,13 +30,17 @@ end
|
|
|
30
30
|
|
|
31
31
|
require_relative "pq_crypto/errors"
|
|
32
32
|
require_relative "pq_crypto/version"
|
|
33
|
+
require_relative "pq_crypto/internal"
|
|
33
34
|
require_relative "pq_crypto/algorithm_registry"
|
|
34
35
|
require_relative "pq_crypto/serialization"
|
|
35
36
|
require_relative "pq_crypto/spki"
|
|
37
|
+
require_relative "pq_crypto/pkcs8/der"
|
|
38
|
+
require_relative "pq_crypto/pkcs8/private_key_choice"
|
|
36
39
|
require_relative "pq_crypto/pkcs8"
|
|
37
40
|
require_relative "pq_crypto/kem"
|
|
38
41
|
require_relative "pq_crypto/signature"
|
|
39
42
|
require_relative "pq_crypto/hybrid_kem"
|
|
43
|
+
require_relative "pq_crypto/key"
|
|
40
44
|
|
|
41
45
|
module PQCrypto
|
|
42
46
|
SUITES = {
|
|
@@ -65,6 +69,7 @@ module PQCrypto
|
|
|
65
69
|
hybrid_kem_encapsulate
|
|
66
70
|
hybrid_kem_expand_secret_key
|
|
67
71
|
hybrid_kem_expand_secret_key_object
|
|
72
|
+
hybrid_kem_expanded_secret_key_wipe
|
|
68
73
|
hybrid_kem_decapsulate
|
|
69
74
|
hybrid_kem_decapsulate_expanded
|
|
70
75
|
hybrid_kem_decapsulate_expanded_object
|
|
@@ -91,6 +96,13 @@ module PQCrypto
|
|
|
91
96
|
public_key_from_pqc_container_pem
|
|
92
97
|
secret_key_from_pqc_container_der
|
|
93
98
|
secret_key_from_pqc_container_pem
|
|
99
|
+
pkcs8_private_key_info_to_der
|
|
100
|
+
pkcs8_private_key_info_from_der
|
|
101
|
+
pkcs8_encrypt_der
|
|
102
|
+
pkcs8_decrypt_der
|
|
103
|
+
pkcs8_encrypted_der?
|
|
104
|
+
pkcs8_der_to_pem
|
|
105
|
+
pkcs8_pem_to_der
|
|
94
106
|
__test_ml_kem_keypair_from_seed
|
|
95
107
|
__test_ml_kem_encapsulate_from_seed
|
|
96
108
|
__test_ml_kem_512_encapsulate_from_seed
|
|
@@ -164,25 +176,25 @@ module PQCrypto
|
|
|
164
176
|
KEM_KEYPAIR_METHODS = {
|
|
165
177
|
ml_kem_512: :native_ml_kem_512_keypair_from_seed,
|
|
166
178
|
ml_kem_768: :native_ml_kem_keypair_from_seed,
|
|
167
|
-
ml_kem_1024: :native_ml_kem_1024_keypair_from_seed
|
|
179
|
+
ml_kem_1024: :native_ml_kem_1024_keypair_from_seed
|
|
168
180
|
}.freeze
|
|
169
181
|
|
|
170
182
|
KEM_ENCAPSULATE_METHODS = {
|
|
171
183
|
ml_kem_512: :native_test_ml_kem_512_encapsulate_from_seed,
|
|
172
184
|
ml_kem_768: :native_test_ml_kem_encapsulate_from_seed,
|
|
173
|
-
ml_kem_1024: :native_test_ml_kem_1024_encapsulate_from_seed
|
|
185
|
+
ml_kem_1024: :native_test_ml_kem_1024_encapsulate_from_seed
|
|
174
186
|
}.freeze
|
|
175
187
|
|
|
176
188
|
MLDSA_KEYPAIR_METHODS = {
|
|
177
189
|
ml_dsa_44: :native_test_ml_dsa_44_keypair_from_seed,
|
|
178
190
|
ml_dsa_65: :native_test_sign_keypair_from_seed,
|
|
179
|
-
ml_dsa_87: :native_test_ml_dsa_87_keypair_from_seed
|
|
191
|
+
ml_dsa_87: :native_test_ml_dsa_87_keypair_from_seed
|
|
180
192
|
}.freeze
|
|
181
193
|
|
|
182
194
|
MLDSA_SIGN_METHODS = {
|
|
183
195
|
ml_dsa_44: :native_test_ml_dsa_44_sign_from_seed,
|
|
184
196
|
ml_dsa_65: :native_test_sign_from_seed,
|
|
185
|
-
ml_dsa_87: :native_test_ml_dsa_87_sign_from_seed
|
|
197
|
+
ml_dsa_87: :native_test_ml_dsa_87_sign_from_seed
|
|
186
198
|
}.freeze
|
|
187
199
|
|
|
188
200
|
def self.ml_kem_keypair_from_seed(seed, algorithm: :ml_kem_768)
|
metadata
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: pq_crypto
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.6.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Roman Haydarov
|
|
8
|
+
autorequire:
|
|
8
9
|
bindir: exe
|
|
9
10
|
cert_chain: []
|
|
10
|
-
date:
|
|
11
|
+
date: 2026-05-14 00:00:00.000000000 Z
|
|
11
12
|
dependencies:
|
|
12
13
|
- !ruby/object:Gem::Dependency
|
|
13
14
|
name: rake
|
|
@@ -313,8 +314,12 @@ files:
|
|
|
313
314
|
- lib/pq_crypto/algorithm_registry.rb
|
|
314
315
|
- lib/pq_crypto/errors.rb
|
|
315
316
|
- lib/pq_crypto/hybrid_kem.rb
|
|
317
|
+
- lib/pq_crypto/internal.rb
|
|
316
318
|
- lib/pq_crypto/kem.rb
|
|
319
|
+
- lib/pq_crypto/key.rb
|
|
317
320
|
- lib/pq_crypto/pkcs8.rb
|
|
321
|
+
- lib/pq_crypto/pkcs8/der.rb
|
|
322
|
+
- lib/pq_crypto/pkcs8/private_key_choice.rb
|
|
318
323
|
- lib/pq_crypto/serialization.rb
|
|
319
324
|
- lib/pq_crypto/signature.rb
|
|
320
325
|
- lib/pq_crypto/spki.rb
|
|
@@ -328,6 +333,7 @@ metadata:
|
|
|
328
333
|
homepage_uri: https://github.com/roman-haidarov/pq_crypto
|
|
329
334
|
source_code_uri: https://github.com/roman-haidarov/pq_crypto/tree/main
|
|
330
335
|
changelog_uri: https://github.com/roman-haidarov/pq_crypto/blob/main/CHANGELOG.md
|
|
336
|
+
post_install_message:
|
|
331
337
|
rdoc_options: []
|
|
332
338
|
require_paths:
|
|
333
339
|
- lib
|
|
@@ -342,7 +348,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
342
348
|
- !ruby/object:Gem::Version
|
|
343
349
|
version: '0'
|
|
344
350
|
requirements: []
|
|
345
|
-
rubygems_version: 3.
|
|
351
|
+
rubygems_version: 3.3.27
|
|
352
|
+
signing_key:
|
|
346
353
|
specification_version: 4
|
|
347
354
|
summary: Primitive-first post-quantum cryptography for Ruby
|
|
348
355
|
test_files: []
|