--- /dev/null
+// Copyright 2016 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.
+
+#include "textflag.h"
+
+// func hasAsm() bool
+TEXT ·hasAsm(SB),NOSPLIT,$16-1
+ XOR R0, R0 // set function code to 0 (query)
+ LA mask-16(SP), R1 // 16-byte stack variable for mask
+ WORD $0xB92E0024 // cipher message (KM)
+
+ // check if bits 18-20 (big endian) are set
+ MOVD mask-16(SP), R2
+ MOVD $(0x38<<40), R3
+ AND R3, R2
+ CMPBNE R2, R3, notfound
+ MOVB $1, ret+0(FP)
+ RET
+notfound:
+ MOVB $0, ret+0(FP)
+ RET
+
+// func cryptBlocks(function code, key, dst, src *byte, length int)
+TEXT ·cryptBlocks(SB),NOSPLIT,$0-40
+ MOVD key+8(FP), R1
+ MOVD dst+16(FP), R2
+ MOVD src+24(FP), R4
+ MOVD length+32(FP), R5
+ MOVD function+0(FP), R0
+loop:
+ WORD $0xB92E0024 // cipher message (KM)
+ BVS loop // branch back if interrupted
+ XOR R0, R0
+ RET
--- /dev/null
+// Copyright 2016 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.
+
+package aes
+
+import (
+ "crypto/cipher"
+)
+
+type code int
+
+// Function codes for the cipher message family of instructions.
+const (
+ aes128 code = 18
+ aes192 = 19
+ aes256 = 20
+)
+
+type aesCipherAsm struct {
+ function code // code for cipher message instruction
+ key []byte // key (128, 192 or 256 bytes)
+ storage [256]byte // array backing key slice
+}
+
+// hasAsm reports whether the AES-128, AES-192 and AES-256
+// cipher message (KM) function codes are supported.
+// Note: this function call is expensive.
+func hasAsm() bool
+
+// cryptBlocks invokes the cipher message (KM) instruction with
+// the given function code. This is equivalent to AES in ECB
+// mode. The length must be a multiple of BlockSize (16).
+//go:noesape
+func cryptBlocks(c code, key, dst, src *byte, length int)
+
+var useAsm = hasAsm()
+
+func newCipher(key []byte) (cipher.Block, error) {
+ if !useAsm {
+ return newCipherGeneric(key)
+ }
+
+ var function code
+ switch len(key) {
+ case 128 / 8:
+ function = aes128
+ case 192 / 8:
+ function = aes192
+ case 256 / 8:
+ function = aes256
+ default:
+ return nil, KeySizeError(len(key))
+ }
+
+ var c aesCipherAsm
+ c.function = function
+ c.key = c.storage[:len(key)]
+ copy(c.key, key)
+ return &c, nil
+}
+
+func (c *aesCipherAsm) BlockSize() int { return BlockSize }
+
+func (c *aesCipherAsm) Encrypt(dst, src []byte) {
+ if len(src) < BlockSize {
+ panic("crypto/aes: input not full block")
+ }
+ if len(dst) < BlockSize {
+ panic("crypto/aes: output not full block")
+ }
+ cryptBlocks(c.function, &c.key[0], &dst[0], &src[0], BlockSize)
+}
+
+func (c *aesCipherAsm) Decrypt(dst, src []byte) {
+ if len(src) < BlockSize {
+ panic("crypto/aes: input not full block")
+ }
+ if len(dst) < BlockSize {
+ panic("crypto/aes: output not full block")
+ }
+ // The decrypt function code is equal to the function code + 128.
+ cryptBlocks(c.function+128, &c.key[0], &dst[0], &src[0], BlockSize)
+}