Skip to content

Enforce that any SharedArrayBuffers that get passed to crypto operations get cloned as non-shared#1116

Merged
steveluscher merged 1 commit into
mainfrom
12-16-enforce_that_any_sharedarraybuffers_passed_to_crypto_operations_get_cloned_as_non-shared
Dec 16, 2025
Merged

Enforce that any SharedArrayBuffers that get passed to crypto operations get cloned as non-shared#1116
steveluscher merged 1 commit into
mainfrom
12-16-enforce_that_any_sharedarraybuffers_passed_to_crypto_operations_get_cloned_as_non-shared

Conversation

@steveluscher
Copy link
Copy Markdown
Contributor

Problem

When you pass a SharedArrayBuffer to a crypto operation (eg. SubtleCrypto#sign) it fatals. TypeScript recently got more strict about this, resulting in type errors that make this PR necessary.

Summary of Changes

In this PR we clone SharedArrayBuffer as non-shared when it's used in a crypto operation.

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Dec 16, 2025

🦋 Changeset detected

Latest commit: bc62790

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 42 packages
Name Type
@solana/codecs-numbers Patch
@solana/codecs-strings Patch
@solana/codecs-core Patch
@solana/compat Patch
@solana/keys Patch
@solana/codecs-data-structures Patch
@solana/codecs Patch
@solana/offchain-messages Patch
@solana/options Patch
@solana/rpc-types Patch
@solana/transaction-messages Patch
@solana/transactions Patch
@solana/accounts Patch
@solana/addresses Patch
@solana/rpc-api Patch
@solana/rpc-graphql Patch
@solana/transaction-confirmation Patch
@solana/instructions Patch
@solana/react Patch
@solana/signers Patch
@solana/instruction-plans Patch
@solana/kit Patch
@solana/rpc-subscriptions-api Patch
@solana/sysvars Patch
@solana/rpc-parsed-types Patch
@solana/rpc-subscriptions Patch
@solana/rpc-transformers Patch
@solana/rpc Patch
@solana/programs Patch
@solana/assertions Patch
@solana/errors Patch
@solana/fast-stable-stringify Patch
@solana/functional Patch
@solana/nominal-types Patch
@solana/promises Patch
@solana/rpc-spec-types Patch
@solana/rpc-spec Patch
@solana/rpc-subscriptions-channel-websocket Patch
@solana/rpc-subscriptions-spec Patch
@solana/rpc-transport-http Patch
@solana/subscribable Patch
@solana/webcrypto-ed25519-polyfill Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

Copy link
Copy Markdown
Contributor Author

steveluscher commented Dec 16, 2025

@bundlemon
Copy link
Copy Markdown

bundlemon Bot commented Dec 16, 2025

BundleMon

Files updated (3)
Status Path Size Limits
keys/dist/index.browser.mjs
2.1KB (+23B +1.08%) -
keys/dist/index.node.mjs
2.1KB (+23B +1.08%) -
keys/dist/index.native.mjs
2.1KB (+22B +1.03%) -
Unchanged files (130)
Status Path Size Limits
@solana/kit production bundle
kit/dist/index.production.min.js
39.06KB -
rpc-graphql/dist/index.browser.mjs
18.82KB -
rpc-graphql/dist/index.native.mjs
18.81KB -
rpc-graphql/dist/index.node.mjs
18.81KB -
errors/dist/index.node.mjs
17.07KB -
errors/dist/index.browser.mjs
17.04KB -
errors/dist/index.native.mjs
17.04KB -
transaction-messages/dist/index.browser.mjs
7.29KB -
transaction-messages/dist/index.native.mjs
7.29KB -
transaction-messages/dist/index.node.mjs
7.29KB -
offchain-messages/dist/index.browser.mjs
4.89KB -
offchain-messages/dist/index.native.mjs
4.89KB -
offchain-messages/dist/index.node.mjs
4.89KB -
codecs-data-structures/dist/index.browser.mjs
4.69KB -
codecs-data-structures/dist/index.native.mjs
4.69KB -
codecs-data-structures/dist/index.node.mjs
4.69KB -
instruction-plans/dist/index.browser.mjs
3.71KB -
instruction-plans/dist/index.native.mjs
3.71KB -
instruction-plans/dist/index.node.mjs
3.71KB -
codecs-core/dist/index.browser.mjs
3.61KB -
codecs-core/dist/index.native.mjs
3.61KB -
codecs-core/dist/index.node.mjs
3.61KB -
webcrypto-ed25519-polyfill/dist/index.node.mj
s
3.61KB -
webcrypto-ed25519-polyfill/dist/index.browser
.mjs
3.59KB -
webcrypto-ed25519-polyfill/dist/index.native.
mjs
3.57KB -
rpc-subscriptions/dist/index.browser.mjs
3.37KB -
rpc-subscriptions/dist/index.node.mjs
3.34KB -
rpc-subscriptions/dist/index.native.mjs
3.31KB -
rpc-transformers/dist/index.browser.mjs
2.93KB -
rpc-transformers/dist/index.native.mjs
2.93KB -
rpc-transformers/dist/index.node.mjs
2.93KB -
addresses/dist/index.browser.mjs
2.93KB -
addresses/dist/index.native.mjs
2.92KB -
addresses/dist/index.node.mjs
2.92KB -
signers/dist/index.browser.mjs
2.9KB -
signers/dist/index.native.mjs
2.9KB -
signers/dist/index.node.mjs
2.9KB -
transactions/dist/index.browser.mjs
2.87KB -
transactions/dist/index.native.mjs
2.86KB -
transactions/dist/index.node.mjs
2.86KB -
codecs-strings/dist/index.browser.mjs
2.53KB -
codecs-strings/dist/index.node.mjs
2.49KB -
codecs-strings/dist/index.native.mjs
2.45KB -
transaction-confirmation/dist/index.node.mjs
2.41KB -
transaction-confirmation/dist/index.native.mj
s
2.36KB -
transaction-confirmation/dist/index.browser.m
js
2.35KB -
sysvars/dist/index.browser.mjs
2.35KB -
sysvars/dist/index.native.mjs
2.34KB -
sysvars/dist/index.node.mjs
2.34KB -
react/dist/index.browser.mjs
2.31KB -
react/dist/index.native.mjs
2.31KB -
react/dist/index.node.mjs
2.31KB -
rpc-subscriptions-spec/dist/index.node.mjs
2.18KB -
rpc-subscriptions-spec/dist/index.native.mjs
2.13KB -
rpc-subscriptions-spec/dist/index.browser.mjs
2.13KB -
rpc/dist/index.node.mjs
1.95KB -
codecs-numbers/dist/index.browser.mjs
1.95KB -
codecs-numbers/dist/index.native.mjs
1.95KB -
codecs-numbers/dist/index.node.mjs
1.94KB -
rpc-transport-http/dist/index.browser.mjs
1.91KB -
rpc-transport-http/dist/index.native.mjs
1.9KB -
rpc/dist/index.native.mjs
1.81KB -
rpc/dist/index.browser.mjs
1.8KB -
subscribable/dist/index.node.mjs
1.8KB -
subscribable/dist/index.native.mjs
1.75KB -
subscribable/dist/index.browser.mjs
1.74KB -
rpc-transport-http/dist/index.node.mjs
1.72KB -
kit/dist/index.browser.mjs
1.69KB -
kit/dist/index.native.mjs
1.68KB -
kit/dist/index.node.mjs
1.68KB -
rpc-types/dist/index.browser.mjs
1.53KB -
rpc-types/dist/index.native.mjs
1.53KB -
rpc-types/dist/index.node.mjs
1.53KB -
rpc-subscriptions-channel-websocket/dist/inde
x.node.mjs
1.33KB -
rpc-subscriptions-channel-websocket/dist/inde
x.native.mjs
1.27KB -
rpc-subscriptions-channel-websocket/dist/inde
x.browser.mjs
1.26KB -
options/dist/index.browser.mjs
1.18KB -
options/dist/index.native.mjs
1.18KB -
options/dist/index.node.mjs
1.17KB -
accounts/dist/index.browser.mjs
1.13KB -
accounts/dist/index.native.mjs
1.12KB -
accounts/dist/index.node.mjs
1.12KB -
rpc-api/dist/index.browser.mjs
976B -
rpc-api/dist/index.native.mjs
975B -
rpc-api/dist/index.node.mjs
973B -
compat/dist/index.browser.mjs
969B -
compat/dist/index.native.mjs
968B -
compat/dist/index.node.mjs
966B -
rpc-spec-types/dist/index.browser.mjs
962B -
rpc-spec-types/dist/index.native.mjs
961B -
rpc-spec-types/dist/index.node.mjs
959B -
rpc-subscriptions-api/dist/index.native.mjs
870B -
rpc-subscriptions-api/dist/index.node.mjs
869B -
rpc-subscriptions-api/dist/index.browser.mjs
868B -
rpc-spec/dist/index.browser.mjs
852B -
rpc-spec/dist/index.native.mjs
851B -
rpc-spec/dist/index.node.mjs
850B -
promises/dist/index.browser.mjs
799B -
promises/dist/index.native.mjs
798B -
promises/dist/index.node.mjs
797B -
assertions/dist/index.browser.mjs
783B -
instructions/dist/index.browser.mjs
771B -
instructions/dist/index.native.mjs
770B -
instructions/dist/index.node.mjs
768B -
fast-stable-stringify/dist/index.browser.mjs
726B -
fast-stable-stringify/dist/index.native.mjs
725B -
assertions/dist/index.native.mjs
724B -
fast-stable-stringify/dist/index.node.mjs
724B -
assertions/dist/index.node.mjs
723B -
programs/dist/index.browser.mjs
329B -
programs/dist/index.native.mjs
327B -
programs/dist/index.node.mjs
325B -
event-target-impl/dist/index.node.mjs
230B -
functional/dist/index.browser.mjs
154B -
functional/dist/index.native.mjs
152B -
text-encoding-impl/dist/index.native.mjs
152B -
functional/dist/index.node.mjs
151B -
codecs/dist/index.browser.mjs
137B -
codecs/dist/index.native.mjs
136B -
codecs/dist/index.node.mjs
134B -
event-target-impl/dist/index.browser.mjs
133B -
ws-impl/dist/index.node.mjs
131B -
text-encoding-impl/dist/index.browser.mjs
122B -
text-encoding-impl/dist/index.node.mjs
119B -
ws-impl/dist/index.browser.mjs
113B -
crypto-impl/dist/index.node.mjs
111B -
crypto-impl/dist/index.browser.mjs
109B -
rpc-parsed-types/dist/index.browser.mjs
66B -
rpc-parsed-types/dist/index.native.mjs
65B -
rpc-parsed-types/dist/index.node.mjs
63B -

Total files change +79B +0.02%

Final result: ✅

View report in BundleMon website ➡️


Current branch size history | Target branch size history

type BaseEncoder<TFrom> = {
/** Encode the provided value and return the encoded bytes directly. */
readonly encode: (value: TFrom) => ReadonlyUint8Array;
readonly encode: (value: TFrom) => ReadonlyUint8Array<ArrayBuffer>;
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you think about this narrowing, @lorisleiva. I presume that encoders should never return a SharedArrayBuffer.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me. I can't think of a scenario where you'd want the returned bytes to be shared — and if that was the case, you'd probably want to be super explicit about it and wrap the encoder into something else.

* ```
*/
export interface ReadonlyUint8Array extends Omit<Uint8Array, TypedArrayMutableProperties> {
export interface ReadonlyUint8Array<TArrayBuffer extends ArrayBufferLike = ArrayBufferLike> extends Omit<
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add the ability to say ‘no really, this ReadonlyUint8Array is not a SharedArrayBuffer’.

import { ED25519_ALGORITHM_IDENTIFIER } from './algorithm';

function addPkcs8Header(bytes: ReadonlyUint8Array): ReadonlyUint8Array {
function addPkcs8Header(bytes: ReadonlyUint8Array): ReadonlyUint8Array<ArrayBuffer> {
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here, we're able to express that it's readonly, and non-shared (because we just created it inline).

export async function signBytes(key: CryptoKey, data: ReadonlyUint8Array): Promise<SignatureBytes> {
assertSigningCapabilityIsAvailable();
const signedData = await crypto.subtle.sign(ED25519_ALGORITHM_IDENTIFIER, key, data);
const signedData = await crypto.subtle.sign(ED25519_ALGORITHM_IDENTIFIER, key, toArrayBuffer(data));
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Allows people to pass SharedArrayBuffers in here for signing, without triggering a runtime error.

@steveluscher steveluscher force-pushed the 12-16-enforce_that_any_sharedarraybuffers_passed_to_crypto_operations_get_cloned_as_non-shared branch from dfb2fab to ae1c4e9 Compare December 16, 2025 08:24
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Dec 16, 2025

Documentation Preview: https://kit-docs-41gy0z0mn-anza-tech.vercel.app

type BaseEncoder<TFrom> = {
/** Encode the provided value and return the encoded bytes directly. */
readonly encode: (value: TFrom) => ReadonlyUint8Array;
readonly encode: (value: TFrom) => ReadonlyUint8Array<ArrayBuffer>;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me. I can't think of a scenario where you'd want the returned bytes to be shared — and if that was the case, you'd probably want to be super explicit about it and wrap the encoder into something else.

@steveluscher steveluscher force-pushed the 12-16-enforce_that_any_sharedarraybuffers_passed_to_crypto_operations_get_cloned_as_non-shared branch from ae1c4e9 to 0769816 Compare December 16, 2025 19:20
@steveluscher steveluscher force-pushed the 12-16-a_shared_method_for_converting_uint8arrays_to_arraybuffers_ branch from aeaf04e to d6e2b8e Compare December 16, 2025 19:20
Copy link
Copy Markdown
Contributor Author

steveluscher commented Dec 16, 2025

Merge activity

  • Dec 16, 7:24 PM UTC: A user started a stack merge that includes this pull request via Graphite.
  • Dec 16, 7:26 PM UTC: Graphite rebased this pull request as part of a merge.
  • Dec 16, 7:28 PM UTC: @steveluscher merged this pull request with Graphite.

@steveluscher steveluscher changed the base branch from 12-16-a_shared_method_for_converting_uint8arrays_to_arraybuffers_ to graphite-base/1116 December 16, 2025 19:24
@steveluscher steveluscher changed the base branch from graphite-base/1116 to main December 16, 2025 19:24
@steveluscher steveluscher force-pushed the 12-16-enforce_that_any_sharedarraybuffers_passed_to_crypto_operations_get_cloned_as_non-shared branch from 0769816 to bc62790 Compare December 16, 2025 19:25
@steveluscher steveluscher merged commit 109c78e into main Dec 16, 2025
13 checks passed
@steveluscher steveluscher deleted the 12-16-enforce_that_any_sharedarraybuffers_passed_to_crypto_operations_get_cloned_as_non-shared branch December 16, 2025 19:28
@github-actions
Copy link
Copy Markdown
Contributor

🔎💬 Inkeep AI search and chat service is syncing content for source 'Solana Kit Docs'

@github-actions
Copy link
Copy Markdown
Contributor

Because there has been no activity on this PR for 14 days since it was merged, it has been automatically locked. Please open a new issue if it requires a follow up.

@github-actions github-actions Bot locked as resolved and limited conversation to collaborators Dec 31, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants