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

import (
	
	
	
)

// A ChaCha8 is a ChaCha8-based cryptographically strong
// random number generator.
type ChaCha8 struct {
	state chacha8rand.State

	// The last readLen bytes of readBuf are still to be consumed by Read.
	readBuf [8]byte
	readLen int // 0 <= readLen <= 8
}

// NewChaCha8 returns a new ChaCha8 seeded with the given seed.
func ( [32]byte) *ChaCha8 {
	 := new(ChaCha8)
	.state.Init()
	return 
}

// Seed resets the ChaCha8 to behave the same way as NewChaCha8(seed).
func ( *ChaCha8) ( [32]byte) {
	.state.Init()
	.readLen = 0
	.readBuf = [8]byte{}
}

// Uint64 returns a uniformly distributed random uint64 value.
func ( *ChaCha8) () uint64 {
	for {
		,  := .state.Next()
		if  {
			return 
		}
		.state.Refill()
	}
}

// Read reads exactly len(p) bytes into p.
// It always returns len(p) and a nil error.
//
// If calls to Read and Uint64 are interleaved, the order in which bits are
// returned by the two is undefined, and Read may return bits generated before
// the last call to Uint64.
func ( *ChaCha8) ( []byte) ( int,  error) {
	if .readLen > 0 {
		 = copy(, .readBuf[len(.readBuf)-.readLen:])
		.readLen -= 
		 = [:]
	}
	for len() >= 8 {
		byteorder.LePutUint64(, .Uint64())
		 = [8:]
		 += 8
	}
	if len() > 0 {
		byteorder.LePutUint64(.readBuf[:], .Uint64())
		 += copy(, .readBuf[:])
		.readLen = 8 - len()
	}
	return
}

// UnmarshalBinary implements the encoding.BinaryUnmarshaler interface.
func ( *ChaCha8) ( []byte) error {
	,  := cutPrefix(, []byte("readbuf:"))
	if  {
		var  []byte
		, ,  = readUint8LengthPrefixed()
		if ! {
			return errors.New("invalid ChaCha8 Read buffer encoding")
		}
		.readLen = copy(.readBuf[len(.readBuf)-len():], )
	}
	return chacha8rand.Unmarshal(&.state, )
}

func cutPrefix(,  []byte) ( []byte,  bool) {
	if len() < len() || string([:len()]) != string() {
		return , false
	}
	return [len():], true
}

func readUint8LengthPrefixed( []byte) (,  []byte,  bool) {
	if len() == 0 || len() < int(1+[0]) {
		return nil, nil, false
	}
	return [1 : 1+[0]], [1+[0]:], true
}

// MarshalBinary implements the encoding.BinaryMarshaler interface.
func ( *ChaCha8) () ([]byte, error) {
	if .readLen > 0 {
		 := []byte("readbuf:")
		 = append(, uint8(.readLen))
		 = append(, .readBuf[len(.readBuf)-.readLen:]...)
		return append(, chacha8rand.Marshal(&.state)...), nil
	}
	return chacha8rand.Marshal(&.state), nil
}