Skip to content

Commit c3bea15

Browse files
committed
Super fast XOR
Closes #76
1 parent 5cdcc5e commit c3bea15

File tree

3 files changed

+41
-2
lines changed

3 files changed

+41
-2
lines changed

websocket_test.go

+1
Original file line numberDiff line numberDiff line change
@@ -776,6 +776,7 @@ func benchConn(b *testing.B, echo, stream bool, size int) {
776776
func BenchmarkConn(b *testing.B) {
777777
sizes := []int{
778778
2,
779+
16,
779780
32,
780781
512,
781782
4096,

xor.go

+39-2
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,10 @@ import (
1313
// to be used for masking in the key. This is so that
1414
// unmasking can be performed without the entire frame.
1515
func fastXOR(key [4]byte, keyPos int, b []byte) int {
16-
// If the payload is greater than 16 bytes, then it's worth
16+
// If the payload is greater than or equal to 16 bytes, then it's worth
1717
// masking 8 bytes at a time.
1818
// Optimization from https://github.com/golang/go/issues/31586#issuecomment-485530859
19-
if len(b) > 16 {
19+
if len(b) >= 16 {
2020
// We first create a key that is 8 bytes long
2121
// and is aligned on the position correctly.
2222
var alignedKey [8]byte
@@ -25,6 +25,43 @@ func fastXOR(key [4]byte, keyPos int, b []byte) int {
2525
}
2626
k := binary.LittleEndian.Uint64(alignedKey[:])
2727

28+
// Then we xor until b is less than 128 bytes.
29+
for len(b) >= 128 {
30+
v := binary.LittleEndian.Uint64(b)
31+
binary.LittleEndian.PutUint64(b, v^k)
32+
v = binary.LittleEndian.Uint64(b[8:])
33+
binary.LittleEndian.PutUint64(b[8:], v^k)
34+
v = binary.LittleEndian.Uint64(b[16:])
35+
binary.LittleEndian.PutUint64(b[16:], v^k)
36+
v = binary.LittleEndian.Uint64(b[24:])
37+
binary.LittleEndian.PutUint64(b[24:], v^k)
38+
v = binary.LittleEndian.Uint64(b[32:])
39+
binary.LittleEndian.PutUint64(b[32:], v^k)
40+
v = binary.LittleEndian.Uint64(b[40:])
41+
binary.LittleEndian.PutUint64(b[40:], v^k)
42+
v = binary.LittleEndian.Uint64(b[48:])
43+
binary.LittleEndian.PutUint64(b[48:], v^k)
44+
v = binary.LittleEndian.Uint64(b[56:])
45+
binary.LittleEndian.PutUint64(b[56:], v^k)
46+
v = binary.LittleEndian.Uint64(b[64:])
47+
binary.LittleEndian.PutUint64(b[64:], v^k)
48+
v = binary.LittleEndian.Uint64(b[72:])
49+
binary.LittleEndian.PutUint64(b[72:], v^k)
50+
v = binary.LittleEndian.Uint64(b[80:])
51+
binary.LittleEndian.PutUint64(b[80:], v^k)
52+
v = binary.LittleEndian.Uint64(b[88:])
53+
binary.LittleEndian.PutUint64(b[88:], v^k)
54+
v = binary.LittleEndian.Uint64(b[96:])
55+
binary.LittleEndian.PutUint64(b[96:], v^k)
56+
v = binary.LittleEndian.Uint64(b[104:])
57+
binary.LittleEndian.PutUint64(b[104:], v^k)
58+
v = binary.LittleEndian.Uint64(b[112:])
59+
binary.LittleEndian.PutUint64(b[112:], v^k)
60+
v = binary.LittleEndian.Uint64(b[120:])
61+
binary.LittleEndian.PutUint64(b[120:], v^k)
62+
b = b[128:]
63+
}
64+
2865
// Then we xor until b is less than 8 bytes.
2966
for len(b) >= 8 {
3067
v := binary.LittleEndian.Uint64(b)

xor_test.go

+1
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ func basixXOR(maskKey [4]byte, pos int, b []byte) int {
3636
func BenchmarkXOR(b *testing.B) {
3737
sizes := []int{
3838
2,
39+
16,
3940
32,
4041
512,
4142
4096,

0 commit comments

Comments
 (0)