| // Copyright 2026 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. | |
| //go:build !purego | |
| // AES-CTR keystream generation for loong64 using LSX vector instructions. | |
| // | |
| // This file implements ctrBlocks1Asm/ctrBlocks2Asm/ctrBlocks4Asm/ctrBlocks8Asm, | |
| // which encrypt 1/2/4/8 counter blocks per call respectively and XOR the | |
| // resulting keystream into the source buffer. | |
| // | |
| // SUBBYTES and MIXCOLUMNS are macro-for-macro identical to the versions | |
| // defined in aes_loong64.s (same VSHUFB-based S-box split and same | |
| // XTIME-based column-mixing identity), but are redefined independently | |
| // in this file rather than shared via a common #include. This mirrors | |
| // the amd64/arm64 convention of aes_{amd64,arm64}.s and ctr_{amd64,arm64}.s | |
| // not sharing macros across files: each file is self-contained and can be | |
| // read/reviewed/regenerated without cross-file macro-expansion context. | |
| // The only symbol actually shared across the two files is the sbox0_0 | |
| // S-box table and the shiftRows/byteSwap32/rot1/rot2/rot3 permutation | |
| // tables, which are defined once in aes_loong64.s as package-global | |
| // (non-<>) symbols and referenced here by plain name. | |
| #include "textflag.h" | |
| #define SUBBYTES(src, sbox_ptr, out) \ | |
| VANDB $0xe0, src, V25; /* V25 = src & 0xe0, keep only bit7/bit6/bit5 */ \ | |
| VSRAB $7, V25, V31; /* V31 = byte-wise broadcast of bit7 (0xFF/0x00) */ \ | |
| VSLLB $1, V25, V24; /* shift bit6 into the sign position */ \ | |
| VSRAB $7, V24, V30; /* V30 = byte-wise broadcast of bit6 */ \ | |
| VSLLB $2, V25, V24; /* shift bit5 into the sign position */ \ | |
| VSRAB $7, V24, V29; /* V29 = byte-wise broadcast of bit5 */ \ | |
| VANDB $0x1f, src, V26; /* V26 = src & 0x1f, index for VSHUFB 32-way lookup */ \ | |
| \ | |
| /* ---- 2. Chunk0/1 -> r01 (V16..V19,V28,V27 freed after use) ---- */ \ | |
| VMOVQ (sbox_ptr), V16; \ | |
| VMOVQ 16(sbox_ptr), V17; \ | |
| VMOVQ 32(sbox_ptr), V18; \ | |
| VMOVQ 48(sbox_ptr), V19; \ | |
| VSHUFB V26, V16, V17, V28; /* V28 = chunk0_raw */ \ | |
| VSHUFB V26, V18, V19, V27; /* V27 = chunk1_raw */ \ | |
| VBITSELV V29, V27, V28, V20; /* V20 = r01 = M5 ? chunk1 : chunk0 */ \ | |
| \ | |
| /* ---- 3. Chunk2/3 -> r23 ---- */ \ | |
| VMOVQ 64(sbox_ptr), V16; \ | |
| VMOVQ 80(sbox_ptr), V17; \ | |
| VMOVQ 96(sbox_ptr), V18; \ | |
| VMOVQ 112(sbox_ptr), V19; \ | |
| VSHUFB V26, V16, V17, V28; /* V28 = chunk2_raw */ \ | |
| VSHUFB V26, V18, V19, V27; /* V27 = chunk3_raw */ \ | |
| VBITSELV V29, V27, V28, V21; /* V21 = r23 */ \ | |
| \ | |
| /* ---- 4. Merge first group (chunk0..3) -> r0123 ---- */ \ | |
| VBITSELV V30, V21, V20, V22; /* V22 = r0123 = M6 ? r23 : r01 */ \ | |
| \ | |
| /* ---- 5. Chunk4/5 -> r45 ---- */ \ | |
| VMOVQ 128(sbox_ptr), V16; \ | |
| VMOVQ 144(sbox_ptr), V17; \ | |
| VMOVQ 160(sbox_ptr), V18; \ | |
| VMOVQ 176(sbox_ptr), V19; \ | |
| VSHUFB V26, V16, V17, V28; /* V28 = chunk4_raw */ \ | |
| VSHUFB V26, V18, V19, V27; /* V27 = chunk5_raw */ \ | |
| VBITSELV V29, V27, V28, V20; /* V20 reused = r45 */ \ | |
| \ | |
| /* ---- 6. Chunk6/7 -> r67 ---- */ \ | |
| VMOVQ 192(sbox_ptr), V16; \ | |
| VMOVQ 208(sbox_ptr), V17; \ | |
| VMOVQ 224(sbox_ptr), V18; \ | |
| VMOVQ 240(sbox_ptr), V19; \ | |
| VSHUFB V26, V16, V17, V28; /* V28 = chunk6_raw */ \ | |
| VSHUFB V26, V18, V19, V27; /* V27 = chunk7_raw */ \ | |
| VBITSELV V29, V27, V28, V21; /* V21 reused = r67 */ \ | |
| \ | |
| /* ---- 7. Merge second group (chunk4..7) -> r4567 ---- */ \ | |
| VBITSELV V30, V21, V20, V23; /* V23 = r4567 = M6 ? r67 : r45 */ \ | |
| \ | |
| /* ---- 8. Final top-level merge ---- */ \ | |
| VBITSELV V31, V23, V22, out /* out = M7 ? r4567 : r0123 */ | |
| // ----------------------------------------------------------------------- | |
| // MixColumns helper: multiply each byte of Vn by 2 in GF(2^8). | |
| // xtime(a) = (a << 1) ^ (0x1b if a & 0x80 else 0) | |
| // ----------------------------------------------------------------------- | |
| #define XTIME(src, dst, tmp) \ | |
| VSLLB $1, src, dst; /* dst = src << 1 */ \ | |
| VSRAB $7, src, tmp; /* tmp[i] = 0xff if src[i]>=0x80, else 0x00 */ \ | |
| VANDB $0x1b, tmp, tmp; /* tmp[i] = 0x1b if src[i]>=0x80, else 0x00 */ \ | |
| VXORV tmp, dst, dst /* dst ^= tmp */ | |
| #define MIXCOLUMNS(src, out, r1, r2, r3, t1, t2, t3) \ | |
| VSHUFB r1, src, src, t1; /* t1 = rot1(a) */ \ | |
| VXORV src, t1, t2; /* t2 = a ^ rot1(a) */ \ | |
| VSHUFB r2, src, src, t3; /* t3 = rot2(a) */ \ | |
| VXORV t2, t3, out; /* out = a^rot1(a)^rot2(a) */ \ | |
| VSHUFB r3, src, src, t3; /* t3 = rot3(a) */ \ | |
| VXORV out, t3, out; /* out = t = a0^a1^a2^a3(each byte) */ \ | |
| XTIME(t2, t1, t3); /* t1 = xtime(a^rot1(a)) */ \ | |
| VXORV src, out, out; /* out = a ^ t */ \ | |
| VXORV out, t1, out /* out ^= xtime(...) */ | |
| // func ctrBlocks1Asm(nr int, xk *[60]uint32, dst, src *[BlockSize]byte, ivlo, ivhi uint64) | |
| TEXT ·ctrBlocks1Asm(SB), NOSPLIT, $0-48 | |
| MOVV nr+0(FP), R4 | |
| MOVV xk+8(FP), R5 | |
| MOVV dst+16(FP), R6 | |
| MOVV src+24(FP), R7 | |
| MOVV ivlo+32(FP), R8 | |
| MOVV ivhi+40(FP), R9 | |
| // Construct a 128-bit counter block directly in V0, big endian [ivhi][ivlo] | |
| REVBV R9, R10 // ivhi little -> big | |
| REVBV R8, R11 // ivlo little -> big | |
| VMOVQ R10, V0.V[0] // V0 = counter block | |
| VMOVQ R11, V0.V[1] | |
| MOVV $shiftRows(SB), R12 | |
| VMOVQ (R12), V7 | |
| MOVV $byteSwap32(SB), R12 | |
| VMOVQ (R12), V2 | |
| MOVV $rot1(SB), R12 | |
| VMOVQ (R12), V10 | |
| MOVV $rot2(SB), R12 | |
| VMOVQ (R12), V11 | |
| MOVV $rot3(SB), R12 | |
| VMOVQ (R12), V12 | |
| MOVV $sbox0_0(SB), R14 | |
| // AddRoundKey | |
| VMOVQ (R5), V8 | |
| ADDV $16, R5 | |
| VSHUFB V2, V8, V8, V8 // V8 = byte-swap each 32-bit word of round key | |
| VXORV V8, V0, V0 | |
| // middle round: nr-1 | |
| MOVV R4, R12 | |
| ADDV $-1, R12 | |
| Lenc_loop: | |
| SUBBYTES(V0, R14, V0) | |
| // ShiftRows | |
| VSHUFB V7, V0, V0, V0 | |
| MIXCOLUMNS(V0, V1, V10, V11, V12, V3, V4, V5) | |
| // AddRoundKey | |
| VMOVQ (R5), V8 | |
| ADDV $16, R5 | |
| VSHUFB V2, V8, V8, V8 | |
| VXORV V8, V1, V0 | |
| ADDV $-1, R12 | |
| BNE R12, R0, Lenc_loop | |
| // last round: SubBytes + ShiftRows + AddRoundKey (no MixColumns) | |
| SUBBYTES(V0, R14, V0) | |
| VSHUFB V7, V0, V0, V0 | |
| VMOVQ (R5), V8 | |
| VSHUFB V2, V8, V8, V8 | |
| VXORV V8, V0, V0 | |
| VMOVQ (R7), V1 | |
| VXORV V0, V1, V0 | |
| VMOVQ V0, (R6) | |
| RET | |
| // func ctrBlocks2Asm(nr int, xk *[60]uint32, dst, src *[2*BlockSize]byte, ivlo, ivhi uint64) | |
| TEXT ·ctrBlocks2Asm(SB), NOSPLIT, $0-48 | |
| MOVV nr+0(FP), R4 | |
| MOVV xk+8(FP), R5 | |
| MOVV dst+16(FP), R6 | |
| MOVV src+24(FP), R7 | |
| MOVV ivlo+32(FP), R8 | |
| MOVV ivhi+40(FP), R9 | |
| // Build counter 0 = (ivlo, ivhi) | |
| REVBV R9, R10 | |
| REVBV R8, R11 | |
| VMOVQ R10, V0.V[0] | |
| VMOVQ R11, V0.V[1] | |
| // Build counter 1 = (ivlo+1, ivhi + carry) | |
| MOVV R8, R16 | |
| ADDV $1, R16, R17 // R17 = ivlo+1 | |
| SGTU R16, R17, R18 // R18 = 1 if overflow (unsigned wraparound), else 0 | |
| ADDV R9, R18, R19 // R19 = ivhi + carry | |
| REVBV R19, R10 | |
| REVBV R17, R11 | |
| VMOVQ R10, V1.V[0] | |
| VMOVQ R11, V1.V[1] | |
| // Load persistent constant tables (same as ctrBlocks1Asm) | |
| MOVV $shiftRows(SB), R12 | |
| VMOVQ (R12), V7 | |
| MOVV $byteSwap32(SB), R12 | |
| VMOVQ (R12), V2 | |
| MOVV $rot1(SB), R12 | |
| VMOVQ (R12), V10 | |
| MOVV $rot2(SB), R12 | |
| VMOVQ (R12), V11 | |
| MOVV $rot3(SB), R12 | |
| VMOVQ (R12), V12 | |
| MOVV $sbox0_0(SB), R14 | |
| // Initial AddRoundKey (both blocks share the same first round key) | |
| VMOVQ (R5), V8 | |
| ADDV $16, R5 | |
| VSHUFB V2, V8, V8, V8 | |
| VXORV V8, V0, V0 | |
| VXORV V8, V1, V1 | |
| MOVV R4, R12 | |
| ADDV $-1, R12 // R12 = nr-1 main rounds | |
| Lenc2_loop: | |
| // Round key for this round (shared) | |
| VMOVQ (R5), V8 | |
| ADDV $16, R5 | |
| VSHUFB V2, V8, V8, V8 | |
| // Block 0 | |
| SUBBYTES(V0, R14, V13) | |
| VSHUFB V7, V13, V13, V0 | |
| MIXCOLUMNS(V0, V3, V10, V11, V12, V4, V5, V6) | |
| VXORV V8, V3, V0 | |
| // Block 1 | |
| SUBBYTES(V1, R14, V13) | |
| VSHUFB V7, V13, V13, V1 | |
| MIXCOLUMNS(V1, V3, V10, V11, V12, V4, V5, V6) | |
| VXORV V8, V3, V1 | |
| ADDV $-1, R12 | |
| BNE R12, R0, Lenc2_loop | |
| // Final round: SubBytes + ShiftRows + AddRoundKey (no MixColumns) | |
| VMOVQ (R5), V8 | |
| VSHUFB V2, V8, V8, V8 | |
| SUBBYTES(V0, R14, V13) | |
| VSHUFB V7, V13, V13, V0 | |
| VXORV V8, V0, V0 | |
| SUBBYTES(V1, R14, V13) | |
| VSHUFB V7, V13, V13, V1 | |
| VXORV V8, V1, V1 | |
| // XOR plaintext, store | |
| VMOVQ (R7), V20 | |
| VMOVQ 16(R7), V21 | |
| VXORV V0, V20, V0 | |
| VXORV V1, V21, V1 | |
| VMOVQ V0, (R6) | |
| VMOVQ V1, 16(R6) | |
| RET | |
| // func ctrBlocks4Asm(nr int, xk *[60]uint32, dst, src *[4*BlockSize]byte, ivlo, ivhi uint64) | |
| TEXT ·ctrBlocks4Asm(SB), NOSPLIT, $0-48 | |
| MOVV nr+0(FP), R4 | |
| MOVV xk+8(FP), R5 | |
| MOVV dst+16(FP), R6 | |
| MOVV src+24(FP), R7 | |
| MOVV ivlo+32(FP), R8 | |
| MOVV ivhi+40(FP), R9 | |
| // Construct 4 consecutive counter blocks in sequence (big endian), ivlo+1 needs to process carry between blocks | |
| REVBV R9, R10 | |
| REVBV R8, R11 | |
| VMOVQ R10, V0.V[0] // block 0 | |
| VMOVQ R11, V0.V[1] | |
| ADDV $1, R8, R16 // R16 = ivlo+1 | |
| SGTU R16, R8, R17 // R17 = 1 if not overflow (R16 > R8); if overflow R17=0 | |
| XOR $1, R17 // R17 = 1 overflow need carry | |
| ADDV R17, R9, R18 // R18 = ivhi + carry | |
| REVBV R18, R10 | |
| REVBV R16, R11 | |
| VMOVQ R10, V1.V[0] // block 1 | |
| VMOVQ R11, V1.V[1] | |
| ADDV $1, R16, R23 | |
| SGTU R23, R16, R17 | |
| XOR $1, R17 | |
| ADDV R17, R18, R24 | |
| REVBV R24, R10 | |
| REVBV R23, R11 | |
| VMOVQ R10, V3.V[0] // block 2 | |
| VMOVQ R11, V3.V[1] | |
| ADDV $1, R23, R25 | |
| SGTU R25, R23, R17 | |
| XOR $1, R17 | |
| ADDV R17, R24, R26 | |
| REVBV R26, R10 | |
| REVBV R25, R11 | |
| VMOVQ R10, V4.V[0] // block 3 | |
| VMOVQ R11, V4.V[1] | |
| MOVV $shiftRows(SB), R12 | |
| VMOVQ (R12), V7 | |
| MOVV $byteSwap32(SB), R12 | |
| VMOVQ (R12), V2 | |
| MOVV $rot1(SB), R12 | |
| VMOVQ (R12), V10 | |
| MOVV $rot2(SB), R12 | |
| VMOVQ (R12), V11 | |
| MOVV $rot3(SB), R12 | |
| VMOVQ (R12), V12 | |
| MOVV $sbox0_0(SB), R14 | |
| // Initial AddRoundKey (4 blocks share the same round key) | |
| VMOVQ (R5), V8 | |
| VSHUFB V2, V8, V8, V8 | |
| VXORV V8, V0, V0 | |
| VXORV V8, V1, V1 | |
| VXORV V8, V3, V3 | |
| VXORV V8, V4, V4 | |
| ADDV $16, R5 | |
| MOVV R4, R15 | |
| ADDV $-1, R15 | |
| Lenc4_loop: | |
| SUBBYTES(V0, R14, V13) | |
| VSHUFB V7, V13, V13, V0 | |
| MIXCOLUMNS(V0, V13, V10, V11, V12, V5, V6, V9) | |
| SUBBYTES(V1, R14, V14) | |
| VSHUFB V7, V14, V14, V1 | |
| MIXCOLUMNS(V1, V14, V10, V11, V12, V5, V6, V9) | |
| SUBBYTES(V3, R14, V15) | |
| VSHUFB V7, V15, V15, V3 | |
| MIXCOLUMNS(V3, V15, V10, V11, V12, V5, V6, V9) | |
| SUBBYTES(V4, R14, V16) | |
| VSHUFB V7, V16, V16, V4 | |
| MIXCOLUMNS(V4, V16, V10, V11, V12, V5, V6, V9) | |
| VMOVQ (R5), V8 | |
| VSHUFB V2, V8, V8, V8 | |
| VXORV V8, V13, V0 | |
| VXORV V8, V14, V1 | |
| VXORV V8, V15, V3 | |
| VXORV V8, V16, V4 | |
| ADDV $16, R5 | |
| ADDV $-1, R15 | |
| BNE R15, R0, Lenc4_loop | |
| // last round: SubBytes + ShiftRows + AddRoundKey (no MixColumns) | |
| VMOVQ (R5), V8 | |
| VSHUFB V2, V8, V8, V8 | |
| SUBBYTES(V0, R14, V13) | |
| VSHUFB V7, V13, V13, V0 | |
| VXORV V8, V0, V0 | |
| SUBBYTES(V1, R14, V13) | |
| VSHUFB V7, V13, V13, V1 | |
| VXORV V8, V1, V1 | |
| SUBBYTES(V3, R14, V13) | |
| VSHUFB V7, V13, V13, V3 | |
| VXORV V8, V3, V3 | |
| SUBBYTES(V4, R14, V13) | |
| VSHUFB V7, V13, V13, V4 | |
| VXORV V8, V4, V4 | |
| VMOVQ (R7), V14 | |
| VMOVQ 16(R7), V15 | |
| VMOVQ 32(R7), V16 | |
| VMOVQ 48(R7), V17 | |
| VXORV V0, V14, V14 | |
| VXORV V1, V15, V15 | |
| VXORV V3, V16, V16 | |
| VXORV V4, V17, V17 | |
| VMOVQ V14, (R6) | |
| VMOVQ V15, 16(R6) | |
| VMOVQ V16, 32(R6) | |
| VMOVQ V17, 48(R6) | |
| RET | |
| // func ctrBlocks8Asm(nr int, xk *[60]uint32, dst, src *[8*BlockSize]byte, ivlo, ivhi uint64) | |
| TEXT ·ctrBlocks8Asm(SB), NOSPLIT, $0-48 | |
| MOVV nr+0(FP), R4 | |
| MOVV xk+8(FP), R5 | |
| MOVV dst+16(FP), R6 | |
| MOVV src+24(FP), R7 | |
| MOVV ivlo+32(FP), R8 | |
| MOVV ivhi+40(FP), R9 | |
| REVBV R9, R10 | |
| REVBV R8, R11 | |
| VMOVQ R10, V0.V[0] | |
| VMOVQ R11, V0.V[1] | |
| ADDV $1, R8, R16 | |
| SGTU R8, R16, R17 | |
| ADDV R17, R9, R17 | |
| MOVV R16, R8 | |
| MOVV R17, R9 | |
| REVBV R9, R10 | |
| REVBV R8, R11 | |
| VMOVQ R10, V1.V[0] | |
| VMOVQ R11, V1.V[1] | |
| ADDV $1, R8, R16 | |
| SGTU R8, R16, R17 | |
| ADDV R17, R9, R17 | |
| MOVV R16, R8 | |
| MOVV R17, R9 | |
| REVBV R9, R10 | |
| REVBV R8, R11 | |
| VMOVQ R10, V3.V[0] | |
| VMOVQ R11, V3.V[1] | |
| ADDV $1, R8, R16 | |
| SGTU R8, R16, R17 | |
| ADDV R17, R9, R17 | |
| MOVV R16, R8 | |
| MOVV R17, R9 | |
| REVBV R9, R10 | |
| REVBV R8, R11 | |
| VMOVQ R10, V4.V[0] | |
| VMOVQ R11, V4.V[1] | |
| ADDV $1, R8, R16 | |
| SGTU R8, R16, R17 | |
| ADDV R17, R9, R17 | |
| MOVV R16, R8 | |
| MOVV R17, R9 | |
| REVBV R9, R10 | |
| REVBV R8, R11 | |
| VMOVQ R10, V5.V[0] | |
| VMOVQ R11, V5.V[1] | |
| ADDV $1, R8, R16 | |
| SGTU R8, R16, R17 | |
| ADDV R17, R9, R17 | |
| MOVV R16, R8 | |
| MOVV R17, R9 | |
| REVBV R9, R10 | |
| REVBV R8, R11 | |
| VMOVQ R10, V6.V[0] | |
| VMOVQ R11, V6.V[1] | |
| ADDV $1, R8, R16 | |
| SGTU R8, R16, R17 | |
| ADDV R17, R9, R17 | |
| MOVV R16, R8 | |
| MOVV R17, R9 | |
| REVBV R9, R10 | |
| REVBV R8, R11 | |
| VMOVQ R10, V8.V[0] | |
| VMOVQ R11, V8.V[1] | |
| ADDV $1, R8, R16 | |
| SGTU R8, R16, R17 | |
| ADDV R17, R9, R17 | |
| MOVV R16, R8 | |
| MOVV R17, R9 | |
| REVBV R9, R10 | |
| REVBV R8, R11 | |
| VMOVQ R10, V9.V[0] | |
| VMOVQ R11, V9.V[1] | |
| MOVV $shiftRows(SB), R12 | |
| VMOVQ (R12), V7 | |
| MOVV $byteSwap32(SB), R12 | |
| VMOVQ (R12), V2 | |
| MOVV $rot1(SB), R12 | |
| VMOVQ (R12), V10 | |
| MOVV $rot2(SB), R12 | |
| VMOVQ (R12), V11 | |
| MOVV $rot3(SB), R12 | |
| VMOVQ (R12), V12 | |
| MOVV $sbox0_0(SB), R14 | |
| VMOVQ (R5), V15 | |
| ADDV $16, R5 | |
| VSHUFB V2, V15, V15, V15 | |
| VXORV V15, V0, V0 | |
| VXORV V15, V1, V1 | |
| VXORV V15, V3, V3 | |
| VXORV V15, V4, V4 | |
| VXORV V15, V5, V5 | |
| VXORV V15, V6, V6 | |
| VXORV V15, V8, V8 | |
| VXORV V15, V9, V9 | |
| MOVV R4, R13 | |
| ADDV $-1, R13 | |
| Lenc8_loop: | |
| // SubBytes + ShiftRows + MixColumns + AddRoundKey, Process 8 state blocks in sequence | |
| SUBBYTES(V0, R14, V0) | |
| SUBBYTES(V1, R14, V1) | |
| SUBBYTES(V3, R14, V3) | |
| SUBBYTES(V4, R14, V4) | |
| SUBBYTES(V5, R14, V5) | |
| SUBBYTES(V6, R14, V6) | |
| SUBBYTES(V8, R14, V8) | |
| SUBBYTES(V9, R14, V9) | |
| VSHUFB V7, V0, V0, V0 | |
| VSHUFB V7, V1, V1, V1 | |
| VSHUFB V7, V3, V3, V3 | |
| VSHUFB V7, V4, V4, V4 | |
| VSHUFB V7, V5, V5, V5 | |
| VSHUFB V7, V6, V6, V6 | |
| VSHUFB V7, V8, V8, V8 | |
| VSHUFB V7, V9, V9, V9 | |
| MIXCOLUMNS(V0, V23, V10, V11, V12, V20, V21, V22) | |
| MIXCOLUMNS(V1, V24, V10, V11, V12, V20, V21, V22) | |
| MIXCOLUMNS(V3, V25, V10, V11, V12, V20, V21, V22) | |
| MIXCOLUMNS(V4, V26, V10, V11, V12, V20, V21, V22) | |
| MIXCOLUMNS(V5, V27, V10, V11, V12, V20, V21, V22) | |
| MIXCOLUMNS(V6, V28, V10, V11, V12, V20, V21, V22) | |
| MIXCOLUMNS(V8, V29, V10, V11, V12, V20, V21, V22) | |
| MIXCOLUMNS(V9, V30, V10, V11, V12, V20, V21, V22) | |
| VMOVQ (R5), V15 | |
| ADDV $16, R5 | |
| VSHUFB V2, V15, V15, V15 | |
| VXORV V15, V23, V0 | |
| VXORV V15, V24, V1 | |
| VXORV V15, V25, V3 | |
| VXORV V15, V26, V4 | |
| VXORV V15, V27, V5 | |
| VXORV V15, V28, V6 | |
| VXORV V15, V29, V8 | |
| VXORV V15, V30, V9 | |
| ADDV $-1, R13 | |
| BNE R13, R0, Lenc8_loop | |
| // last round: SubBytes + ShiftRows + AddRoundKey (no MixColumns) | |
| SUBBYTES(V0, R14, V0) | |
| SUBBYTES(V1, R14, V1) | |
| SUBBYTES(V3, R14, V3) | |
| SUBBYTES(V4, R14, V4) | |
| SUBBYTES(V5, R14, V5) | |
| SUBBYTES(V6, R14, V6) | |
| SUBBYTES(V8, R14, V8) | |
| SUBBYTES(V9, R14, V9) | |
| VSHUFB V7, V0, V0, V0 | |
| VSHUFB V7, V1, V1, V1 | |
| VSHUFB V7, V3, V3, V3 | |
| VSHUFB V7, V4, V4, V4 | |
| VSHUFB V7, V5, V5, V5 | |
| VSHUFB V7, V6, V6, V6 | |
| VSHUFB V7, V8, V8, V8 | |
| VSHUFB V7, V9, V9, V9 | |
| VMOVQ (R5), V15 | |
| VSHUFB V2, V15, V15, V15 | |
| VXORV V15, V0, V0 | |
| VXORV V15, V1, V1 | |
| VXORV V15, V3, V3 | |
| VXORV V15, V4, V4 | |
| VXORV V15, V5, V5 | |
| VXORV V15, V6, V6 | |
| VXORV V15, V8, V8 | |
| VXORV V15, V9, V9 | |
| VMOVQ (0*16)(R7), V16; VXORV V0, V16, V16; VMOVQ V16, (0*16)(R6) | |
| VMOVQ (1*16)(R7), V17; VXORV V1, V17, V17; VMOVQ V17, (1*16)(R6) | |
| VMOVQ (2*16)(R7), V18; VXORV V3, V18, V18; VMOVQ V18, (2*16)(R6) | |
| VMOVQ (3*16)(R7), V19; VXORV V4, V19, V19; VMOVQ V19, (3*16)(R6) | |
| VMOVQ (4*16)(R7), V20; VXORV V5, V20, V20; VMOVQ V20, (4*16)(R6) | |
| VMOVQ (5*16)(R7), V21; VXORV V6, V21, V21; VMOVQ V21, (5*16)(R6) | |
| VMOVQ (6*16)(R7), V22; VXORV V8, V22, V22; VMOVQ V22, (6*16)(R6) | |
| VMOVQ (7*16)(R7), V23; VXORV V9, V23, V23; VMOVQ V23, (7*16)(R6) | |
| RET |