Files
crypto/chacha20poly1305/_asm/chacha20poly1305_amd64_asm.go
T
Roland Shoemaker a749d17980 chacha20poly1305: remove usages of BYTE instr
We have had VBROADCASTI128 since at least Go 1.11, so no need to use
BYTE instructions.

Change-Id: I297bbc636320ae830f6e8f83eb174efe8251a9a3
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/672838
Reviewed-by: Daniel McCarney <daniel@binaryparadox.net>
Auto-Submit: Roland Shoemaker <roland@golang.org>
LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Cherry Mui <cherryyz@google.com>
2026-05-18 11:44:40 -07:00

3467 lines
94 KiB
Go

// Copyright 2024 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.
// This assembly implementation was originally from https://golang.org/cl/24717 by Vlad Krasnov of CloudFlare.
package main
import (
"os"
"strings"
. "github.com/mmcloughlin/avo/build"
"github.com/mmcloughlin/avo/ir"
. "github.com/mmcloughlin/avo/operand"
. "github.com/mmcloughlin/avo/reg"
_ "golang.org/x/crypto/chacha20poly1305"
)
//go:generate go run . -out ../chacha20poly1305_amd64.s -pkg chacha20poly1305
var (
// General register allocation
oup GPPhysical = RDI
inp = RSI
inl = RBX
adp = RCX // free to reuse, after we hash the additional data
keyp = R8 // free to reuse, when we copy the key to stack
itr2 = R9 // general iterator
itr1 = RCX // general iterator
acc0 = R10
acc1 = R11
acc2 = R12
t0 = R13
t1 = R14
t2 = R15
t3 = R8
// Register and stack allocation for the SSE code
sStore = Mem{Base: BP}.Offset(1 * 16)
tmpStore = Mem{Base: BP}.Offset(4 * 16)
A0 VecPhysical = X0
A1 = X1
T0 = X12
// Register and stack allocation for the AVX2 code
rsStoreAVX2 Mem = Mem{Base: BP}.Offset(0 * 32)
state1StoreAVX2 = Mem{Base: BP}.Offset(1 * 32)
state2StoreAVX2 = Mem{Base: BP}.Offset(2 * 32)
ctr0StoreAVX2 = Mem{Base: BP}.Offset(3 * 32)
ctr1StoreAVX2 = Mem{Base: BP}.Offset(4 * 32)
ctr2StoreAVX2 = Mem{Base: BP}.Offset(5 * 32)
ctr3StoreAVX2 = Mem{Base: BP}.Offset(6 * 32)
tmpStoreAVX2 = Mem{Base: BP}.Offset(7 * 32) // 256 bytes on stack
AA0 VecPhysical = Y0
AA1 = Y5
AA2 = Y6
AA3 = Y7
BB0 = Y14
BB1 = Y9
BB2 = Y10
BB3 = Y11
CC0 = Y12
CC1 = Y13
CC2 = Y8
CC3 = Y15
DD0 = Y4
DD1 = Y1
DD2 = Y2
DD3 = Y3
TT0 = DD3
TT1 = AA3
TT2 = BB3
TT3 = CC3
)
const ThatPeskyUnicodeDot = "\u00b7"
func main() {
Package("golang.org/x/crypto/chacha20poly1305")
ConstraintExpr("gc,!purego")
polyHashADInternal()
chacha20Poly1305Open()
chacha20Poly1305Seal()
Generate()
var internalFunctions []string = []string{"·polyHashADInternal"}
removePeskyUnicodeDot(internalFunctions, "../chacha20poly1305_amd64.s")
}
func chachaQR_AVX2(A, B, C, D, T VecPhysical) {
VPADDD(B, A, A)
VPXOR(A, D, D)
rol16 := rol16_DATA()
VPSHUFB(rol16, D, D)
VPADDD(D, C, C)
VPXOR(C, B, B)
VPSLLD(Imm(12), B, T)
VPSRLD(Imm(20), B, B)
VPXOR(T, B, B)
VPADDD(B, A, A)
VPXOR(A, D, D)
rol8 := rol8_DATA()
VPSHUFB(rol8, D, D)
VPADDD(D, C, C)
VPXOR(C, B, B)
VPSLLD(Imm(7), B, T)
VPSRLD(Imm(25), B, B)
VPXOR(T, B, B)
}
func polyAdd(S Mem) {
ADDQ(S, acc0)
ADCQ(S.Offset(8), acc1)
ADCQ(Imm(1), acc2)
}
func polyMulStage1() {
MOVQ(Mem{Base: BP}.Offset(0*8), RAX)
MOVQ(RAX, t2)
MULQ(acc0)
MOVQ(RAX, t0)
MOVQ(RDX, t1)
MOVQ(Mem{Base: BP}.Offset(0*8), RAX)
MULQ(acc1)
IMULQ(acc2, t2)
ADDQ(RAX, t1)
ADCQ(RDX, t2)
}
func polyMulStage2() {
MOVQ(Mem{Base: BP}.Offset(1*8), RAX)
MOVQ(RAX, t3)
MULQ(acc0)
ADDQ(RAX, t1)
ADCQ(Imm(0), RDX)
MOVQ(RDX, acc0)
MOVQ(Mem{Base: BP}.Offset(1*8), RAX)
MULQ(acc1)
ADDQ(RAX, t2)
ADCQ(Imm(0), RDX)
}
func polyMulStage3() {
IMULQ(acc2, t3)
ADDQ(acc0, t2)
ADCQ(RDX, t3)
}
func polyMulReduceStage() {
MOVQ(t0, acc0)
MOVQ(t1, acc1)
MOVQ(t2, acc2)
ANDQ(Imm(3), acc2)
MOVQ(t2, t0)
ANDQ(I8(-4), t0)
MOVQ(t3, t1)
SHRQ(Imm(2), t3, t2)
SHRQ(Imm(2), t3)
ADDQ(t0, acc0)
ADCQ(t1, acc1)
ADCQ(Imm(0), acc2)
ADDQ(t2, acc0)
ADCQ(t3, acc1)
ADCQ(Imm(0), acc2)
}
func polyMulStage1_AVX2() {
MOVQ(Mem{Base: BP}.Offset(0*8), RDX)
MOVQ(RDX, t2)
MULXQ(acc0, t0, t1)
IMULQ(acc2, t2)
MULXQ(acc1, RAX, RDX)
ADDQ(RAX, t1)
ADCQ(RDX, t2)
}
func polyMulStage2_AVX2() {
MOVQ(Mem{Base: BP}.Offset(1*8), RDX)
MULXQ(acc0, acc0, RAX)
ADDQ(acc0, t1)
MULXQ(acc1, acc1, t3)
ADCQ(acc1, t2)
ADCQ(Imm(0), t3)
}
func polyMulStage3_AVX2() {
IMULQ(acc2, RDX)
ADDQ(RAX, t2)
ADCQ(RDX, t3)
}
func polyMul() {
polyMulStage1()
polyMulStage2()
polyMulStage3()
polyMulReduceStage()
}
func polyMulAVX2() {
polyMulStage1_AVX2()
polyMulStage2_AVX2()
polyMulStage3_AVX2()
polyMulReduceStage()
}
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
func polyHashADInternal() {
Function("polyHashADInternal<>")
Attributes(NOSPLIT)
AllocLocal(0)
// adp points to beginning of additional data
// itr2 holds ad length
XORQ(acc0, acc0)
XORQ(acc1, acc1)
XORQ(acc2, acc2)
CMPQ(itr2, Imm(13))
JNE(LabelRef("hashADLoop"))
openFastTLSAD()
hashADLoop()
hashADTail()
hashADTailLoop()
hashADTailFinish()
hashADDone()
}
// Special treatment for the TLS case of 13 bytes
func openFastTLSAD() {
Label("openFastTLSAD")
MOVQ(Mem{Base: adp}, acc0)
MOVQ(Mem{Base: adp}.Offset(5), acc1)
SHRQ(Imm(24), acc1)
MOVQ(U32(1), acc2)
polyMul()
RET()
}
// Hash in 16 byte chunks
func hashADLoop() {
Label("hashADLoop")
Comment("Hash in 16 byte chunks")
CMPQ(itr2, Imm(16))
JB(LabelRef("hashADTail"))
polyAdd(Mem{Base: adp}.Offset(0))
LEAQ(Mem{Base: adp}.Offset(1*16), adp)
SUBQ(Imm(16), itr2)
polyMul()
JMP(LabelRef("hashADLoop"))
}
func hashADTail() {
Label("hashADTail")
CMPQ(itr2, Imm(0))
JE(LabelRef("hashADDone"))
Comment("Hash last < 16 byte tail")
XORQ(t0, t0)
XORQ(t1, t1)
XORQ(t2, t2)
ADDQ(itr2, adp)
}
func hashADTailLoop() {
Label("hashADTailLoop")
SHLQ(Imm(8), t0, t1)
SHLQ(Imm(8), t0)
// Hack to get Avo to emit:
// MOVB -1(adp), t2
Instruction(&ir.Instruction{Opcode: "MOVB", Operands: []Op{Mem{Base: adp}.Offset(-1), t2}})
XORQ(t2, t0)
DECQ(adp)
DECQ(itr2)
JNE(LabelRef("hashADTailLoop"))
}
func hashADTailFinish() {
ADDQ(t0, acc0)
ADCQ(t1, acc1)
ADCQ(Imm(1), acc2)
polyMul()
}
// Finished AD
func hashADDone() {
Label("hashADDone")
RET()
}
func openSSEFinalize() {
Label("openSSEFinalize")
Comment("Hash in the PT, AAD lengths")
ADDQ(NewParamAddr("ad_len", 80), acc0)
ADCQ(NewParamAddr("src_len", 56), acc1)
ADCQ(Imm(1), acc2)
polyMul()
Comment("Final reduce")
MOVQ(acc0, t0)
MOVQ(acc1, t1)
MOVQ(acc2, t2)
SUBQ(I8(-5), acc0)
SBBQ(I8(-1), acc1)
SBBQ(Imm(3), acc2)
CMOVQCS(t0, acc0)
CMOVQCS(t1, acc1)
CMOVQCS(t2, acc2)
Comment("Add in the \"s\" part of the key")
ADDQ(sStore.Offset(0), acc0)
ADCQ(sStore.Offset(8), acc1)
Comment("Finally, constant time compare to the tag at the end of the message")
XORQ(RAX, RAX)
MOVQ(U32(1), RDX)
XORQ(Mem{Base: inp}.Offset(0*8), acc0)
XORQ(Mem{Base: inp}.Offset(1*8), acc1)
ORQ(acc1, acc0)
CMOVQEQ(RDX, RAX)
Comment("Return true iff tags are equal")
// Hack to get Avo to emit:
// MOVB AX, ret+96(FP)
Instruction(&ir.Instruction{Opcode: "MOVB", Operands: []Op{AX, NewParamAddr("ret", 96)}})
RET()
}
// ----------------------------------------------------------------------------
// Special optimization for buffers smaller than 129 bytes
func openSSETail16() {
Label("openSSETail16")
TESTQ(inl, inl)
JE(LabelRef("openSSEFinalize"))
Comment("We can safely load the CT from the end, because it is padded with the MAC")
MOVQ(inl, itr2)
SHLQ(Imm(4), itr2)
andMask := andMask_DATA()
LEAQ(andMask, t0)
MOVOU(Mem{Base: inp}, T0)
ADDQ(inl, inp)
PAND(Mem{Base: t0, Index: itr2, Scale: 1}.Offset(-16), T0)
MOVO(T0, tmpStore.Offset(0))
MOVQ(T0, t0)
MOVQ(tmpStore.Offset(8), t1)
PXOR(A1, T0)
}
func openSSETail16Store() {
Comment("We can only store one byte at a time, since plaintext can be shorter than 16 bytes")
Label("openSSETail16Store")
MOVQ(T0, t3)
// Hack to get Avo to emit:
// MOVB t3, (oup)
Instruction(&ir.Instruction{Opcode: "MOVB", Operands: []Op{t3, Mem{Base: oup}}})
PSRLDQ(Imm(1), T0)
INCQ(oup)
DECQ(inl)
JNE(LabelRef("openSSETail16Store"))
ADDQ(t0, acc0)
ADCQ(t1, acc1)
ADCQ(Imm(1), acc2)
polyMul()
JMP(LabelRef("openSSEFinalize"))
}
// Implements the following function signature:
//
// func chacha20Poly1305Open(dst []byte, key []uint32, src []byte, ad []byte) bool
func chacha20Poly1305Open() {
Implement("chacha20Poly1305Open")
Attributes(0)
AllocLocal(288)
Comment("For aligned stack access")
MOVQ(RSP, RBP)
ADDQ(Imm(32), RBP)
ANDQ(I8(-32), RBP)
Load(Param("dst").Base(), oup)
Load(Param("key").Base(), keyp)
Load(Param("src").Base(), inp)
Load(Param("src").Len(), inl)
Load(Param("ad").Base(), adp)
VZEROUPPER()
chacha20Constants := chacha20Constants_DATA()
VMOVDQU(chacha20Constants, AA0)
VBROADCASTI128(Mem{Base: R8}.Offset(16), BB0)
VBROADCASTI128(Mem{Base: R8}.Offset(32), CC0)
VBROADCASTI128(Mem{Base: R8}.Offset(48), DD0)
avx2InitMask := avx2InitMask_DATA()
VPADDD(avx2InitMask, DD0, DD0)
Comment("Special optimization, for very short buffers")
CMPQ(inl, Imm(192))
JBE(LabelRef("openAVX2192"))
CMPQ(inl, U32(320))
JBE(LabelRef("openAVX2320"))
Comment("For the general key prepare the key first - as a byproduct we have 64 bytes of cipher stream")
VMOVDQA(BB0, state1StoreAVX2)
VMOVDQA(CC0, state2StoreAVX2)
VMOVDQA(DD0, ctr3StoreAVX2)
MOVQ(U32(10), itr2)
openAVX2PreparePolyKey()
openAVX2InitialHash64()
openAVX2MainLoop()
openAVX2InternalLoop()
openAVX2MainLoopDone()
openSSEFinalize()
// ----------------------------------------------------------------------------
// Special optimization for buffers smaller than 129 bytes
openSSETail16()
openSSETail16Store()
// ----------------------------------------------------------------------------
// Special optimization for buffers smaller than 193 bytes
openAVX2192()
openAVX2192InnerCipherLoop()
openAVX2ShortOpen()
openAVX2ShortOpenLoop()
openAVX2ShortTail32()
openAVX2ShortDone()
// ----------------------------------------------------------------------------
// Special optimization for buffers smaller than 321 bytes
openAVX2320()
openAVX2320InnerCipherLoop()
// ----------------------------------------------------------------------------
// Special optimization for the last 128 bytes of ciphertext
openAVX2Tail128()
openAVX2Tail128LoopA()
openAVX2Tail128LoopB()
openAVX2TailLoop()
openAVX2Tail()
openAVX2TailDone()
// ----------------------------------------------------------------------------
// Special optimization for the last 256 bytes of ciphertext
openAVX2Tail256()
openAVX2Tail256LoopA()
openAVX2Tail256LoopB()
openAVX2Tail256Hash()
openAVX2Tail256HashEnd()
// ----------------------------------------------------------------------------
// Special optimization for the last 384 bytes of ciphertext
openAVX2Tail384()
openAVX2Tail384LoopB()
openAVX2Tail384LoopA()
openAVX2Tail384Hash()
openAVX2Tail384HashEnd()
// ----------------------------------------------------------------------------
// Special optimization for the last 512 bytes of ciphertext
openAVX2Tail512()
openAVX2Tail512LoopB()
openAVX2Tail512LoopA()
openAVX2Tail512HashLoop()
openAVX2Tail512HashEnd()
}
func openAVX2PreparePolyKey() {
Label("openAVX2PreparePolyKey")
chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0)
VPALIGNR(Imm(4), BB0, BB0, BB0)
VPALIGNR(Imm(8), CC0, CC0, CC0)
VPALIGNR(Imm(12), DD0, DD0, DD0)
chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0)
VPALIGNR(Imm(12), BB0, BB0, BB0)
VPALIGNR(Imm(8), CC0, CC0, CC0)
VPALIGNR(Imm(4), DD0, DD0, DD0)
DECQ(itr2)
JNE(LabelRef("openAVX2PreparePolyKey"))
chacha20Constants := chacha20Constants_DATA()
VPADDD(chacha20Constants, AA0, AA0)
VPADDD(state1StoreAVX2, BB0, BB0)
VPADDD(state2StoreAVX2, CC0, CC0)
VPADDD(ctr3StoreAVX2, DD0, DD0)
VPERM2I128(Imm(0x02), AA0, BB0, TT0)
Comment("Clamp and store poly key")
polyClampMask := polyClampMask_DATA()
VPAND(polyClampMask, TT0, TT0)
VMOVDQA(TT0, rsStoreAVX2)
Comment("Stream for the first 64 bytes")
VPERM2I128(Imm(0x13), AA0, BB0, AA0)
VPERM2I128(Imm(0x13), CC0, DD0, BB0)
Comment("Hash AD + first 64 bytes")
// MOVQ ad_len+80(FP), itr2
MOVQ(NewParamAddr("ad_len", 80), itr2)
CALL(LabelRef("polyHashADInternal<>(SB)"))
XORQ(itr1, itr1)
}
func openAVX2InitialHash64() {
Label("openAVX2InitialHash64")
// polyAdd(0(inp)(itr1*1))
polyAdd(Mem{Base: inp, Index: itr1, Scale: 1}.Offset(0))
polyMulAVX2()
ADDQ(Imm(16), itr1)
CMPQ(itr1, Imm(64))
JNE(LabelRef("openAVX2InitialHash64"))
Comment("Decrypt the first 64 bytes")
VPXOR(Mem{Base: inp}.Offset(0*32), AA0, AA0)
VPXOR(Mem{Base: inp}.Offset(1*32), BB0, BB0)
VMOVDQU(AA0, Mem{Base: oup}.Offset(0*32))
VMOVDQU(BB0, Mem{Base: oup}.Offset(1*32))
LEAQ(Mem{Base: inp}.Offset(2*32), inp)
LEAQ(Mem{Base: oup}.Offset(2*32), oup)
SUBQ(Imm(64), inl)
}
func openAVX2MainLoop() {
Label("openAVX2MainLoop")
CMPQ(inl, U32(512))
JB(LabelRef("openAVX2MainLoopDone"))
Comment("Load state, increment counter blocks, store the incremented counters")
chacha20Constants := chacha20Constants_DATA()
VMOVDQU(chacha20Constants, AA0)
VMOVDQA(AA0, AA1)
VMOVDQA(AA0, AA2)
VMOVDQA(AA0, AA3)
VMOVDQA(state1StoreAVX2, BB0)
VMOVDQA(BB0, BB1)
VMOVDQA(BB0, BB2)
VMOVDQA(BB0, BB3)
VMOVDQA(state2StoreAVX2, CC0)
VMOVDQA(CC0, CC1)
VMOVDQA(CC0, CC2)
VMOVDQA(CC0, CC3)
VMOVDQA(ctr3StoreAVX2, DD0)
avx2IncMask := avx2IncMask_DATA()
VPADDD(avx2IncMask, DD0, DD0)
VPADDD(avx2IncMask, DD0, DD1)
VPADDD(avx2IncMask, DD1, DD2)
VPADDD(avx2IncMask, DD2, DD3)
VMOVDQA(DD0, ctr0StoreAVX2)
VMOVDQA(DD1, ctr1StoreAVX2)
VMOVDQA(DD2, ctr2StoreAVX2)
VMOVDQA(DD3, ctr3StoreAVX2)
XORQ(itr1, itr1)
}
// Lets just say this spaghetti loop interleaves 2 quarter rounds with 3 poly multiplications
// Effectively per 512 bytes of stream we hash 480 bytes of ciphertext
func openAVX2InternalLoop() {
Label("openAVX2InternalLoop")
polyAdd(Mem{Base: inp, Index: itr1, Scale: 1}.Offset(0 * 8))
VPADDD(BB0, AA0, AA0)
VPADDD(BB1, AA1, AA1)
VPADDD(BB2, AA2, AA2)
VPADDD(BB3, AA3, AA3)
polyMulStage1_AVX2()
VPXOR(AA0, DD0, DD0)
VPXOR(AA1, DD1, DD1)
VPXOR(AA2, DD2, DD2)
VPXOR(AA3, DD3, DD3)
rol16 := rol16_DATA()
VPSHUFB(rol16, DD0, DD0)
VPSHUFB(rol16, DD1, DD1)
VPSHUFB(rol16, DD2, DD2)
VPSHUFB(rol16, DD3, DD3)
polyMulStage2_AVX2()
VPADDD(DD0, CC0, CC0)
VPADDD(DD1, CC1, CC1)
VPADDD(DD2, CC2, CC2)
VPADDD(DD3, CC3, CC3)
VPXOR(CC0, BB0, BB0)
VPXOR(CC1, BB1, BB1)
VPXOR(CC2, BB2, BB2)
VPXOR(CC3, BB3, BB3)
polyMulStage3_AVX2()
VMOVDQA(CC3, tmpStoreAVX2)
VPSLLD(Imm(12), BB0, CC3)
VPSRLD(Imm(20), BB0, BB0)
VPXOR(CC3, BB0, BB0)
VPSLLD(Imm(12), BB1, CC3)
VPSRLD(Imm(20), BB1, BB1)
VPXOR(CC3, BB1, BB1)
VPSLLD(Imm(12), BB2, CC3)
VPSRLD(Imm(20), BB2, BB2)
VPXOR(CC3, BB2, BB2)
VPSLLD(Imm(12), BB3, CC3)
VPSRLD(Imm(20), BB3, BB3)
VPXOR(CC3, BB3, BB3)
VMOVDQA(tmpStoreAVX2, CC3)
polyMulReduceStage()
VPADDD(BB0, AA0, AA0)
VPADDD(BB1, AA1, AA1)
VPADDD(BB2, AA2, AA2)
VPADDD(BB3, AA3, AA3)
VPXOR(AA0, DD0, DD0)
VPXOR(AA1, DD1, DD1)
VPXOR(AA2, DD2, DD2)
VPXOR(AA3, DD3, DD3)
rol8 := rol8_DATA()
VPSHUFB(rol8, DD0, DD0)
VPSHUFB(rol8, DD1, DD1)
VPSHUFB(rol8, DD2, DD2)
VPSHUFB(rol8, DD3, DD3)
polyAdd(Mem{Base: inp, Index: itr1, Scale: 1}.Offset(2 * 8))
VPADDD(DD0, CC0, CC0)
VPADDD(DD1, CC1, CC1)
VPADDD(DD2, CC2, CC2)
VPADDD(DD3, CC3, CC3)
polyMulStage1_AVX2()
VPXOR(CC0, BB0, BB0)
VPXOR(CC1, BB1, BB1)
VPXOR(CC2, BB2, BB2)
VPXOR(CC3, BB3, BB3)
VMOVDQA(CC3, tmpStoreAVX2)
VPSLLD(Imm(7), BB0, CC3)
VPSRLD(Imm(25), BB0, BB0)
VPXOR(CC3, BB0, BB0)
VPSLLD(Imm(7), BB1, CC3)
VPSRLD(Imm(25), BB1, BB1)
VPXOR(CC3, BB1, BB1)
VPSLLD(Imm(7), BB2, CC3)
VPSRLD(Imm(25), BB2, BB2)
VPXOR(CC3, BB2, BB2)
VPSLLD(Imm(7), BB3, CC3)
VPSRLD(Imm(25), BB3, BB3)
VPXOR(CC3, BB3, BB3)
VMOVDQA(tmpStoreAVX2, CC3)
polyMulStage2_AVX2()
VPALIGNR(Imm(4), BB0, BB0, BB0)
VPALIGNR(Imm(4), BB1, BB1, BB1)
VPALIGNR(Imm(4), BB2, BB2, BB2)
VPALIGNR(Imm(4), BB3, BB3, BB3)
VPALIGNR(Imm(8), CC0, CC0, CC0)
VPALIGNR(Imm(8), CC1, CC1, CC1)
VPALIGNR(Imm(8), CC2, CC2, CC2)
VPALIGNR(Imm(8), CC3, CC3, CC3)
VPALIGNR(Imm(12), DD0, DD0, DD0)
VPALIGNR(Imm(12), DD1, DD1, DD1)
VPALIGNR(Imm(12), DD2, DD2, DD2)
VPALIGNR(Imm(12), DD3, DD3, DD3)
VPADDD(BB0, AA0, AA0)
VPADDD(BB1, AA1, AA1)
VPADDD(BB2, AA2, AA2)
VPADDD(BB3, AA3, AA3)
polyMulStage3_AVX2()
VPXOR(AA0, DD0, DD0)
VPXOR(AA1, DD1, DD1)
VPXOR(AA2, DD2, DD2)
VPXOR(AA3, DD3, DD3)
VPSHUFB(rol16, DD0, DD0)
VPSHUFB(rol16, DD1, DD1)
VPSHUFB(rol16, DD2, DD2)
VPSHUFB(rol16, DD3, DD3)
polyMulReduceStage()
VPADDD(DD0, CC0, CC0)
VPADDD(DD1, CC1, CC1)
VPADDD(DD2, CC2, CC2)
VPADDD(DD3, CC3, CC3)
VPXOR(CC0, BB0, BB0)
VPXOR(CC1, BB1, BB1)
VPXOR(CC2, BB2, BB2)
VPXOR(CC3, BB3, BB3)
polyAdd(Mem{Base: inp, Index: itr1, Scale: 1}.Offset(4 * 8))
LEAQ(Mem{Base: itr1}.Offset(6*8), itr1)
VMOVDQA(CC3, tmpStoreAVX2)
VPSLLD(Imm(12), BB0, CC3)
VPSRLD(Imm(20), BB0, BB0)
VPXOR(CC3, BB0, BB0)
VPSLLD(Imm(12), BB1, CC3)
VPSRLD(Imm(20), BB1, BB1)
VPXOR(CC3, BB1, BB1)
VPSLLD(Imm(12), BB2, CC3)
VPSRLD(Imm(20), BB2, BB2)
VPXOR(CC3, BB2, BB2)
VPSLLD(Imm(12), BB3, CC3)
VPSRLD(Imm(20), BB3, BB3)
VPXOR(CC3, BB3, BB3)
VMOVDQA(tmpStoreAVX2, CC3)
polyMulStage1_AVX2()
VPADDD(BB0, AA0, AA0)
VPADDD(BB1, AA1, AA1)
VPADDD(BB2, AA2, AA2)
VPADDD(BB3, AA3, AA3)
VPXOR(AA0, DD0, DD0)
VPXOR(AA1, DD1, DD1)
VPXOR(AA2, DD2, DD2)
VPXOR(AA3, DD3, DD3)
polyMulStage2_AVX2()
VPSHUFB(rol8, DD0, DD0)
VPSHUFB(rol8, DD1, DD1)
VPSHUFB(rol8, DD2, DD2)
VPSHUFB(rol8, DD3, DD3)
VPADDD(DD0, CC0, CC0)
VPADDD(DD1, CC1, CC1)
VPADDD(DD2, CC2, CC2)
VPADDD(DD3, CC3, CC3)
polyMulStage3_AVX2()
VPXOR(CC0, BB0, BB0)
VPXOR(CC1, BB1, BB1)
VPXOR(CC2, BB2, BB2)
VPXOR(CC3, BB3, BB3)
VMOVDQA(CC3, tmpStoreAVX2)
VPSLLD(Imm(7), BB0, CC3)
VPSRLD(Imm(25), BB0, BB0)
VPXOR(CC3, BB0, BB0)
VPSLLD(Imm(7), BB1, CC3)
VPSRLD(Imm(25), BB1, BB1)
VPXOR(CC3, BB1, BB1)
VPSLLD(Imm(7), BB2, CC3)
VPSRLD(Imm(25), BB2, BB2)
VPXOR(CC3, BB2, BB2)
VPSLLD(Imm(7), BB3, CC3)
VPSRLD(Imm(25), BB3, BB3)
VPXOR(CC3, BB3, BB3)
VMOVDQA(tmpStoreAVX2, CC3)
polyMulReduceStage()
VPALIGNR(Imm(12), BB0, BB0, BB0)
VPALIGNR(Imm(12), BB1, BB1, BB1)
VPALIGNR(Imm(12), BB2, BB2, BB2)
VPALIGNR(Imm(12), BB3, BB3, BB3)
VPALIGNR(Imm(8), CC0, CC0, CC0)
VPALIGNR(Imm(8), CC1, CC1, CC1)
VPALIGNR(Imm(8), CC2, CC2, CC2)
VPALIGNR(Imm(8), CC3, CC3, CC3)
VPALIGNR(Imm(4), DD0, DD0, DD0)
VPALIGNR(Imm(4), DD1, DD1, DD1)
VPALIGNR(Imm(4), DD2, DD2, DD2)
VPALIGNR(Imm(4), DD3, DD3, DD3)
CMPQ(itr1, U32(480))
JNE(LabelRef("openAVX2InternalLoop"))
chacha20Constants := chacha20Constants_DATA()
VPADDD(chacha20Constants, AA0, AA0)
VPADDD(chacha20Constants, AA1, AA1)
VPADDD(chacha20Constants, AA2, AA2)
VPADDD(chacha20Constants, AA3, AA3)
VPADDD(state1StoreAVX2, BB0, BB0)
VPADDD(state1StoreAVX2, BB1, BB1)
VPADDD(state1StoreAVX2, BB2, BB2)
VPADDD(state1StoreAVX2, BB3, BB3)
VPADDD(state2StoreAVX2, CC0, CC0)
VPADDD(state2StoreAVX2, CC1, CC1)
VPADDD(state2StoreAVX2, CC2, CC2)
VPADDD(state2StoreAVX2, CC3, CC3)
VPADDD(ctr0StoreAVX2, DD0, DD0)
VPADDD(ctr1StoreAVX2, DD1, DD1)
VPADDD(ctr2StoreAVX2, DD2, DD2)
VPADDD(ctr3StoreAVX2, DD3, DD3)
VMOVDQA(CC3, tmpStoreAVX2)
Comment("We only hashed 480 of the 512 bytes available - hash the remaining 32 here")
polyAdd(Mem{Base: inp}.Offset(480))
polyMulAVX2()
VPERM2I128(Imm(0x02), AA0, BB0, CC3)
VPERM2I128(Imm(0x13), AA0, BB0, BB0)
VPERM2I128(Imm(0x02), CC0, DD0, AA0)
VPERM2I128(Imm(0x13), CC0, DD0, CC0)
VPXOR(Mem{Base: inp}.Offset(0*32), CC3, CC3)
VPXOR(Mem{Base: inp}.Offset(1*32), AA0, AA0)
VPXOR(Mem{Base: inp}.Offset(2*32), BB0, BB0)
VPXOR(Mem{Base: inp}.Offset(3*32), CC0, CC0)
VMOVDQU(CC3, Mem{Base: oup}.Offset(0*32))
VMOVDQU(AA0, Mem{Base: oup}.Offset(1*32))
VMOVDQU(BB0, Mem{Base: oup}.Offset(2*32))
VMOVDQU(CC0, Mem{Base: oup}.Offset(3*32))
VPERM2I128(Imm(0x02), AA1, BB1, AA0)
VPERM2I128(Imm(0x02), CC1, DD1, BB0)
VPERM2I128(Imm(0x13), AA1, BB1, CC0)
VPERM2I128(Imm(0x13), CC1, DD1, DD0)
VPXOR(Mem{Base: inp}.Offset(4*32), AA0, AA0)
VPXOR(Mem{Base: inp}.Offset(5*32), BB0, BB0)
VPXOR(Mem{Base: inp}.Offset(6*32), CC0, CC0)
VPXOR(Mem{Base: inp}.Offset(7*32), DD0, DD0)
VMOVDQU(AA0, Mem{Base: oup}.Offset(4*32))
VMOVDQU(BB0, Mem{Base: oup}.Offset(5*32))
VMOVDQU(CC0, Mem{Base: oup}.Offset(6*32))
VMOVDQU(DD0, Mem{Base: oup}.Offset(7*32))
Comment("and here")
polyAdd(Mem{Base: inp}.Offset(496))
polyMulAVX2()
VPERM2I128(Imm(0x02), AA2, BB2, AA0)
VPERM2I128(Imm(0x02), CC2, DD2, BB0)
VPERM2I128(Imm(0x13), AA2, BB2, CC0)
VPERM2I128(Imm(0x13), CC2, DD2, DD0)
VPXOR(Mem{Base: inp}.Offset(8*32), AA0, AA0)
VPXOR(Mem{Base: inp}.Offset(9*32), BB0, BB0)
VPXOR(Mem{Base: inp}.Offset(10*32), CC0, CC0)
VPXOR(Mem{Base: inp}.Offset(11*32), DD0, DD0)
VMOVDQU(AA0, Mem{Base: oup}.Offset(8*32))
VMOVDQU(BB0, Mem{Base: oup}.Offset(9*32))
VMOVDQU(CC0, Mem{Base: oup}.Offset(10*32))
VMOVDQU(DD0, Mem{Base: oup}.Offset(11*32))
VPERM2I128(Imm(0x02), AA3, BB3, AA0)
VPERM2I128(Imm(0x02), tmpStoreAVX2, DD3, BB0)
VPERM2I128(Imm(0x13), AA3, BB3, CC0)
VPERM2I128(Imm(0x13), tmpStoreAVX2, DD3, DD0)
VPXOR(Mem{Base: inp}.Offset(12*32), AA0, AA0)
VPXOR(Mem{Base: inp}.Offset(13*32), BB0, BB0)
VPXOR(Mem{Base: inp}.Offset(14*32), CC0, CC0)
VPXOR(Mem{Base: inp}.Offset(15*32), DD0, DD0)
VMOVDQU(AA0, Mem{Base: oup}.Offset(12*32))
VMOVDQU(BB0, Mem{Base: oup}.Offset(13*32))
VMOVDQU(CC0, Mem{Base: oup}.Offset(14*32))
VMOVDQU(DD0, Mem{Base: oup}.Offset(15*32))
LEAQ(Mem{Base: inp}.Offset(32*16), inp)
LEAQ(Mem{Base: oup}.Offset(32*16), oup)
SUBQ(U32(32*16), inl)
JMP(LabelRef("openAVX2MainLoop"))
}
// Handle the various tail sizes efficiently
func openAVX2MainLoopDone() {
Label("openAVX2MainLoopDone")
Comment("Handle the various tail sizes efficiently")
TESTQ(inl, inl)
JE(LabelRef("openSSEFinalize"))
CMPQ(inl, Imm(128))
JBE(LabelRef("openAVX2Tail128"))
CMPQ(inl, U32(256))
JBE(LabelRef("openAVX2Tail256"))
CMPQ(inl, U32(384))
JBE(LabelRef("openAVX2Tail384"))
JMP(LabelRef("openAVX2Tail512"))
}
// ----------------------------------------------------------------------------
// Special optimization for buffers smaller than 193 bytes
// For up to 192 bytes of ciphertext and 64 bytes for the poly key, we process four blocks
func openAVX2192() {
Label("openAVX2192")
VMOVDQA(AA0, AA1)
VMOVDQA(BB0, BB1)
VMOVDQA(CC0, CC1)
avx2IncMask := avx2IncMask_DATA()
VPADDD(avx2IncMask, DD0, DD1)
VMOVDQA(AA0, AA2)
VMOVDQA(BB0, BB2)
VMOVDQA(CC0, CC2)
VMOVDQA(DD0, DD2)
VMOVDQA(DD1, TT3)
MOVQ(U32(10), itr2)
}
func openAVX2192InnerCipherLoop() {
Label("openAVX2192InnerCipherLoop")
chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0)
chachaQR_AVX2(AA1, BB1, CC1, DD1, TT0)
VPALIGNR(Imm(4), BB0, BB0, BB0)
VPALIGNR(Imm(4), BB1, BB1, BB1)
VPALIGNR(Imm(8), CC0, CC0, CC0)
VPALIGNR(Imm(8), CC1, CC1, CC1)
VPALIGNR(Imm(12), DD0, DD0, DD0)
VPALIGNR(Imm(12), DD1, DD1, DD1)
chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0)
chachaQR_AVX2(AA1, BB1, CC1, DD1, TT0)
VPALIGNR(Imm(12), BB0, BB0, BB0)
VPALIGNR(Imm(12), BB1, BB1, BB1)
VPALIGNR(Imm(8), CC0, CC0, CC0)
VPALIGNR(Imm(8), CC1, CC1, CC1)
VPALIGNR(Imm(4), DD0, DD0, DD0)
VPALIGNR(Imm(4), DD1, DD1, DD1)
DECQ(itr2)
JNE(LabelRef("openAVX2192InnerCipherLoop"))
VPADDD(AA2, AA0, AA0)
VPADDD(AA2, AA1, AA1)
VPADDD(BB2, BB0, BB0)
VPADDD(BB2, BB1, BB1)
VPADDD(CC2, CC0, CC0)
VPADDD(CC2, CC1, CC1)
VPADDD(DD2, DD0, DD0)
VPADDD(TT3, DD1, DD1)
VPERM2I128(Imm(0x02), AA0, BB0, TT0)
Comment("Clamp and store poly key")
polyClampMask := polyClampMask_DATA()
VPAND(polyClampMask, TT0, TT0)
VMOVDQA(TT0, rsStoreAVX2)
Comment("Stream for up to 192 bytes")
VPERM2I128(Imm(0x13), AA0, BB0, AA0)
VPERM2I128(Imm(0x13), CC0, DD0, BB0)
VPERM2I128(Imm(0x02), AA1, BB1, CC0)
VPERM2I128(Imm(0x02), CC1, DD1, DD0)
VPERM2I128(Imm(0x13), AA1, BB1, AA1)
VPERM2I128(Imm(0x13), CC1, DD1, BB1)
}
func openAVX2ShortOpen() {
Label("openAVX2ShortOpen")
Comment("Hash")
Load(Param("ad").Len(), itr2)
CALL(LabelRef("polyHashADInternal<>(SB)"))
}
func openAVX2ShortOpenLoop() {
Label("openAVX2ShortOpenLoop")
CMPQ(inl, Imm(32))
JB(LabelRef("openAVX2ShortTail32"))
SUBQ(Imm(32), inl)
Comment("Load for hashing")
polyAdd(Mem{Base: inp}.Offset(0 * 8))
polyMulAVX2()
polyAdd(Mem{Base: inp}.Offset(2 * 8))
polyMulAVX2()
Comment("Load for decryption")
VPXOR(Mem{Base: inp}, AA0, AA0)
VMOVDQU(AA0, Mem{Base: oup})
LEAQ(Mem{Base: inp}.Offset(1*32), inp)
LEAQ(Mem{Base: oup}.Offset(1*32), oup)
Comment("Shift stream left")
VMOVDQA(BB0, AA0)
VMOVDQA(CC0, BB0)
VMOVDQA(DD0, CC0)
VMOVDQA(AA1, DD0)
VMOVDQA(BB1, AA1)
VMOVDQA(CC1, BB1)
VMOVDQA(DD1, CC1)
VMOVDQA(AA2, DD1)
VMOVDQA(BB2, AA2)
JMP(LabelRef("openAVX2ShortOpenLoop"))
}
func openAVX2ShortTail32() {
Label("openAVX2ShortTail32")
CMPQ(inl, Imm(16))
VMOVDQA(A0, A1)
JB(LabelRef("openAVX2ShortDone"))
SUBQ(Imm(16), inl)
Comment("Load for hashing")
polyAdd(Mem{Base: inp}.Offset(0 * 8))
polyMulAVX2()
Comment("Load for decryption")
VPXOR(Mem{Base: inp}, A0, T0)
VMOVDQU(T0, Mem{Base: oup})
LEAQ(Mem{Base: inp}.Offset(1*16), inp)
LEAQ(Mem{Base: oup}.Offset(1*16), oup)
VPERM2I128(Imm(0x11), AA0, AA0, AA0)
VMOVDQA(A0, A1)
}
func openAVX2ShortDone() {
Label("openAVX2ShortDone")
VZEROUPPER()
JMP(LabelRef("openSSETail16"))
}
// ----------------------------------------------------------------------------
// Special optimization for buffers smaller than 321 bytes
// For up to 320 bytes of ciphertext and 64 bytes for the poly key, we process six blocks
func openAVX2320() {
Label("openAVX2320")
VMOVDQA(AA0, AA1)
VMOVDQA(BB0, BB1)
VMOVDQA(CC0, CC1)
avx2IncMask := avx2IncMask_DATA()
VPADDD(avx2IncMask, DD0, DD1)
VMOVDQA(AA0, AA2)
VMOVDQA(BB0, BB2)
VMOVDQA(CC0, CC2)
VPADDD(avx2IncMask, DD1, DD2)
VMOVDQA(BB0, TT1)
VMOVDQA(CC0, TT2)
VMOVDQA(DD0, TT3)
MOVQ(U32(10), itr2)
}
func openAVX2320InnerCipherLoop() {
Label("openAVX2320InnerCipherLoop")
chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0)
chachaQR_AVX2(AA1, BB1, CC1, DD1, TT0)
chachaQR_AVX2(AA2, BB2, CC2, DD2, TT0)
VPALIGNR(Imm(4), BB0, BB0, BB0)
VPALIGNR(Imm(4), BB1, BB1, BB1)
VPALIGNR(Imm(4), BB2, BB2, BB2)
VPALIGNR(Imm(8), CC0, CC0, CC0)
VPALIGNR(Imm(8), CC1, CC1, CC1)
VPALIGNR(Imm(8), CC2, CC2, CC2)
VPALIGNR(Imm(12), DD0, DD0, DD0)
VPALIGNR(Imm(12), DD1, DD1, DD1)
VPALIGNR(Imm(12), DD2, DD2, DD2)
chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0)
chachaQR_AVX2(AA1, BB1, CC1, DD1, TT0)
chachaQR_AVX2(AA2, BB2, CC2, DD2, TT0)
VPALIGNR(Imm(12), BB0, BB0, BB0)
VPALIGNR(Imm(12), BB1, BB1, BB1)
VPALIGNR(Imm(12), BB2, BB2, BB2)
VPALIGNR(Imm(8), CC0, CC0, CC0)
VPALIGNR(Imm(8), CC1, CC1, CC1)
VPALIGNR(Imm(8), CC2, CC2, CC2)
VPALIGNR(Imm(4), DD0, DD0, DD0)
VPALIGNR(Imm(4), DD1, DD1, DD1)
VPALIGNR(Imm(4), DD2, DD2, DD2)
DECQ(itr2)
JNE(LabelRef("openAVX2320InnerCipherLoop"))
chacha20Constants := chacha20Constants_DATA()
VMOVDQA(chacha20Constants, TT0)
VPADDD(TT0, AA0, AA0)
VPADDD(TT0, AA1, AA1)
VPADDD(TT0, AA2, AA2)
VPADDD(TT1, BB0, BB0)
VPADDD(TT1, BB1, BB1)
VPADDD(TT1, BB2, BB2)
VPADDD(TT2, CC0, CC0)
VPADDD(TT2, CC1, CC1)
VPADDD(TT2, CC2, CC2)
avx2IncMask := avx2IncMask_DATA()
VMOVDQA(avx2IncMask, TT0)
VPADDD(TT3, DD0, DD0)
VPADDD(TT0, TT3, TT3)
VPADDD(TT3, DD1, DD1)
VPADDD(TT0, TT3, TT3)
VPADDD(TT3, DD2, DD2)
Comment("Clamp and store poly key")
VPERM2I128(Imm(0x02), AA0, BB0, TT0)
polyClampMask := polyClampMask_DATA()
VPAND(polyClampMask, TT0, TT0)
VMOVDQA(TT0, rsStoreAVX2)
Comment("Stream for up to 320 bytes")
VPERM2I128(Imm(0x13), AA0, BB0, AA0)
VPERM2I128(Imm(0x13), CC0, DD0, BB0)
VPERM2I128(Imm(0x02), AA1, BB1, CC0)
VPERM2I128(Imm(0x02), CC1, DD1, DD0)
VPERM2I128(Imm(0x13), AA1, BB1, AA1)
VPERM2I128(Imm(0x13), CC1, DD1, BB1)
VPERM2I128(Imm(0x02), AA2, BB2, CC1)
VPERM2I128(Imm(0x02), CC2, DD2, DD1)
VPERM2I128(Imm(0x13), AA2, BB2, AA2)
VPERM2I128(Imm(0x13), CC2, DD2, BB2)
JMP(LabelRef("openAVX2ShortOpen"))
}
// ----------------------------------------------------------------------------
// Special optimization for the last 128 bytes of ciphertext
// Need to decrypt up to 128 bytes - prepare two blocks
func openAVX2Tail128() {
Label("openAVX2Tail128")
Comment("Need to decrypt up to 128 bytes - prepare two blocks")
chacha20Constants := chacha20Constants_DATA()
VMOVDQA(chacha20Constants, AA1)
VMOVDQA(state1StoreAVX2, BB1)
VMOVDQA(state2StoreAVX2, CC1)
VMOVDQA(ctr3StoreAVX2, DD1)
avx2IncMask := avx2IncMask_DATA()
VPADDD(avx2IncMask, DD1, DD1)
VMOVDQA(DD1, DD0)
XORQ(itr2, itr2)
MOVQ(inl, itr1)
ANDQ(I8(-16), itr1)
TESTQ(itr1, itr1)
JE(LabelRef("openAVX2Tail128LoopB"))
}
// Perform ChaCha rounds, while hashing the remaining input
func openAVX2Tail128LoopA() {
Label("openAVX2Tail128LoopA")
polyAdd(Mem{Base: inp, Index: itr2, Scale: 1}.Offset(0))
polyMulAVX2()
}
func openAVX2Tail128LoopB() {
Label("openAVX2Tail128LoopB")
ADDQ(Imm(16), itr2)
chachaQR_AVX2(AA1, BB1, CC1, DD1, TT0)
VPALIGNR(Imm(4), BB1, BB1, BB1)
VPALIGNR(Imm(8), CC1, CC1, CC1)
VPALIGNR(Imm(12), DD1, DD1, DD1)
chachaQR_AVX2(AA1, BB1, CC1, DD1, TT0)
VPALIGNR(Imm(12), BB1, BB1, BB1)
VPALIGNR(Imm(8), CC1, CC1, CC1)
VPALIGNR(Imm(4), DD1, DD1, DD1)
CMPQ(itr2, itr1)
JB(LabelRef("openAVX2Tail128LoopA"))
CMPQ(itr2, Imm(160))
JNE(LabelRef("openAVX2Tail128LoopB"))
chacha20Constants := chacha20Constants_DATA()
VPADDD(chacha20Constants, AA1, AA1)
VPADDD(state1StoreAVX2, BB1, BB1)
VPADDD(state2StoreAVX2, CC1, CC1)
VPADDD(DD0, DD1, DD1)
VPERM2I128(Imm(0x02), AA1, BB1, AA0)
VPERM2I128(Imm(0x02), CC1, DD1, BB0)
VPERM2I128(Imm(0x13), AA1, BB1, CC0)
VPERM2I128(Imm(0x13), CC1, DD1, DD0)
}
func openAVX2TailLoop() {
Label("openAVX2TailLoop")
CMPQ(inl, Imm(32))
JB(LabelRef("openAVX2Tail"))
SUBQ(Imm(32), inl)
Comment("Load for decryption")
VPXOR(Mem{Base: inp}, AA0, AA0)
VMOVDQU(AA0, Mem{Base: oup})
LEAQ(Mem{Base: inp}.Offset(1*32), inp)
LEAQ(Mem{Base: oup}.Offset(1*32), oup)
VMOVDQA(BB0, AA0)
VMOVDQA(CC0, BB0)
VMOVDQA(DD0, CC0)
JMP(LabelRef("openAVX2TailLoop"))
}
func openAVX2Tail() {
Label("openAVX2Tail")
CMPQ(inl, Imm(16))
VMOVDQA(A0, A1)
JB(LabelRef("openAVX2TailDone"))
SUBQ(Imm(16), inl)
Comment("Load for decryption")
VPXOR(Mem{Base: inp}, A0, T0)
VMOVDQU(T0, Mem{Base: oup})
LEAQ(Mem{Base: inp}.Offset(1*16), inp)
LEAQ(Mem{Base: oup}.Offset(1*16), oup)
VPERM2I128(Imm(0x11), AA0, AA0, AA0)
VMOVDQA(A0, A1)
}
func openAVX2TailDone() {
Label("openAVX2TailDone")
VZEROUPPER()
JMP(LabelRef("openSSETail16"))
}
// ----------------------------------------------------------------------------
// Special optimization for the last 256 bytes of ciphertext
// Need to decrypt up to 256 bytes - prepare four blocks
func openAVX2Tail256() {
Label("openAVX2Tail256")
chacha20Constants := chacha20Constants_DATA()
VMOVDQA(chacha20Constants, AA0)
VMOVDQA(AA0, AA1)
VMOVDQA(state1StoreAVX2, BB0)
VMOVDQA(BB0, BB1)
VMOVDQA(state2StoreAVX2, CC0)
VMOVDQA(CC0, CC1)
VMOVDQA(ctr3StoreAVX2, DD0)
avx2IncMask := avx2IncMask_DATA()
VPADDD(avx2IncMask, DD0, DD0)
VPADDD(avx2IncMask, DD0, DD1)
VMOVDQA(DD0, TT1)
VMOVDQA(DD1, TT2)
Comment("Compute the number of iterations that will hash data")
MOVQ(inl, tmpStoreAVX2)
MOVQ(inl, itr1)
SUBQ(Imm(128), itr1)
SHRQ(Imm(4), itr1)
MOVQ(U32(10), itr2)
CMPQ(itr1, Imm(10))
CMOVQGT(itr2, itr1)
MOVQ(inp, inl)
XORQ(itr2, itr2)
}
func openAVX2Tail256LoopA() {
Label("openAVX2Tail256LoopA")
polyAdd(Mem{Base: inl}.Offset(0))
polyMulAVX2()
LEAQ(Mem{Base: inl}.Offset(16), inl)
}
// Perform ChaCha rounds, while hashing the remaining input
func openAVX2Tail256LoopB() {
Label("openAVX2Tail256LoopB")
chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0)
chachaQR_AVX2(AA1, BB1, CC1, DD1, TT0)
VPALIGNR(Imm(4), BB0, BB0, BB0)
VPALIGNR(Imm(4), BB1, BB1, BB1)
VPALIGNR(Imm(8), CC0, CC0, CC0)
VPALIGNR(Imm(8), CC1, CC1, CC1)
VPALIGNR(Imm(12), DD0, DD0, DD0)
VPALIGNR(Imm(12), DD1, DD1, DD1)
INCQ(itr2)
chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0)
chachaQR_AVX2(AA1, BB1, CC1, DD1, TT0)
VPALIGNR(Imm(12), BB0, BB0, BB0)
VPALIGNR(Imm(12), BB1, BB1, BB1)
VPALIGNR(Imm(8), CC0, CC0, CC0)
VPALIGNR(Imm(8), CC1, CC1, CC1)
VPALIGNR(Imm(4), DD0, DD0, DD0)
VPALIGNR(Imm(4), DD1, DD1, DD1)
CMPQ(itr2, itr1)
JB(LabelRef("openAVX2Tail256LoopA"))
CMPQ(itr2, Imm(10))
JNE(LabelRef("openAVX2Tail256LoopB"))
MOVQ(inl, itr2)
SUBQ(inp, inl)
MOVQ(inl, itr1)
MOVQ(tmpStoreAVX2, inl)
}
// Hash the remainder of data (if any)
func openAVX2Tail256Hash() {
Label("openAVX2Tail256Hash")
ADDQ(Imm(16), itr1)
CMPQ(itr1, inl)
JGT(LabelRef("openAVX2Tail256HashEnd"))
polyAdd(Mem{Base: itr2}.Offset(0))
polyMulAVX2()
LEAQ(Mem{Base: itr2}.Offset(16), itr2)
JMP(LabelRef("openAVX2Tail256Hash"))
}
// Store 128 bytes safely, then go to store loop
func openAVX2Tail256HashEnd() {
Label("openAVX2Tail256HashEnd")
chacha20Constants := chacha20Constants_DATA()
VPADDD(chacha20Constants, AA0, AA0)
VPADDD(chacha20Constants, AA1, AA1)
VPADDD(state1StoreAVX2, BB0, BB0)
VPADDD(state1StoreAVX2, BB1, BB1)
VPADDD(state2StoreAVX2, CC0, CC0)
VPADDD(state2StoreAVX2, CC1, CC1)
VPADDD(TT1, DD0, DD0)
VPADDD(TT2, DD1, DD1)
VPERM2I128(Imm(0x02), AA0, BB0, AA2)
VPERM2I128(Imm(0x02), CC0, DD0, BB2)
VPERM2I128(Imm(0x13), AA0, BB0, CC2)
VPERM2I128(Imm(0x13), CC0, DD0, DD2)
VPERM2I128(Imm(0x02), AA1, BB1, AA0)
VPERM2I128(Imm(0x02), CC1, DD1, BB0)
VPERM2I128(Imm(0x13), AA1, BB1, CC0)
VPERM2I128(Imm(0x13), CC1, DD1, DD0)
VPXOR(Mem{Base: inp}.Offset(0*32), AA2, AA2)
VPXOR(Mem{Base: inp}.Offset(1*32), BB2, BB2)
VPXOR(Mem{Base: inp}.Offset(2*32), CC2, CC2)
VPXOR(Mem{Base: inp}.Offset(3*32), DD2, DD2)
VMOVDQU(AA2, Mem{Base: oup}.Offset(0*32))
VMOVDQU(BB2, Mem{Base: oup}.Offset(1*32))
VMOVDQU(CC2, Mem{Base: oup}.Offset(2*32))
VMOVDQU(DD2, Mem{Base: oup}.Offset(3*32))
LEAQ(Mem{Base: inp}.Offset(4*32), inp)
LEAQ(Mem{Base: oup}.Offset(4*32), oup)
SUBQ(Imm(4*32), inl)
JMP(LabelRef("openAVX2TailLoop"))
}
// ----------------------------------------------------------------------------
// Special optimization for the last 384 bytes of ciphertext
// Need to decrypt up to 384 bytes - prepare six blocks
func openAVX2Tail384() {
Label("openAVX2Tail384")
Comment("Need to decrypt up to 384 bytes - prepare six blocks")
chacha20Constants := chacha20Constants_DATA()
VMOVDQA(chacha20Constants, AA0)
VMOVDQA(AA0, AA1)
VMOVDQA(AA0, AA2)
VMOVDQA(state1StoreAVX2, BB0)
VMOVDQA(BB0, BB1)
VMOVDQA(BB0, BB2)
VMOVDQA(state2StoreAVX2, CC0)
VMOVDQA(CC0, CC1)
VMOVDQA(CC0, CC2)
VMOVDQA(ctr3StoreAVX2, DD0)
avx2IncMask := avx2IncMask_DATA()
VPADDD(avx2IncMask, DD0, DD0)
VPADDD(avx2IncMask, DD0, DD1)
VPADDD(avx2IncMask, DD1, DD2)
VMOVDQA(DD0, ctr0StoreAVX2)
VMOVDQA(DD1, ctr1StoreAVX2)
VMOVDQA(DD2, ctr2StoreAVX2)
Comment("Compute the number of iterations that will hash two blocks of data")
MOVQ(inl, tmpStoreAVX2)
MOVQ(inl, itr1)
SUBQ(U32(256), itr1)
SHRQ(Imm(4), itr1)
ADDQ(Imm(6), itr1)
MOVQ(U32(10), itr2)
CMPQ(itr1, Imm(10))
CMOVQGT(itr2, itr1)
MOVQ(inp, inl)
XORQ(itr2, itr2)
}
// Perform ChaCha rounds, while hashing the remaining input
func openAVX2Tail384LoopB() {
Label("openAVX2Tail384LoopB")
polyAdd(Mem{Base: inl}.Offset(0))
polyMulAVX2()
LEAQ(Mem{Base: inl}.Offset(16), inl)
}
func openAVX2Tail384LoopA() {
Label("openAVX2Tail384LoopA")
chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0)
chachaQR_AVX2(AA1, BB1, CC1, DD1, TT0)
chachaQR_AVX2(AA2, BB2, CC2, DD2, TT0)
VPALIGNR(Imm(4), BB0, BB0, BB0)
VPALIGNR(Imm(4), BB1, BB1, BB1)
VPALIGNR(Imm(4), BB2, BB2, BB2)
VPALIGNR(Imm(8), CC0, CC0, CC0)
VPALIGNR(Imm(8), CC1, CC1, CC1)
VPALIGNR(Imm(8), CC2, CC2, CC2)
VPALIGNR(Imm(12), DD0, DD0, DD0)
VPALIGNR(Imm(12), DD1, DD1, DD1)
VPALIGNR(Imm(12), DD2, DD2, DD2)
polyAdd(Mem{Base: inl}.Offset(0))
polyMulAVX2()
LEAQ(Mem{Base: inl}.Offset(16), inl)
INCQ(itr2)
chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0)
chachaQR_AVX2(AA1, BB1, CC1, DD1, TT0)
chachaQR_AVX2(AA2, BB2, CC2, DD2, TT0)
VPALIGNR(Imm(12), BB0, BB0, BB0)
VPALIGNR(Imm(12), BB1, BB1, BB1)
VPALIGNR(Imm(12), BB2, BB2, BB2)
VPALIGNR(Imm(8), CC0, CC0, CC0)
VPALIGNR(Imm(8), CC1, CC1, CC1)
VPALIGNR(Imm(8), CC2, CC2, CC2)
VPALIGNR(Imm(4), DD0, DD0, DD0)
VPALIGNR(Imm(4), DD1, DD1, DD1)
VPALIGNR(Imm(4), DD2, DD2, DD2)
CMPQ(itr2, itr1)
JB(LabelRef("openAVX2Tail384LoopB"))
CMPQ(itr2, Imm(10))
JNE(LabelRef("openAVX2Tail384LoopA"))
MOVQ(inl, itr2)
SUBQ(inp, inl)
MOVQ(inl, itr1)
MOVQ(tmpStoreAVX2, inl)
}
func openAVX2Tail384Hash() {
Label("openAVX2Tail384Hash")
ADDQ(Imm(16), itr1)
CMPQ(itr1, inl)
JGT(LabelRef("openAVX2Tail384HashEnd"))
polyAdd(Mem{Base: itr2}.Offset(0))
polyMulAVX2()
LEAQ(Mem{Base: itr2}.Offset(16), itr2)
JMP(LabelRef("openAVX2Tail384Hash"))
}
// Store 256 bytes safely, then go to store loop
func openAVX2Tail384HashEnd() {
Label("openAVX2Tail384HashEnd")
chacha20Constants := chacha20Constants_DATA()
VPADDD(chacha20Constants, AA0, AA0)
VPADDD(chacha20Constants, AA1, AA1)
VPADDD(chacha20Constants, AA2, AA2)
VPADDD(state1StoreAVX2, BB0, BB0)
VPADDD(state1StoreAVX2, BB1, BB1)
VPADDD(state1StoreAVX2, BB2, BB2)
VPADDD(state2StoreAVX2, CC0, CC0)
VPADDD(state2StoreAVX2, CC1, CC1)
VPADDD(state2StoreAVX2, CC2, CC2)
VPADDD(ctr0StoreAVX2, DD0, DD0)
VPADDD(ctr1StoreAVX2, DD1, DD1)
VPADDD(ctr2StoreAVX2, DD2, DD2)
VPERM2I128(Imm(0x02), AA0, BB0, TT0)
VPERM2I128(Imm(0x02), CC0, DD0, TT1)
VPERM2I128(Imm(0x13), AA0, BB0, TT2)
VPERM2I128(Imm(0x13), CC0, DD0, TT3)
VPXOR(Mem{Base: inp}.Offset(0*32), TT0, TT0)
VPXOR(Mem{Base: inp}.Offset(1*32), TT1, TT1)
VPXOR(Mem{Base: inp}.Offset(2*32), TT2, TT2)
VPXOR(Mem{Base: inp}.Offset(3*32), TT3, TT3)
VMOVDQU(TT0, Mem{Base: oup}.Offset(0*32))
VMOVDQU(TT1, Mem{Base: oup}.Offset(1*32))
VMOVDQU(TT2, Mem{Base: oup}.Offset(2*32))
VMOVDQU(TT3, Mem{Base: oup}.Offset(3*32))
VPERM2I128(Imm(0x02), AA1, BB1, TT0)
VPERM2I128(Imm(0x02), CC1, DD1, TT1)
VPERM2I128(Imm(0x13), AA1, BB1, TT2)
VPERM2I128(Imm(0x13), CC1, DD1, TT3)
VPXOR(Mem{Base: inp}.Offset(4*32), TT0, TT0)
VPXOR(Mem{Base: inp}.Offset(5*32), TT1, TT1)
VPXOR(Mem{Base: inp}.Offset(6*32), TT2, TT2)
VPXOR(Mem{Base: inp}.Offset(7*32), TT3, TT3)
VMOVDQU(TT0, Mem{Base: oup}.Offset(4*32))
VMOVDQU(TT1, Mem{Base: oup}.Offset(5*32))
VMOVDQU(TT2, Mem{Base: oup}.Offset(6*32))
VMOVDQU(TT3, Mem{Base: oup}.Offset(7*32))
VPERM2I128(Imm(0x02), AA2, BB2, AA0)
VPERM2I128(Imm(0x02), CC2, DD2, BB0)
VPERM2I128(Imm(0x13), AA2, BB2, CC0)
VPERM2I128(Imm(0x13), CC2, DD2, DD0)
LEAQ(Mem{Base: inp}.Offset(8*32), inp)
LEAQ(Mem{Base: oup}.Offset(8*32), oup)
SUBQ(U32(8*32), inl)
JMP(LabelRef("openAVX2TailLoop"))
}
// ----------------------------------------------------------------------------
// Special optimization for the last 512 bytes of ciphertext
func openAVX2Tail512() {
Label("openAVX2Tail512")
chacha20Constants := chacha20Constants_DATA()
VMOVDQU(chacha20Constants, AA0)
VMOVDQA(AA0, AA1)
VMOVDQA(AA0, AA2)
VMOVDQA(AA0, AA3)
VMOVDQA(state1StoreAVX2, BB0)
VMOVDQA(BB0, BB1)
VMOVDQA(BB0, BB2)
VMOVDQA(BB0, BB3)
VMOVDQA(state2StoreAVX2, CC0)
VMOVDQA(CC0, CC1)
VMOVDQA(CC0, CC2)
VMOVDQA(CC0, CC3)
VMOVDQA(ctr3StoreAVX2, DD0)
avx2IncMask := avx2IncMask_DATA()
VPADDD(avx2IncMask, DD0, DD0)
VPADDD(avx2IncMask, DD0, DD1)
VPADDD(avx2IncMask, DD1, DD2)
VPADDD(avx2IncMask, DD2, DD3)
VMOVDQA(DD0, ctr0StoreAVX2)
VMOVDQA(DD1, ctr1StoreAVX2)
VMOVDQA(DD2, ctr2StoreAVX2)
VMOVDQA(DD3, ctr3StoreAVX2)
XORQ(itr1, itr1)
MOVQ(inp, itr2)
}
func openAVX2Tail512LoopB() {
Label("openAVX2Tail512LoopB")
polyAdd(Mem{Base: itr2}.Offset(0))
polyMulAVX2()
LEAQ(Mem{Base: itr2}.Offset(2*8), itr2)
}
func openAVX2Tail512LoopA() {
Label("openAVX2Tail512LoopA")
VPADDD(BB0, AA0, AA0)
VPADDD(BB1, AA1, AA1)
VPADDD(BB2, AA2, AA2)
VPADDD(BB3, AA3, AA3)
VPXOR(AA0, DD0, DD0)
VPXOR(AA1, DD1, DD1)
VPXOR(AA2, DD2, DD2)
VPXOR(AA3, DD3, DD3)
rol16 := rol16_DATA()
VPSHUFB(rol16, DD0, DD0)
VPSHUFB(rol16, DD1, DD1)
VPSHUFB(rol16, DD2, DD2)
VPSHUFB(rol16, DD3, DD3)
VPADDD(DD0, CC0, CC0)
VPADDD(DD1, CC1, CC1)
VPADDD(DD2, CC2, CC2)
VPADDD(DD3, CC3, CC3)
VPXOR(CC0, BB0, BB0)
VPXOR(CC1, BB1, BB1)
VPXOR(CC2, BB2, BB2)
VPXOR(CC3, BB3, BB3)
VMOVDQA(CC3, tmpStoreAVX2)
VPSLLD(Imm(12), BB0, CC3)
VPSRLD(Imm(20), BB0, BB0)
VPXOR(CC3, BB0, BB0)
VPSLLD(Imm(12), BB1, CC3)
VPSRLD(Imm(20), BB1, BB1)
VPXOR(CC3, BB1, BB1)
VPSLLD(Imm(12), BB2, CC3)
VPSRLD(Imm(20), BB2, BB2)
VPXOR(CC3, BB2, BB2)
VPSLLD(Imm(12), BB3, CC3)
VPSRLD(Imm(20), BB3, BB3)
VPXOR(CC3, BB3, BB3)
VMOVDQA(tmpStoreAVX2, CC3)
polyAdd(Mem{Base: itr2}.Offset(0 * 8))
polyMulAVX2()
VPADDD(BB0, AA0, AA0)
VPADDD(BB1, AA1, AA1)
VPADDD(BB2, AA2, AA2)
VPADDD(BB3, AA3, AA3)
VPXOR(AA0, DD0, DD0)
VPXOR(AA1, DD1, DD1)
VPXOR(AA2, DD2, DD2)
VPXOR(AA3, DD3, DD3)
rol8 := rol8_DATA()
VPSHUFB(rol8, DD0, DD0)
VPSHUFB(rol8, DD1, DD1)
VPSHUFB(rol8, DD2, DD2)
VPSHUFB(rol8, DD3, DD3)
VPADDD(DD0, CC0, CC0)
VPADDD(DD1, CC1, CC1)
VPADDD(DD2, CC2, CC2)
VPADDD(DD3, CC3, CC3)
VPXOR(CC0, BB0, BB0)
VPXOR(CC1, BB1, BB1)
VPXOR(CC2, BB2, BB2)
VPXOR(CC3, BB3, BB3)
VMOVDQA(CC3, tmpStoreAVX2)
VPSLLD(Imm(7), BB0, CC3)
VPSRLD(Imm(25), BB0, BB0)
VPXOR(CC3, BB0, BB0)
VPSLLD(Imm(7), BB1, CC3)
VPSRLD(Imm(25), BB1, BB1)
VPXOR(CC3, BB1, BB1)
VPSLLD(Imm(7), BB2, CC3)
VPSRLD(Imm(25), BB2, BB2)
VPXOR(CC3, BB2, BB2)
VPSLLD(Imm(7), BB3, CC3)
VPSRLD(Imm(25), BB3, BB3)
VPXOR(CC3, BB3, BB3)
VMOVDQA(tmpStoreAVX2, CC3)
VPALIGNR(Imm(4), BB0, BB0, BB0)
VPALIGNR(Imm(4), BB1, BB1, BB1)
VPALIGNR(Imm(4), BB2, BB2, BB2)
VPALIGNR(Imm(4), BB3, BB3, BB3)
VPALIGNR(Imm(8), CC0, CC0, CC0)
VPALIGNR(Imm(8), CC1, CC1, CC1)
VPALIGNR(Imm(8), CC2, CC2, CC2)
VPALIGNR(Imm(8), CC3, CC3, CC3)
VPALIGNR(Imm(12), DD0, DD0, DD0)
VPALIGNR(Imm(12), DD1, DD1, DD1)
VPALIGNR(Imm(12), DD2, DD2, DD2)
VPALIGNR(Imm(12), DD3, DD3, DD3)
VPADDD(BB0, AA0, AA0)
VPADDD(BB1, AA1, AA1)
VPADDD(BB2, AA2, AA2)
VPADDD(BB3, AA3, AA3)
VPXOR(AA0, DD0, DD0)
VPXOR(AA1, DD1, DD1)
VPXOR(AA2, DD2, DD2)
VPXOR(AA3, DD3, DD3)
VPSHUFB(rol16, DD0, DD0)
VPSHUFB(rol16, DD1, DD1)
VPSHUFB(rol16, DD2, DD2)
VPSHUFB(rol16, DD3, DD3)
VPADDD(DD0, CC0, CC0)
VPADDD(DD1, CC1, CC1)
VPADDD(DD2, CC2, CC2)
VPADDD(DD3, CC3, CC3)
VPXOR(CC0, BB0, BB0)
VPXOR(CC1, BB1, BB1)
VPXOR(CC2, BB2, BB2)
VPXOR(CC3, BB3, BB3)
polyAdd(Mem{Base: itr2}.Offset(2 * 8))
polyMulAVX2()
LEAQ(Mem{Base: itr2}.Offset(4*8), itr2)
VMOVDQA(CC3, tmpStoreAVX2)
VPSLLD(Imm(12), BB0, CC3)
VPSRLD(Imm(20), BB0, BB0)
VPXOR(CC3, BB0, BB0)
VPSLLD(Imm(12), BB1, CC3)
VPSRLD(Imm(20), BB1, BB1)
VPXOR(CC3, BB1, BB1)
VPSLLD(Imm(12), BB2, CC3)
VPSRLD(Imm(20), BB2, BB2)
VPXOR(CC3, BB2, BB2)
VPSLLD(Imm(12), BB3, CC3)
VPSRLD(Imm(20), BB3, BB3)
VPXOR(CC3, BB3, BB3)
VMOVDQA(tmpStoreAVX2, CC3)
VPADDD(BB0, AA0, AA0)
VPADDD(BB1, AA1, AA1)
VPADDD(BB2, AA2, AA2)
VPADDD(BB3, AA3, AA3)
VPXOR(AA0, DD0, DD0)
VPXOR(AA1, DD1, DD1)
VPXOR(AA2, DD2, DD2)
VPXOR(AA3, DD3, DD3)
VPSHUFB(rol8, DD0, DD0)
VPSHUFB(rol8, DD1, DD1)
VPSHUFB(rol8, DD2, DD2)
VPSHUFB(rol8, DD3, DD3)
VPADDD(DD0, CC0, CC0)
VPADDD(DD1, CC1, CC1)
VPADDD(DD2, CC2, CC2)
VPADDD(DD3, CC3, CC3)
VPXOR(CC0, BB0, BB0)
VPXOR(CC1, BB1, BB1)
VPXOR(CC2, BB2, BB2)
VPXOR(CC3, BB3, BB3)
VMOVDQA(CC3, tmpStoreAVX2)
VPSLLD(Imm(7), BB0, CC3)
VPSRLD(Imm(25), BB0, BB0)
VPXOR(CC3, BB0, BB0)
VPSLLD(Imm(7), BB1, CC3)
VPSRLD(Imm(25), BB1, BB1)
VPXOR(CC3, BB1, BB1)
VPSLLD(Imm(7), BB2, CC3)
VPSRLD(Imm(25), BB2, BB2)
VPXOR(CC3, BB2, BB2)
VPSLLD(Imm(7), BB3, CC3)
VPSRLD(Imm(25), BB3, BB3)
VPXOR(CC3, BB3, BB3)
VMOVDQA(tmpStoreAVX2, CC3)
VPALIGNR(Imm(12), BB0, BB0, BB0)
VPALIGNR(Imm(12), BB1, BB1, BB1)
VPALIGNR(Imm(12), BB2, BB2, BB2)
VPALIGNR(Imm(12), BB3, BB3, BB3)
VPALIGNR(Imm(8), CC0, CC0, CC0)
VPALIGNR(Imm(8), CC1, CC1, CC1)
VPALIGNR(Imm(8), CC2, CC2, CC2)
VPALIGNR(Imm(8), CC3, CC3, CC3)
VPALIGNR(Imm(4), DD0, DD0, DD0)
VPALIGNR(Imm(4), DD1, DD1, DD1)
VPALIGNR(Imm(4), DD2, DD2, DD2)
VPALIGNR(Imm(4), DD3, DD3, DD3)
INCQ(itr1)
CMPQ(itr1, Imm(4))
JLT(LabelRef("openAVX2Tail512LoopB"))
CMPQ(itr1, Imm(10))
JNE(LabelRef("openAVX2Tail512LoopA"))
MOVQ(inl, itr1)
SUBQ(U32(384), itr1)
ANDQ(I8(-16), itr1)
}
func openAVX2Tail512HashLoop() {
Label("openAVX2Tail512HashLoop")
TESTQ(itr1, itr1)
JE(LabelRef("openAVX2Tail512HashEnd"))
polyAdd(Mem{Base: itr2}.Offset(0))
polyMulAVX2()
LEAQ(Mem{Base: itr2}.Offset(16), itr2)
SUBQ(Imm(16), itr1)
JMP(LabelRef("openAVX2Tail512HashLoop"))
}
func openAVX2Tail512HashEnd() {
Label("openAVX2Tail512HashEnd")
chacha20Constants := chacha20Constants_DATA()
VPADDD(chacha20Constants, AA0, AA0)
VPADDD(chacha20Constants, AA1, AA1)
VPADDD(chacha20Constants, AA2, AA2)
VPADDD(chacha20Constants, AA3, AA3)
VPADDD(state1StoreAVX2, BB0, BB0)
VPADDD(state1StoreAVX2, BB1, BB1)
VPADDD(state1StoreAVX2, BB2, BB2)
VPADDD(state1StoreAVX2, BB3, BB3)
VPADDD(state2StoreAVX2, CC0, CC0)
VPADDD(state2StoreAVX2, CC1, CC1)
VPADDD(state2StoreAVX2, CC2, CC2)
VPADDD(state2StoreAVX2, CC3, CC3)
VPADDD(ctr0StoreAVX2, DD0, DD0)
VPADDD(ctr1StoreAVX2, DD1, DD1)
VPADDD(ctr2StoreAVX2, DD2, DD2)
VPADDD(ctr3StoreAVX2, DD3, DD3)
VMOVDQA(CC3, tmpStoreAVX2)
VPERM2I128(Imm(0x02), AA0, BB0, CC3)
VPERM2I128(Imm(0x13), AA0, BB0, BB0)
VPERM2I128(Imm(0x02), CC0, DD0, AA0)
VPERM2I128(Imm(0x13), CC0, DD0, CC0)
VPXOR(Mem{Base: inp}.Offset(0*32), CC3, CC3)
VPXOR(Mem{Base: inp}.Offset(1*32), AA0, AA0)
VPXOR(Mem{Base: inp}.Offset(2*32), BB0, BB0)
VPXOR(Mem{Base: inp}.Offset(3*32), CC0, CC0)
VMOVDQU(CC3, Mem{Base: oup}.Offset(0*32))
VMOVDQU(AA0, Mem{Base: oup}.Offset(1*32))
VMOVDQU(BB0, Mem{Base: oup}.Offset(2*32))
VMOVDQU(CC0, Mem{Base: oup}.Offset(3*32))
VPERM2I128(Imm(0x02), AA1, BB1, AA0)
VPERM2I128(Imm(0x02), CC1, DD1, BB0)
VPERM2I128(Imm(0x13), AA1, BB1, CC0)
VPERM2I128(Imm(0x13), CC1, DD1, DD0)
VPXOR(Mem{Base: inp}.Offset(4*32), AA0, AA0)
VPXOR(Mem{Base: inp}.Offset(5*32), BB0, BB0)
VPXOR(Mem{Base: inp}.Offset(6*32), CC0, CC0)
VPXOR(Mem{Base: inp}.Offset(7*32), DD0, DD0)
VMOVDQU(AA0, Mem{Base: oup}.Offset(4*32))
VMOVDQU(BB0, Mem{Base: oup}.Offset(5*32))
VMOVDQU(CC0, Mem{Base: oup}.Offset(6*32))
VMOVDQU(DD0, Mem{Base: oup}.Offset(7*32))
VPERM2I128(Imm(0x02), AA2, BB2, AA0)
VPERM2I128(Imm(0x02), CC2, DD2, BB0)
VPERM2I128(Imm(0x13), AA2, BB2, CC0)
VPERM2I128(Imm(0x13), CC2, DD2, DD0)
VPXOR(Mem{Base: inp}.Offset(8*32), AA0, AA0)
VPXOR(Mem{Base: inp}.Offset(9*32), BB0, BB0)
VPXOR(Mem{Base: inp}.Offset(10*32), CC0, CC0)
VPXOR(Mem{Base: inp}.Offset(11*32), DD0, DD0)
VMOVDQU(AA0, Mem{Base: oup}.Offset(8*32))
VMOVDQU(BB0, Mem{Base: oup}.Offset(9*32))
VMOVDQU(CC0, Mem{Base: oup}.Offset(10*32))
VMOVDQU(DD0, Mem{Base: oup}.Offset(11*32))
VPERM2I128(Imm(0x02), AA3, BB3, AA0)
VPERM2I128(Imm(0x02), tmpStoreAVX2, DD3, BB0)
VPERM2I128(Imm(0x13), AA3, BB3, CC0)
VPERM2I128(Imm(0x13), tmpStoreAVX2, DD3, DD0)
LEAQ(Mem{Base: inp}.Offset(12*32), inp)
LEAQ(Mem{Base: oup}.Offset(12*32), oup)
SUBQ(U32(12*32), inl)
JMP(LabelRef("openAVX2TailLoop"))
}
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// Special seal optimization for buffers smaller than 129 bytes
func sealSSETail() {
Label("sealSSETail")
TESTQ(inl, inl)
JE(LabelRef("sealSSEFinalize"))
Comment("We can only load the PT one byte at a time to avoid read after end of buffer")
MOVQ(inl, itr2)
SHLQ(Imm(4), itr2)
andMask := andMask_DATA()
LEAQ(andMask, t0)
MOVQ(inl, itr1)
LEAQ(Mem{Base: inp, Index: inl, Scale: 1}.Offset(-1), inp)
XORQ(t2, t2)
XORQ(t3, t3)
XORQ(RAX, RAX)
}
func sealSSETailLoadLoop() {
Label("sealSSETailLoadLoop")
SHLQ(Imm(8), t2, t3)
SHLQ(Imm(8), t2)
// Hack to get Avo to emit:
// MOVB (inp), AX
Instruction(&ir.Instruction{Opcode: "MOVB", Operands: []Op{Mem{Base: inp}, AX}})
XORQ(RAX, t2)
LEAQ(Mem{Base: inp}.Offset(-1), inp)
DECQ(itr1)
JNE(LabelRef("sealSSETailLoadLoop"))
MOVQ(t2, tmpStore.Offset(0))
MOVQ(t3, tmpStore.Offset(8))
PXOR(tmpStore.Offset(0), A1)
MOVOU(A1, Mem{Base: oup})
MOVOU(Mem{Base: t0, Index: itr2, Scale: 1}.Offset(-16), T0)
PAND(T0, A1)
MOVQ(A1, t0)
PSRLDQ(Imm(8), A1)
MOVQ(A1, t1)
ADDQ(t0, acc0)
ADCQ(t1, acc1)
ADCQ(Imm(1), acc2)
polyMul()
ADDQ(inl, oup)
}
func sealSSEFinalize() {
Label("sealSSEFinalize")
Comment("Hash in the buffer lengths")
ADDQ(NewParamAddr("ad_len", 80), acc0)
ADCQ(NewParamAddr("src_len", 56), acc1)
ADCQ(Imm(1), acc2)
polyMul()
Comment("Final reduce")
MOVQ(acc0, t0)
MOVQ(acc1, t1)
MOVQ(acc2, t2)
SUBQ(I8(-5), acc0)
SBBQ(I8(-1), acc1)
SBBQ(Imm(3), acc2)
CMOVQCS(t0, acc0)
CMOVQCS(t1, acc1)
CMOVQCS(t2, acc2)
Comment("Add in the \"s\" part of the key")
ADDQ(sStore.Offset(0), acc0)
ADCQ(sStore.Offset(8), acc1)
Comment("Finally store the tag at the end of the message")
MOVQ(acc0, Mem{Base: oup}.Offset(0*8))
MOVQ(acc1, Mem{Base: oup}.Offset(1*8))
RET()
}
func chacha20Poly1305Seal() {
Implement("chacha20Poly1305Seal")
Attributes(0)
AllocLocal(288)
MOVQ(RSP, RBP)
ADDQ(Imm(32), RBP)
ANDQ(I32(-32), RBP)
Load(Param("dst").Base(), oup)
Load(Param("key").Base(), keyp)
Load(Param("src").Base(), inp)
Load(Param("src").Len(), inl)
Load(Param("ad").Base(), adp)
VZEROUPPER()
chacha20Constants := chacha20Constants_DATA()
VMOVDQU(chacha20Constants, AA0)
VBROADCASTI128(Mem{Base: R8}.Offset(16), BB0)
VBROADCASTI128(Mem{Base: R8}.Offset(32), CC0)
VBROADCASTI128(Mem{Base: R8}.Offset(48), DD0)
avx2InitMask := avx2InitMask_DATA()
VPADDD(avx2InitMask, DD0, DD0)
Comment("Special optimizations, for very short buffers")
CMPQ(inl, U32(192))
JBE(LabelRef("seal192AVX2"))
CMPQ(inl, U32(320))
JBE(LabelRef("seal320AVX2"))
Comment("For the general key prepare the key first - as a byproduct we have 64 bytes of cipher stream")
VMOVDQA(AA0, AA1)
VMOVDQA(AA0, AA2)
VMOVDQA(AA0, AA3)
VMOVDQA(BB0, BB1)
VMOVDQA(BB0, BB2)
VMOVDQA(BB0, BB3)
VMOVDQA(BB0, state1StoreAVX2)
VMOVDQA(CC0, CC1)
VMOVDQA(CC0, CC2)
VMOVDQA(CC0, CC3)
VMOVDQA(CC0, state2StoreAVX2)
avx2IncMask := avx2IncMask_DATA()
VPADDD(avx2IncMask, DD0, DD1)
VMOVDQA(DD0, ctr0StoreAVX2)
VPADDD(avx2IncMask, DD1, DD2)
VMOVDQA(DD1, ctr1StoreAVX2)
VPADDD(avx2IncMask, DD2, DD3)
VMOVDQA(DD2, ctr2StoreAVX2)
VMOVDQA(DD3, ctr3StoreAVX2)
MOVQ(U32(10), itr2)
sealAVX2IntroLoop()
sealAVX2MainLoop()
sealAVX2InternalLoop()
sealAVX2InternalLoopStart()
// ----------------------------------------------------------------------------
// Special optimization for buffers smaller than 129 bytes
sealSSETail()
sealSSETailLoadLoop()
sealSSEFinalize()
// ----------------------------------------------------------------------------
// Special optimization for buffers smaller than 193 bytes
seal192AVX2()
sealAVX2192InnerCipherLoop()
sealAVX2ShortSeal()
sealAVX2SealHash()
sealAVX2ShortSealLoop()
sealAVX2ShortTail32()
sealAVX2ShortDone()
// ----------------------------------------------------------------------------
// Special optimization for buffers smaller than 321 bytes
seal320AVX2()
sealAVX2320InnerCipherLoop()
// ----------------------------------------------------------------------------
// Special optimization for the last 128 bytes of ciphertext
sealAVX2Tail128()
sealAVX2Tail128LoopA()
sealAVX2Tail128LoopB()
// ----------------------------------------------------------------------------
// Special optimization for the last 256 bytes of ciphertext
sealAVX2Tail256()
sealAVX2Tail256LoopA()
sealAVX2Tail256LoopB()
// ----------------------------------------------------------------------------
// Special optimization for the last 384 bytes of ciphertext
sealAVX2Tail384()
sealAVX2Tail384LoopA()
sealAVX2Tail384LoopB()
// ----------------------------------------------------------------------------
// Special optimization for the last 512 bytes of ciphertext
sealAVX2Tail512()
sealAVX2Tail512LoopA()
sealAVX2Tail512LoopB()
}
func sealAVX2IntroLoop() {
Label("sealAVX2IntroLoop")
VMOVDQA(CC3, tmpStoreAVX2)
chachaQR_AVX2(AA0, BB0, CC0, DD0, CC3)
chachaQR_AVX2(AA1, BB1, CC1, DD1, CC3)
chachaQR_AVX2(AA2, BB2, CC2, DD2, CC3)
VMOVDQA(tmpStoreAVX2, CC3)
VMOVDQA(CC1, tmpStoreAVX2)
chachaQR_AVX2(AA3, BB3, CC3, DD3, CC1)
VMOVDQA(tmpStoreAVX2, CC1)
VPALIGNR(Imm(4), BB0, BB0, BB0)
VPALIGNR(Imm(8), CC0, CC0, CC0)
VPALIGNR(Imm(12), DD0, DD0, DD0)
VPALIGNR(Imm(4), BB1, BB1, BB1)
VPALIGNR(Imm(8), CC1, CC1, CC1)
VPALIGNR(Imm(12), DD1, DD1, DD1)
VPALIGNR(Imm(4), BB2, BB2, BB2)
VPALIGNR(Imm(8), CC2, CC2, CC2)
VPALIGNR(Imm(12), DD2, DD2, DD2)
VPALIGNR(Imm(4), BB3, BB3, BB3)
VPALIGNR(Imm(8), CC3, CC3, CC3)
VPALIGNR(Imm(12), DD3, DD3, DD3)
VMOVDQA(CC3, tmpStoreAVX2)
chachaQR_AVX2(AA0, BB0, CC0, DD0, CC3)
chachaQR_AVX2(AA1, BB1, CC1, DD1, CC3)
chachaQR_AVX2(AA2, BB2, CC2, DD2, CC3)
VMOVDQA(tmpStoreAVX2, CC3)
VMOVDQA(CC1, tmpStoreAVX2)
chachaQR_AVX2(AA3, BB3, CC3, DD3, CC1)
VMOVDQA(tmpStoreAVX2, CC1)
VPALIGNR(Imm(12), BB0, BB0, BB0)
VPALIGNR(Imm(8), CC0, CC0, CC0)
VPALIGNR(Imm(4), DD0, DD0, DD0)
VPALIGNR(Imm(12), BB1, BB1, BB1)
VPALIGNR(Imm(8), CC1, CC1, CC1)
VPALIGNR(Imm(4), DD1, DD1, DD1)
VPALIGNR(Imm(12), BB2, BB2, BB2)
VPALIGNR(Imm(8), CC2, CC2, CC2)
VPALIGNR(Imm(4), DD2, DD2, DD2)
VPALIGNR(Imm(12), BB3, BB3, BB3)
VPALIGNR(Imm(8), CC3, CC3, CC3)
VPALIGNR(Imm(4), DD3, DD3, DD3)
DECQ(itr2)
JNE(LabelRef("sealAVX2IntroLoop"))
chacha20Constants := chacha20Constants_DATA()
VPADDD(chacha20Constants, AA0, AA0)
VPADDD(chacha20Constants, AA1, AA1)
VPADDD(chacha20Constants, AA2, AA2)
VPADDD(chacha20Constants, AA3, AA3)
VPADDD(state1StoreAVX2, BB0, BB0)
VPADDD(state1StoreAVX2, BB1, BB1)
VPADDD(state1StoreAVX2, BB2, BB2)
VPADDD(state1StoreAVX2, BB3, BB3)
VPADDD(state2StoreAVX2, CC0, CC0)
VPADDD(state2StoreAVX2, CC1, CC1)
VPADDD(state2StoreAVX2, CC2, CC2)
VPADDD(state2StoreAVX2, CC3, CC3)
VPADDD(ctr0StoreAVX2, DD0, DD0)
VPADDD(ctr1StoreAVX2, DD1, DD1)
VPADDD(ctr2StoreAVX2, DD2, DD2)
VPADDD(ctr3StoreAVX2, DD3, DD3)
VPERM2I128(Imm(0x13), CC0, DD0, CC0)
VPERM2I128(Imm(0x02), AA0, BB0, DD0)
VPERM2I128(Imm(0x13), AA0, BB0, AA0)
Comment("Clamp and store poly key")
polyClampMask := polyClampMask_DATA()
VPAND(polyClampMask, DD0, DD0)
VMOVDQA(DD0, rsStoreAVX2)
Comment("Hash AD")
MOVQ(NewParamAddr("ad_len", 80), itr2)
CALL(LabelRef("polyHashADInternal<>(SB)"))
Comment("Can store at least 320 bytes")
VPXOR(Mem{Base: inp}.Offset(0*32), AA0, AA0)
VPXOR(Mem{Base: inp}.Offset(1*32), CC0, CC0)
VMOVDQU(AA0, Mem{Base: oup}.Offset(0*32))
VMOVDQU(CC0, Mem{Base: oup}.Offset(1*32))
VPERM2I128(Imm(0x02), AA1, BB1, AA0)
VPERM2I128(Imm(0x02), CC1, DD1, BB0)
VPERM2I128(Imm(0x13), AA1, BB1, CC0)
VPERM2I128(Imm(0x13), CC1, DD1, DD0)
VPXOR(Mem{Base: inp}.Offset(2*32), AA0, AA0)
VPXOR(Mem{Base: inp}.Offset(3*32), BB0, BB0)
VPXOR(Mem{Base: inp}.Offset(4*32), CC0, CC0)
VPXOR(Mem{Base: inp}.Offset(5*32), DD0, DD0)
VMOVDQU(AA0, Mem{Base: oup}.Offset(2*32))
VMOVDQU(BB0, Mem{Base: oup}.Offset(3*32))
VMOVDQU(CC0, Mem{Base: oup}.Offset(4*32))
VMOVDQU(DD0, Mem{Base: oup}.Offset(5*32))
VPERM2I128(Imm(0x02), AA2, BB2, AA0)
VPERM2I128(Imm(0x02), CC2, DD2, BB0)
VPERM2I128(Imm(0x13), AA2, BB2, CC0)
VPERM2I128(Imm(0x13), CC2, DD2, DD0)
VPXOR(Mem{Base: inp}.Offset(6*32), AA0, AA0)
VPXOR(Mem{Base: inp}.Offset(7*32), BB0, BB0)
VPXOR(Mem{Base: inp}.Offset(8*32), CC0, CC0)
VPXOR(Mem{Base: inp}.Offset(9*32), DD0, DD0)
VMOVDQU(AA0, Mem{Base: oup}.Offset(6*32))
VMOVDQU(BB0, Mem{Base: oup}.Offset(7*32))
VMOVDQU(CC0, Mem{Base: oup}.Offset(8*32))
VMOVDQU(DD0, Mem{Base: oup}.Offset(9*32))
MOVQ(U32(320), itr1)
SUBQ(U32(320), inl)
LEAQ(Mem{Base: inp}.Offset(320), inp)
VPERM2I128(Imm(0x02), AA3, BB3, AA0)
VPERM2I128(Imm(0x02), CC3, DD3, BB0)
VPERM2I128(Imm(0x13), AA3, BB3, CC0)
VPERM2I128(Imm(0x13), CC3, DD3, DD0)
CMPQ(inl, Imm(128))
JBE(LabelRef("sealAVX2SealHash"))
VPXOR(Mem{Base: inp}.Offset(0*32), AA0, AA0)
VPXOR(Mem{Base: inp}.Offset(1*32), BB0, BB0)
VPXOR(Mem{Base: inp}.Offset(2*32), CC0, CC0)
VPXOR(Mem{Base: inp}.Offset(3*32), DD0, DD0)
VMOVDQU(AA0, Mem{Base: oup}.Offset(10*32))
VMOVDQU(BB0, Mem{Base: oup}.Offset(11*32))
VMOVDQU(CC0, Mem{Base: oup}.Offset(12*32))
VMOVDQU(DD0, Mem{Base: oup}.Offset(13*32))
SUBQ(Imm(128), inl)
LEAQ(Mem{Base: inp}.Offset(128), inp)
MOVQ(U32(8), itr1)
MOVQ(U32(2), itr2)
CMPQ(inl, Imm(128))
JBE(LabelRef("sealAVX2Tail128"))
CMPQ(inl, U32(256))
JBE(LabelRef("sealAVX2Tail256"))
CMPQ(inl, U32(384))
JBE(LabelRef("sealAVX2Tail384"))
CMPQ(inl, U32(512))
JBE(LabelRef("sealAVX2Tail512"))
Comment("We have 448 bytes to hash, but main loop hashes 512 bytes at a time - perform some rounds, before the main loop")
VMOVDQA(chacha20Constants, AA0)
VMOVDQA(AA0, AA1)
VMOVDQA(AA0, AA2)
VMOVDQA(AA0, AA3)
VMOVDQA(state1StoreAVX2, BB0)
VMOVDQA(BB0, BB1)
VMOVDQA(BB0, BB2)
VMOVDQA(BB0, BB3)
VMOVDQA(state2StoreAVX2, CC0)
VMOVDQA(CC0, CC1)
VMOVDQA(CC0, CC2)
VMOVDQA(CC0, CC3)
VMOVDQA(ctr3StoreAVX2, DD0)
avx2IncMask := avx2IncMask_DATA()
VPADDD(avx2IncMask, DD0, DD0)
VPADDD(avx2IncMask, DD0, DD1)
VPADDD(avx2IncMask, DD1, DD2)
VPADDD(avx2IncMask, DD2, DD3)
VMOVDQA(DD0, ctr0StoreAVX2)
VMOVDQA(DD1, ctr1StoreAVX2)
VMOVDQA(DD2, ctr2StoreAVX2)
VMOVDQA(DD3, ctr3StoreAVX2)
VMOVDQA(CC3, tmpStoreAVX2)
chachaQR_AVX2(AA0, BB0, CC0, DD0, CC3)
chachaQR_AVX2(AA1, BB1, CC1, DD1, CC3)
chachaQR_AVX2(AA2, BB2, CC2, DD2, CC3)
VMOVDQA(tmpStoreAVX2, CC3)
VMOVDQA(CC1, tmpStoreAVX2)
chachaQR_AVX2(AA3, BB3, CC3, DD3, CC1)
VMOVDQA(tmpStoreAVX2, CC1)
VPALIGNR(Imm(4), BB0, BB0, BB0)
VPALIGNR(Imm(8), CC0, CC0, CC0)
VPALIGNR(Imm(12), DD0, DD0, DD0)
VPALIGNR(Imm(4), BB1, BB1, BB1)
VPALIGNR(Imm(8), CC1, CC1, CC1)
VPALIGNR(Imm(12), DD1, DD1, DD1)
VPALIGNR(Imm(4), BB2, BB2, BB2)
VPALIGNR(Imm(8), CC2, CC2, CC2)
VPALIGNR(Imm(12), DD2, DD2, DD2)
VPALIGNR(Imm(4), BB3, BB3, BB3)
VPALIGNR(Imm(8), CC3, CC3, CC3)
VPALIGNR(Imm(12), DD3, DD3, DD3)
VMOVDQA(CC3, tmpStoreAVX2)
chachaQR_AVX2(AA0, BB0, CC0, DD0, CC3)
chachaQR_AVX2(AA1, BB1, CC1, DD1, CC3)
chachaQR_AVX2(AA2, BB2, CC2, DD2, CC3)
VMOVDQA(tmpStoreAVX2, CC3)
VMOVDQA(CC1, tmpStoreAVX2)
chachaQR_AVX2(AA3, BB3, CC3, DD3, CC1)
VMOVDQA(tmpStoreAVX2, CC1)
VPALIGNR(Imm(12), BB0, BB0, BB0)
VPALIGNR(Imm(8), CC0, CC0, CC0)
VPALIGNR(Imm(4), DD0, DD0, DD0)
VPALIGNR(Imm(12), BB1, BB1, BB1)
VPALIGNR(Imm(8), CC1, CC1, CC1)
VPALIGNR(Imm(4), DD1, DD1, DD1)
VPALIGNR(Imm(12), BB2, BB2, BB2)
VPALIGNR(Imm(8), CC2, CC2, CC2)
VPALIGNR(Imm(4), DD2, DD2, DD2)
VPALIGNR(Imm(12), BB3, BB3, BB3)
VPALIGNR(Imm(8), CC3, CC3, CC3)
VPALIGNR(Imm(4), DD3, DD3, DD3)
VPADDD(BB0, AA0, AA0)
VPADDD(BB1, AA1, AA1)
VPADDD(BB2, AA2, AA2)
VPADDD(BB3, AA3, AA3)
VPXOR(AA0, DD0, DD0)
VPXOR(AA1, DD1, DD1)
VPXOR(AA2, DD2, DD2)
VPXOR(AA3, DD3, DD3)
rol16 := rol16_DATA()
VPSHUFB(rol16, DD0, DD0)
VPSHUFB(rol16, DD1, DD1)
VPSHUFB(rol16, DD2, DD2)
VPSHUFB(rol16, DD3, DD3)
VPADDD(DD0, CC0, CC0)
VPADDD(DD1, CC1, CC1)
VPADDD(DD2, CC2, CC2)
VPADDD(DD3, CC3, CC3)
VPXOR(CC0, BB0, BB0)
VPXOR(CC1, BB1, BB1)
VPXOR(CC2, BB2, BB2)
VPXOR(CC3, BB3, BB3)
VMOVDQA(CC3, tmpStoreAVX2)
VPSLLD(Imm(12), BB0, CC3)
VPSRLD(Imm(20), BB0, BB0)
VPXOR(CC3, BB0, BB0)
VPSLLD(Imm(12), BB1, CC3)
VPSRLD(Imm(20), BB1, BB1)
VPXOR(CC3, BB1, BB1)
VPSLLD(Imm(12), BB2, CC3)
VPSRLD(Imm(20), BB2, BB2)
VPXOR(CC3, BB2, BB2)
VPSLLD(Imm(12), BB3, CC3)
VPSRLD(Imm(20), BB3, BB3)
VPXOR(CC3, BB3, BB3)
VMOVDQA(tmpStoreAVX2, CC3)
SUBQ(Imm(16), oup) // Adjust the pointer
MOVQ(U32(9), itr1)
JMP(LabelRef("sealAVX2InternalLoopStart"))
}
// Load state, increment counter blocks, store the incremented counters
func sealAVX2MainLoop() {
Label("sealAVX2MainLoop")
chacha20Constants := chacha20Constants_DATA()
VMOVDQU(chacha20Constants, AA0)
VMOVDQA(AA0, AA1)
VMOVDQA(AA0, AA2)
VMOVDQA(AA0, AA3)
VMOVDQA(state1StoreAVX2, BB0)
VMOVDQA(BB0, BB1)
VMOVDQA(BB0, BB2)
VMOVDQA(BB0, BB3)
VMOVDQA(state2StoreAVX2, CC0)
VMOVDQA(CC0, CC1)
VMOVDQA(CC0, CC2)
VMOVDQA(CC0, CC3)
VMOVDQA(ctr3StoreAVX2, DD0)
avx2IncMask := avx2IncMask_DATA()
VPADDD(avx2IncMask, DD0, DD0)
VPADDD(avx2IncMask, DD0, DD1)
VPADDD(avx2IncMask, DD1, DD2)
VPADDD(avx2IncMask, DD2, DD3)
VMOVDQA(DD0, ctr0StoreAVX2)
VMOVDQA(DD1, ctr1StoreAVX2)
VMOVDQA(DD2, ctr2StoreAVX2)
VMOVDQA(DD3, ctr3StoreAVX2)
MOVQ(U32(10), itr1)
}
func sealAVX2InternalLoop() {
Label("sealAVX2InternalLoop")
polyAdd(Mem{Base: oup}.Offset(0 * 8))
VPADDD(BB0, AA0, AA0)
VPADDD(BB1, AA1, AA1)
VPADDD(BB2, AA2, AA2)
VPADDD(BB3, AA3, AA3)
polyMulStage1_AVX2()
VPXOR(AA0, DD0, DD0)
VPXOR(AA1, DD1, DD1)
VPXOR(AA2, DD2, DD2)
VPXOR(AA3, DD3, DD3)
rol16 := rol16_DATA()
VPSHUFB(rol16, DD0, DD0)
VPSHUFB(rol16, DD1, DD1)
VPSHUFB(rol16, DD2, DD2)
VPSHUFB(rol16, DD3, DD3)
polyMulStage2_AVX2()
VPADDD(DD0, CC0, CC0)
VPADDD(DD1, CC1, CC1)
VPADDD(DD2, CC2, CC2)
VPADDD(DD3, CC3, CC3)
VPXOR(CC0, BB0, BB0)
VPXOR(CC1, BB1, BB1)
VPXOR(CC2, BB2, BB2)
VPXOR(CC3, BB3, BB3)
polyMulStage3_AVX2()
VMOVDQA(CC3, tmpStoreAVX2)
VPSLLD(Imm(12), BB0, CC3)
VPSRLD(Imm(20), BB0, BB0)
VPXOR(CC3, BB0, BB0)
VPSLLD(Imm(12), BB1, CC3)
VPSRLD(Imm(20), BB1, BB1)
VPXOR(CC3, BB1, BB1)
VPSLLD(Imm(12), BB2, CC3)
VPSRLD(Imm(20), BB2, BB2)
VPXOR(CC3, BB2, BB2)
VPSLLD(Imm(12), BB3, CC3)
VPSRLD(Imm(20), BB3, BB3)
VPXOR(CC3, BB3, BB3)
VMOVDQA(tmpStoreAVX2, CC3)
polyMulReduceStage()
}
func sealAVX2InternalLoopStart() {
Label("sealAVX2InternalLoopStart")
VPADDD(BB0, AA0, AA0)
VPADDD(BB1, AA1, AA1)
VPADDD(BB2, AA2, AA2)
VPADDD(BB3, AA3, AA3)
VPXOR(AA0, DD0, DD0)
VPXOR(AA1, DD1, DD1)
VPXOR(AA2, DD2, DD2)
VPXOR(AA3, DD3, DD3)
rol8 := rol8_DATA()
VPSHUFB(rol8, DD0, DD0)
VPSHUFB(rol8, DD1, DD1)
VPSHUFB(rol8, DD2, DD2)
VPSHUFB(rol8, DD3, DD3)
polyAdd(Mem{Base: oup}.Offset(2 * 8))
VPADDD(DD0, CC0, CC0)
VPADDD(DD1, CC1, CC1)
VPADDD(DD2, CC2, CC2)
VPADDD(DD3, CC3, CC3)
polyMulStage1_AVX2()
VPXOR(CC0, BB0, BB0)
VPXOR(CC1, BB1, BB1)
VPXOR(CC2, BB2, BB2)
VPXOR(CC3, BB3, BB3)
VMOVDQA(CC3, tmpStoreAVX2)
VPSLLD(Imm(7), BB0, CC3)
VPSRLD(Imm(25), BB0, BB0)
VPXOR(CC3, BB0, BB0)
VPSLLD(Imm(7), BB1, CC3)
VPSRLD(Imm(25), BB1, BB1)
VPXOR(CC3, BB1, BB1)
VPSLLD(Imm(7), BB2, CC3)
VPSRLD(Imm(25), BB2, BB2)
VPXOR(CC3, BB2, BB2)
VPSLLD(Imm(7), BB3, CC3)
VPSRLD(Imm(25), BB3, BB3)
VPXOR(CC3, BB3, BB3)
VMOVDQA(tmpStoreAVX2, CC3)
polyMulStage2_AVX2()
VPALIGNR(Imm(4), BB0, BB0, BB0)
VPALIGNR(Imm(4), BB1, BB1, BB1)
VPALIGNR(Imm(4), BB2, BB2, BB2)
VPALIGNR(Imm(4), BB3, BB3, BB3)
VPALIGNR(Imm(8), CC0, CC0, CC0)
VPALIGNR(Imm(8), CC1, CC1, CC1)
VPALIGNR(Imm(8), CC2, CC2, CC2)
VPALIGNR(Imm(8), CC3, CC3, CC3)
VPALIGNR(Imm(12), DD0, DD0, DD0)
VPALIGNR(Imm(12), DD1, DD1, DD1)
VPALIGNR(Imm(12), DD2, DD2, DD2)
VPALIGNR(Imm(12), DD3, DD3, DD3)
VPADDD(BB0, AA0, AA0)
VPADDD(BB1, AA1, AA1)
VPADDD(BB2, AA2, AA2)
VPADDD(BB3, AA3, AA3)
polyMulStage3_AVX2()
VPXOR(AA0, DD0, DD0)
VPXOR(AA1, DD1, DD1)
VPXOR(AA2, DD2, DD2)
VPXOR(AA3, DD3, DD3)
rol16 := rol16_DATA()
VPSHUFB(rol16, DD0, DD0)
VPSHUFB(rol16, DD1, DD1)
VPSHUFB(rol16, DD2, DD2)
VPSHUFB(rol16, DD3, DD3)
polyMulReduceStage()
VPADDD(DD0, CC0, CC0)
VPADDD(DD1, CC1, CC1)
VPADDD(DD2, CC2, CC2)
VPADDD(DD3, CC3, CC3)
VPXOR(CC0, BB0, BB0)
VPXOR(CC1, BB1, BB1)
VPXOR(CC2, BB2, BB2)
VPXOR(CC3, BB3, BB3)
polyAdd(Mem{Base: oup}.Offset(4 * 8))
LEAQ(Mem{Base: oup}.Offset(6*8), oup)
VMOVDQA(CC3, tmpStoreAVX2)
VPSLLD(Imm(12), BB0, CC3)
VPSRLD(Imm(20), BB0, BB0)
VPXOR(CC3, BB0, BB0)
VPSLLD(Imm(12), BB1, CC3)
VPSRLD(Imm(20), BB1, BB1)
VPXOR(CC3, BB1, BB1)
VPSLLD(Imm(12), BB2, CC3)
VPSRLD(Imm(20), BB2, BB2)
VPXOR(CC3, BB2, BB2)
VPSLLD(Imm(12), BB3, CC3)
VPSRLD(Imm(20), BB3, BB3)
VPXOR(CC3, BB3, BB3)
VMOVDQA(tmpStoreAVX2, CC3)
polyMulStage1_AVX2()
VPADDD(BB0, AA0, AA0)
VPADDD(BB1, AA1, AA1)
VPADDD(BB2, AA2, AA2)
VPADDD(BB3, AA3, AA3)
VPXOR(AA0, DD0, DD0)
VPXOR(AA1, DD1, DD1)
VPXOR(AA2, DD2, DD2)
VPXOR(AA3, DD3, DD3)
polyMulStage2_AVX2()
VPSHUFB(rol8, DD0, DD0)
VPSHUFB(rol8, DD1, DD1)
VPSHUFB(rol8, DD2, DD2)
VPSHUFB(rol8, DD3, DD3)
VPADDD(DD0, CC0, CC0)
VPADDD(DD1, CC1, CC1)
VPADDD(DD2, CC2, CC2)
VPADDD(DD3, CC3, CC3)
polyMulStage3_AVX2()
VPXOR(CC0, BB0, BB0)
VPXOR(CC1, BB1, BB1)
VPXOR(CC2, BB2, BB2)
VPXOR(CC3, BB3, BB3)
VMOVDQA(CC3, tmpStoreAVX2)
VPSLLD(Imm(7), BB0, CC3)
VPSRLD(Imm(25), BB0, BB0)
VPXOR(CC3, BB0, BB0)
VPSLLD(Imm(7), BB1, CC3)
VPSRLD(Imm(25), BB1, BB1)
VPXOR(CC3, BB1, BB1)
VPSLLD(Imm(7), BB2, CC3)
VPSRLD(Imm(25), BB2, BB2)
VPXOR(CC3, BB2, BB2)
VPSLLD(Imm(7), BB3, CC3)
VPSRLD(Imm(25), BB3, BB3)
VPXOR(CC3, BB3, BB3)
VMOVDQA(tmpStoreAVX2, CC3)
polyMulReduceStage()
VPALIGNR(Imm(12), BB0, BB0, BB0)
VPALIGNR(Imm(12), BB1, BB1, BB1)
VPALIGNR(Imm(12), BB2, BB2, BB2)
VPALIGNR(Imm(12), BB3, BB3, BB3)
VPALIGNR(Imm(8), CC0, CC0, CC0)
VPALIGNR(Imm(8), CC1, CC1, CC1)
VPALIGNR(Imm(8), CC2, CC2, CC2)
VPALIGNR(Imm(8), CC3, CC3, CC3)
VPALIGNR(Imm(4), DD0, DD0, DD0)
VPALIGNR(Imm(4), DD1, DD1, DD1)
VPALIGNR(Imm(4), DD2, DD2, DD2)
VPALIGNR(Imm(4), DD3, DD3, DD3)
DECQ(itr1)
JNE(LabelRef("sealAVX2InternalLoop"))
chacha20Constants := chacha20Constants_DATA()
VPADDD(chacha20Constants, AA0, AA0)
VPADDD(chacha20Constants, AA1, AA1)
VPADDD(chacha20Constants, AA2, AA2)
VPADDD(chacha20Constants, AA3, AA3)
VPADDD(state1StoreAVX2, BB0, BB0)
VPADDD(state1StoreAVX2, BB1, BB1)
VPADDD(state1StoreAVX2, BB2, BB2)
VPADDD(state1StoreAVX2, BB3, BB3)
VPADDD(state2StoreAVX2, CC0, CC0)
VPADDD(state2StoreAVX2, CC1, CC1)
VPADDD(state2StoreAVX2, CC2, CC2)
VPADDD(state2StoreAVX2, CC3, CC3)
VPADDD(ctr0StoreAVX2, DD0, DD0)
VPADDD(ctr1StoreAVX2, DD1, DD1)
VPADDD(ctr2StoreAVX2, DD2, DD2)
VPADDD(ctr3StoreAVX2, DD3, DD3)
VMOVDQA(CC3, tmpStoreAVX2)
Comment("We only hashed 480 of the 512 bytes available - hash the remaining 32 here")
polyAdd(Mem{Base: oup}.Offset(0 * 8))
polyMulAVX2()
LEAQ(Mem{Base: oup}.Offset(4*8), oup)
VPERM2I128(Imm(0x02), AA0, BB0, CC3)
VPERM2I128(Imm(0x13), AA0, BB0, BB0)
VPERM2I128(Imm(0x02), CC0, DD0, AA0)
VPERM2I128(Imm(0x13), CC0, DD0, CC0)
VPXOR(Mem{Base: inp}.Offset(0*32), CC3, CC3)
VPXOR(Mem{Base: inp}.Offset(1*32), AA0, AA0)
VPXOR(Mem{Base: inp}.Offset(2*32), BB0, BB0)
VPXOR(Mem{Base: inp}.Offset(3*32), CC0, CC0)
VMOVDQU(CC3, Mem{Base: oup}.Offset(0*32))
VMOVDQU(AA0, Mem{Base: oup}.Offset(1*32))
VMOVDQU(BB0, Mem{Base: oup}.Offset(2*32))
VMOVDQU(CC0, Mem{Base: oup}.Offset(3*32))
VPERM2I128(Imm(0x02), AA1, BB1, AA0)
VPERM2I128(Imm(0x02), CC1, DD1, BB0)
VPERM2I128(Imm(0x13), AA1, BB1, CC0)
VPERM2I128(Imm(0x13), CC1, DD1, DD0)
VPXOR(Mem{Base: inp}.Offset(4*32), AA0, AA0)
VPXOR(Mem{Base: inp}.Offset(5*32), BB0, BB0)
VPXOR(Mem{Base: inp}.Offset(6*32), CC0, CC0)
VPXOR(Mem{Base: inp}.Offset(7*32), DD0, DD0)
VMOVDQU(AA0, Mem{Base: oup}.Offset(4*32))
VMOVDQU(BB0, Mem{Base: oup}.Offset(5*32))
VMOVDQU(CC0, Mem{Base: oup}.Offset(6*32))
VMOVDQU(DD0, Mem{Base: oup}.Offset(7*32))
Comment("and here")
polyAdd(Mem{Base: oup}.Offset(-2 * 8))
polyMulAVX2()
VPERM2I128(Imm(0x02), AA2, BB2, AA0)
VPERM2I128(Imm(0x02), CC2, DD2, BB0)
VPERM2I128(Imm(0x13), AA2, BB2, CC0)
VPERM2I128(Imm(0x13), CC2, DD2, DD0)
VPXOR(Mem{Base: inp}.Offset(8*32), AA0, AA0)
VPXOR(Mem{Base: inp}.Offset(9*32), BB0, BB0)
VPXOR(Mem{Base: inp}.Offset(10*32), CC0, CC0)
VPXOR(Mem{Base: inp}.Offset(11*32), DD0, DD0)
VMOVDQU(AA0, Mem{Base: oup}.Offset(8*32))
VMOVDQU(BB0, Mem{Base: oup}.Offset(9*32))
VMOVDQU(CC0, Mem{Base: oup}.Offset(10*32))
VMOVDQU(DD0, Mem{Base: oup}.Offset(11*32))
VPERM2I128(Imm(0x02), AA3, BB3, AA0)
VPERM2I128(Imm(0x02), tmpStoreAVX2, DD3, BB0)
VPERM2I128(Imm(0x13), AA3, BB3, CC0)
VPERM2I128(Imm(0x13), tmpStoreAVX2, DD3, DD0)
VPXOR(Mem{Base: inp}.Offset(12*32), AA0, AA0)
VPXOR(Mem{Base: inp}.Offset(13*32), BB0, BB0)
VPXOR(Mem{Base: inp}.Offset(14*32), CC0, CC0)
VPXOR(Mem{Base: inp}.Offset(15*32), DD0, DD0)
VMOVDQU(AA0, Mem{Base: oup}.Offset(12*32))
VMOVDQU(BB0, Mem{Base: oup}.Offset(13*32))
VMOVDQU(CC0, Mem{Base: oup}.Offset(14*32))
VMOVDQU(DD0, Mem{Base: oup}.Offset(15*32))
LEAQ(Mem{Base: inp}.Offset(32*16), inp)
SUBQ(U32(32*16), inl)
CMPQ(inl, U32(512))
JG(LabelRef("sealAVX2MainLoop"))
Comment("Tail can only hash 480 bytes")
polyAdd(Mem{Base: oup}.Offset(0 * 8))
polyMulAVX2()
polyAdd(Mem{Base: oup}.Offset(2 * 8))
polyMulAVX2()
LEAQ(Mem{Base: oup}.Offset(32), oup)
MOVQ(U32(10), itr1)
MOVQ(U32(0), itr2)
CMPQ(inl, Imm(128))
JBE(LabelRef("sealAVX2Tail128"))
CMPQ(inl, U32(256))
JBE(LabelRef("sealAVX2Tail256"))
CMPQ(inl, U32(384))
JBE(LabelRef("sealAVX2Tail384"))
JMP(LabelRef("sealAVX2Tail512"))
}
// ----------------------------------------------------------------------------
// Special optimization for buffers smaller than 193 bytes
// For up to 192 bytes of ciphertext and 64 bytes for the poly key, we process four blocks
func seal192AVX2() {
Label("seal192AVX2")
VMOVDQA(AA0, AA1)
VMOVDQA(BB0, BB1)
VMOVDQA(CC0, CC1)
avx2IncMask := avx2IncMask_DATA()
VPADDD(avx2IncMask, DD0, DD1)
VMOVDQA(AA0, AA2)
VMOVDQA(BB0, BB2)
VMOVDQA(CC0, CC2)
VMOVDQA(DD0, DD2)
VMOVDQA(DD1, TT3)
MOVQ(U32(10), itr2)
}
func sealAVX2192InnerCipherLoop() {
Label("sealAVX2192InnerCipherLoop")
chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0)
chachaQR_AVX2(AA1, BB1, CC1, DD1, TT0)
VPALIGNR(Imm(4), BB0, BB0, BB0)
VPALIGNR(Imm(4), BB1, BB1, BB1)
VPALIGNR(Imm(8), CC0, CC0, CC0)
VPALIGNR(Imm(8), CC1, CC1, CC1)
VPALIGNR(Imm(12), DD0, DD0, DD0)
VPALIGNR(Imm(12), DD1, DD1, DD1)
chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0)
chachaQR_AVX2(AA1, BB1, CC1, DD1, TT0)
VPALIGNR(Imm(12), BB0, BB0, BB0)
VPALIGNR(Imm(12), BB1, BB1, BB1)
VPALIGNR(Imm(8), CC0, CC0, CC0)
VPALIGNR(Imm(8), CC1, CC1, CC1)
VPALIGNR(Imm(4), DD0, DD0, DD0)
VPALIGNR(Imm(4), DD1, DD1, DD1)
DECQ(itr2)
JNE(LabelRef("sealAVX2192InnerCipherLoop"))
VPADDD(AA2, AA0, AA0)
VPADDD(AA2, AA1, AA1)
VPADDD(BB2, BB0, BB0)
VPADDD(BB2, BB1, BB1)
VPADDD(CC2, CC0, CC0)
VPADDD(CC2, CC1, CC1)
VPADDD(DD2, DD0, DD0)
VPADDD(TT3, DD1, DD1)
VPERM2I128(Imm(0x02), AA0, BB0, TT0)
Comment("Clamp and store poly key")
polyClampMask := polyClampMask_DATA()
VPAND(polyClampMask, TT0, TT0)
VMOVDQA(TT0, rsStoreAVX2)
Comment("Stream for up to 192 bytes")
VPERM2I128(Imm(0x13), AA0, BB0, AA0)
VPERM2I128(Imm(0x13), CC0, DD0, BB0)
VPERM2I128(Imm(0x02), AA1, BB1, CC0)
VPERM2I128(Imm(0x02), CC1, DD1, DD0)
VPERM2I128(Imm(0x13), AA1, BB1, AA1)
VPERM2I128(Imm(0x13), CC1, DD1, BB1)
}
func sealAVX2ShortSeal() {
Label("sealAVX2ShortSeal")
Comment("Hash aad")
MOVQ(NewParamAddr("ad_len", 80), itr2)
CALL(LabelRef("polyHashADInternal<>(SB)"))
XORQ(itr1, itr1)
}
func sealAVX2SealHash() {
Label("sealAVX2SealHash")
Comment("itr1 holds the number of bytes encrypted but not yet hashed")
CMPQ(itr1, Imm(16))
JB(LabelRef("sealAVX2ShortSealLoop"))
polyAdd(Mem{Base: oup}.Offset(0))
polyMul()
SUBQ(Imm(16), itr1)
ADDQ(Imm(16), oup)
JMP(LabelRef("sealAVX2SealHash"))
}
func sealAVX2ShortSealLoop() {
Label("sealAVX2ShortSealLoop")
CMPQ(inl, Imm(32))
JB(LabelRef("sealAVX2ShortTail32"))
SUBQ(Imm(32), inl)
Comment("Load for encryption")
VPXOR(Mem{Base: inp}, AA0, AA0)
VMOVDQU(AA0, Mem{Base: oup})
LEAQ(Mem{Base: inp}.Offset(1*32), inp)
Comment("Now can hash")
polyAdd(Mem{Base: oup}.Offset(0 * 8))
polyMulAVX2()
polyAdd(Mem{Base: oup}.Offset(2 * 8))
polyMulAVX2()
LEAQ(Mem{Base: oup}.Offset(1*32), oup)
Comment("Shift stream left")
VMOVDQA(BB0, AA0)
VMOVDQA(CC0, BB0)
VMOVDQA(DD0, CC0)
VMOVDQA(AA1, DD0)
VMOVDQA(BB1, AA1)
VMOVDQA(CC1, BB1)
VMOVDQA(DD1, CC1)
VMOVDQA(AA2, DD1)
VMOVDQA(BB2, AA2)
JMP(LabelRef("sealAVX2ShortSealLoop"))
}
func sealAVX2ShortTail32() {
Label("sealAVX2ShortTail32")
CMPQ(inl, Imm(16))
VMOVDQA(A0, A1)
JB(LabelRef("sealAVX2ShortDone"))
SUBQ(Imm(16), inl)
Comment("Load for encryption")
VPXOR(Mem{Base: inp}, A0, T0)
VMOVDQU(T0, Mem{Base: oup})
LEAQ(Mem{Base: inp}.Offset(1*16), inp)
Comment("Hash")
polyAdd(Mem{Base: oup}.Offset(0 * 8))
polyMulAVX2()
LEAQ(Mem{Base: oup}.Offset(1*16), oup)
VPERM2I128(Imm(0x11), AA0, AA0, AA0)
VMOVDQA(A0, A1)
}
func sealAVX2ShortDone() {
Label("sealAVX2ShortDone")
VZEROUPPER()
JMP(LabelRef("sealSSETail"))
}
// ----------------------------------------------------------------------------
// Special optimization for buffers smaller than 321 bytes
// For up to 320 bytes of ciphertext and 64 bytes for the poly key, we process six blocks
func seal320AVX2() {
Label("seal320AVX2")
VMOVDQA(AA0, AA1)
VMOVDQA(BB0, BB1)
VMOVDQA(CC0, CC1)
avx2IncMask := avx2IncMask_DATA()
VPADDD(avx2IncMask, DD0, DD1)
VMOVDQA(AA0, AA2)
VMOVDQA(BB0, BB2)
VMOVDQA(CC0, CC2)
VPADDD(avx2IncMask, DD1, DD2)
VMOVDQA(BB0, TT1)
VMOVDQA(CC0, TT2)
VMOVDQA(DD0, TT3)
MOVQ(U32(10), itr2)
}
func sealAVX2320InnerCipherLoop() {
Label("sealAVX2320InnerCipherLoop")
chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0)
chachaQR_AVX2(AA1, BB1, CC1, DD1, TT0)
chachaQR_AVX2(AA2, BB2, CC2, DD2, TT0)
VPALIGNR(Imm(4), BB0, BB0, BB0)
VPALIGNR(Imm(4), BB1, BB1, BB1)
VPALIGNR(Imm(4), BB2, BB2, BB2)
VPALIGNR(Imm(8), CC0, CC0, CC0)
VPALIGNR(Imm(8), CC1, CC1, CC1)
VPALIGNR(Imm(8), CC2, CC2, CC2)
VPALIGNR(Imm(12), DD0, DD0, DD0)
VPALIGNR(Imm(12), DD1, DD1, DD1)
VPALIGNR(Imm(12), DD2, DD2, DD2)
chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0)
chachaQR_AVX2(AA1, BB1, CC1, DD1, TT0)
chachaQR_AVX2(AA2, BB2, CC2, DD2, TT0)
VPALIGNR(Imm(12), BB0, BB0, BB0)
VPALIGNR(Imm(12), BB1, BB1, BB1)
VPALIGNR(Imm(12), BB2, BB2, BB2)
VPALIGNR(Imm(8), CC0, CC0, CC0)
VPALIGNR(Imm(8), CC1, CC1, CC1)
VPALIGNR(Imm(8), CC2, CC2, CC2)
VPALIGNR(Imm(4), DD0, DD0, DD0)
VPALIGNR(Imm(4), DD1, DD1, DD1)
VPALIGNR(Imm(4), DD2, DD2, DD2)
DECQ(itr2)
JNE(LabelRef("sealAVX2320InnerCipherLoop"))
chacha20Constants := chacha20Constants_DATA()
VMOVDQA(chacha20Constants, TT0)
VPADDD(TT0, AA0, AA0)
VPADDD(TT0, AA1, AA1)
VPADDD(TT0, AA2, AA2)
VPADDD(TT1, BB0, BB0)
VPADDD(TT1, BB1, BB1)
VPADDD(TT1, BB2, BB2)
VPADDD(TT2, CC0, CC0)
VPADDD(TT2, CC1, CC1)
VPADDD(TT2, CC2, CC2)
avx2IncMask := avx2IncMask_DATA()
VMOVDQA(avx2IncMask, TT0)
VPADDD(TT3, DD0, DD0)
VPADDD(TT0, TT3, TT3)
VPADDD(TT3, DD1, DD1)
VPADDD(TT0, TT3, TT3)
VPADDD(TT3, DD2, DD2)
Comment("Clamp and store poly key")
VPERM2I128(Imm(0x02), AA0, BB0, TT0)
polyClampMask := polyClampMask_DATA()
VPAND(polyClampMask, TT0, TT0)
VMOVDQA(TT0, rsStoreAVX2)
Comment("Stream for up to 320 bytes")
VPERM2I128(Imm(0x13), AA0, BB0, AA0)
VPERM2I128(Imm(0x13), CC0, DD0, BB0)
VPERM2I128(Imm(0x02), AA1, BB1, CC0)
VPERM2I128(Imm(0x02), CC1, DD1, DD0)
VPERM2I128(Imm(0x13), AA1, BB1, AA1)
VPERM2I128(Imm(0x13), CC1, DD1, BB1)
VPERM2I128(Imm(0x02), AA2, BB2, CC1)
VPERM2I128(Imm(0x02), CC2, DD2, DD1)
VPERM2I128(Imm(0x13), AA2, BB2, AA2)
VPERM2I128(Imm(0x13), CC2, DD2, BB2)
JMP(LabelRef("sealAVX2ShortSeal"))
}
// Need to decrypt up to 128 bytes - prepare two blocks:
// - If we got here after the main loop - there are 512 encrypted bytes waiting to be hashed.
// - If we got here before the main loop - there are 448 encrpyred bytes waiting to be hashed.
func sealAVX2Tail128() {
Label("sealAVX2Tail128")
chacha20Constants := chacha20Constants_DATA()
VMOVDQA(chacha20Constants, AA0)
VMOVDQA(state1StoreAVX2, BB0)
VMOVDQA(state2StoreAVX2, CC0)
VMOVDQA(ctr3StoreAVX2, DD0)
avx2IncMask := avx2IncMask_DATA()
VPADDD(avx2IncMask, DD0, DD0)
VMOVDQA(DD0, DD1)
}
func sealAVX2Tail128LoopA() {
Label("sealAVX2Tail128LoopA")
polyAdd(Mem{Base: oup}.Offset(0))
polyMul()
LEAQ(Mem{Base: oup}.Offset(16), oup)
}
func sealAVX2Tail128LoopB() {
Label("sealAVX2Tail128LoopB")
chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0)
polyAdd(Mem{Base: oup}.Offset(0))
polyMul()
VPALIGNR(Imm(4), BB0, BB0, BB0)
VPALIGNR(Imm(8), CC0, CC0, CC0)
VPALIGNR(Imm(12), DD0, DD0, DD0)
chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0)
polyAdd(Mem{Base: oup}.Offset(16))
polyMul()
LEAQ(Mem{Base: oup}.Offset(32), oup)
VPALIGNR(Imm(12), BB0, BB0, BB0)
VPALIGNR(Imm(8), CC0, CC0, CC0)
VPALIGNR(Imm(4), DD0, DD0, DD0)
DECQ(itr1)
JG(LabelRef("sealAVX2Tail128LoopA"))
DECQ(itr2)
JGE(LabelRef("sealAVX2Tail128LoopB"))
chacha20Constants := chacha20Constants_DATA()
VPADDD(chacha20Constants, AA0, AA1)
VPADDD(state1StoreAVX2, BB0, BB1)
VPADDD(state2StoreAVX2, CC0, CC1)
VPADDD(DD1, DD0, DD1)
VPERM2I128(Imm(0x02), AA1, BB1, AA0)
VPERM2I128(Imm(0x02), CC1, DD1, BB0)
VPERM2I128(Imm(0x13), AA1, BB1, CC0)
VPERM2I128(Imm(0x13), CC1, DD1, DD0)
JMP(LabelRef("sealAVX2ShortSealLoop"))
}
// ----------------------------------------------------------------------------
// Special optimization for the last 256 bytes of ciphertext
// Need to decrypt up to 256 bytes - prepare two blocks
// - If we got here after the main loop - there are 512 encrypted bytes waiting to be hashed
// - If we got here before the main loop - there are 448 encrpyred bytes waiting to be hashed
func sealAVX2Tail256() {
Label("sealAVX2Tail256")
chacha20Constants := chacha20Constants_DATA()
VMOVDQA(chacha20Constants, AA0)
VMOVDQA(chacha20Constants, AA1)
VMOVDQA(state1StoreAVX2, BB0)
VMOVDQA(state1StoreAVX2, BB1)
VMOVDQA(state2StoreAVX2, CC0)
VMOVDQA(state2StoreAVX2, CC1)
VMOVDQA(ctr3StoreAVX2, DD0)
avx2IncMask := avx2IncMask_DATA()
VPADDD(avx2IncMask, DD0, DD0)
VPADDD(avx2IncMask, DD0, DD1)
VMOVDQA(DD0, TT1)
VMOVDQA(DD1, TT2)
}
func sealAVX2Tail256LoopA() {
Label("sealAVX2Tail256LoopA")
polyAdd(Mem{Base: oup}.Offset(0))
polyMul()
LEAQ(Mem{Base: oup}.Offset(16), oup)
}
// LIne 2493
func sealAVX2Tail256LoopB() {
Label("sealAVX2Tail256LoopB")
chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0)
chachaQR_AVX2(AA1, BB1, CC1, DD1, TT0)
polyAdd(Mem{Base: oup}.Offset(0))
polyMul()
VPALIGNR(Imm(4), BB0, BB0, BB0)
VPALIGNR(Imm(4), BB1, BB1, BB1)
VPALIGNR(Imm(8), CC0, CC0, CC0)
VPALIGNR(Imm(8), CC1, CC1, CC1)
VPALIGNR(Imm(12), DD0, DD0, DD0)
VPALIGNR(Imm(12), DD1, DD1, DD1)
chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0)
chachaQR_AVX2(AA1, BB1, CC1, DD1, TT0)
polyAdd(Mem{Base: oup}.Offset(16))
polyMul()
LEAQ(Mem{Base: oup}.Offset(32), oup)
VPALIGNR(Imm(12), BB0, BB0, BB0)
VPALIGNR(Imm(12), BB1, BB1, BB1)
VPALIGNR(Imm(8), CC0, CC0, CC0)
VPALIGNR(Imm(8), CC1, CC1, CC1)
VPALIGNR(Imm(4), DD0, DD0, DD0)
VPALIGNR(Imm(4), DD1, DD1, DD1)
DECQ(itr1)
JG(LabelRef("sealAVX2Tail256LoopA"))
DECQ(itr2)
JGE(LabelRef("sealAVX2Tail256LoopB"))
chacha20Constants := chacha20Constants_DATA()
VPADDD(chacha20Constants, AA0, AA0)
VPADDD(chacha20Constants, AA1, AA1)
VPADDD(state1StoreAVX2, BB0, BB0)
VPADDD(state1StoreAVX2, BB1, BB1)
VPADDD(state2StoreAVX2, CC0, CC0)
VPADDD(state2StoreAVX2, CC1, CC1)
VPADDD(TT1, DD0, DD0)
VPADDD(TT2, DD1, DD1)
VPERM2I128(Imm(0x02), AA0, BB0, TT0)
VPERM2I128(Imm(0x02), CC0, DD0, TT1)
VPERM2I128(Imm(0x13), AA0, BB0, TT2)
VPERM2I128(Imm(0x13), CC0, DD0, TT3)
VPXOR(Mem{Base: inp}.Offset(0*32), TT0, TT0)
VPXOR(Mem{Base: inp}.Offset(1*32), TT1, TT1)
VPXOR(Mem{Base: inp}.Offset(2*32), TT2, TT2)
VPXOR(Mem{Base: inp}.Offset(3*32), TT3, TT3)
VMOVDQU(TT0, Mem{Base: oup}.Offset(0*32))
VMOVDQU(TT1, Mem{Base: oup}.Offset(1*32))
VMOVDQU(TT2, Mem{Base: oup}.Offset(2*32))
VMOVDQU(TT3, Mem{Base: oup}.Offset(3*32))
MOVQ(U32(128), itr1)
LEAQ(Mem{Base: inp}.Offset(128), inp)
SUBQ(Imm(128), inl)
VPERM2I128(Imm(0x02), AA1, BB1, AA0)
VPERM2I128(Imm(0x02), CC1, DD1, BB0)
VPERM2I128(Imm(0x13), AA1, BB1, CC0)
VPERM2I128(Imm(0x13), CC1, DD1, DD0)
JMP(LabelRef("sealAVX2SealHash"))
}
// ----------------------------------------------------------------------------
// Special optimization for the last 384 bytes of ciphertext
// Need to decrypt up to 384 bytes - prepare two blocks
// - If we got here after the main loop - there are 512 encrypted bytes waiting to be hashed
// - If we got here before the main loop - there are 448 encrpyred bytes waiting to be hashed
func sealAVX2Tail384() {
Label("sealAVX2Tail384")
chacha20Constants := chacha20Constants_DATA()
VMOVDQA(chacha20Constants, AA0)
VMOVDQA(AA0, AA1)
VMOVDQA(AA0, AA2)
VMOVDQA(state1StoreAVX2, BB0)
VMOVDQA(BB0, BB1)
VMOVDQA(BB0, BB2)
VMOVDQA(state2StoreAVX2, CC0)
VMOVDQA(CC0, CC1)
VMOVDQA(CC0, CC2)
VMOVDQA(ctr3StoreAVX2, DD0)
avx2IncMask := avx2IncMask_DATA()
VPADDD(avx2IncMask, DD0, DD0)
VPADDD(avx2IncMask, DD0, DD1)
VPADDD(avx2IncMask, DD1, DD2)
VMOVDQA(DD0, TT1)
VMOVDQA(DD1, TT2)
VMOVDQA(DD2, TT3)
}
func sealAVX2Tail384LoopA() {
Label("sealAVX2Tail384LoopA")
polyAdd(Mem{Base: oup}.Offset(0))
polyMul()
LEAQ(Mem{Base: oup}.Offset(16), oup)
}
func sealAVX2Tail384LoopB() {
Label("sealAVX2Tail384LoopB")
chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0)
chachaQR_AVX2(AA1, BB1, CC1, DD1, TT0)
chachaQR_AVX2(AA2, BB2, CC2, DD2, TT0)
polyAdd(Mem{Base: oup}.Offset(0))
polyMul()
VPALIGNR(Imm(4), BB0, BB0, BB0)
VPALIGNR(Imm(4), BB1, BB1, BB1)
VPALIGNR(Imm(4), BB2, BB2, BB2)
VPALIGNR(Imm(8), CC0, CC0, CC0)
VPALIGNR(Imm(8), CC1, CC1, CC1)
VPALIGNR(Imm(8), CC2, CC2, CC2)
VPALIGNR(Imm(12), DD0, DD0, DD0)
VPALIGNR(Imm(12), DD1, DD1, DD1)
VPALIGNR(Imm(12), DD2, DD2, DD2)
chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0)
chachaQR_AVX2(AA1, BB1, CC1, DD1, TT0)
chachaQR_AVX2(AA2, BB2, CC2, DD2, TT0)
polyAdd(Mem{Base: oup}.Offset(16))
polyMul()
LEAQ(Mem{Base: oup}.Offset(32), oup)
VPALIGNR(Imm(12), BB0, BB0, BB0)
VPALIGNR(Imm(12), BB1, BB1, BB1)
VPALIGNR(Imm(12), BB2, BB2, BB2)
VPALIGNR(Imm(8), CC0, CC0, CC0)
VPALIGNR(Imm(8), CC1, CC1, CC1)
VPALIGNR(Imm(8), CC2, CC2, CC2)
VPALIGNR(Imm(4), DD0, DD0, DD0)
VPALIGNR(Imm(4), DD1, DD1, DD1)
VPALIGNR(Imm(4), DD2, DD2, DD2)
DECQ(itr1)
JG(LabelRef("sealAVX2Tail384LoopA"))
DECQ(itr2)
JGE(LabelRef("sealAVX2Tail384LoopB"))
chacha20Constants := chacha20Constants_DATA()
VPADDD(chacha20Constants, AA0, AA0)
VPADDD(chacha20Constants, AA1, AA1)
VPADDD(chacha20Constants, AA2, AA2)
VPADDD(state1StoreAVX2, BB0, BB0)
VPADDD(state1StoreAVX2, BB1, BB1)
VPADDD(state1StoreAVX2, BB2, BB2)
VPADDD(state2StoreAVX2, CC0, CC0)
VPADDD(state2StoreAVX2, CC1, CC1)
VPADDD(state2StoreAVX2, CC2, CC2)
VPADDD(TT1, DD0, DD0)
VPADDD(TT2, DD1, DD1)
VPADDD(TT3, DD2, DD2)
VPERM2I128(Imm(0x02), AA0, BB0, TT0)
VPERM2I128(Imm(0x02), CC0, DD0, TT1)
VPERM2I128(Imm(0x13), AA0, BB0, TT2)
VPERM2I128(Imm(0x13), CC0, DD0, TT3)
VPXOR(Mem{Base: inp}.Offset(0*32), TT0, TT0)
VPXOR(Mem{Base: inp}.Offset(1*32), TT1, TT1)
VPXOR(Mem{Base: inp}.Offset(2*32), TT2, TT2)
VPXOR(Mem{Base: inp}.Offset(3*32), TT3, TT3)
VMOVDQU(TT0, Mem{Base: oup}.Offset(0*32))
VMOVDQU(TT1, Mem{Base: oup}.Offset(1*32))
VMOVDQU(TT2, Mem{Base: oup}.Offset(2*32))
VMOVDQU(TT3, Mem{Base: oup}.Offset(3*32))
VPERM2I128(Imm(0x02), AA1, BB1, TT0)
VPERM2I128(Imm(0x02), CC1, DD1, TT1)
VPERM2I128(Imm(0x13), AA1, BB1, TT2)
VPERM2I128(Imm(0x13), CC1, DD1, TT3)
VPXOR(Mem{Base: inp}.Offset(4*32), TT0, TT0)
VPXOR(Mem{Base: inp}.Offset(5*32), TT1, TT1)
VPXOR(Mem{Base: inp}.Offset(6*32), TT2, TT2)
VPXOR(Mem{Base: inp}.Offset(7*32), TT3, TT3)
VMOVDQU(TT0, Mem{Base: oup}.Offset(4*32))
VMOVDQU(TT1, Mem{Base: oup}.Offset(5*32))
VMOVDQU(TT2, Mem{Base: oup}.Offset(6*32))
VMOVDQU(TT3, Mem{Base: oup}.Offset(7*32))
MOVQ(U32(256), itr1)
LEAQ(Mem{Base: inp}.Offset(256), inp)
SUBQ(U32(256), inl)
VPERM2I128(Imm(0x02), AA2, BB2, AA0)
VPERM2I128(Imm(0x02), CC2, DD2, BB0)
VPERM2I128(Imm(0x13), AA2, BB2, CC0)
VPERM2I128(Imm(0x13), CC2, DD2, DD0)
JMP(LabelRef("sealAVX2SealHash"))
}
// ----------------------------------------------------------------------------
// Special optimization for the last 512 bytes of ciphertext
// Need to decrypt up to 512 bytes - prepare two blocks
// - If we got here after the main loop - there are 512 encrypted bytes waiting to be hashed
// - If we got here before the main loop - there are 448 encrpyred bytes waiting to be hashed
func sealAVX2Tail512() {
Label("sealAVX2Tail512")
chacha20Constants := chacha20Constants_DATA()
VMOVDQA(chacha20Constants, AA0)
VMOVDQA(AA0, AA1)
VMOVDQA(AA0, AA2)
VMOVDQA(AA0, AA3)
VMOVDQA(state1StoreAVX2, BB0)
VMOVDQA(BB0, BB1)
VMOVDQA(BB0, BB2)
VMOVDQA(BB0, BB3)
VMOVDQA(state2StoreAVX2, CC0)
VMOVDQA(CC0, CC1)
VMOVDQA(CC0, CC2)
VMOVDQA(CC0, CC3)
VMOVDQA(ctr3StoreAVX2, DD0)
avx2IncMask := avx2IncMask_DATA()
VPADDD(avx2IncMask, DD0, DD0)
VPADDD(avx2IncMask, DD0, DD1)
VPADDD(avx2IncMask, DD1, DD2)
VPADDD(avx2IncMask, DD2, DD3)
VMOVDQA(DD0, ctr0StoreAVX2)
VMOVDQA(DD1, ctr1StoreAVX2)
VMOVDQA(DD2, ctr2StoreAVX2)
VMOVDQA(DD3, ctr3StoreAVX2)
}
func sealAVX2Tail512LoopA() {
Label("sealAVX2Tail512LoopA")
polyAdd(Mem{Base: oup}.Offset(0))
polyMul()
LEAQ(Mem{Base: oup}.Offset(16), oup)
}
func sealAVX2Tail512LoopB() {
Label("sealAVX2Tail512LoopB")
VPADDD(BB0, AA0, AA0)
VPADDD(BB1, AA1, AA1)
VPADDD(BB2, AA2, AA2)
VPADDD(BB3, AA3, AA3)
VPXOR(AA0, DD0, DD0)
VPXOR(AA1, DD1, DD1)
VPXOR(AA2, DD2, DD2)
VPXOR(AA3, DD3, DD3)
rol16 := rol16_DATA()
VPSHUFB(rol16, DD0, DD0)
VPSHUFB(rol16, DD1, DD1)
VPSHUFB(rol16, DD2, DD2)
VPSHUFB(rol16, DD3, DD3)
VPADDD(DD0, CC0, CC0)
VPADDD(DD1, CC1, CC1)
VPADDD(DD2, CC2, CC2)
VPADDD(DD3, CC3, CC3)
VPXOR(CC0, BB0, BB0)
VPXOR(CC1, BB1, BB1)
VPXOR(CC2, BB2, BB2)
VPXOR(CC3, BB3, BB3)
VMOVDQA(CC3, tmpStoreAVX2)
VPSLLD(Imm(12), BB0, CC3)
VPSRLD(Imm(20), BB0, BB0)
VPXOR(CC3, BB0, BB0)
VPSLLD(Imm(12), BB1, CC3)
VPSRLD(Imm(20), BB1, BB1)
VPXOR(CC3, BB1, BB1)
VPSLLD(Imm(12), BB2, CC3)
VPSRLD(Imm(20), BB2, BB2)
VPXOR(CC3, BB2, BB2)
VPSLLD(Imm(12), BB3, CC3)
VPSRLD(Imm(20), BB3, BB3)
VPXOR(CC3, BB3, BB3)
VMOVDQA(tmpStoreAVX2, CC3)
polyAdd(Mem{Base: oup}.Offset(0 * 8))
polyMulAVX2()
VPADDD(BB0, AA0, AA0)
VPADDD(BB1, AA1, AA1)
VPADDD(BB2, AA2, AA2)
VPADDD(BB3, AA3, AA3)
VPXOR(AA0, DD0, DD0)
VPXOR(AA1, DD1, DD1)
VPXOR(AA2, DD2, DD2)
VPXOR(AA3, DD3, DD3)
rol8 := rol8_DATA()
VPSHUFB(rol8, DD0, DD0)
VPSHUFB(rol8, DD1, DD1)
VPSHUFB(rol8, DD2, DD2)
VPSHUFB(rol8, DD3, DD3)
VPADDD(DD0, CC0, CC0)
VPADDD(DD1, CC1, CC1)
VPADDD(DD2, CC2, CC2)
VPADDD(DD3, CC3, CC3)
VPXOR(CC0, BB0, BB0)
VPXOR(CC1, BB1, BB1)
VPXOR(CC2, BB2, BB2)
VPXOR(CC3, BB3, BB3)
VMOVDQA(CC3, tmpStoreAVX2)
VPSLLD(Imm(7), BB0, CC3)
VPSRLD(Imm(25), BB0, BB0)
VPXOR(CC3, BB0, BB0)
VPSLLD(Imm(7), BB1, CC3)
VPSRLD(Imm(25), BB1, BB1)
VPXOR(CC3, BB1, BB1)
VPSLLD(Imm(7), BB2, CC3)
VPSRLD(Imm(25), BB2, BB2)
VPXOR(CC3, BB2, BB2)
VPSLLD(Imm(7), BB3, CC3)
VPSRLD(Imm(25), BB3, BB3)
VPXOR(CC3, BB3, BB3)
VMOVDQA(tmpStoreAVX2, CC3)
VPALIGNR(Imm(4), BB0, BB0, BB0)
VPALIGNR(Imm(4), BB1, BB1, BB1)
VPALIGNR(Imm(4), BB2, BB2, BB2)
VPALIGNR(Imm(4), BB3, BB3, BB3)
VPALIGNR(Imm(8), CC0, CC0, CC0)
VPALIGNR(Imm(8), CC1, CC1, CC1)
VPALIGNR(Imm(8), CC2, CC2, CC2)
VPALIGNR(Imm(8), CC3, CC3, CC3)
VPALIGNR(Imm(12), DD0, DD0, DD0)
VPALIGNR(Imm(12), DD1, DD1, DD1)
VPALIGNR(Imm(12), DD2, DD2, DD2)
VPALIGNR(Imm(12), DD3, DD3, DD3)
VPADDD(BB0, AA0, AA0)
VPADDD(BB1, AA1, AA1)
VPADDD(BB2, AA2, AA2)
VPADDD(BB3, AA3, AA3)
VPXOR(AA0, DD0, DD0)
VPXOR(AA1, DD1, DD1)
VPXOR(AA2, DD2, DD2)
VPXOR(AA3, DD3, DD3)
VPSHUFB(rol16, DD0, DD0)
VPSHUFB(rol16, DD1, DD1)
VPSHUFB(rol16, DD2, DD2)
VPSHUFB(rol16, DD3, DD3)
VPADDD(DD0, CC0, CC0)
VPADDD(DD1, CC1, CC1)
VPADDD(DD2, CC2, CC2)
VPADDD(DD3, CC3, CC3)
VPXOR(CC0, BB0, BB0)
VPXOR(CC1, BB1, BB1)
VPXOR(CC2, BB2, BB2)
VPXOR(CC3, BB3, BB3)
polyAdd(Mem{Base: oup}.Offset(2 * 8))
polyMulAVX2()
LEAQ(Mem{Base: oup}.Offset(4*8), oup)
VMOVDQA(CC3, tmpStoreAVX2)
VPSLLD(Imm(12), BB0, CC3)
VPSRLD(Imm(20), BB0, BB0)
VPXOR(CC3, BB0, BB0)
VPSLLD(Imm(12), BB1, CC3)
VPSRLD(Imm(20), BB1, BB1)
VPXOR(CC3, BB1, BB1)
VPSLLD(Imm(12), BB2, CC3)
VPSRLD(Imm(20), BB2, BB2)
VPXOR(CC3, BB2, BB2)
VPSLLD(Imm(12), BB3, CC3)
VPSRLD(Imm(20), BB3, BB3)
VPXOR(CC3, BB3, BB3)
VMOVDQA(tmpStoreAVX2, CC3)
VPADDD(BB0, AA0, AA0)
VPADDD(BB1, AA1, AA1)
VPADDD(BB2, AA2, AA2)
VPADDD(BB3, AA3, AA3)
VPXOR(AA0, DD0, DD0)
VPXOR(AA1, DD1, DD1)
VPXOR(AA2, DD2, DD2)
VPXOR(AA3, DD3, DD3)
VPSHUFB(rol8, DD0, DD0)
VPSHUFB(rol8, DD1, DD1)
VPSHUFB(rol8, DD2, DD2)
VPSHUFB(rol8, DD3, DD3)
VPADDD(DD0, CC0, CC0)
VPADDD(DD1, CC1, CC1)
VPADDD(DD2, CC2, CC2)
VPADDD(DD3, CC3, CC3)
VPXOR(CC0, BB0, BB0)
VPXOR(CC1, BB1, BB1)
VPXOR(CC2, BB2, BB2)
VPXOR(CC3, BB3, BB3)
VMOVDQA(CC3, tmpStoreAVX2)
VPSLLD(Imm(7), BB0, CC3)
VPSRLD(Imm(25), BB0, BB0)
VPXOR(CC3, BB0, BB0)
VPSLLD(Imm(7), BB1, CC3)
VPSRLD(Imm(25), BB1, BB1)
VPXOR(CC3, BB1, BB1)
VPSLLD(Imm(7), BB2, CC3)
VPSRLD(Imm(25), BB2, BB2)
VPXOR(CC3, BB2, BB2)
VPSLLD(Imm(7), BB3, CC3)
VPSRLD(Imm(25), BB3, BB3)
VPXOR(CC3, BB3, BB3)
VMOVDQA(tmpStoreAVX2, CC3)
VPALIGNR(Imm(12), BB0, BB0, BB0)
VPALIGNR(Imm(12), BB1, BB1, BB1)
VPALIGNR(Imm(12), BB2, BB2, BB2)
VPALIGNR(Imm(12), BB3, BB3, BB3)
VPALIGNR(Imm(8), CC0, CC0, CC0)
VPALIGNR(Imm(8), CC1, CC1, CC1)
VPALIGNR(Imm(8), CC2, CC2, CC2)
VPALIGNR(Imm(8), CC3, CC3, CC3)
VPALIGNR(Imm(4), DD0, DD0, DD0)
VPALIGNR(Imm(4), DD1, DD1, DD1)
VPALIGNR(Imm(4), DD2, DD2, DD2)
VPALIGNR(Imm(4), DD3, DD3, DD3)
DECQ(itr1)
JG(LabelRef("sealAVX2Tail512LoopA"))
DECQ(itr2)
JGE(LabelRef("sealAVX2Tail512LoopB"))
chacha20Constants := chacha20Constants_DATA()
VPADDD(chacha20Constants, AA0, AA0)
VPADDD(chacha20Constants, AA1, AA1)
VPADDD(chacha20Constants, AA2, AA2)
VPADDD(chacha20Constants, AA3, AA3)
VPADDD(state1StoreAVX2, BB0, BB0)
VPADDD(state1StoreAVX2, BB1, BB1)
VPADDD(state1StoreAVX2, BB2, BB2)
VPADDD(state1StoreAVX2, BB3, BB3)
VPADDD(state2StoreAVX2, CC0, CC0)
VPADDD(state2StoreAVX2, CC1, CC1)
VPADDD(state2StoreAVX2, CC2, CC2)
VPADDD(state2StoreAVX2, CC3, CC3)
VPADDD(ctr0StoreAVX2, DD0, DD0)
VPADDD(ctr1StoreAVX2, DD1, DD1)
VPADDD(ctr2StoreAVX2, DD2, DD2)
VPADDD(ctr3StoreAVX2, DD3, DD3)
VMOVDQA(CC3, tmpStoreAVX2)
VPERM2I128(Imm(0x02), AA0, BB0, CC3)
VPXOR(Mem{Base: inp}.Offset(0*32), CC3, CC3)
VMOVDQU(CC3, Mem{Base: oup}.Offset(0*32))
VPERM2I128(Imm(0x02), CC0, DD0, CC3)
VPXOR(Mem{Base: inp}.Offset(1*32), CC3, CC3)
VMOVDQU(CC3, Mem{Base: oup}.Offset(1*32))
VPERM2I128(Imm(0x13), AA0, BB0, CC3)
VPXOR(Mem{Base: inp}.Offset(2*32), CC3, CC3)
VMOVDQU(CC3, Mem{Base: oup}.Offset(2*32))
VPERM2I128(Imm(0x13), CC0, DD0, CC3)
VPXOR(Mem{Base: inp}.Offset(3*32), CC3, CC3)
VMOVDQU(CC3, Mem{Base: oup}.Offset(3*32))
VPERM2I128(Imm(0x02), AA1, BB1, AA0)
VPERM2I128(Imm(0x02), CC1, DD1, BB0)
VPERM2I128(Imm(0x13), AA1, BB1, CC0)
VPERM2I128(Imm(0x13), CC1, DD1, DD0)
VPXOR(Mem{Base: inp}.Offset(4*32), AA0, AA0)
VPXOR(Mem{Base: inp}.Offset(5*32), BB0, BB0)
VPXOR(Mem{Base: inp}.Offset(6*32), CC0, CC0)
VPXOR(Mem{Base: inp}.Offset(7*32), DD0, DD0)
VMOVDQU(AA0, Mem{Base: oup}.Offset(4*32))
VMOVDQU(BB0, Mem{Base: oup}.Offset(5*32))
VMOVDQU(CC0, Mem{Base: oup}.Offset(6*32))
VMOVDQU(DD0, Mem{Base: oup}.Offset(7*32))
VPERM2I128(Imm(0x02), AA2, BB2, AA0)
VPERM2I128(Imm(0x02), CC2, DD2, BB0)
VPERM2I128(Imm(0x13), AA2, BB2, CC0)
VPERM2I128(Imm(0x13), CC2, DD2, DD0)
VPXOR(Mem{Base: inp}.Offset(8*32), AA0, AA0)
VPXOR(Mem{Base: inp}.Offset(9*32), BB0, BB0)
VPXOR(Mem{Base: inp}.Offset(10*32), CC0, CC0)
VPXOR(Mem{Base: inp}.Offset(11*32), DD0, DD0)
VMOVDQU(AA0, Mem{Base: oup}.Offset(8*32))
VMOVDQU(BB0, Mem{Base: oup}.Offset(9*32))
VMOVDQU(CC0, Mem{Base: oup}.Offset(10*32))
VMOVDQU(DD0, Mem{Base: oup}.Offset(11*32))
MOVQ(U32(384), itr1)
LEAQ(Mem{Base: inp}.Offset(384), inp)
SUBQ(U32(384), inl)
VPERM2I128(Imm(0x02), AA3, BB3, AA0)
VPERM2I128(Imm(0x02), tmpStoreAVX2, DD3, BB0)
VPERM2I128(Imm(0x13), AA3, BB3, CC0)
VPERM2I128(Imm(0x13), tmpStoreAVX2, DD3, DD0)
JMP(LabelRef("sealAVX2SealHash"))
}
// ##~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~DATA SECTION~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~##
var (
// Pointers for memoizing DATA section symbols
chacha20Constants_DATA_ptr,
rol16_DATA_ptr,
rol8_DATA_ptr,
sseIncMask_DATA_ptr,
avx2IncMask_DATA_ptr,
avx2InitMask_DATA_ptr,
polyClampMask_DATA_ptr,
andMask_DATA_ptr *Mem
)
var nothingUpMySleeve = [8]uint32{
0x61707865,
0x3320646e,
0x79622d32,
0x6b206574,
0x61707865,
0x3320646e,
0x79622d32,
0x6b206574,
}
// ChaCha20 constants
func chacha20Constants_DATA() Mem {
if chacha20Constants_DATA_ptr != nil {
return *chacha20Constants_DATA_ptr
}
chacha20Constants := GLOBL(ThatPeskyUnicodeDot+"chacha20Constants", NOPTR|RODATA)
chacha20Constants_DATA_ptr = &chacha20Constants
for i, v := range nothingUpMySleeve {
DATA(i*4, U32(v))
}
return chacha20Constants
}
var rol16Consts = [4]uint64{
0x0504070601000302,
0x0D0C0F0E09080B0A,
0x0504070601000302,
0x0D0C0F0E09080B0A,
}
// <<< 16 with PSHUFB
func rol16_DATA() Mem {
if rol16_DATA_ptr != nil {
return *rol16_DATA_ptr
}
rol16 := GLOBL(ThatPeskyUnicodeDot+"rol16", NOPTR|RODATA)
rol16_DATA_ptr = &rol16
for i, v := range rol16Consts {
DATA(i*8, U64(v))
}
return rol16
}
var rol8Consts = [4]uint64{
0x0605040702010003,
0x0E0D0C0F0A09080B,
0x0605040702010003,
0x0E0D0C0F0A09080B,
}
// <<< 8 with PSHUFB
func rol8_DATA() Mem {
if rol8_DATA_ptr != nil {
return *rol8_DATA_ptr
}
rol8 := GLOBL(ThatPeskyUnicodeDot+"rol8", NOPTR|RODATA)
rol8_DATA_ptr = &rol8
for i, v := range rol8Consts {
DATA(i*8, U64(v))
}
return rol8
}
var avx2InitMaskConsts = [4]uint64{
0x0,
0x0,
0x1,
0x0,
}
func avx2InitMask_DATA() Mem {
if avx2InitMask_DATA_ptr != nil {
return *avx2InitMask_DATA_ptr
}
avx2InitMask := GLOBL(ThatPeskyUnicodeDot+"avx2InitMask", NOPTR|RODATA)
avx2InitMask_DATA_ptr = &avx2InitMask
for i, v := range avx2InitMaskConsts {
DATA(i*8, U64(v))
}
return avx2InitMask
}
var avx2IncMaskConsts = [4]uint64{
0x2,
0x0,
0x2,
0x0,
}
func avx2IncMask_DATA() Mem {
if avx2IncMask_DATA_ptr != nil {
return *avx2IncMask_DATA_ptr
}
avx2IncMask := GLOBL(ThatPeskyUnicodeDot+"avx2IncMask", NOPTR|RODATA)
avx2IncMask_DATA_ptr = &avx2IncMask
for i, v := range avx2IncMaskConsts {
DATA(i*8, U64(v))
}
return avx2IncMask
}
var polyClampMaskConsts = [4]uint64{
0x0FFFFFFC0FFFFFFF,
0x0FFFFFFC0FFFFFFC,
0xFFFFFFFFFFFFFFFF,
0xFFFFFFFFFFFFFFFF,
}
// Poly1305 key clamp
func polyClampMask_DATA() Mem {
if polyClampMask_DATA_ptr != nil {
return *polyClampMask_DATA_ptr
}
polyClampMask := GLOBL(ThatPeskyUnicodeDot+"polyClampMask", NOPTR|RODATA)
polyClampMask_DATA_ptr = &polyClampMask
for i, v := range polyClampMaskConsts {
DATA(i*8, U64(v))
}
return polyClampMask
}
var andMaskConsts = [30]uint64{
0x00000000000000ff,
0x0000000000000000,
0x000000000000ffff,
0x0000000000000000,
0x0000000000ffffff,
0x0000000000000000,
0x00000000ffffffff,
0x0000000000000000,
0x000000ffffffffff,
0x0000000000000000,
0x0000ffffffffffff,
0x0000000000000000,
0x00ffffffffffffff,
0x0000000000000000,
0xffffffffffffffff,
0x0000000000000000,
0xffffffffffffffff,
0x00000000000000ff,
0xffffffffffffffff,
0x000000000000ffff,
0xffffffffffffffff,
0x0000000000ffffff,
0xffffffffffffffff,
0x00000000ffffffff,
0xffffffffffffffff,
0x000000ffffffffff,
0xffffffffffffffff,
0x0000ffffffffffff,
0xffffffffffffffff,
0x00ffffffffffffff,
}
func andMask_DATA() Mem {
if andMask_DATA_ptr != nil {
return *andMask_DATA_ptr
}
andMask := GLOBL(ThatPeskyUnicodeDot+"andMask", NOPTR|RODATA)
andMask_DATA_ptr = &andMask
for i, v := range andMaskConsts {
DATA(i*8, U64(v))
}
return andMask
}
// removePeskyUnicodeDot strips the dot from the relevant TEXT directives such that they
// can exist as internal assembly functions
//
// Avo v0.6.0 does not support the generation of internal assembly functions. Go's unicode
// dot tells the compiler to link a TEXT symbol to a function in the current Go package
// (or another package if specified). Avo unconditionally prepends the unicode dot to all
// TEXT symbols, making it impossible to emit an internal function without this hack.
//
// There is a pending PR to add internal functions to Avo:
// https://github.com/mmcloughlin/avo/pull/443
//
// If merged it should allow the usage of InternalFunction("NAME") for the specified functions
func removePeskyUnicodeDot(internalFunctions []string, target string) {
bytes, err := os.ReadFile(target)
if err != nil {
panic(err)
}
content := string(bytes)
for _, from := range internalFunctions {
to := strings.ReplaceAll(from, ThatPeskyUnicodeDot, "")
content = strings.ReplaceAll(content, from, to)
}
err = os.WriteFile(target, []byte(content), 0644)
if err != nil {
panic(err)
}
}