// Copyright 2009 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 Go implementation is derived in part from the reference
// ANSI C implementation, which carries the following notice:
//
//	rijndael-alg-fst.c
//
//	@version 3.0 (December 2000)
//
//	Optimised ANSI C code for the Rijndael cipher (now AES)
//
//	@author Vincent Rijmen <vincent.rijmen@esat.kuleuven.ac.be>
//	@author Antoon Bosselaers <antoon.bosselaers@esat.kuleuven.ac.be>
//	@author Paulo Barreto <paulo.barreto@terra.com.br>
//
//	This code is hereby placed in the public domain.
//
//	THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS
//	OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
//	WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
//	ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
//	LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
//	CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
//	SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
//	BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
//	WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
//	OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
//	EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// See FIPS 197 for specification, and see Daemen and Rijmen's Rijndael submission
// for implementation details.
//	https://csrc.nist.gov/csrc/media/publications/fips/197/final/documents/fips-197.pdf
//	https://csrc.nist.gov/archive/aes/rijndael/Rijndael-ammended.pdf

package aes

import (
	
)

// Encrypt one block from src into dst, using the expanded key xk.
func encryptBlockGo( []uint32, ,  []byte) {
	_ = [15] // early bounds check
	 := binary.BigEndian.Uint32([0:4])
	 := binary.BigEndian.Uint32([4:8])
	 := binary.BigEndian.Uint32([8:12])
	 := binary.BigEndian.Uint32([12:16])

	// First round just XORs input with key.
	 ^= [0]
	 ^= [1]
	 ^= [2]
	 ^= [3]

	// Middle rounds shuffle using tables.
	// Number of rounds is set by length of expanded key.
	 := len()/4 - 2 // - 2: one above, one more below
	 := 4
	var , , ,  uint32
	for  := 0;  < ; ++ {
		 = [+0] ^ te0[uint8(>>24)] ^ te1[uint8(>>16)] ^ te2[uint8(>>8)] ^ te3[uint8()]
		 = [+1] ^ te0[uint8(>>24)] ^ te1[uint8(>>16)] ^ te2[uint8(>>8)] ^ te3[uint8()]
		 = [+2] ^ te0[uint8(>>24)] ^ te1[uint8(>>16)] ^ te2[uint8(>>8)] ^ te3[uint8()]
		 = [+3] ^ te0[uint8(>>24)] ^ te1[uint8(>>16)] ^ te2[uint8(>>8)] ^ te3[uint8()]
		 += 4
		, , ,  = , , , 
	}

	// Last round uses s-box directly and XORs to produce output.
	 = uint32(sbox0[>>24])<<24 | uint32(sbox0[>>16&0xff])<<16 | uint32(sbox0[>>8&0xff])<<8 | uint32(sbox0[&0xff])
	 = uint32(sbox0[>>24])<<24 | uint32(sbox0[>>16&0xff])<<16 | uint32(sbox0[>>8&0xff])<<8 | uint32(sbox0[&0xff])
	 = uint32(sbox0[>>24])<<24 | uint32(sbox0[>>16&0xff])<<16 | uint32(sbox0[>>8&0xff])<<8 | uint32(sbox0[&0xff])
	 = uint32(sbox0[>>24])<<24 | uint32(sbox0[>>16&0xff])<<16 | uint32(sbox0[>>8&0xff])<<8 | uint32(sbox0[&0xff])

	 ^= [+0]
	 ^= [+1]
	 ^= [+2]
	 ^= [+3]

	_ = [15] // early bounds check
	binary.BigEndian.PutUint32([0:4], )
	binary.BigEndian.PutUint32([4:8], )
	binary.BigEndian.PutUint32([8:12], )
	binary.BigEndian.PutUint32([12:16], )
}

// Decrypt one block from src into dst, using the expanded key xk.
func decryptBlockGo( []uint32, ,  []byte) {
	_ = [15] // early bounds check
	 := binary.BigEndian.Uint32([0:4])
	 := binary.BigEndian.Uint32([4:8])
	 := binary.BigEndian.Uint32([8:12])
	 := binary.BigEndian.Uint32([12:16])

	// First round just XORs input with key.
	 ^= [0]
	 ^= [1]
	 ^= [2]
	 ^= [3]

	// Middle rounds shuffle using tables.
	// Number of rounds is set by length of expanded key.
	 := len()/4 - 2 // - 2: one above, one more below
	 := 4
	var , , ,  uint32
	for  := 0;  < ; ++ {
		 = [+0] ^ td0[uint8(>>24)] ^ td1[uint8(>>16)] ^ td2[uint8(>>8)] ^ td3[uint8()]
		 = [+1] ^ td0[uint8(>>24)] ^ td1[uint8(>>16)] ^ td2[uint8(>>8)] ^ td3[uint8()]
		 = [+2] ^ td0[uint8(>>24)] ^ td1[uint8(>>16)] ^ td2[uint8(>>8)] ^ td3[uint8()]
		 = [+3] ^ td0[uint8(>>24)] ^ td1[uint8(>>16)] ^ td2[uint8(>>8)] ^ td3[uint8()]
		 += 4
		, , ,  = , , , 
	}

	// Last round uses s-box directly and XORs to produce output.
	 = uint32(sbox1[>>24])<<24 | uint32(sbox1[>>16&0xff])<<16 | uint32(sbox1[>>8&0xff])<<8 | uint32(sbox1[&0xff])
	 = uint32(sbox1[>>24])<<24 | uint32(sbox1[>>16&0xff])<<16 | uint32(sbox1[>>8&0xff])<<8 | uint32(sbox1[&0xff])
	 = uint32(sbox1[>>24])<<24 | uint32(sbox1[>>16&0xff])<<16 | uint32(sbox1[>>8&0xff])<<8 | uint32(sbox1[&0xff])
	 = uint32(sbox1[>>24])<<24 | uint32(sbox1[>>16&0xff])<<16 | uint32(sbox1[>>8&0xff])<<8 | uint32(sbox1[&0xff])

	 ^= [+0]
	 ^= [+1]
	 ^= [+2]
	 ^= [+3]

	_ = [15] // early bounds check
	binary.BigEndian.PutUint32([0:4], )
	binary.BigEndian.PutUint32([4:8], )
	binary.BigEndian.PutUint32([8:12], )
	binary.BigEndian.PutUint32([12:16], )
}

// Apply sbox0 to each byte in w.
func subw( uint32) uint32 {
	return uint32(sbox0[>>24])<<24 |
		uint32(sbox0[>>16&0xff])<<16 |
		uint32(sbox0[>>8&0xff])<<8 |
		uint32(sbox0[&0xff])
}

// Rotate
func rotw( uint32) uint32 { return <<8 | >>24 }

// Key expansion algorithm. See FIPS-197, Figure 11.
// Their rcon[i] is our powx[i-1] << 24.
func expandKeyGo( []byte, ,  []uint32) {
	// Encryption key setup.
	var  int
	 := len() / 4
	for  = 0;  < ; ++ {
		[] = binary.BigEndian.Uint32([4*:])
	}
	for ;  < len(); ++ {
		 := [-1]
		if % == 0 {
			 = subw(rotw()) ^ (uint32(powx[/-1]) << 24)
		} else if  > 6 && % == 4 {
			 = subw()
		}
		[] = [-] ^ 
	}

	// Derive decryption key from encryption key.
	// Reverse the 4-word round key sets from enc to produce dec.
	// All sets but the first and last get the MixColumn transform applied.
	if  == nil {
		return
	}
	 := len()
	for  := 0;  < ;  += 4 {
		 :=  -  - 4
		for  := 0;  < 4; ++ {
			 := [+]
			if  > 0 && +4 <  {
				 = td0[sbox0[>>24]] ^ td1[sbox0[>>16&0xff]] ^ td2[sbox0[>>8&0xff]] ^ td3[sbox0[&0xff]]
			}
			[+] = 
		}
	}
}