Skip to content

Commit 17c2532

Browse files
committed
xts: reduce tweak allocations
The call to k2.Encrypt causes tweak to escape to the heap, resulting in a 16-byte allocation for each call to Encrypt/Decrypt. Moving tweak into the Cipher struct would allow it to be reused, but this is ruled out by the Cipher docstring, which states that it is safe for concurrent use. Instead, manage tweak arrays with a sync.Pool. Benchmarks indicate that this amortizes allocation cost without impacting performance. benchmark old ns/op new ns/op delta BenchmarkXTS-4 234 245 +4.70% benchmark old allocs new allocs delta BenchmarkXTS-4 2 0 -100.00% benchmark old bytes new bytes delta BenchmarkXTS-4 32 0 -100.00%
1 parent 20e8f4b commit 17c2532

File tree

1 file changed

+21
-4
lines changed

1 file changed

+21
-4
lines changed

xts/xts.go

+21-4
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import (
2525
"crypto/cipher"
2626
"encoding/binary"
2727
"errors"
28+
"sync"
2829

2930
"golang.org/x/crypto/internal/subtle"
3031
)
@@ -39,6 +40,12 @@ type Cipher struct {
3940
// only defined for 16-byte ciphers.
4041
const blockSize = 16
4142

43+
var tweakPool = sync.Pool{
44+
New: func() interface{} {
45+
return new([blockSize]byte)
46+
},
47+
}
48+
4249
// NewCipher creates a Cipher given a function for creating the underlying
4350
// block cipher (which must have a block size of 16 bytes). The key must be
4451
// twice the length of the underlying cipher's key.
@@ -70,7 +77,10 @@ func (c *Cipher) Encrypt(ciphertext, plaintext []byte, sectorNum uint64) {
7077
panic("xts: invalid buffer overlap")
7178
}
7279

73-
var tweak [blockSize]byte
80+
tweak := tweakPool.Get().(*[blockSize]byte)
81+
for i := range tweak {
82+
tweak[i] = 0
83+
}
7484
binary.LittleEndian.PutUint64(tweak[:8], sectorNum)
7585

7686
c.k2.Encrypt(tweak[:], tweak[:])
@@ -86,8 +96,10 @@ func (c *Cipher) Encrypt(ciphertext, plaintext []byte, sectorNum uint64) {
8696
plaintext = plaintext[blockSize:]
8797
ciphertext = ciphertext[blockSize:]
8898

89-
mul2(&tweak)
99+
mul2(tweak)
90100
}
101+
102+
tweakPool.Put(tweak)
91103
}
92104

93105
// Decrypt decrypts a sector of ciphertext and puts the result into plaintext.
@@ -104,7 +116,10 @@ func (c *Cipher) Decrypt(plaintext, ciphertext []byte, sectorNum uint64) {
104116
panic("xts: invalid buffer overlap")
105117
}
106118

107-
var tweak [blockSize]byte
119+
tweak := tweakPool.Get().(*[blockSize]byte)
120+
for i := range tweak {
121+
tweak[i] = 0
122+
}
108123
binary.LittleEndian.PutUint64(tweak[:8], sectorNum)
109124

110125
c.k2.Encrypt(tweak[:], tweak[:])
@@ -120,8 +135,10 @@ func (c *Cipher) Decrypt(plaintext, ciphertext []byte, sectorNum uint64) {
120135
plaintext = plaintext[blockSize:]
121136
ciphertext = ciphertext[blockSize:]
122137

123-
mul2(&tweak)
138+
mul2(tweak)
124139
}
140+
141+
tweakPool.Put(tweak)
125142
}
126143

127144
// mul2 multiplies tweak by 2 in GF(2¹²⁸) with an irreducible polynomial of

0 commit comments

Comments
 (0)