107 lines
1.8 KiB
Go
107 lines
1.8 KiB
Go
//go:build !change
|
|
|
|
package psycher
|
|
|
|
import (
|
|
"crypto/cipher"
|
|
"crypto/rand"
|
|
"slices"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
type slowCipher struct {
|
|
keys [][]byte
|
|
}
|
|
|
|
var _ cipher.Block = (*slowCipher)(nil)
|
|
|
|
func (c slowCipher) BlockSize() int {
|
|
return 16
|
|
}
|
|
|
|
func (c slowCipher) Encrypt(dst, src []byte) {
|
|
var idx int
|
|
for srcI, b := range src {
|
|
for ; b != 0; b /= 2 {
|
|
if b%2 == 1 {
|
|
for i := range dst {
|
|
dst[i] ^= c.keys[idx][i]
|
|
}
|
|
}
|
|
idx++
|
|
}
|
|
idx = (srcI + 1) * 8
|
|
}
|
|
}
|
|
|
|
func (c slowCipher) Decrypt(_, _ []byte) {
|
|
panic("something nerdy")
|
|
}
|
|
|
|
func genKeys() [][]byte {
|
|
var keys [][]byte
|
|
for i := range 128 {
|
|
keys = append(keys, make([]byte, 16))
|
|
_, _ = rand.Read(keys[i])
|
|
}
|
|
return keys
|
|
}
|
|
|
|
func TestCorrectness(t *testing.T) {
|
|
keys := genKeys()
|
|
|
|
solCipher, correctCipher := New(keys), slowCipher{keys: keys}
|
|
|
|
for range 1000 {
|
|
src := make([]byte, 16)
|
|
_, _ = rand.Read(src)
|
|
|
|
srcCopy := slices.Clone(src)
|
|
dst1, dst2 := make([]byte, 16), make([]byte, 16)
|
|
|
|
correctCipher.Encrypt(dst1, src)
|
|
solCipher.Encrypt(dst2, srcCopy)
|
|
|
|
require.Equal(t, src, srcCopy, "shouldn't modify src")
|
|
require.Equal(t, dst1, dst2, "wrong Encrypt output")
|
|
}
|
|
}
|
|
|
|
func benchCipher(b *testing.B, constructor func([][]byte) cipher.Block) {
|
|
keys := genKeys()
|
|
c := constructor(keys)
|
|
|
|
const blocksLen = 1_000_000
|
|
var blocks [][]byte
|
|
for range blocksLen {
|
|
src := make([]byte, 16)
|
|
_, _ = rand.Read(src)
|
|
|
|
blocks = append(blocks, src)
|
|
}
|
|
dst := make([]byte, 16)
|
|
|
|
b.ReportAllocs()
|
|
b.SetBytes(16)
|
|
b.ResetTimer()
|
|
|
|
for i := range b.N {
|
|
c.Encrypt(dst, blocks[i%blocksLen])
|
|
}
|
|
}
|
|
|
|
func BenchmarkSlowCipher(b *testing.B) {
|
|
benchCipher(b, func(keys [][]byte) cipher.Block {
|
|
c := slowCipher{keys: keys}
|
|
return c
|
|
})
|
|
}
|
|
|
|
func BenchmarkCipher(b *testing.B) {
|
|
benchCipher(b, func(keys [][]byte) cipher.Block {
|
|
c := New(keys)
|
|
return c
|
|
})
|
|
}
|