brontide: when decrypting re-use the allocated ciphertext buf

In this commit, we implement a simple optimization that dramatically
reduces the number of allocations we need to make when we decrypt a new
message. Before this commit, we would pass in a `nil` value to the
`Decrypt` method which meant that it would always allocate a new
buffers.

Rather than force this behavior, in this commit, we pass in the
ciphertext buffer (with a length of zero), such that the decryption
operation will simply copy the plaintext bytes over the cipher text in
place. This works as the cipher text is always larger than the
plaintext, since the plaintext doesn't have a MAC attached.

The amount the perf increase, amount of allocations, and amount of bytes
allocated are pretty nice:
```
benchmark                        old ns/op     new ns/op     delta
BenchmarkReadHeaderAndBody-8     88652         75896         -14.39%

benchmark                        old allocs     new allocs     delta
BenchmarkReadHeaderAndBody-8     6              4              -33.33%

benchmark                        old bytes     new bytes     delta
BenchmarkReadHeaderAndBody-8     65664         128           -99.81%
```

Here old is without this change, and new with it.
This commit is contained in:
Olaoluwa Osuntokun 2021-08-11 17:55:26 -07:00
parent 02509025d5
commit 8c6dbc9ffa
No known key found for this signature in database
GPG key ID: 3BBD59E99B280306

View file

@ -854,8 +854,11 @@ func (b *Machine) ReadHeader(r io.Reader) (uint32, error) {
}
// Attempt to decrypt+auth the packet length present in the stream.
//
// By passing in `nextCipherHeader` as the destination, we avoid making
// the library allocate a new buffer to decode the plaintext.
pktLenBytes, err := b.recvCipher.Decrypt(
nil, nil, b.nextCipherHeader[:],
nil, b.nextCipherHeader[:0], b.nextCipherHeader[:],
)
if err != nil {
return 0, err
@ -880,10 +883,13 @@ func (b *Machine) ReadBody(r io.Reader, buf []byte) ([]byte, error) {
return nil, err
}
// Finally, decrypt the message held in the buffer, and return a
// new byte slice containing the plaintext.
// TODO(roasbeef): modify to let pass in slice
return b.recvCipher.Decrypt(nil, nil, buf)
// Finally, decrypt the message held in the buffer, and return a new
// byte slice containing the plaintext.
//
// By passing in the buf (the ciphertext) as the first argument, we end
// up re-using it as we don't force the library to allocate a new
// buffer to decode the plaintext.
return b.recvCipher.Decrypt(nil, buf[:0], buf)
}
// SetCurveToNil sets the 'Curve' parameter to nil on the handshakeState keys.