jwt-pq 0.3.0 → 0.5.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/.yardopts +9 -0
- data/CHANGELOG.md +61 -1
- data/Gemfile +1 -0
- data/README.md +107 -1
- data/SECURITY.md +56 -0
- data/SPEC.md +72 -0
- data/jwt-pq.gemspec +5 -2
- data/lib/jwt/pq/algorithms/hybrid_eddsa.rb +46 -45
- data/lib/jwt/pq/algorithms/ml_dsa.rb +10 -12
- data/lib/jwt/pq/errors.rb +12 -0
- data/lib/jwt/pq/hybrid_key.rb +109 -16
- data/lib/jwt/pq/jwk.rb +79 -10
- data/lib/jwt/pq/jwk_set.rb +196 -0
- data/lib/jwt/pq/jwks_loader.rb +221 -0
- data/lib/jwt/pq/key.rb +190 -28
- data/lib/jwt/pq/liboqs.rb +4 -0
- data/lib/jwt/pq/ml_dsa.rb +23 -2
- data/lib/jwt/pq/version.rb +2 -1
- data/lib/jwt/pq.rb +42 -1
- metadata +8 -7
- data/bench/fixtures/ml_dsa_65_sk.pem +0 -128
- data/bench/sign_throughput.rb +0 -26
- data/bench/verify_throughput.rb +0 -29
- data/bin/smoke.rb +0 -40
data/lib/jwt/pq.rb
CHANGED
|
@@ -7,17 +7,58 @@ require_relative "pq/ml_dsa"
|
|
|
7
7
|
require_relative "pq/key"
|
|
8
8
|
require_relative "pq/algorithms/ml_dsa"
|
|
9
9
|
require_relative "pq/jwk"
|
|
10
|
+
require_relative "pq/jwk_set"
|
|
11
|
+
require_relative "pq/jwks_loader"
|
|
10
12
|
require_relative "pq/hybrid_key"
|
|
11
13
|
require_relative "pq/algorithms/hybrid_eddsa"
|
|
12
14
|
|
|
13
15
|
module JWT
|
|
16
|
+
# Post-quantum signature support for the ruby-jwt ecosystem.
|
|
17
|
+
#
|
|
18
|
+
# Provides ML-DSA (FIPS 204) signatures as JWT algorithms `ML-DSA-44`,
|
|
19
|
+
# `ML-DSA-65`, and `ML-DSA-87`, plus optional hybrid modes `EdDSA+ML-DSA-*`
|
|
20
|
+
# that concatenate an Ed25519 signature with an ML-DSA signature.
|
|
21
|
+
#
|
|
22
|
+
# @example Encode a JWT with ML-DSA-65
|
|
23
|
+
# key = JWT::PQ::Key.generate(:ml_dsa_65)
|
|
24
|
+
# token = JWT.encode({ sub: "user-1" }, key, "ML-DSA-65")
|
|
25
|
+
#
|
|
26
|
+
# @example Decode and verify
|
|
27
|
+
# decoded, _header = JWT.decode(token, key, true, algorithms: ["ML-DSA-65"])
|
|
28
|
+
#
|
|
29
|
+
# @see https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.204.pdf FIPS 204 (ML-DSA)
|
|
30
|
+
# @see https://datatracker.ietf.org/doc/draft-ietf-cose-dilithium/ draft-ietf-cose-dilithium
|
|
14
31
|
module PQ
|
|
15
|
-
# Whether jwt-eddsa
|
|
32
|
+
# Whether the `ed25519` (or `jwt-eddsa`) gem is available for hybrid mode.
|
|
33
|
+
#
|
|
34
|
+
# Hybrid `EdDSA+ML-DSA-*` algorithms require the `ed25519` gem at runtime.
|
|
35
|
+
# This method probes for it without raising, so callers can decide whether
|
|
36
|
+
# to offer hybrid options.
|
|
37
|
+
#
|
|
38
|
+
# @return [Boolean] true when `ed25519` can be required, false otherwise.
|
|
16
39
|
def self.hybrid_available?
|
|
17
40
|
require "ed25519"
|
|
18
41
|
true
|
|
19
42
|
rescue LoadError
|
|
20
43
|
false
|
|
21
44
|
end
|
|
45
|
+
|
|
46
|
+
# Drop the cache of liboqs signature handles held by this process.
|
|
47
|
+
#
|
|
48
|
+
# Call from a post-fork hook in clustered Rack/Rails servers so
|
|
49
|
+
# that child workers allocate fresh FFI handles instead of reusing
|
|
50
|
+
# pointers inherited from the parent via copy-on-write. The first
|
|
51
|
+
# sign/verify call in the child will lazily rebuild the handle.
|
|
52
|
+
#
|
|
53
|
+
# @example Puma (config/puma.rb)
|
|
54
|
+
# on_worker_boot { JWT::PQ.reset_handles! }
|
|
55
|
+
#
|
|
56
|
+
# @example Unicorn
|
|
57
|
+
# after_fork { |_server, _worker| JWT::PQ.reset_handles! }
|
|
58
|
+
#
|
|
59
|
+
# @return [void]
|
|
60
|
+
def self.reset_handles!
|
|
61
|
+
MlDsa.reset_handles!
|
|
62
|
+
end
|
|
22
63
|
end
|
|
23
64
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: jwt-pq
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.5.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Marcelo Almeida
|
|
@@ -43,14 +43,14 @@ dependencies:
|
|
|
43
43
|
requirements:
|
|
44
44
|
- - "~>"
|
|
45
45
|
- !ruby/object:Gem::Version
|
|
46
|
-
version:
|
|
46
|
+
version: 0.1.0
|
|
47
47
|
type: :runtime
|
|
48
48
|
prerelease: false
|
|
49
49
|
version_requirements: !ruby/object:Gem::Requirement
|
|
50
50
|
requirements:
|
|
51
51
|
- - "~>"
|
|
52
52
|
- !ruby/object:Gem::Version
|
|
53
|
-
version:
|
|
53
|
+
version: 0.1.0
|
|
54
54
|
description: Adds ML-DSA-44, ML-DSA-65, and ML-DSA-87 post-quantum signature algorithms
|
|
55
55
|
to the ruby-jwt ecosystem, with optional hybrid EdDSA + ML-DSA mode. Uses liboqs
|
|
56
56
|
via FFI.
|
|
@@ -61,15 +61,14 @@ extensions:
|
|
|
61
61
|
- ext/jwt/pq/extconf.rb
|
|
62
62
|
extra_rdoc_files: []
|
|
63
63
|
files:
|
|
64
|
+
- ".yardopts"
|
|
64
65
|
- CHANGELOG.md
|
|
65
66
|
- Gemfile
|
|
66
67
|
- LICENSE
|
|
67
68
|
- README.md
|
|
68
69
|
- Rakefile
|
|
69
|
-
-
|
|
70
|
-
-
|
|
71
|
-
- bench/verify_throughput.rb
|
|
72
|
-
- bin/smoke.rb
|
|
70
|
+
- SECURITY.md
|
|
71
|
+
- SPEC.md
|
|
73
72
|
- ext/jwt/pq/extconf.rb
|
|
74
73
|
- jwt-pq.gemspec
|
|
75
74
|
- lib/jwt/pq.rb
|
|
@@ -78,6 +77,8 @@ files:
|
|
|
78
77
|
- lib/jwt/pq/errors.rb
|
|
79
78
|
- lib/jwt/pq/hybrid_key.rb
|
|
80
79
|
- lib/jwt/pq/jwk.rb
|
|
80
|
+
- lib/jwt/pq/jwk_set.rb
|
|
81
|
+
- lib/jwt/pq/jwks_loader.rb
|
|
81
82
|
- lib/jwt/pq/key.rb
|
|
82
83
|
- lib/jwt/pq/liboqs.rb
|
|
83
84
|
- lib/jwt/pq/ml_dsa.rb
|
|
@@ -1,128 +0,0 @@
|
|
|
1
|
-
-----BEGIN PRIVATE KEY-----
|
|
2
|
-
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
-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
-
cfvs1SbhcvFmep1IFutp5Jr2l80XTNxF9B2n4boijFcMgiKCNIPwTjVSHPQzf0Qg
|
|
5
|
-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
-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
-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
-
YSRCJYZmUyCAI1FFNEYGQGJIEABVdkVRJjVIF3NyNRMjhxd3eFMDgUNlQmWHEiRn
|
|
9
|
-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
-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
-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
-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
-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
-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
-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
-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
-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
-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
-
cTJxEodkVDFQZkMiMAYYAGVldUIUFiMyZTGDQyQFMSJ3cnFoBAZ3cncFVzQnB3E1
|
|
20
|
-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
-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
-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
-
FmhBQEUBN1RoFIAIVzR4hAKEJFQmZgBGKGUAJBFXaGYAB2ISEAiHSAUQFIMxQ2h4
|
|
24
|
-
BHBUFCAUAzhYQFB0YyU4YCUBIGUyV0J4YiQXCBEUR2ZoN3FjAVARNgF2KBiFBIZo
|
|
25
|
-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
-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
-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
-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
-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
-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
-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
-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
-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
-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
-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
-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
-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
-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
-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
-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
-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
-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
-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
-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
-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
-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
-
930PocruGgOVQ532MCyO7t3R+PyKTwmd+RzhWkK4cI6mPEsNgG5tY66pmzdtd0Hw
|
|
48
|
-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
-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
-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
-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
-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
-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
-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
-
6pPXk0vmLmUo1KRsSr9yE2ns0cCN7bnPGJ8wVso+ZEBlGMABTv7bSEmHpiAL2Kh5
|
|
56
|
-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
-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
-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
-
3NiImMTx048qXQpfBSKUjs1WNQJw4B/2sI6SxI8dK6/HxT9QjJaP8D0g6jAFPCg0
|
|
60
|
-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
-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
-
Sa1xdq4AYhoyJluKaUP+lyGb59rL9DoYAMoY9ssSyuOXbv7tAfzat0eoSiZcss3R
|
|
63
|
-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
-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
-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
-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
-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
-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
-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
-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
-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
-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
-
TJytdbsIfzK+T7n85PaYs/T5xt7QoFfgYvMwdVI2u9b7vpZyw9gTqE/XgPRPcpB3
|
|
74
|
-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
-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
-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
-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
-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
-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
-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
-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
-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
-
SnNGy9/x3KKb+lodA1v5hUsaPr5D6qStz07ZeXlK+S7HqdgEx+LOqyQTz5pVr0nm
|
|
84
|
-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
-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
-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
-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
-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
-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
-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
-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
-
ePmdjCsciV/GM0nxbXGgKYtODlF7k6GfxHus7A/WQFF+3sFRmNxoJPkcNV/mqLc3
|
|
93
|
-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
-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
-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
-
FIddUMIZe4xi3TmHG4yrj6rKFf+ObC0unEj4kYTn1hxenxEv/7RF/kbxWdM14web
|
|
97
|
-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
-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
-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
-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
-
MIusJGExWAbhA4+Sz0hrfKZsONi2IHES6uvi7jufBchRdbBSJe//Rtfd61Ra4F5V
|
|
102
|
-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
-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
-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
-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
-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
-
ZASHV4pq+T8zPssuqiHrHpdVsXOmWpd9vEfbqmBdPjL6uik4offptNcgyL9051uf
|
|
108
|
-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
-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
-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
-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
-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
-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
-
gd7ggT6Z2p1oRuqWLrwb4CiohsWW8lzAJYkU6Su8V0aTeQYiOg0e3554+wM4vv8A
|
|
115
|
-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
-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
-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
-
3uk2f2PZiegfTICJa96JVnXQ9CZ2bqlVwfkpJ7+NEfFom5fB7RTlS/0e8Kjmk7Io
|
|
119
|
-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
-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
-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
-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
-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
-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
-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
-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
|
|
127
|
-
aEqLBCQtoXub0y7W
|
|
128
|
-
-----END PRIVATE KEY-----
|
data/bench/sign_throughput.rb
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require "benchmark/ips"
|
|
4
|
-
require "jwt"
|
|
5
|
-
require "jwt/pq"
|
|
6
|
-
|
|
7
|
-
ALG = "ML-DSA-65"
|
|
8
|
-
PAYLOAD = { sub: "user-123", iat: 1_700_000_000, exp: 1_700_003_600 }.freeze
|
|
9
|
-
FIXTURE = File.expand_path("fixtures/ml_dsa_65_sk.pem", __dir__)
|
|
10
|
-
|
|
11
|
-
abort "Missing bench fixture: #{FIXTURE}" unless File.exist?(FIXTURE)
|
|
12
|
-
key = JWT::PQ::Key.from_pem(File.read(FIXTURE))
|
|
13
|
-
|
|
14
|
-
100.times { JWT.encode(PAYLOAD, key, ALG) }
|
|
15
|
-
|
|
16
|
-
report = Benchmark.ips(quiet: true) do |x|
|
|
17
|
-
x.config(time: 5, warmup: 2)
|
|
18
|
-
x.report("sign") { JWT.encode(PAYLOAD, key, ALG) }
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
entry = report.entries.first
|
|
22
|
-
ips = entry.stats.central_tendency
|
|
23
|
-
us_per_op = 1_000_000.0 / ips
|
|
24
|
-
|
|
25
|
-
puts "METRIC sigs_per_sec=#{ips.round(2)}"
|
|
26
|
-
puts "METRIC us_per_sig=#{us_per_op.round(2)}"
|
data/bench/verify_throughput.rb
DELETED
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require "benchmark/ips"
|
|
4
|
-
require "jwt"
|
|
5
|
-
require "jwt/pq"
|
|
6
|
-
|
|
7
|
-
ALG = "ML-DSA-65"
|
|
8
|
-
PAYLOAD = { sub: "user-123", iat: 1_700_000_000, exp: 1_700_003_600 }.freeze
|
|
9
|
-
FIXTURE = File.expand_path("fixtures/ml_dsa_65_sk.pem", __dir__)
|
|
10
|
-
|
|
11
|
-
abort "Missing bench fixture: #{FIXTURE}" unless File.exist?(FIXTURE)
|
|
12
|
-
key = JWT::PQ::Key.from_pem(File.read(FIXTURE))
|
|
13
|
-
pub_key = JWT::PQ::Key.from_public_key(ALG, key.public_key)
|
|
14
|
-
|
|
15
|
-
TOKEN = JWT.encode(PAYLOAD, key, ALG)
|
|
16
|
-
|
|
17
|
-
100.times { JWT.decode(TOKEN, pub_key, true, algorithms: [ALG], verify_expiration: false) }
|
|
18
|
-
|
|
19
|
-
report = Benchmark.ips(quiet: true) do |x|
|
|
20
|
-
x.config(time: 5, warmup: 2)
|
|
21
|
-
x.report("verify") { JWT.decode(TOKEN, pub_key, true, algorithms: [ALG], verify_expiration: false) }
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
entry = report.entries.first
|
|
25
|
-
ips = entry.stats.central_tendency
|
|
26
|
-
us_per_op = 1_000_000.0 / ips
|
|
27
|
-
|
|
28
|
-
puts "METRIC verifies_per_sec=#{ips.round(2)}"
|
|
29
|
-
puts "METRIC us_per_verify=#{us_per_op.round(2)}"
|
data/bin/smoke.rb
DELETED
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env ruby
|
|
2
|
-
# frozen_string_literal: true
|
|
3
|
-
|
|
4
|
-
require "jwt/pq"
|
|
5
|
-
|
|
6
|
-
puts "jwt-pq v#{JWT::PQ::VERSION} smoke test"
|
|
7
|
-
|
|
8
|
-
# ML-DSA-65 sign/verify round-trip
|
|
9
|
-
key = JWT::PQ::Key.generate(:ml_dsa_65)
|
|
10
|
-
token = JWT.encode({ "sub" => "smoke-test" }, key, "ML-DSA-65")
|
|
11
|
-
decoded = JWT.decode(token, key, true, algorithms: ["ML-DSA-65"])
|
|
12
|
-
|
|
13
|
-
raise "Decode failed" unless decoded.first["sub"] == "smoke-test"
|
|
14
|
-
|
|
15
|
-
puts "ML-DSA-65 sign/verify: OK"
|
|
16
|
-
|
|
17
|
-
# PEM round-trip
|
|
18
|
-
pub_pem = key.to_pem
|
|
19
|
-
restored = JWT::PQ::Key.from_pem(pub_pem)
|
|
20
|
-
decoded = JWT.decode(token, restored, true, algorithms: ["ML-DSA-65"])
|
|
21
|
-
|
|
22
|
-
raise "PEM round-trip failed" unless decoded.first["sub"] == "smoke-test"
|
|
23
|
-
|
|
24
|
-
puts "PEM round-trip: OK"
|
|
25
|
-
|
|
26
|
-
# JWK round-trip
|
|
27
|
-
jwk = JWT::PQ::JWK.new(key)
|
|
28
|
-
imported = JWT::PQ::JWK.import(jwk.export)
|
|
29
|
-
decoded = JWT.decode(token, imported, true, algorithms: ["ML-DSA-65"])
|
|
30
|
-
|
|
31
|
-
raise "JWK round-trip failed" unless decoded.first["sub"] == "smoke-test"
|
|
32
|
-
|
|
33
|
-
puts "JWK round-trip: OK"
|
|
34
|
-
|
|
35
|
-
# Key destroy
|
|
36
|
-
key.destroy!
|
|
37
|
-
raise "destroy! failed" if key.private?
|
|
38
|
-
|
|
39
|
-
puts "Key#destroy!: OK"
|
|
40
|
-
puts "All smoke tests passed"
|