// 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 (
	
	
	
	
	
	
)

// SealWithRandomNonce encrypts plaintext to out, and writes a random nonce to
// nonce. nonce must be 12 bytes, and out must be 16 bytes longer than plaintext.
// out and plaintext may overlap exactly or not at all. additionalData and out
// must not overlap.
//
// This complies with FIPS 140-3 IG C.H Scenario 2.
//
// Note that this is NOT a [cipher.AEAD].Seal method.
func ( *GCM, , , ,  []byte) {
	if uint64(len()) > uint64((1<<32)-2)*gcmBlockSize {
		panic("crypto/cipher: message too large for GCM")
	}
	if len() != gcmStandardNonceSize {
		panic("crypto/cipher: incorrect nonce length given to GCMWithRandomNonce")
	}
	if len() != len()+gcmTagSize {
		panic("crypto/cipher: incorrect output length given to GCMWithRandomNonce")
	}
	if alias.InexactOverlap(, ) {
		panic("crypto/cipher: invalid buffer overlap of output and input")
	}
	if alias.AnyOverlap(, ) {
		panic("crypto/cipher: invalid buffer overlap of output and additional data")
	}
	fips140.RecordApproved()
	drbg.Read()
	seal(, , , , )
}

// NewGCMWithCounterNonce returns a new AEAD that works like GCM, but enforces
// the construction of deterministic nonces. The nonce must be 96 bits, the
// first 32 bits must be an encoding of the module name, and the last 64 bits
// must be a counter.
//
// This complies with FIPS 140-3 IG C.H Scenario 3.
func ( *aes.Block) (*GCMWithCounterNonce, error) {
	,  := newGCM(&GCM{}, , gcmStandardNonceSize, gcmTagSize)
	if  != nil {
		return nil, 
	}
	return &GCMWithCounterNonce{g: *}, nil
}

type GCMWithCounterNonce struct {
	g         GCM
	ready     bool
	fixedName uint32
	start     uint64
	next      uint64
}

func ( *GCMWithCounterNonce) () int { return gcmStandardNonceSize }

func ( *GCMWithCounterNonce) () int { return gcmTagSize }

func ( *GCMWithCounterNonce) (, , ,  []byte) []byte {
	if len() != gcmStandardNonceSize {
		panic("crypto/cipher: incorrect nonce length given to GCM")
	}

	 := byteorder.BEUint64([len()-8:])
	if !.ready {
		// The first invocation sets the fixed name encoding and start counter.
		.ready = true
		.start = 
		.fixedName = byteorder.BEUint32([:4])
	}
	if .fixedName != byteorder.BEUint32([:4]) {
		panic("crypto/cipher: incorrect module name given to GCMWithCounterNonce")
	}
	 -= .start

	// Ensure the counter is monotonically increasing.
	if  == math.MaxUint64 {
		panic("crypto/cipher: counter wrapped")
	}
	if  < .next {
		panic("crypto/cipher: counter decreased")
	}
	.next =  + 1

	fips140.RecordApproved()
	return .g.sealAfterIndicator(, , , )
}

func ( *GCMWithCounterNonce) (, , ,  []byte) ([]byte, error) {
	fips140.RecordApproved()
	return .g.Open(, , , )
}

// NewGCMForTLS12 returns a new AEAD that works like GCM, but enforces the
// construction of nonces as specified in RFC 5288, Section 3 and RFC 9325,
// Section 7.2.1.
//
// This complies with FIPS 140-3 IG C.H Scenario 1.a.
func ( *aes.Block) (*GCMForTLS12, error) {
	,  := newGCM(&GCM{}, , gcmStandardNonceSize, gcmTagSize)
	if  != nil {
		return nil, 
	}
	return &GCMForTLS12{g: *}, nil
}

type GCMForTLS12 struct {
	g    GCM
	next uint64
}

func ( *GCMForTLS12) () int { return gcmStandardNonceSize }

func ( *GCMForTLS12) () int { return gcmTagSize }

func ( *GCMForTLS12) (, , ,  []byte) []byte {
	if len() != gcmStandardNonceSize {
		panic("crypto/cipher: incorrect nonce length given to GCM")
	}

	 := byteorder.BEUint64([len()-8:])

	// Ensure the counter is monotonically increasing.
	if  == math.MaxUint64 {
		panic("crypto/cipher: counter wrapped")
	}
	if  < .next {
		panic("crypto/cipher: counter decreased")
	}
	.next =  + 1

	fips140.RecordApproved()
	return .g.sealAfterIndicator(, , , )
}

func ( *GCMForTLS12) (, , ,  []byte) ([]byte, error) {
	fips140.RecordApproved()
	return .g.Open(, , , )
}

// NewGCMForTLS13 returns a new AEAD that works like GCM, but enforces the
// construction of nonces as specified in RFC 8446, Section 5.3.
func ( *aes.Block) (*GCMForTLS13, error) {
	,  := newGCM(&GCM{}, , gcmStandardNonceSize, gcmTagSize)
	if  != nil {
		return nil, 
	}
	return &GCMForTLS13{g: *}, nil
}

type GCMForTLS13 struct {
	g     GCM
	ready bool
	mask  uint64
	next  uint64
}

func ( *GCMForTLS13) () int { return gcmStandardNonceSize }

func ( *GCMForTLS13) () int { return gcmTagSize }

func ( *GCMForTLS13) (, , ,  []byte) []byte {
	if len() != gcmStandardNonceSize {
		panic("crypto/cipher: incorrect nonce length given to GCM")
	}

	 := byteorder.BEUint64([len()-8:])
	if !.ready {
		// In the first call, the counter is zero, so we learn the XOR mask.
		.ready = true
		.mask = 
	}
	 ^= .mask

	// Ensure the counter is monotonically increasing.
	if  == math.MaxUint64 {
		panic("crypto/cipher: counter wrapped")
	}
	if  < .next {
		panic("crypto/cipher: counter decreased")
	}
	.next =  + 1

	fips140.RecordApproved()
	return .g.sealAfterIndicator(, , , )
}

func ( *GCMForTLS13) (, , ,  []byte) ([]byte, error) {
	fips140.RecordApproved()
	return .g.Open(, , , )
}

// NewGCMForSSH returns a new AEAD that works like GCM, but enforces the
// construction of nonces as specified in RFC 5647.
//
// This complies with FIPS 140-3 IG C.H Scenario 1.d.
func ( *aes.Block) (*GCMForSSH, error) {
	,  := newGCM(&GCM{}, , gcmStandardNonceSize, gcmTagSize)
	if  != nil {
		return nil, 
	}
	return &GCMForSSH{g: *}, nil
}

type GCMForSSH struct {
	g     GCM
	ready bool
	start uint64
	next  uint64
}

func ( *GCMForSSH) () int { return gcmStandardNonceSize }

func ( *GCMForSSH) () int { return gcmTagSize }

func ( *GCMForSSH) (, , ,  []byte) []byte {
	if len() != gcmStandardNonceSize {
		panic("crypto/cipher: incorrect nonce length given to GCM")
	}

	 := byteorder.BEUint64([len()-8:])
	if !.ready {
		// In the first call we learn the start value.
		.ready = true
		.start = 
	}
	 -= .start

	// Ensure the counter is monotonically increasing.
	if  == math.MaxUint64 {
		panic("crypto/cipher: counter wrapped")
	}
	if  < .next {
		panic("crypto/cipher: counter decreased")
	}
	.next =  + 1

	fips140.RecordApproved()
	return .g.sealAfterIndicator(, , , )
}

func ( *GCMForSSH) (, , ,  []byte) ([]byte, error) {
	fips140.RecordApproved()
	return .g.Open(, , , )
}