// Copyright 2024 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 gcm

import (
	
	
	
)

// CMAC implements the CMAC mode from NIST SP 800-38B.
//
// It is optimized for use in Counter KDF (SP 800-108r1) and XAES-256-GCM
// (https://c2sp.org/XAES-256-GCM), rather than for exposing it to applications
// as a stand-alone MAC.
type CMAC struct {
	b  aes.Block
	k1 [aes.BlockSize]byte
	k2 [aes.BlockSize]byte
}

func ( *aes.Block) *CMAC {
	 := &CMAC{b: *}
	.deriveSubkeys()
	return 
}

func ( *CMAC) () {
	.b.Encrypt(.k1[:], .k1[:])
	 := shiftLeft(&.k1)
	.k1[len(.k1)-1] ^=  * 0b10000111

	.k2 = .k1
	 = shiftLeft(&.k2)
	.k2[len(.k2)-1] ^=  * 0b10000111
}

func ( *CMAC) ( []byte) [aes.BlockSize]byte {
	fips140.RecordApproved()
	_ = .b // Hoist the nil check out of the loop.
	var  [aes.BlockSize]byte
	if len() == 0 {
		// Special-cased as a single empty partial final block.
		 = .k2
		[len()] ^= 0b10000000
		.b.Encrypt([:], [:])
		return 
	}
	for len() >= aes.BlockSize {
		subtle.XORBytes([:], [:aes.BlockSize], [:])
		if len() == aes.BlockSize {
			// Final complete block.
			subtle.XORBytes([:], .k1[:], [:])
		}
		.b.Encrypt([:], [:])
		 = [aes.BlockSize:]
	}
	if len() > 0 {
		// Final incomplete block.
		subtle.XORBytes([:], , [:])
		subtle.XORBytes([:], .k2[:], [:])
		[len()] ^= 0b10000000
		.b.Encrypt([:], [:])
	}
	return 
}

// shiftLeft sets x to x << 1, and returns MSB₁(x).
func shiftLeft( *[aes.BlockSize]byte) byte {
	var  byte
	for  := len() - 1;  >= 0; -- {
		, [] = []>>7, []<<1|
	}
	return 
}