Conversation
The package supports OS 26, where CryptoKit lacks span-based `seal(inPlace:)` and `open(inPlace:)`, so it ships copying wrappers with the same names. Because they share CryptoKit's signatures, they shadow its API throughout the module, and a client supporting OS 26 takes the copying path even on OS 27. `DISABLE_SHIM_CRYPTO_SPAN_APIS` only avoids that by requiring an OS 27 deployment target. That costs three allocations per packet, one to seal and two to open. Added `sealInPlace` and `openInPlace` entry points that call CryptoKit's span API when the running OS has it, and otherwise fall back to the wrappers, now named `sealInPlaceThroughSealedBox` and `openInPlaceThroughSealedBox` after how they work. With `DISABLE_SHIM_CRYPTO_SPAN_APIS` they call CryptoKit directly, as before. Measured on my Mac against `main` with the package's QUIC benchmark tools. Allocation counts come from full malloc stack logging, which records every allocation: QUICTransfer -size 1200, per message 24.37 -> 19.17 QUICTransfer, per 500 KB transfer 6,187.6 -> 4,027.2 QUICHandshake, per connection 1,947.4 -> 1,919.3 QUICStreamLoad, per stream 111.8 -> 102.3 Wall-clock time comes from running `main`, this change and the other changes measured alongside it in a rotating order for 9 rounds, and comparing each run with `main`'s in the same round. Changes moved paths they do not touch by up to about 1.3%, so differences that size count as noise. The 500 KB transfers took 8.3% less time, the handshakes 1.8% less and the stream load 16.2% less, faster in all 9 rounds each; the 1,200-byte messages did not change beyond noise.
rnro
requested review from
agnosticdev,
ekinnear,
kkuk24,
rpaulo and
tfpauly
as code owners
October 1, 2026 19:53
agnosticdev
reviewed
Oct 2, 2026
agnosticdev
left a comment
Collaborator
There was a problem hiding this comment.
So you're saying that passing through the wrappers was the part that is taking extra allocations, not actually when DISABLE_SHIM_CRYPTO_SPAN_APIS is enabled, correct?
Contributor
Author
Yes, that's correct. This change means that even if |
agnosticdev
approved these changes
Oct 2, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The package supports OS 26, where CryptoKit lacks span-based
seal(inPlace:)and
open(inPlace:), so it ships copying wrappers with the same names. Becausethey share CryptoKit's signatures, they shadow its API throughout the module,
and a client supporting OS 26 takes the copying path even on OS 27.
DISABLE_SHIM_CRYPTO_SPAN_APISonly avoids that by requiring an OS 27deployment target. That costs three allocations per packet, one to seal and two
to open.
Added
sealInPlaceandopenInPlaceentry points that call CryptoKit's spanAPI when the running OS has it, and otherwise fall back to the wrappers, now
named
sealInPlaceThroughSealedBoxandopenInPlaceThroughSealedBoxafter howthey work. With
DISABLE_SHIM_CRYPTO_SPAN_APISthey call CryptoKit directly, asbefore.
Measured on my Mac against
mainwith the package's QUIC benchmark tools.Allocation counts come from full malloc stack logging, which records every
allocation:
Wall-clock time comes from running
main, this change and the other changesmeasured alongside it in a rotating order for 9 rounds, and comparing each run
with
main's in the same round. Changes moved paths they do not touch by up toabout 1.3%, so differences that size count as noise. The 500 KB transfers took
8.3% less time, the handshakes 1.8% less and the stream load 16.2% less, faster
in all 9 rounds each; the 1,200-byte messages did not change beyond noise.