func (c *ccm) auth(nonce, plaintext, additionalData []byte, tagMask *[ccmBlockSize]byte) []byte {
	var out [ccmTagSize]byte
	if len(additionalData) > 0 {
		out[0] = 1 << 6  
	}
	out[0] |= byte(c.tagSize-2) << 2  
	out[0] |= byte(14 - c.nonceSize)  
	binary.BigEndian.PutUint64(out[ccmBlockSize-8:], uint64(len(plaintext)))
	copy(out[1:], nonce)
	c.cipher.Encrypt(out[:], out[:])
	var block [ccmBlockSize]byte
	if n := uint64(len(additionalData)); n > 0 {
		i := 2
		if n <= 0xfeff {  
			binary.BigEndian.PutUint16(block[:i], uint16(n))
		} else {
			block[0] = 0xff
			if n < uint64(1<<32) {
				block[1] = 0xfe
				i = 2 + 4
				binary.BigEndian.PutUint32(block[2:i], uint32(n))
			} else {
				block[1] = 0xff
				i = 2 + 8
				binary.BigEndian.PutUint64(block[2:i], uint64(n))
			}
		}
		i = copy(block[i:], additionalData)  
		c.cmac(out[:], block[:])
		c.cmac(out[:], additionalData[i:])
	}
	if len(plaintext) > 0 {
		c.cmac(out[:], plaintext)
	}
	xor.XorWords(out[:], out[:], tagMask[:])
	return out[:c.tagSize]
}
https://tools.ietf.org/html/rfc3610 2.2. Authentication
package cipher
import (
	goCipher "crypto/cipher"
	goSubtle "crypto/subtle"
	"encoding/binary"
	"math"
	"errors"
	"github.com/emmansun/gmsm/internal/subtle"
	"github.com/emmansun/gmsm/internal/xor"
)
const (
	ccmBlockSize         = 16
	ccmTagSize           = 16
	ccmMinimumTagSize    = 4
	ccmStandardNonceSize = 12
)
type ccmAble interface {
	NewCCM(nonceSize, tagSize int) (goCipher.AEAD, error)
}
type ccm struct {
	cipher    goCipher.Block
	nonceSize int
	tagSize   int
}
func (c *ccm) NonceSize() int {
	return c.nonceSize
}
func (c *ccm) Overhead() int {
	return c.tagSize
}
func (c *ccm) MaxLength() int {
	return maxlen(15-c.NonceSize(), c.Overhead())
}
func maxlen(L, tagsize int) int {
	max := (uint64(1) << (8 * L)) - 1
	if m64 := uint64(math.MaxInt64) - uint64(tagsize); L > 8 || max > m64 {
		max = m64  
	}
	if max != uint64(int(max)) {
		return math.MaxInt32 - tagsize  
	}
	return int(max)
}
func NewCCM(cipher goCipher.Block) (goCipher.AEAD, error) {
	return NewCCMWithNonceAndTagSize(cipher, ccmStandardNonceSize, ccmTagSize)
}
func NewCCMWithNonceSize(cipher goCipher.Block, size int) (goCipher.AEAD, error) {
	return NewCCMWithNonceAndTagSize(cipher, size, ccmTagSize)
}
func NewCCMWithTagSize(cipher goCipher.Block, tagSize int) (goCipher.AEAD, error) {
	return NewCCMWithNonceAndTagSize(cipher, ccmStandardNonceSize, tagSize)
}
func NewCCMWithNonceAndTagSize(cipher goCipher.Block, nonceSize, tagSize int) (goCipher.AEAD, error) {
	if tagSize < ccmMinimumTagSize || tagSize > ccmBlockSize || tagSize&1 != 0 {
		return nil, errors.New("cipher: incorrect tag size given to CCM")
	}
	if nonceSize <= 0 {
		return nil, errors.New("cipher: the nonce can't have zero length, or the security of the key will be immediately compromised")
	}
	lenSize := 15 - nonceSize
	if lenSize < 2 || lenSize > 8 {
		return nil, errors.New("cipher: invalid ccm nounce size, should be in [7,13]")
	}
	if cipher, ok := cipher.(ccmAble); ok {
		return cipher.NewCCM(nonceSize, tagSize)
	}
	if cipher.BlockSize() != ccmBlockSize {
		return nil, errors.New("cipher: NewCCM requires 128-bit block cipher")
	}
	c := &ccm{cipher: cipher, nonceSize: nonceSize, tagSize: tagSize}
	return c, nil
}
func (c *ccm) deriveCounter(counter *[ccmBlockSize]byte, nonce []byte) {
	counter[0] = byte(14 - c.nonceSize)
	copy(counter[1:], nonce)
}
func (c *ccm) cmac(out, data []byte) {
	for len(data) >= ccmBlockSize {
		xor.XorBytes(out, out, data)
		c.cipher.Encrypt(out, out)
		data = data[ccmBlockSize:]
	}
	if len(data) > 0 {
		var block [ccmBlockSize]byte
		copy(block[:], data)
		xor.XorBytes(out, out, data)
		c.cipher.Encrypt(out, out)
	}
}