// Copyright 2012 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 (amd64 || arm64 || ppc64 || ppc64le) && !purego

package aes

import (
	
	
	
	
	
)

// defined in asm_*.s

//go:noescape
func encryptBlockAsm( int,  *uint32, ,  *byte)

//go:noescape
func decryptBlockAsm( int,  *uint32, ,  *byte)

//go:noescape
func expandKeyAsm( int,  *byte,  *uint32,  *uint32)

type aesCipherAsm struct {
	aesCipher
}

// aesCipherGCM implements crypto/cipher.gcmAble so that crypto/cipher.NewGCM
// will use the optimised implementation in aes_gcm.go when possible.
// Instances of this type only exist when hasGCMAsm returns true. Likewise,
// the gcmAble implementation is in aes_gcm.go.
type aesCipherGCM struct {
	aesCipherAsm
}

var supportsAES = cpu.X86.HasAES || cpu.ARM64.HasAES || goarch.IsPpc64 == 1 || goarch.IsPpc64le == 1
var supportsGFMUL = cpu.X86.HasPCLMULQDQ || cpu.ARM64.HasPMULL

func newCipher( []byte) (cipher.Block, error) {
	if !supportsAES {
		return newCipherGeneric()
	}
	// Note that under certain circumstances, we only return the inner aesCipherAsm.
	// This avoids an unnecessary allocation of the aesCipher struct.
	 := aesCipherGCM{aesCipherAsm{aesCipher{l: uint8(len() + 28)}}}
	var  int
	switch len() {
	case 128 / 8:
		 = 10
	case 192 / 8:
		 = 12
	case 256 / 8:
		 = 14
	default:
		return nil, KeySizeError(len())
	}

	expandKeyAsm(, &[0], &.enc[0], &.dec[0])
	if supportsAES && supportsGFMUL {
		return &, nil
	}
	return &.aesCipherAsm, nil
}

func ( *aesCipherAsm) () int { return BlockSize }

func ( *aesCipherAsm) (,  []byte) {
	boring.Unreachable()
	if len() < BlockSize {
		panic("crypto/aes: input not full block")
	}
	if len() < BlockSize {
		panic("crypto/aes: output not full block")
	}
	if alias.InexactOverlap([:BlockSize], [:BlockSize]) {
		panic("crypto/aes: invalid buffer overlap")
	}
	encryptBlockAsm(int(.l)/4-1, &.enc[0], &[0], &[0])
}

func ( *aesCipherAsm) (,  []byte) {
	boring.Unreachable()
	if len() < BlockSize {
		panic("crypto/aes: input not full block")
	}
	if len() < BlockSize {
		panic("crypto/aes: output not full block")
	}
	if alias.InexactOverlap([:BlockSize], [:BlockSize]) {
		panic("crypto/aes: invalid buffer overlap")
	}
	decryptBlockAsm(int(.l)/4-1, &.dec[0], &[0], &[0])
}

// expandKey is used by BenchmarkExpand to ensure that the asm implementation
// of key expansion is used for the benchmark when it is available.
func expandKey( []byte, ,  []uint32) {
	if supportsAES {
		 := 10 // rounds needed for AES128
		switch len() {
		case 192 / 8:
			 = 12
		case 256 / 8:
			 = 14
		}
		expandKeyAsm(, &[0], &[0], &[0])
	} else {
		expandKeyGo(, , )
	}
}