Skip to content

fix(pnet): bound xsalsa20 wasm memory per message and per connection - #3585

Merged
tabcat merged 4 commits into
libp2p:mainfrom
saul-jb:fix/pnet-wasm-memory
Aug 22, 2026
Merged

fix(pnet): bound xsalsa20 wasm memory per message and per connection#3585
tabcat merged 4 commits into
libp2p:mainfrom
saul-jb:fix/pnet-wasm-memory

Conversation

@saul-jb

@saul-jb saul-jb commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

Sending large messages through connections protected by pnet throws:

WebAssembly.Memory.grow(): Maximum memory size exceeded

This PR windows the xsalsa xor so it never grows and exceeds its memory limits. There is also a test added that demonstrates this fix.

@saul-jb
saul-jb requested a review from a team as a code owner July 26, 2026 22:06
tabcat added 2 commits August 21, 2026 18:47
# Conflicts:
#	packages/pnet/src/crypto.ts
#	packages/pnet/test/index.spec.ts
Each cipher holds a slot in a process-global wasm pool that is only returned by
finalize, which pnet never called, so every connection leaked one per direction
until the pool was exhausted and all pnet traffic began to fail.
@tabcat

tabcat commented Aug 22, 2026

Copy link
Copy Markdown
Member

Added a few things to this branch.

pnet has never called finalize() on its ciphers. Each cipher holds a 64 byte slot in a pool that xsalsa20 shares across the whole process, and only finalize() hands it back, so every connection used up two for good. After a few thousand connections a node can't open any more, and the ones it has start failing. It's also the call that wipes the key from memory.

Opening and closing 500 connections now leaves the pool where it started. Before, it grew every time and never came back down.

This is on your PR rather than its own because it doesn't work without your chunking. Growing the wasm memory breaks finalize() for every other cipher, so one big message would stop all of them releasing.

I also reworked the tests. The large message test only checked how many bytes arrived, which passes even with encryption turned off, so it now checks the bytes themselves.

I renamed xorWindowed to xorInChunks and moved it out of the class, since the tests said chunk and the source said window.

@tabcat tabcat changed the title fix(pnet): Handle messages larger than the xsalsa wasm memory limit. fix(pnet): bound xsalsa20 wasm memory per message and per connection Aug 22, 2026
@tabcat
tabcat merged commit 947d304 into libp2p:main Aug 22, 2026
47 of 49 checks passed
@tabcat tabcat mentioned this pull request Aug 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants