Optimize non-overlapping CFB8 decryption using SIMD XOR (#265)
This commit is contained in:
2
.github/workflows/codeql-analysis.yml
vendored
2
.github/workflows/codeql-analysis.yml
vendored
@ -32,7 +32,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v4
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
|
44
.github/workflows/go.yml
vendored
44
.github/workflows/go.yml
vendored
@ -1,31 +1,39 @@
|
||||
name: Go
|
||||
on: [push, pull_request]
|
||||
on: [ push, pull_request ]
|
||||
jobs:
|
||||
|
||||
test:
|
||||
name: Test
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
# match the minimum supported and the latest Go versions
|
||||
go_version: [ '1.20', '^1.20' ]
|
||||
|
||||
steps:
|
||||
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@v1
|
||||
with:
|
||||
go-version: 1.19
|
||||
id: go
|
||||
- name: Check out code into the Go module directory
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Check out code into the Go module directory
|
||||
uses: actions/checkout@v1
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: ${{ matrix.go_version }}
|
||||
check-latest: true
|
||||
|
||||
- name: Test
|
||||
run: go test ./...
|
||||
- name: Test
|
||||
run: go test ./...
|
||||
|
||||
- run: mkdir -p ./bin/tools
|
||||
- run: mkdir -p ./bin/tools
|
||||
|
||||
- name: Build tools
|
||||
run: go build -o ./bin/tools ./examples/...
|
||||
- name: Build tools
|
||||
run: go build -o ./bin/tools ./examples/...
|
||||
|
||||
- name: Upload tools
|
||||
uses: actions/upload-artifact@v1
|
||||
with:
|
||||
name: tools
|
||||
path: ./bin/tools
|
||||
- name: Upload tools
|
||||
if: ${{ startsWith(matrix.go_version, '^') }}
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: tools
|
||||
path: ./bin/tools
|
||||
|
@ -7,7 +7,7 @@
|
||||
|
||||
### [教程 · Tutorial](https://go-mc.github.io/tutorial/)
|
||||
|
||||
Require Go version: 1.19
|
||||
Require Go version: 1.20
|
||||
|
||||
There's some library in Go support you to create your Minecraft client or server.
|
||||
这是一些Golang库,用于帮助你编写自己的Minecraft客户端或服务器。
|
||||
|
2
go.mod
2
go.mod
@ -1,6 +1,6 @@
|
||||
module github.com/Tnze/go-mc
|
||||
|
||||
go 1.19
|
||||
go 1.20
|
||||
|
||||
require (
|
||||
github.com/google/uuid v1.3.0
|
||||
|
@ -3,6 +3,7 @@ package CFB8
|
||||
|
||||
import (
|
||||
"crypto/cipher"
|
||||
"crypto/subtle"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
@ -48,7 +49,7 @@ func (cf *CFB8) XORKeyStream(dst, src []byte) {
|
||||
// After this, the IV will come to the same as
|
||||
// the last blockSize of ciphertext, so
|
||||
// we can reuse them without copy.
|
||||
cf.XORKeyStream(dst, src[:cf.blockSize])
|
||||
cf.xorKeyStream(dst, src[:cf.blockSize])
|
||||
var ciphertext []byte
|
||||
if cf.de {
|
||||
ciphertext = src
|
||||
@ -63,16 +64,37 @@ func (cf *CFB8) XORKeyStream(dst, src []byte) {
|
||||
i int
|
||||
val byte
|
||||
)
|
||||
for i, val = range src {
|
||||
cf.c.Encrypt(iv, ciphertext[i:])
|
||||
dst[i] = val ^ iv[0]
|
||||
dst = dst[:len(src)]
|
||||
if cf.de {
|
||||
for i = 0; i < len(src)-cf.blockSize; i += 1 {
|
||||
cf.c.Encrypt(dst[i:], ciphertext[i:])
|
||||
}
|
||||
subtle.XORBytes(dst, src[:i], dst)
|
||||
for ; i < len(src); i += 1 {
|
||||
cf.c.Encrypt(iv, ciphertext[i:])
|
||||
dst[i] = src[i] ^ iv[0]
|
||||
}
|
||||
} else {
|
||||
_ = ciphertext[len(src)]
|
||||
for i, val = range src {
|
||||
cf.c.Encrypt(iv, ciphertext[i:])
|
||||
dst[i] = val ^ iv[0]
|
||||
}
|
||||
// for-range does not increase i in the last loop,
|
||||
// compared to the classic for clause
|
||||
i += 1
|
||||
}
|
||||
// copy the current IV for next operation
|
||||
copy(iv, ciphertext[i+1:i+1+cf.blockSize])
|
||||
copy(iv, ciphertext[i:i+cf.blockSize])
|
||||
cf.ivPos = 0
|
||||
return
|
||||
}
|
||||
|
||||
cf.xorKeyStream(dst, src)
|
||||
}
|
||||
|
||||
func (cf *CFB8) xorKeyStream(dst, src []byte) {
|
||||
dst = dst[:len(src)] // remove bounds check in loop
|
||||
for i, val := range src {
|
||||
posPlusBlockSize := cf.ivPos + cf.blockSize
|
||||
// fast mod; 2*blockSize must be a non-negative integer power of 2
|
||||
|
@ -3,6 +3,7 @@ package CFB8
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"testing"
|
||||
@ -150,14 +151,8 @@ func TestCFB8VectorsOverlapped(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkCFB8AES1KOverlapped(b *testing.B) {
|
||||
var key [16]byte
|
||||
var iv [16]byte
|
||||
rand.Read(key[:])
|
||||
rand.Read(iv[:])
|
||||
func benchmarkStreamOverlapped(b *testing.B, stream cipher.Stream) {
|
||||
buf := make([]byte, 1024)
|
||||
aes, _ := aes.NewCipher(key[:])
|
||||
stream := NewCFB8Encrypt(aes, iv[:])
|
||||
|
||||
b.SetBytes(int64(len(buf)))
|
||||
b.ReportAllocs()
|
||||
@ -167,15 +162,9 @@ func BenchmarkCFB8AES1KOverlapped(b *testing.B) {
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkCFB8AES1KNonOverlapping(b *testing.B) {
|
||||
var key [16]byte
|
||||
var iv [16]byte
|
||||
rand.Read(key[:])
|
||||
rand.Read(iv[:])
|
||||
func benchmarkStreamNonOverlapping(b *testing.B, stream cipher.Stream) {
|
||||
buf := make([]byte, 1024)
|
||||
buf2 := make([]byte, 1024)
|
||||
aes, _ := aes.NewCipher(key[:])
|
||||
stream := NewCFB8Encrypt(aes, iv[:])
|
||||
|
||||
b.SetBytes(int64(len(buf)))
|
||||
b.ReportAllocs()
|
||||
@ -184,3 +173,46 @@ func BenchmarkCFB8AES1KNonOverlapping(b *testing.B) {
|
||||
stream.XORKeyStream(buf2, buf)
|
||||
}
|
||||
}
|
||||
func BenchmarkCFB8AES1KEncryptOverlapped(b *testing.B) {
|
||||
var key [16]byte
|
||||
var iv [16]byte
|
||||
rand.Read(key[:])
|
||||
rand.Read(iv[:])
|
||||
aes, _ := aes.NewCipher(key[:])
|
||||
stream := NewCFB8Encrypt(aes, iv[:])
|
||||
|
||||
benchmarkStreamOverlapped(b, stream)
|
||||
}
|
||||
|
||||
func BenchmarkCFB8AES1KEncryptNonOverlapping(b *testing.B) {
|
||||
var key [16]byte
|
||||
var iv [16]byte
|
||||
rand.Read(key[:])
|
||||
rand.Read(iv[:])
|
||||
aes, _ := aes.NewCipher(key[:])
|
||||
stream := NewCFB8Encrypt(aes, iv[:])
|
||||
|
||||
benchmarkStreamNonOverlapping(b, stream)
|
||||
}
|
||||
|
||||
func BenchmarkCFB8AES1KDecryptOverlapped(b *testing.B) {
|
||||
var key [16]byte
|
||||
var iv [16]byte
|
||||
rand.Read(key[:])
|
||||
rand.Read(iv[:])
|
||||
aes, _ := aes.NewCipher(key[:])
|
||||
stream := NewCFB8Decrypt(aes, iv[:])
|
||||
|
||||
benchmarkStreamOverlapped(b, stream)
|
||||
}
|
||||
|
||||
func BenchmarkCFB8AES1KDecryptNonOverlapping(b *testing.B) {
|
||||
var key [16]byte
|
||||
var iv [16]byte
|
||||
rand.Read(key[:])
|
||||
rand.Read(iv[:])
|
||||
aes, _ := aes.NewCipher(key[:])
|
||||
stream := NewCFB8Decrypt(aes, iv[:])
|
||||
|
||||
benchmarkStreamNonOverlapping(b, stream)
|
||||
}
|
||||
|
Reference in New Issue
Block a user