Skip to content

fix(noise): size handshake read buffer with correct overhead - #631

Open
dimartiro wants to merge 1 commit into
paritytech:masterfrom
dimartiro:fix/noise-handshake-prealloc-overhead
Open

fix(noise): size handshake read buffer with correct overhead#631
dimartiro wants to merge 1 commit into
paritytech:masterfrom
dimartiro:fix/noise-handshake-prealloc-overhead

Conversation

@dimartiro

Copy link
Copy Markdown
Contributor

Description

read_handshake_message allocated its decryption output buffer as message.len() + 200 — an arbitrary overhead flagged with a TODO.

Closes #332

Comment thread src/crypto/noise/mod.rs
// Noise decryption strips the 16-byte AEAD (Poly1305) tag, so the decrypted
// plaintext is never larger than the ciphertext. `message.len()` is therefore
// a guaranteed-sufficient upper bound for the output buffer.
let mut out = BytesMut::zeroed(message.len());

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Could you please double check for running nodes in Kusama and Polkadot? 🙏 I would simply place info logs for before and after with the actual length.

IIRC the actual message we receive is bigger than the message.len() hence the added 200, which would otherwise trigger a reallocation and affect performance

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.

The out buffer holds the decrypted plaintext, not the received frame — and in Noise the plaintext is always smaller than the ciphertext, so message.len() can't be exceeded. I traced this in snow 0.9.6:

  • _read_message writes to out only in the final decrypt_and_mix_hash(ptr, payload) (handshakestate.rs:445); the ephemeral/static DH keys go to internal buffers (self.re/self.rs), never to out. ptr is a suffix of message, so ptr.len() <= message.len().
  • The size check is out.len() >= ciphertext.len() - TAGLEN with TAGLEN = 16 (cipherstate.rs:53), so out.len() = message.len() is sufficient with margin.
  • read_message takes a fixed &mut [u8]; an undersized buffer returns Error::Decrypt, never a reallocation. So the old +200 was pure over-allocation, not realloc-avoidance.

Happy to add temporary before/after info logs on a Kusama/Polkadot node if you'd still like empirical confirmation, but the bound is provable from the snow source.

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.

crypto/noise: Preallocate handshake memory with correct overhead

2 participants