// Code generated by command: go run amd64_aesni_ssse3.go. DO NOT EDIT.

// +build amd64,!purego

#include "textflag.h"

DATA rcons<>+0(SB)/8, $0x2f2f2f2f08040201
DATA rcons<>+8(SB)/8, $0x0000000000000000
DATA rcons<>+16(SB)/8, $0x5e5e5e5e08040201
DATA rcons<>+24(SB)/8, $0x0000000000000000
DATA rcons<>+32(SB)/8, $0xbcbcbcbc08040201
DATA rcons<>+40(SB)/8, $0x0000000000000000
DATA rcons<>+48(SB)/8, $0x6363636308040201
DATA rcons<>+56(SB)/8, $0x0000000000000000
DATA rcons<>+64(SB)/8, $0xc6c6c6c608040201
DATA rcons<>+72(SB)/8, $0x0000000000000000
DATA rcons<>+80(SB)/8, $0x9797979708040201
DATA rcons<>+88(SB)/8, $0x0000000000000000
DATA rcons<>+96(SB)/8, $0x3535353508040201
DATA rcons<>+104(SB)/8, $0x0000000000000000
DATA rcons<>+112(SB)/8, $0x6a6a6a6a08040201
DATA rcons<>+120(SB)/8, $0x0000000000000000
DATA rcons<>+128(SB)/8, $0xd4d4d4d408040201
DATA rcons<>+136(SB)/8, $0x0000000000000000
DATA rcons<>+144(SB)/8, $0xb3b3b3b308040201
DATA rcons<>+152(SB)/8, $0x0000000000000000
DATA rcons<>+160(SB)/8, $0x7d7d7d7d08040201
DATA rcons<>+168(SB)/8, $0x0000000000000000
DATA rcons<>+176(SB)/8, $0xfafafafa08040201
DATA rcons<>+184(SB)/8, $0x0000000000000000
DATA rcons<>+192(SB)/8, $0xefefefef08040201
DATA rcons<>+200(SB)/8, $0x0000000000000000
DATA rcons<>+208(SB)/8, $0xc5c5c5c508040201
DATA rcons<>+216(SB)/8, $0x0000000000000000
DATA rcons<>+224(SB)/8, $0x9191919108040201
DATA rcons<>+232(SB)/8, $0x0000000000000000
DATA rcons<>+240(SB)/8, $0x3939393908040201
DATA rcons<>+248(SB)/8, $0x0000000000000000
DATA rcons<>+256(SB)/8, $0x7272727208040201
DATA rcons<>+264(SB)/8, $0x0000000000000000
GLOBL rcons<>(SB), RODATA|NOPTR, $272

DATA x0mask<>+0(SB)/8, $0x0101010101010101
DATA x0mask<>+8(SB)/8, $0x0101010101010101
GLOBL x0mask<>(SB), RODATA|NOPTR, $16

DATA invx0mask<>+0(SB)/8, $0xfefefefefefefefe
DATA invx0mask<>+8(SB)/8, $0xfefefefefefefefe
GLOBL invx0mask<>(SB), RODATA|NOPTR, $16

DATA x7mask<>+0(SB)/8, $0x8080808080808080
DATA x7mask<>+8(SB)/8, $0x8080808080808080
GLOBL x7mask<>(SB), RODATA|NOPTR, $16

DATA invx7mask<>+0(SB)/8, $0x7f7f7f7f7f7f7f7f
DATA invx7mask<>+8(SB)/8, $0x7f7f7f7f7f7f7f7f
GLOBL invx7mask<>(SB), RODATA|NOPTR, $16

DATA hshuf<>+0(SB)/8, $0x000f0a050c0b0601
DATA hshuf<>+8(SB)/8, $0x0807020d04030e09
GLOBL hshuf<>(SB), RODATA|NOPTR, $16

DATA beshuf<>+0(SB)/8, $0x8080808080808080
DATA beshuf<>+8(SB)/8, $0x0001020304050607
GLOBL beshuf<>(SB), RODATA|NOPTR, $16

DATA one<>+0(SB)/8, $0x0000000000000001
DATA one<>+8(SB)/8, $0x0000000000000000
GLOBL one<>(SB), RODATA|NOPTR, $16

// func stkDeriveK(key *byte, derivedKs *[17][16]byte)
// Requires: SSE2, SSSE3
TEXT ·stkDeriveK(SB), NOSPLIT|NOFRAME, $0-16
	// Derive the Sub-Tweak Key 'K' component for each round from the key
	MOVQ key+0(FP), AX
	MOVQ derivedKs+8(FP), CX

	// Load the various constants
	LEAQ rcons<>+0(SB), DX
	MOVO x0mask<>+0(SB), X0
	MOVO invx0mask<>+0(SB), X1
	MOVO x7mask<>+0(SB), X2
	MOVO invx7mask<>+0(SB), X3
	MOVO hshuf<>+0(SB), X4

	// Load tk2/tk3
	MOVOU 16(AX), X4
	MOVOU (AX), X5

	// i == 0
	MOVO  X4, X6
	PXOR  X5, X6
	PXOR  (DX), X6
	MOVOU X6, (CX)

	// i == 1 -> i == 16
	MOVQ $0x0000000000000010, AX
	MOVQ $0x0000000000000010, BX

derive_stk_loop:
	// lfsr2(tk2)
	MOVO  X4, X6
	MOVO  X4, X7
	PSRLQ $0x07, X6
	PSRLQ $0x05, X7
	PSLLQ $0x01, X4
	PAND  X1, X4
	PXOR  X7, X6
	PAND  X0, X6
	POR   X6, X4

	// lfsr3(tk)
	MOVO  X5, X6
	MOVO  X5, X7
	PSLLQ $0x07, X6
	PSLLQ $0x01, X7
	PSRLQ $0x01, X5
	PAND  X3, X5
	PXOR  X7, X6
	PAND  X2, X6
	POR   X6, X5

	// h(tk2), h(tk3)
	PSHUFB hshuf<>+0(SB), X4
	PSHUFB hshuf<>+0(SB), X5

	// stk = tk1 ^ tk2 ^ tk3 ^ rcon[i]
	// 
	// Note: tk1 is h(tk1), where tk1 is initialized to the tweak.
	// This (the permutation and XOR to derive the actual STK) is handled
	// in bcEncrypt.
	MOVO  X4, X6
	PXOR  X5, X6
	PXOR  (DX)(AX*1), X6
	MOVOU X6, (CX)(AX*1)

	// Offset bookkeeping, and the loop
	ADDQ $0x10, AX
	DECQ BX
	JNZ  derive_stk_loop

	// Sanitize registers of key material, return
	PXOR X6, X6
	PXOR X7, X7
	PXOR X4, X4
	PXOR X5, X5
	RET

// func bcEncrypt(ciphertext *byte, derivedKs *[17][16]byte, tweak *[16]byte, plaintext *byte)
// Requires: AES, SSE2, SSSE3
TEXT ·bcEncrypt(SB), NOSPLIT|NOFRAME, $0-32
	// Encrypt 1 block of plaintext with derivedKs/tweak, store output in
	// ciphertext
	MOVQ ciphertext+0(FP), AX
	MOVQ derivedKs+8(FP), CX
	MOVQ tweak+16(FP), DX
	MOVQ plaintext+24(FP), BX
	MOVO hshuf<>+0(SB), X0

	// i == 0
	MOVOU (BX), X1
	MOVOU (CX), X2
	MOVOU (DX), X3
	PXOR  X3, X2
	PXOR  X2, X1

	// i == 1 -> i == 16
	PSHUFB X0, X3
	MOVOU  16(CX), X2
	PXOR   X3, X2
	AESENC X2, X1
	PSHUFB X0, X3
	MOVOU  32(CX), X2
	PXOR   X3, X2
	AESENC X2, X1
	PSHUFB X0, X3
	MOVOU  48(CX), X2
	PXOR   X3, X2
	AESENC X2, X1
	PSHUFB X0, X3
	MOVOU  64(CX), X2
	PXOR   X3, X2
	AESENC X2, X1
	PSHUFB X0, X3
	MOVOU  80(CX), X2
	PXOR   X3, X2
	AESENC X2, X1
	PSHUFB X0, X3
	MOVOU  96(CX), X2
	PXOR   X3, X2
	AESENC X2, X1
	PSHUFB X0, X3
	MOVOU  112(CX), X2
	PXOR   X3, X2
	AESENC X2, X1
	PSHUFB X0, X3
	MOVOU  128(CX), X2
	PXOR   X3, X2
	AESENC X2, X1
	PSHUFB X0, X3
	MOVOU  144(CX), X2
	PXOR   X3, X2
	AESENC X2, X1
	PSHUFB X0, X3
	MOVOU  160(CX), X2
	PXOR   X3, X2
	AESENC X2, X1
	PSHUFB X0, X3
	MOVOU  176(CX), X2
	PXOR   X3, X2
	AESENC X2, X1
	PSHUFB X0, X3
	MOVOU  192(CX), X2
	PXOR   X3, X2
	AESENC X2, X1
	PSHUFB X0, X3
	MOVOU  208(CX), X2
	PXOR   X3, X2
	AESENC X2, X1
	PSHUFB X0, X3
	MOVOU  224(CX), X2
	PXOR   X3, X2
	AESENC X2, X1
	PSHUFB X0, X3
	MOVOU  240(CX), X2
	PXOR   X3, X2
	AESENC X2, X1
	PSHUFB X0, X3
	MOVOU  256(CX), X2
	PXOR   X3, X2
	AESENC X2, X1

	// Write ciphertext, sanitize key material, return
	MOVOU X1, (AX)
	PXOR  X3, X3
	PXOR  X2, X2
	RET

// func bcTag(tag *[16]byte, derivedKs *[17][16]byte, prefix byte, blockNr int, plaintext *byte, n int)
// Requires: AES, SSE2, SSSE3
TEXT ·bcTag(SB), NOSPLIT|NOFRAME, $0-48
	// Accumulate n blocks of plaintext with derivedKs/prefix/blockNr into
	// tag
	MOVQ    tag+0(FP), AX
	MOVQ    derivedKs+8(FP), CX
	MOVBQZX prefix+16(FP), DX
	MOVQ    blockNr+24(FP), BX
	MOVQ    plaintext+32(FP), SI
	MOVQ    n+40(FP), DI
	SHLQ    $0x04, DX
	MOVO    beshuf<>+0(SB), X0
	MOVQ    DX, X1
	MOVO    hshuf<>+0(SB), X2
	MOVOU   (AX), X3

	// 4 blocks at a time
	CMPQ DI, $0x04
	JL   block_x4_loop_skip

block_x4_loop:
	MOVO   one<>+0(SB), X13
	MOVQ   BX, X4
	MOVO   X4, X5
	PADDQ  X13, X5
	MOVO   X5, X6
	PADDQ  X13, X6
	MOVO   X6, X7
	PADDQ  X13, X7
	PSHUFB X0, X4
	PSHUFB X0, X5
	PSHUFB X0, X6
	PSHUFB X0, X7
	POR    X1, X4
	POR    X1, X5
	POR    X1, X6
	POR    X1, X7
	ADDQ   $0x04, BX
	MOVOU  (CX), X12
	MOVOU  (SI), X8
	MOVOU  16(SI), X9
	MOVOU  32(SI), X10
	MOVOU  48(SI), X11
	PXOR   X4, X8
	PXOR   X5, X9
	PXOR   X6, X10
	PXOR   X7, X11
	PXOR   X12, X8
	PXOR   X12, X9
	PXOR   X12, X10
	PXOR   X12, X11
	ADDQ   $0x40, SI
	MOVOU  16(CX), X12
	MOVO   X12, X14
	MOVO   X12, X15
	MOVO   X12, X13
	PSHUFB X2, X4
	PSHUFB X2, X5
	PSHUFB X2, X6
	PSHUFB X2, X7
	PXOR   X4, X12
	PXOR   X5, X14
	PXOR   X6, X15
	PXOR   X7, X13
	AESENC X12, X8
	AESENC X14, X9
	AESENC X15, X10
	AESENC X13, X11
	MOVOU  32(CX), X12
	MOVO   X12, X14
	MOVO   X12, X15
	MOVO   X12, X13
	PSHUFB X2, X4
	PSHUFB X2, X5
	PSHUFB X2, X6
	PSHUFB X2, X7
	PXOR   X4, X12
	PXOR   X5, X14
	PXOR   X6, X15
	PXOR   X7, X13
	AESENC X12, X8
	AESENC X14, X9
	AESENC X15, X10
	AESENC X13, X11
	MOVOU  48(CX), X12
	MOVO   X12, X14
	MOVO   X12, X15
	MOVO   X12, X13
	PSHUFB X2, X4
	PSHUFB X2, X5
	PSHUFB X2, X6
	PSHUFB X2, X7
	PXOR   X4, X12
	PXOR   X5, X14
	PXOR   X6, X15
	PXOR   X7, X13
	AESENC X12, X8
	AESENC X14, X9
	AESENC X15, X10
	AESENC X13, X11
	MOVOU  64(CX), X12
	MOVO   X12, X14
	MOVO   X12, X15
	MOVO   X12, X13
	PSHUFB X2, X4
	PSHUFB X2, X5
	PSHUFB X2, X6
	PSHUFB X2, X7
	PXOR   X4, X12
	PXOR   X5, X14
	PXOR   X6, X15
	PXOR   X7, X13
	AESENC X12, X8
	AESENC X14, X9
	AESENC X15, X10
	AESENC X13, X11
	MOVOU  80(CX), X12
	MOVO   X12, X14
	MOVO   X12, X15
	MOVO   X12, X13
	PSHUFB X2, X4
	PSHUFB X2, X5
	PSHUFB X2, X6
	PSHUFB X2, X7
	PXOR   X4, X12
	PXOR   X5, X14
	PXOR   X6, X15
	PXOR   X7, X13
	AESENC X12, X8
	AESENC X14, X9
	AESENC X15, X10
	AESENC X13, X11
	MOVOU  96(CX), X12
	MOVO   X12, X14
	MOVO   X12, X15
	MOVO   X12, X13
	PSHUFB X2, X4
	PSHUFB X2, X5
	PSHUFB X2, X6
	PSHUFB X2, X7
	PXOR   X4, X12
	PXOR   X5, X14
	PXOR   X6, X15
	PXOR   X7, X13
	AESENC X12, X8
	AESENC X14, X9
	AESENC X15, X10
	AESENC X13, X11
	MOVOU  112(CX), X12
	MOVO   X12, X14
	MOVO   X12, X15
	MOVO   X12, X13
	PSHUFB X2, X4
	PSHUFB X2, X5
	PSHUFB X2, X6
	PSHUFB X2, X7
	PXOR   X4, X12
	PXOR   X5, X14
	PXOR   X6, X15
	PXOR   X7, X13
	AESENC X12, X8
	AESENC X14, X9
	AESENC X15, X10
	AESENC X13, X11
	MOVOU  128(CX), X12
	MOVO   X12, X14
	MOVO   X12, X15
	MOVO   X12, X13
	PSHUFB X2, X4
	PSHUFB X2, X5
	PSHUFB X2, X6
	PSHUFB X2, X7
	PXOR   X4, X12
	PXOR   X5, X14
	PXOR   X6, X15
	PXOR   X7, X13
	AESENC X12, X8
	AESENC X14, X9
	AESENC X15, X10
	AESENC X13, X11
	MOVOU  144(CX), X12
	MOVO   X12, X14
	MOVO   X12, X15
	MOVO   X12, X13
	PSHUFB X2, X4
	PSHUFB X2, X5
	PSHUFB X2, X6
	PSHUFB X2, X7
	PXOR   X4, X12
	PXOR   X5, X14
	PXOR   X6, X15
	PXOR   X7, X13
	AESENC X12, X8
	AESENC X14, X9
	AESENC X15, X10
	AESENC X13, X11
	MOVOU  160(CX), X12
	MOVO   X12, X14
	MOVO   X12, X15
	MOVO   X12, X13
	PSHUFB X2, X4
	PSHUFB X2, X5
	PSHUFB X2, X6
	PSHUFB X2, X7
	PXOR   X4, X12
	PXOR   X5, X14
	PXOR   X6, X15
	PXOR   X7, X13
	AESENC X12, X8
	AESENC X14, X9
	AESENC X15, X10
	AESENC X13, X11
	MOVOU  176(CX), X12
	MOVO   X12, X14
	MOVO   X12, X15
	MOVO   X12, X13
	PSHUFB X2, X4
	PSHUFB X2, X5
	PSHUFB X2, X6
	PSHUFB X2, X7
	PXOR   X4, X12
	PXOR   X5, X14
	PXOR   X6, X15
	PXOR   X7, X13
	AESENC X12, X8
	AESENC X14, X9
	AESENC X15, X10
	AESENC X13, X11
	MOVOU  192(CX), X12
	MOVO   X12, X14
	MOVO   X12, X15
	MOVO   X12, X13
	PSHUFB X2, X4
	PSHUFB X2, X5
	PSHUFB X2, X6
	PSHUFB X2, X7
	PXOR   X4, X12
	PXOR   X5, X14
	PXOR   X6, X15
	PXOR   X7, X13
	AESENC X12, X8
	AESENC X14, X9
	AESENC X15, X10
	AESENC X13, X11
	MOVOU  208(CX), X12
	MOVO   X12, X14
	MOVO   X12, X15
	MOVO   X12, X13
	PSHUFB X2, X4
	PSHUFB X2, X5
	PSHUFB X2, X6
	PSHUFB X2, X7
	PXOR   X4, X12
	PXOR   X5, X14
	PXOR   X6, X15
	PXOR   X7, X13
	AESENC X12, X8
	AESENC X14, X9
	AESENC X15, X10
	AESENC X13, X11
	MOVOU  224(CX), X12
	MOVO   X12, X14
	MOVO   X12, X15
	MOVO   X12, X13
	PSHUFB X2, X4
	PSHUFB X2, X5
	PSHUFB X2, X6
	PSHUFB X2, X7
	PXOR   X4, X12
	PXOR   X5, X14
	PXOR   X6, X15
	PXOR   X7, X13
	AESENC X12, X8
	AESENC X14, X9
	AESENC X15, X10
	AESENC X13, X11
	MOVOU  240(CX), X12
	MOVO   X12, X14
	MOVO   X12, X15
	MOVO   X12, X13
	PSHUFB X2, X4
	PSHUFB X2, X5
	PSHUFB X2, X6
	PSHUFB X2, X7
	PXOR   X4, X12
	PXOR   X5, X14
	PXOR   X6, X15
	PXOR   X7, X13
	AESENC X12, X8
	AESENC X14, X9
	AESENC X15, X10
	AESENC X13, X11
	MOVOU  256(CX), X12
	MOVO   X12, X14
	MOVO   X12, X15
	MOVO   X12, X13
	PSHUFB X2, X4
	PSHUFB X2, X5
	PSHUFB X2, X6
	PSHUFB X2, X7
	PXOR   X4, X12
	PXOR   X5, X14
	PXOR   X6, X15
	PXOR   X7, X13
	AESENC X12, X8
	AESENC X14, X9
	AESENC X15, X10
	AESENC X13, X11
	PXOR   X8, X3
	PXOR   X9, X3
	PXOR   X10, X3
	PXOR   X11, X3
	SUBQ   $0x04, DI
	CMPQ   DI, $0x04
	JG     block_x4_loop
	MOVOU  X3, (AX)

	// Sanitize registers of key material (block 0 handled prior to return)
	PXOR X5, X5
	PXOR X6, X6
	PXOR X7, X7
	PXOR X14, X14
	PXOR X15, X15
	PXOR X13, X13

block_x4_loop_skip:
	// 1 block at a time
	TESTQ DI, DI
	JZ    out

block_x1_loop:
	MOVQ   BX, X4
	PSHUFB X0, X4
	POR    X1, X4
	INCQ   BX
	MOVOU  (CX), X12
	MOVOU  (SI), X8
	PXOR   X4, X12
	PXOR   X12, X8
	ADDQ   $0x10, SI
	MOVOU  16(CX), X12
	PSHUFB X2, X4
	PXOR   X4, X12
	AESENC X12, X8
	MOVOU  32(CX), X12
	PSHUFB X2, X4
	PXOR   X4, X12
	AESENC X12, X8
	MOVOU  48(CX), X12
	PSHUFB X2, X4
	PXOR   X4, X12
	AESENC X12, X8
	MOVOU  64(CX), X12
	PSHUFB X2, X4
	PXOR   X4, X12
	AESENC X12, X8
	MOVOU  80(CX), X12
	PSHUFB X2, X4
	PXOR   X4, X12
	AESENC X12, X8
	MOVOU  96(CX), X12
	PSHUFB X2, X4
	PXOR   X4, X12
	AESENC X12, X8
	MOVOU  112(CX), X12
	PSHUFB X2, X4
	PXOR   X4, X12
	AESENC X12, X8
	MOVOU  128(CX), X12
	PSHUFB X2, X4
	PXOR   X4, X12
	AESENC X12, X8
	MOVOU  144(CX), X12
	PSHUFB X2, X4
	PXOR   X4, X12
	AESENC X12, X8
	MOVOU  160(CX), X12
	PSHUFB X2, X4
	PXOR   X4, X12
	AESENC X12, X8
	MOVOU  176(CX), X12
	PSHUFB X2, X4
	PXOR   X4, X12
	AESENC X12, X8
	MOVOU  192(CX), X12
	PSHUFB X2, X4
	PXOR   X4, X12
	AESENC X12, X8
	MOVOU  208(CX), X12
	PSHUFB X2, X4
	PXOR   X4, X12
	AESENC X12, X8
	MOVOU  224(CX), X12
	PSHUFB X2, X4
	PXOR   X4, X12
	AESENC X12, X8
	MOVOU  240(CX), X12
	PSHUFB X2, X4
	PXOR   X4, X12
	AESENC X12, X8
	MOVOU  256(CX), X12
	PSHUFB X2, X4
	PXOR   X4, X12
	AESENC X12, X8
	PXOR   X8, X3
	DECQ   DI
	JNZ    block_x1_loop
	MOVOU  X3, (AX)

out:
	// Sanitize remaining registers of key material and return
	PXOR X4, X4
	PXOR X12, X12
	RET

// func bcXOR(ciphertext *byte, derivedKs *[17][16]byte, tag *[16]byte, blockNr int, nonce *[16]byte, plaintext *byte, n int)
// Requires: AES, SSE2, SSSE3
TEXT ·bcXOR(SB), NOSPLIT|NOFRAME, $0-56
	// XOR n blocks of keystream generated with key/tag/blockNr/nonce with
	// plaintext and save to ciphertext.
	MOVQ  ciphertext+0(FP), AX
	MOVQ  derivedKs+8(FP), CX
	MOVQ  tag+16(FP), DX
	MOVQ  blockNr+24(FP), BX
	MOVQ  nonce+32(FP), SI
	MOVQ  plaintext+40(FP), DI
	MOVQ  n+48(FP), R8
	MOVO  hshuf<>+0(SB), X0
	MOVOU (DX), X1
	MOVOU (SI), X2

	// 4 blocks at a time
	CMPQ R8, $0x04
	JL   block_x4_loop_skip

block_x4_loop:
	MOVO   beshuf<>+0(SB), X12
	MOVO   one<>+0(SB), X13
	MOVQ   BX, X3
	MOVO   X3, X4
	PADDQ  X13, X4
	MOVO   X4, X5
	PADDQ  X13, X5
	MOVO   X5, X6
	PADDQ  X13, X6
	PSHUFB X12, X3
	PSHUFB X12, X4
	PSHUFB X12, X5
	PSHUFB X12, X6
	PXOR   X1, X3
	PXOR   X1, X4
	PXOR   X1, X5
	PXOR   X1, X6
	ADDQ   $0x04, BX
	MOVOU  (CX), X11
	MOVO   X2, X7
	MOVO   X2, X8
	MOVO   X2, X9
	MOVO   X2, X10
	PXOR   X3, X7
	PXOR   X4, X8
	PXOR   X5, X9
	PXOR   X6, X10
	PXOR   X11, X7
	PXOR   X11, X8
	PXOR   X11, X9
	PXOR   X11, X10
	MOVOU  16(CX), X11
	MOVO   X11, X14
	MOVO   X11, X12
	MOVO   X11, X13
	PSHUFB hshuf<>+0(SB), X3
	PSHUFB hshuf<>+0(SB), X4
	PSHUFB hshuf<>+0(SB), X5
	PSHUFB hshuf<>+0(SB), X6
	PXOR   X3, X11
	PXOR   X4, X14
	PXOR   X5, X12
	PXOR   X6, X13
	AESENC X11, X7
	AESENC X14, X8
	AESENC X12, X9
	AESENC X13, X10
	MOVOU  32(CX), X11
	MOVO   X11, X14
	MOVO   X11, X12
	MOVO   X11, X13
	PSHUFB hshuf<>+0(SB), X3
	PSHUFB hshuf<>+0(SB), X4
	PSHUFB hshuf<>+0(SB), X5
	PSHUFB hshuf<>+0(SB), X6
	PXOR   X3, X11
	PXOR   X4, X14
	PXOR   X5, X12
	PXOR   X6, X13
	AESENC X11, X7
	AESENC X14, X8
	AESENC X12, X9
	AESENC X13, X10
	MOVOU  48(CX), X11
	MOVO   X11, X14
	MOVO   X11, X12
	MOVO   X11, X13
	PSHUFB hshuf<>+0(SB), X3
	PSHUFB hshuf<>+0(SB), X4
	PSHUFB hshuf<>+0(SB), X5
	PSHUFB hshuf<>+0(SB), X6
	PXOR   X3, X11
	PXOR   X4, X14
	PXOR   X5, X12
	PXOR   X6, X13
	AESENC X11, X7
	AESENC X14, X8
	AESENC X12, X9
	AESENC X13, X10
	MOVOU  64(CX), X11
	MOVO   X11, X14
	MOVO   X11, X12
	MOVO   X11, X13
	PSHUFB hshuf<>+0(SB), X3
	PSHUFB hshuf<>+0(SB), X4
	PSHUFB hshuf<>+0(SB), X5
	PSHUFB hshuf<>+0(SB), X6
	PXOR   X3, X11
	PXOR   X4, X14
	PXOR   X5, X12
	PXOR   X6, X13
	AESENC X11, X7
	AESENC X14, X8
	AESENC X12, X9
	AESENC X13, X10
	MOVOU  80(CX), X11
	MOVO   X11, X14
	MOVO   X11, X12
	MOVO   X11, X13
	PSHUFB hshuf<>+0(SB), X3
	PSHUFB hshuf<>+0(SB), X4
	PSHUFB hshuf<>+0(SB), X5
	PSHUFB hshuf<>+0(SB), X6
	PXOR   X3, X11
	PXOR   X4, X14
	PXOR   X5, X12
	PXOR   X6, X13
	AESENC X11, X7
	AESENC X14, X8
	AESENC X12, X9
	AESENC X13, X10
	MOVOU  96(CX), X11
	MOVO   X11, X14
	MOVO   X11, X12
	MOVO   X11, X13
	PSHUFB hshuf<>+0(SB), X3
	PSHUFB hshuf<>+0(SB), X4
	PSHUFB hshuf<>+0(SB), X5
	PSHUFB hshuf<>+0(SB), X6
	PXOR   X3, X11
	PXOR   X4, X14
	PXOR   X5, X12
	PXOR   X6, X13
	AESENC X11, X7
	AESENC X14, X8
	AESENC X12, X9
	AESENC X13, X10
	MOVOU  112(CX), X11
	MOVO   X11, X14
	MOVO   X11, X12
	MOVO   X11, X13
	PSHUFB hshuf<>+0(SB), X3
	PSHUFB hshuf<>+0(SB), X4
	PSHUFB hshuf<>+0(SB), X5
	PSHUFB hshuf<>+0(SB), X6
	PXOR   X3, X11
	PXOR   X4, X14
	PXOR   X5, X12
	PXOR   X6, X13
	AESENC X11, X7
	AESENC X14, X8
	AESENC X12, X9
	AESENC X13, X10
	MOVOU  128(CX), X11
	MOVO   X11, X14
	MOVO   X11, X12
	MOVO   X11, X13
	PSHUFB hshuf<>+0(SB), X3
	PSHUFB hshuf<>+0(SB), X4
	PSHUFB hshuf<>+0(SB), X5
	PSHUFB hshuf<>+0(SB), X6
	PXOR   X3, X11
	PXOR   X4, X14
	PXOR   X5, X12
	PXOR   X6, X13
	AESENC X11, X7
	AESENC X14, X8
	AESENC X12, X9
	AESENC X13, X10
	MOVOU  144(CX), X11
	MOVO   X11, X14
	MOVO   X11, X12
	MOVO   X11, X13
	PSHUFB hshuf<>+0(SB), X3
	PSHUFB hshuf<>+0(SB), X4
	PSHUFB hshuf<>+0(SB), X5
	PSHUFB hshuf<>+0(SB), X6
	PXOR   X3, X11
	PXOR   X4, X14
	PXOR   X5, X12
	PXOR   X6, X13
	AESENC X11, X7
	AESENC X14, X8
	AESENC X12, X9
	AESENC X13, X10
	MOVOU  160(CX), X11
	MOVO   X11, X14
	MOVO   X11, X12
	MOVO   X11, X13
	PSHUFB hshuf<>+0(SB), X3
	PSHUFB hshuf<>+0(SB), X4
	PSHUFB hshuf<>+0(SB), X5
	PSHUFB hshuf<>+0(SB), X6
	PXOR   X3, X11
	PXOR   X4, X14
	PXOR   X5, X12
	PXOR   X6, X13
	AESENC X11, X7
	AESENC X14, X8
	AESENC X12, X9
	AESENC X13, X10
	MOVOU  176(CX), X11
	MOVO   X11, X14
	MOVO   X11, X12
	MOVO   X11, X13
	PSHUFB hshuf<>+0(SB), X3
	PSHUFB hshuf<>+0(SB), X4
	PSHUFB hshuf<>+0(SB), X5
	PSHUFB hshuf<>+0(SB), X6
	PXOR   X3, X11
	PXOR   X4, X14
	PXOR   X5, X12
	PXOR   X6, X13
	AESENC X11, X7
	AESENC X14, X8
	AESENC X12, X9
	AESENC X13, X10
	MOVOU  192(CX), X11
	MOVO   X11, X14
	MOVO   X11, X12
	MOVO   X11, X13
	PSHUFB hshuf<>+0(SB), X3
	PSHUFB hshuf<>+0(SB), X4
	PSHUFB hshuf<>+0(SB), X5
	PSHUFB hshuf<>+0(SB), X6
	PXOR   X3, X11
	PXOR   X4, X14
	PXOR   X5, X12
	PXOR   X6, X13
	AESENC X11, X7
	AESENC X14, X8
	AESENC X12, X9
	AESENC X13, X10
	MOVOU  208(CX), X11
	MOVO   X11, X14
	MOVO   X11, X12
	MOVO   X11, X13
	PSHUFB hshuf<>+0(SB), X3
	PSHUFB hshuf<>+0(SB), X4
	PSHUFB hshuf<>+0(SB), X5
	PSHUFB hshuf<>+0(SB), X6
	PXOR   X3, X11
	PXOR   X4, X14
	PXOR   X5, X12
	PXOR   X6, X13
	AESENC X11, X7
	AESENC X14, X8
	AESENC X12, X9
	AESENC X13, X10
	MOVOU  224(CX), X11
	MOVO   X11, X14
	MOVO   X11, X12
	MOVO   X11, X13
	PSHUFB hshuf<>+0(SB), X3
	PSHUFB hshuf<>+0(SB), X4
	PSHUFB hshuf<>+0(SB), X5
	PSHUFB hshuf<>+0(SB), X6
	PXOR   X3, X11
	PXOR   X4, X14
	PXOR   X5, X12
	PXOR   X6, X13
	AESENC X11, X7
	AESENC X14, X8
	AESENC X12, X9
	AESENC X13, X10
	MOVOU  240(CX), X11
	MOVO   X11, X14
	MOVO   X11, X12
	MOVO   X11, X13
	PSHUFB hshuf<>+0(SB), X3
	PSHUFB hshuf<>+0(SB), X4
	PSHUFB hshuf<>+0(SB), X5
	PSHUFB hshuf<>+0(SB), X6
	PXOR   X3, X11
	PXOR   X4, X14
	PXOR   X5, X12
	PXOR   X6, X13
	AESENC X11, X7
	AESENC X14, X8
	AESENC X12, X9
	AESENC X13, X10
	MOVOU  256(CX), X11
	MOVO   X11, X14
	MOVO   X11, X12
	MOVO   X11, X13
	PSHUFB hshuf<>+0(SB), X3
	PSHUFB hshuf<>+0(SB), X4
	PSHUFB hshuf<>+0(SB), X5
	PSHUFB hshuf<>+0(SB), X6
	PXOR   X3, X11
	PXOR   X4, X14
	PXOR   X5, X12
	PXOR   X6, X13
	AESENC X11, X7
	AESENC X14, X8
	AESENC X12, X9
	AESENC X13, X10
	MOVOU  (DI), X11
	MOVOU  16(DI), X14
	MOVOU  32(DI), X12
	MOVOU  48(DI), X13
	PXOR   X7, X11
	PXOR   X8, X14
	PXOR   X9, X12
	PXOR   X10, X13
	MOVOU  X11, (AX)
	MOVOU  X14, 16(AX)
	MOVOU  X12, 32(AX)
	MOVOU  X13, 48(AX)
	ADDQ   $0x40, DI
	ADDQ   $0x40, AX
	SUBQ   $0x04, R8
	CMPQ   R8, $0x04
	JG     block_x4_loop

	// Sanitize registers of key material (block 0 handled prior to return)
	PXOR X4, X4
	PXOR X5, X5
	PXOR X6, X6
	PXOR X8, X8
	PXOR X9, X9
	PXOR X10, X10

block_x4_loop_skip:
	// 1 block at a time
	TESTQ R8, R8
	JZ    out
	MOVO  beshuf<>+0(SB), X12

block_x1_loop:
	MOVQ   BX, X3
	PSHUFB X12, X3
	PXOR   X1, X3
	INCQ   BX
	MOVOU  (CX), X11
	MOVO   X2, X7
	PXOR   X3, X11
	PXOR   X11, X7
	PSHUFB X0, X3
	MOVOU  16(CX), X11
	PXOR   X3, X11
	AESENC X11, X7
	PSHUFB X0, X3
	MOVOU  32(CX), X11
	PXOR   X3, X11
	AESENC X11, X7
	PSHUFB X0, X3
	MOVOU  48(CX), X11
	PXOR   X3, X11
	AESENC X11, X7
	PSHUFB X0, X3
	MOVOU  64(CX), X11
	PXOR   X3, X11
	AESENC X11, X7
	PSHUFB X0, X3
	MOVOU  80(CX), X11
	PXOR   X3, X11
	AESENC X11, X7
	PSHUFB X0, X3
	MOVOU  96(CX), X11
	PXOR   X3, X11
	AESENC X11, X7
	PSHUFB X0, X3
	MOVOU  112(CX), X11
	PXOR   X3, X11
	AESENC X11, X7
	PSHUFB X0, X3
	MOVOU  128(CX), X11
	PXOR   X3, X11
	AESENC X11, X7
	PSHUFB X0, X3
	MOVOU  144(CX), X11
	PXOR   X3, X11
	AESENC X11, X7
	PSHUFB X0, X3
	MOVOU  160(CX), X11
	PXOR   X3, X11
	AESENC X11, X7
	PSHUFB X0, X3
	MOVOU  176(CX), X11
	PXOR   X3, X11
	AESENC X11, X7
	PSHUFB X0, X3
	MOVOU  192(CX), X11
	PXOR   X3, X11
	AESENC X11, X7
	PSHUFB X0, X3
	MOVOU  208(CX), X11
	PXOR   X3, X11
	AESENC X11, X7
	PSHUFB X0, X3
	MOVOU  224(CX), X11
	PXOR   X3, X11
	AESENC X11, X7
	PSHUFB X0, X3
	MOVOU  240(CX), X11
	PXOR   X3, X11
	AESENC X11, X7
	PSHUFB X0, X3
	MOVOU  256(CX), X11
	PXOR   X3, X11
	AESENC X11, X7
	MOVOU  (DI), X11
	PXOR   X7, X11
	MOVOU  X11, (AX)
	ADDQ   $0x10, DI
	ADDQ   $0x10, AX
	DECQ   R8
	JNZ    block_x1_loop

out:
	// Sanitize remaining registers of key material and return
	PXOR X3, X3
	PXOR X7, X7
	RET
