This improves the performance of the asm implementation for chacha20 on ppc64le by updating to the vsx implementation provided in cryptogams. The previous implementation was found to not perform as well as possible on power9. This implementation improves performance on both power8 and power9. Power9 improvement with this change as compared to current: name old time/op new time/op delta ChaCha20/32-64 361ns ± 0% 225ns ± 0% -37.67% (p=1.000 n=1+1) ChaCha20/63-64 364ns ± 0% 229ns ± 0% -37.09% (p=1.000 n=1+1) ChaCha20/64-64 364ns ± 0% 231ns ± 0% -36.54% (p=1.000 n=1+1) ChaCha20/256-64 332ns ± 0% 199ns ± 0% -40.06% (p=1.000 n=1+1) ChaCha20/1024-64 1.24µs ± 0% 0.70µs ± 0% -43.23% (p=1.000 n=1+1) ChaCha20/1350-64 1.89µs ± 0% 1.03µs ± 0% -45.35% (p=1.000 n=1+1) ChaCha20/65536-64 77.0µs ± 0% 42.5µs ± 0% -44.83% (p=1.000 n=1+1) This is discussed in issue golang/go#25051. A few asm instructions vmrgew and vmrgow were just added in Go 1.14 so have been encoded using WORD at this point. Change-Id: I2b192a63cf46b0b20195e60e4412c43c5dd14ad8 Reviewed-on: https://go-review.googlesource.com/c/crypto/+/195959 Run-TryBot: Lynn Boger <laboger@linux.vnet.ibm.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Carlos Eduardo Seo <cseo@linux.vnet.ibm.com>
54 lines
1.7 KiB
Go
54 lines
1.7 KiB
Go
// Copyright 2019 The Go Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
// +build ppc64le,!gccgo,!appengine
|
|
|
|
package chacha20
|
|
|
|
import (
|
|
"encoding/binary"
|
|
)
|
|
|
|
var haveAsm = true
|
|
|
|
const bufSize = 256
|
|
|
|
//go:noescape
|
|
func chaCha20_ctr32_vsx(out, inp *byte, len int, key *[8]uint32, counter *uint32)
|
|
|
|
func (c *Cipher) xorKeyStreamAsm(dst, src []byte) {
|
|
// This implementation can handle buffers that aren't multiples of
|
|
// 256.
|
|
if len(src) >= bufSize {
|
|
chaCha20_ctr32_vsx(&dst[0], &src[0], len(src), &c.key, &c.counter)
|
|
} else if len(src)%bufSize != 0 {
|
|
chaCha20_ctr32_vsx(&c.buf[0], &c.buf[0], bufSize, &c.key, &c.counter)
|
|
start := len(src) - len(src)%bufSize
|
|
ts, td, tb := src[start:], dst[start:], c.buf[:]
|
|
// Unroll loop to XOR 32 bytes per iteration.
|
|
for i := 0; i < len(ts)-32; i += 32 {
|
|
td, tb = td[:len(ts)], tb[:len(ts)] // bounds check elimination
|
|
s0 := binary.LittleEndian.Uint64(ts[0:8])
|
|
s1 := binary.LittleEndian.Uint64(ts[8:16])
|
|
s2 := binary.LittleEndian.Uint64(ts[16:24])
|
|
s3 := binary.LittleEndian.Uint64(ts[24:32])
|
|
b0 := binary.LittleEndian.Uint64(tb[0:8])
|
|
b1 := binary.LittleEndian.Uint64(tb[8:16])
|
|
b2 := binary.LittleEndian.Uint64(tb[16:24])
|
|
b3 := binary.LittleEndian.Uint64(tb[24:32])
|
|
binary.LittleEndian.PutUint64(td[0:8], s0^b0)
|
|
binary.LittleEndian.PutUint64(td[8:16], s1^b1)
|
|
binary.LittleEndian.PutUint64(td[16:24], s2^b2)
|
|
binary.LittleEndian.PutUint64(td[24:32], s3^b3)
|
|
ts, td, tb = ts[32:], td[32:], tb[32:]
|
|
}
|
|
td, tb = td[:len(ts)], tb[:len(ts)] // bounds check elimination
|
|
for i, v := range ts {
|
|
td[i] = tb[i] ^ v
|
|
}
|
|
c.len = bufSize - (len(src) % bufSize)
|
|
}
|
|
|
|
}
|