// 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 drbg

import (
	
	
	
	
	
)

// Counter is an SP 800-90A Rev. 1 CTR_DRBG instantiated with AES-256.
//
// Per Table 3, it has a security strength of 256 bits, a seed size of 384 bits,
// a counter length of 128 bits, a reseed interval of 2^48 requests, and a
// maximum request size of 2^19 bits (2^16 bytes, 64 KiB).
//
// We support a narrow range of parameters that fit the needs of our RNG:
// AES-256, no derivation function, no personalization string, no prediction
// resistance, and 384-bit additional input.
type Counter struct {
	// c is instantiated with K as the key and V as the counter.
	c aes.CTR

	reseedCounter uint64
}

const (
	keySize        = 256 / 8
	SeedSize       = keySize + aes.BlockSize
	reseedInterval = 1 << 48
	maxRequestSize = (1 << 19) / 8
)

func ( *[SeedSize]byte) *Counter {
	// CTR_DRBG_Instantiate_algorithm, per Section 10.2.1.3.1.
	fips140.RecordApproved()

	 := make([]byte, keySize)
	 := make([]byte, aes.BlockSize)

	// V starts at 0, but is incremented in CTR_DRBG_Update before each use,
	// unlike AES-CTR where it is incremented after each use.
	[len()-1] = 1

	,  := aes.New()
	if  != nil {
		panic()
	}

	 := &Counter{}
	.c = *aes.NewCTR(, )
	.update()
	.reseedCounter = 1
	return 
}

func ( *Counter) ( *[SeedSize]byte) {
	// CTR_DRBG_Update, per Section 10.2.1.2.

	 := make([]byte, SeedSize)
	.c.XORKeyStream(, [:])
	 := [:keySize]
	 := [keySize:]

	// Again, we pre-increment V, like in NewCounter.
	increment((*[aes.BlockSize]byte)())

	,  := aes.New()
	if  != nil {
		panic()
	}
	.c = *aes.NewCTR(, )
}

func increment( *[aes.BlockSize]byte) {
	 := byteorder.BEUint64([:8])
	 := byteorder.BEUint64([8:])
	,  := bits.Add64(, 1, 0)
	, _ = bits.Add64(, 0, )
	byteorder.BEPutUint64([:8], )
	byteorder.BEPutUint64([8:], )
}

func ( *Counter) (,  *[SeedSize]byte) {
	// CTR_DRBG_Reseed_algorithm, per Section 10.2.1.4.1.
	fips140.RecordApproved()

	var  [SeedSize]byte
	subtle.XORBytes([:], [:], [:])
	.update(&)
	.reseedCounter = 1
}

// Generate produces at most maxRequestSize bytes of random data in out.
func ( *Counter) ( []byte,  *[SeedSize]byte) ( bool) {
	// CTR_DRBG_Generate_algorithm, per Section 10.2.1.5.1.
	fips140.RecordApproved()

	if len() > maxRequestSize {
		panic("crypto/drbg: internal error: request size exceeds maximum")
	}

	// Step 1.
	if .reseedCounter > reseedInterval {
		return true
	}

	// Step 2.
	if  != nil {
		.update()
	} else {
		// If the additional input is null, the first CTR_DRBG_Update is
		// skipped, but the additional input is replaced with an all-zero string
		// for the second CTR_DRBG_Update.
		 = new([SeedSize]byte)
	}

	// Steps 3-5.
	clear()
	.c.XORKeyStream(, )
	aes.RoundToBlock(&.c)

	// Step 6.
	.update()

	// Step 7.
	.reseedCounter++

	// Step 8.
	return false
}