Huge performance gap of `JwtPublicKeyVerify` depending on the key within a keyset used for signature generation
まだ誰も着手していません。
評価
- 難易度
- 4/5
- 見積もり時間
- 3〜5日
- 初心者へのやさしさ
- 35/100
- issue の種類
- バグ
- 明瞭さ
- おおむね明確
- 活発さ
- 停滞
- 技術スタック
- java
調査の方向性
Reproduce the behavior with the linked JwtPublicKeyVerifyBenchmark and inspect WrappedJwtPublicKeyVerify#verifyAndDecode, JwtPublicKeyVerificationInternal, JwtPublicKeyVerification, and JwtFormat#splitSignedCompact. Compare key selection and decoding costs across key positions; done means verification uses the available key ID without repeated signature attempts and the benchmark no longer shows a substantial position-dependent gap.
索引モデルが issue の本文から書いたものです。
説明
Help us help you
We'd like to know more about
your Tink deployment.
Describe the bug:
JwtPublicKeyVerify primitive shows a huge performance gap in verifying a JWT depending on the key, within a keyset, used
to generate the JWT signature.
- JHM Benchmark Result (BM Code)
# JMH version: 1.35 # VM version: JDK 11.0.17, OpenJDK 64-Bit Server VM, 11.0.17+8 # VM invoker: /Users/ks-yim/.sdkman/candidates/java/11.0.17-tem/bin/java # VM options: -Dfile.encoding=UTF-8 -Djava.io.tmpdir=/Users/ks-yim/IdeaProjects/tink-bm/build/tmp/jmh -Duser.country=KR -Duser.language=en -Duser.variant # Blackhole mode: full + dont-inline hint (auto-detected, use -Djmh.blackhole.autoDetect=false to disable) # Warmup: 1 iterations, 10 s each # Measurement: 1 iterations, 10 s each # Timeout: 10 min per iteration # Threads: 8 threads, will synchronize iterations # Benchmark mode: Throughput, ops/time Benchmark Mode Cnt Score Error Units JwtPublicKeyVerifyBenchmark.verifyJwt_signedWith1stKey thrpt 17936.100 ops/s JwtPublicKeyVerifyBenchmark.verifyJwt_signedWith2ndKey thrpt 21440.300 ops/s JwtPublicKeyVerifyBenchmark.verifyJwt_signedWith3rdKey thrpt 21041.441 ops/s JwtPublicKeyVerifyBenchmark.verifyJwt_signedWith4thKey thrpt 43127.601 ops/s JwtPublicKeyVerifyBenchmark.verifyJwt_signedWith5thKey thrpt 39966.294 ops/s
What was the expected behavior?
No significant signature verification performance gap
How can we reproduce the bug?
Clone the BM code repository and hit the following command:
./gradlew --no-daemon clean jmh -Pjmh.includes=^com.example.tink.bm.JwtPublicKeyVerifyBenchmark
Do you have any debugging information?
WrappedJwtPublicKeyVerify#verifyAndDecode doesn't use TINK's conventional way of determining the right key within a keyset by parsing the keyId prefix which is done at O(1) time.
Instead, it iterates over PrimitiveSet<JwtPublicKeyVerifyInternal> until it finds a matching key which generates the same signature as the one in the JWT, which makes the worst-case time complexity O(n).
But, it's not enough to explain the huge perf gap shown in the benchmark.
The real problem comes from the fact that verifyAndDecode generates a token signature with all tried keys within a keyset until it finds a match and uses GeneralSecurityException to control the code execution flow, which is very costly due to stacktrace generation.
A CPU profiling result for the worst case BM reveals that CPU cycles consumed for signature verification & token decoding process can potentially be optimized away. (For interactive version, hit curl -O https://raw.githubusercontent.com/ks-yim/tink-bm/master/src/jmh/java/com/example/tink/bm/jwt-public-key-verify-cpu-profiling.svg and open the downloaded file on your local)
- Signature Verification Part

- Token Decoding Part

What version of Tink are you using?
1.7.0
Can you tell us more about your development environment?
JDK 11, MacBook Pro(16-inch, 2021) Apple M1 Pro 32 GB
Is there anything else you'd like to add?
I'd like to suggest to move JwtFormat#splitSignedCompact from JwtPublicKeyVerificationInternal to JwtPublicKeyVerification so that we can have access to the parsed keyID upfront and find the right keyset at O(1) and do the token decoding & signature verification only once no matter how many keys exist in the keyset.
This will introduce a change to JwtPublicKeyVerifyInternal#verifyAndDecodeWithKid's method signature so I'd like to get some advices from the maintainers about whether it is the right direction.
- 主要言語
- Java
- スター
- 309
- フォーク
- 41
- PR マージ指標
- 30日以内にマージされた PR はありません
環境構築
- Dockerfile・Docker Compose ファイルなし
- プルリクエストのテンプレートなし
- コントリビューションガイドを読む
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
tink-crypto/tink-java のほかの issue
-
StreamingAeadSeekableDecryptingChannel.read() never returns -1 — infinite CPU spin / hang on empty or truncated ciphertexts対応中かも @willinois が 32 日前に担当しました。 オープン
難易度 3/5 1〜2日 初心者へのやさしさ 74/100
tink-crypto/tink-java#79 · 担当者 1 名 ·
-
java.lang.NoSuchMethodError: java.nio.ByteBuffer.position(I)Ljava/nio/ByteBuffer; in InsecureNonceChaCha20Poly1305Base on JDK8対応中かも @Sineaggi が 162 日前に担当しました。 オープン
難易度 3/5 1〜2日 初心者へのやさしさ 48/100
tink-crypto/tink-java#68 · コメント 13 件 ·
-
Support registering custom key managers for user-defined primitives (or provide a migration path)再び着手できるかも @tholenst が 242 日前に担当しましたが、オープン中のプルリクエストはありません。 オープン
tink-crypto/tink-java#67 · コメント 5 件 · 担当者 1 名 ·
-
p3
難易度 5/5 1週間以上 初心者へのやさしさ 25/100
tink-crypto/tink-java#66 · コメント 3 件 ·
-
p3
難易度 5/5 1週間以上 初心者へのやさしさ 25/100
tink-crypto/tink-java#41 · コメント 1 件 ·
tink-crypto/tink-java の issue をすべて見る
似ている issue
-
code-maintenance
難易度 2/5 1〜3時間 初心者へのやさしさ 77/100
メンテナーはふだん 1 日以内に返信
-
bug priority: medium Review effort [1-5]: 3 status: needs-triage type: bug
難易度 2/5 1〜3時間 初心者へのやさしさ 82/100
carlos-emr/carlos#5258 ·
メンテナーはふだん 1 日以内に返信
-
bug: author create/update with an unknown avatarId returns 404 instead of 400 UNKNOWN_REFERENCE対応中かも @Vinu2111 が今日担当しました。 オープンbug
難易度 2/5 1〜3時間 初心者へのやさしさ 74/100
atomityhq/blog-cms#59 · コメント 1 件 ·
メンテナーはふだん 1 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 70/100
メンテナーはふだん 1 日以内に返信
-
dev/release: verify-release-candidate.sh runs 0 Java tests with Debian's Maven対応中かも @kou が今日担当しました。 オープンType: bug
難易度 2/5 1〜3時間 初心者へのやさしさ 72/100
apache/arrow-adbc#4947 ·
メンテナーはふだん 1 日以内に返信