Skip to content

Instantly share code, notes, and snippets.

@hoelzro
Created March 11, 2020 17:27
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hoelzro/7999d1f0a4123d3d1220e3d87ca9542f to your computer and use it in GitHub Desktop.
Save hoelzro/7999d1f0a4123d3d1220e3d87ca9542f to your computer and use it in GitHub Desktop.
package main
import (
"bytes"
"crypto/aes"
"fmt"
"runtime"
"sync"
"time"
)
func singleThreaded(rounds int, key, origPayload [32]byte) []byte {
payload := make([]byte, 32)
copy(payload, origPayload[:])
cipher, err := aes.NewCipher(key[:])
if err != nil {
panic(err.Error())
}
for i := 0; i < rounds; i++ {
cipher.Encrypt(payload[0:16], payload[0:16])
cipher.Encrypt(payload[16:32], payload[16:32])
}
return payload
}
func dualThreaded(rounds int, key, origPayload [32]byte) []byte {
payload := make([]byte, 32)
copy(payload, origPayload[:])
cipher, err := aes.NewCipher(key[:])
if err != nil {
panic(err.Error())
}
wg := sync.WaitGroup{}
wg.Add(1)
go func() {
for i := 0; i < rounds; i++ {
cipher.Encrypt(payload[0:16], payload[0:16])
}
wg.Done()
}()
wg.Add(1)
go func() {
for i := 0; i < rounds; i++ {
cipher.Encrypt(payload[16:32], payload[16:32])
}
wg.Done()
}()
wg.Wait()
return payload
}
func dualThreadedAvoidFalseSharing(rounds int, key, origPayload [32]byte) []byte {
payload := make([]byte, 80)
copy(payload[0:16], origPayload[0:16])
copy(payload[64:80], origPayload[16:32])
cipher, err := aes.NewCipher(key[:])
if err != nil {
panic(err.Error())
}
wg := sync.WaitGroup{}
wg.Add(1)
go func() {
for i := 0; i < rounds; i++ {
cipher.Encrypt(payload[0:16], payload[0:16])
}
wg.Done()
}()
wg.Add(1)
go func() {
for i := 0; i < rounds; i++ {
cipher.Encrypt(payload[64:80], payload[64:80])
}
wg.Done()
}()
wg.Wait()
result := make([]byte, 32)
copy(result[0:16], payload[0:16])
copy(result[16:32], payload[64:80])
return result
}
func main() {
runtime.GOMAXPROCS(4)
key := [32]byte{0xe, 0x0, 0x0, 0x46, 0x0, 0x0, 0x5, 0x1, 0x0, 0x5e, 0x0, 0x4f, 0x58, 0x0, 0x42, 0x45, 0x8, 0x0, 0x0, 0x0, 0x7, 0x0, 0x0, 0x38, 0x6, 0x49, 0x1, 0x1b, 0x44, 0x0, 0x0, 0x4b}
rounds := 20_000_000
payload := [32]byte{0x0, 0x13, 0x39, 0x1e, 0x10, 0x8, 0x0, 0x0, 0x0, 0x24, 0x6, 0x0, 0x0, 0x1, 0x60, 0x1f, 0x37, 0x3, 0x0, 0x0, 0x0, 0x8, 0x41, 0x45, 0x2, 0x0, 0x0, 0x3f, 0x1, 0xc, 0x4b, 0x3e}
expectedResult := [32]byte{0x94, 0x6c, 0x51, 0x9b, 0x92, 0x5, 0x20, 0xbd, 0x3e, 0x16, 0x46, 0x94, 0xf0, 0xa8, 0xd4, 0x97, 0xa, 0xf5, 0xcc, 0xbe, 0xd5, 0x9c, 0xef, 0xf0, 0x19, 0x8d, 0x61, 0xcb, 0xe0, 0x1, 0x90, 0x49}
type bench struct {
name string
code func(int, [32]byte, [32]byte) []byte
}
benches := []bench{
{"Single threaded", singleThreaded},
{"Dual threaded", dualThreaded},
{"Dual threaded, avoiding false sharing", dualThreadedAvoidFalseSharing},
}
for _, b := range benches {
start := time.Now()
gotResult := b.code(rounds, key, payload)
elapsed := time.Since(start)
if !bytes.Equal(gotResult, expectedResult[:]) {
fmt.Printf("%s: Incorrect result\n", b.name)
} else {
fmt.Printf("%s: %v\n", b.name, elapsed)
}
}
}
Single threaded: 964.790093ms
Dual threaded: 1.469041773s
Dual threaded, avoiding false sharing: 666.44416ms
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment