// Copyright 2023 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 aes

import (
	
	
	
	
)

type CTR struct {
	b          Block
	ivlo, ivhi uint64 // start counter as 64-bit limbs
	offset     uint64 // for XORKeyStream only
}

func ( *Block,  []byte) *CTR {
	// Allocate the CTR here, in an easily inlineable function, so
	// the allocation can be done in the caller's stack frame
	// instead of the heap.  See issue 70499.
	 := newCTR(, )
	return &
}
func newCTR( *Block,  []byte) CTR {
	if len() != BlockSize {
		panic("bad IV length")
	}

	return CTR{
		b:      *,
		ivlo:   byteorder.BEUint64([8:16]),
		ivhi:   byteorder.BEUint64([0:8]),
		offset: 0,
	}
}

func ( *CTR) (,  []byte) {
	.XORKeyStreamAt(, , .offset)

	var  uint64
	.offset,  = bits.Add64(.offset, uint64(len()), 0)
	if  != 0 {
		panic("crypto/aes: counter overflow")
	}
}

// RoundToBlock is used by CTR_DRBG, which discards the rightmost unused bits at
// each request. It rounds the offset up to the next block boundary.
func ( *CTR) {
	if  := .offset % BlockSize;  != 0 {
		var  uint64
		.offset,  = bits.Add64(.offset, BlockSize-, 0)
		if  != 0 {
			panic("crypto/aes: counter overflow")
		}
	}
}

// XORKeyStreamAt behaves like XORKeyStream but keeps no state, and instead
// seeks into the keystream by the given bytes offset from the start (ignoring
// any XORKetStream calls). This allows for random access into the keystream, up
// to 16 EiB from the start.
func ( *CTR) (,  []byte,  uint64) {
	if len() < len() {
		panic("crypto/aes: len(dst) < len(src)")
	}
	 = [:len()]
	if alias.InexactOverlap(, ) {
		panic("crypto/aes: invalid buffer overlap")
	}

	,  := add128(.ivlo, .ivhi, /BlockSize)

	if  :=  % BlockSize;  != 0 {
		// We have a partial block at the beginning.
		var ,  [BlockSize]byte
		copy([:], )
		ctrBlocks1(&.b, &, &, , )
		 := copy(, [:])
		 = [:]
		 = [:]
		,  = add128(, , 1)
	}

	for len() >= 8*BlockSize {
		ctrBlocks8(&.b, (*[8 * BlockSize]byte)(), (*[8 * BlockSize]byte)(), , )
		 = [8*BlockSize:]
		 = [8*BlockSize:]
		,  = add128(, , 8)
	}

	// The tail can have at most 7 = 4 + 2 + 1 blocks.
	if len() >= 4*BlockSize {
		ctrBlocks4(&.b, (*[4 * BlockSize]byte)(), (*[4 * BlockSize]byte)(), , )
		 = [4*BlockSize:]
		 = [4*BlockSize:]
		,  = add128(, , 4)
	}
	if len() >= 2*BlockSize {
		ctrBlocks2(&.b, (*[2 * BlockSize]byte)(), (*[2 * BlockSize]byte)(), , )
		 = [2*BlockSize:]
		 = [2*BlockSize:]
		,  = add128(, , 2)
	}
	if len() >= 1*BlockSize {
		ctrBlocks1(&.b, (*[1 * BlockSize]byte)(), (*[1 * BlockSize]byte)(), , )
		 = [1*BlockSize:]
		 = [1*BlockSize:]
		,  = add128(, , 1)
	}

	if len() != 0 {
		// We have a partial block at the end.
		var ,  [BlockSize]byte
		copy([:], )
		ctrBlocks1(&.b, &, &, , )
		copy(, [:])
	}
}

// Each ctrBlocksN function XORs src with N blocks of counter keystream, and
// stores it in dst. src is loaded in full before storing dst, so they can
// overlap even inexactly. The starting counter value is passed in as a pair of
// little-endian 64-bit integers.

func ctrBlocks( *Block, ,  []byte, ,  uint64) {
	 := make([]byte, len(), 8*BlockSize)
	for  := 0;  < len();  += BlockSize {
		byteorder.BEPutUint64([:], )
		byteorder.BEPutUint64([+8:], )
		,  = add128(, , 1)
		.Encrypt([:], [:])
	}
	// XOR into buf first, in case src and dst overlap (see above).
	subtle.XORBytes(, , )
	copy(, )
}

func add128(,  uint64,  uint64) (uint64, uint64) {
	,  := bits.Add64(, , 0)
	, _ = bits.Add64(, 0, )
	return , 
}