Repository navigation
Conversation
|
Review requested:
|
|
Please split the inlining from general improvements. I explored this in #63595, including operation-specific thresholds and a guard that sent fanout to the threadpool. The reason I stopped was HTTP server responsiveness. After @mcollina raised that concern, I measured it and found that accounting for responsiveness reduced the viable candidates to non-RSA key generation and symmetric operations, with thresholds below 4 KiB, sometimes 8 KiB, rather than 64 KiB. At that point I didn't think the remaining benefit justified the churn and maintenance burden. Closing comment. The narrower scope and 1 KiB budget here are relevant differences, but crypto throughput alone doesn't establish that the responsiveness concern is resolved. Deferring promise settlement to a microtask still allows serial There's also a specification question. The current A separate synchronous WebCrypto API is being discussed as well. |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #67109 +/- ##
==========================================
+ Coverage 90.64% 90.67% +0.02%
==========================================
Files 797 797
Lines 278797 278809 +12
Branches 53627 53625 -2
==========================================
+ Hits 252717 252799 +82
+ Misses 16413 16378 -35
+ Partials 9667 9632 -35
🚀 New features to boost your workflow:
|
|
Please add regression tests covering:
|
createHmac(), createSign(), createVerify() and the synchronous one-shot sign, verify, HKDF and PBKDF2 functions looked up their digest with Digest::FromName(). That returns OpenSSL's legacy EVP_MD, so every EVP_DigestInit_ex() and HMAC init had to fetch the provider implementation again through the method store. Look these digests up through the per-Environment cache that createHash() and crypto.hash() already use. Jobs on the thread pool keep using Digest::FromName(): with the cache, Web Crypto digest and HMAC throughput went down, because workers that finish sooner have to be woken up for each new job more often. Signed-off-by: Yagiz Nizipli <yagiz@nizipli.com> Assisted-by: Grok
ClearErrorOnReturn calls ERR_clear_error() when it is created and again when it goes out of scope. That function resets all 16 slots of the thread's error queue, including two free() calls per slot, even when the queue is empty, which is almost always the case. Check for a queued error first, which costs a fraction of that. ClearErrorOnReturn guards most crypto operations, including every CryptoJob, so this applies to all of them. Signed-off-by: Yagiz Nizipli <yagiz@nizipli.com> Assisted-by: Grok
Every HMAC context was created with EVP_MAC_fetch() and keyed with the digest passed by name, so the provider fetched the digest again on each init. Both lookups go through OpenSSL's method store. Keep an HMAC context without a key for each digest in the per-Environment digest cache, and duplicate it in createHmac(). A duplicated context already has its digest, so keying it with the same digest no longer fetches anything. Signed-off-by: Yagiz Nizipli <yagiz@nizipli.com> Assisted-by: Grok
Check that HMAC instances duplicated from the same cached context stay independent when their updates are interleaved, and that warmed digest and HMAC caches follow FIPS mode changes without breaking an HMAC that is already in progress. Signed-off-by: Yagiz Nizipli <yagiz@nizipli.com> Assisted-by: Grok
The first three commits remove OpenSSL lookups that were repeated on every call. The fourth adds tests for the new caches.
createHmac(),createSign(),createVerify()and the synchronous one-shot sign, verify, HKDF and PBKDF2 functions looked up their digest withDigest::FromName(). That returns OpenSSL's legacyEVP_MD, so everyEVP_DigestInit_ex()and HMAC init had to fetch the provider implementation again. They now use the per-Environmentcache thatcreateHash()andcrypto.hash()already use. Jobs on the thread pool keep usingDigest::FromName(). With the cache, parallelsubtle.digest()throughput dropped 5% to 7%. Those benchmarks are bound by the main thread, and workers that finish sooner have to be woken up for each new job more often.ClearErrorOnReturncalledERR_clear_error()twice per operation. That function resets all 16 slots of the error queue, with twofree()calls each, even when the queue is empty, which is almost always the case. It now checks withERR_peek_error()first. In a small C benchmark against OpenSSL 4.1, a call on an empty queue went from about 45-50 ns to about 9 ns.HMACCtxPointerusesEVP_MAC, so each context fetchedHMAC, and keying it with a digest name made the provider fetch the digest again.DigestCachenow keeps a context without a key for each digest, andcreateHmac()duplicates it.The first version of this PR also ran small Web Crypto jobs on the calling thread. I've split that out. It'll come back as its own PR, with HTTP latency and event loop responsiveness measurements under crypto load.
Benchmarks
benchmark/compare.json an Apple M5 Max running macOS 26.7.1. The base is 48cb57d, and the branch merges cleanly with current main.***), geomean +10.9%DiffieHellmanGroup+25%,Hmac+13%,Sign+11%,Verify+11%sync=1These were 30 runs each. Nothing else is slower after Holm-Bonferroni correction:
scenario=first-after-generate(-1.5%). Neither reproduced as significant in 30 interleaved runs (-2.4% with z=1.35 and -3.5% with z=1.43, while A/A runs were within 1%).createHash()doesn't run any changed code. Interleaved runs of thecreateHashconfigs in webcrypto-digest.js show about -2% (A/A: +0.2%), which I haven't been able to attribute. crypto/create-hash.js and theHashcase of crypto/class-construction.js show no significant change.Tests
test: cover crypto digest and HMAC caches adds two tests:
createHmac()instances with the same digest and different keys, interleaves their updates, and checks each result against the RFC 4231 vectors for SHA-256 and SHA-512.createHmac()is the only one of these operations that would reveal a stale cache entry, because the other ones also need a signature or KDF fetch that fails in FIPS mode. I checked that the test fails when the cache is never invalidated.The existing crypto, webcrypto, WPT webcrypto, async-hooks, TLS and HTTPS tests pass locally, and each commit builds on its own.
This was developed with an AI coding agent (Grok), which also drafted this description.