func HChaCha20(key *[8]uint32, nonce *[4]uint32) [8]uint32 {
	x0, x1, x2, x3 := j0, j1, j2, j3
	x4, x5, x6, x7 := key[0], key[1], key[2], key[3]
	x8, x9, x10, x11 := key[4], key[5], key[6], key[7]
	x12, x13, x14, x15 := nonce[0], nonce[1], nonce[2], nonce[3]
	for i := 0; i < 10; i++ {
		x0, x4, x8, x12 = quarterRound(x0, x4, x8, x12)
		x1, x5, x9, x13 = quarterRound(x1, x5, x9, x13)
		x2, x6, x10, x14 = quarterRound(x2, x6, x10, x14)
		x3, x7, x11, x15 = quarterRound(x3, x7, x11, x15)
		x0, x5, x10, x15 = quarterRound(x0, x5, x10, x15)
		x1, x6, x11, x12 = quarterRound(x1, x6, x11, x12)
		x2, x7, x8, x13 = quarterRound(x2, x7, x8, x13)
		x3, x4, x9, x14 = quarterRound(x3, x4, x9, x14)
	}
	var out [8]uint32
	out[0], out[1], out[2], out[3] = x0, x1, x2, x3
	out[4], out[5], out[6], out[7] = x12, x13, x14, x15
	return out
}
HChaCha20 uses the ChaCha20 core to generate a derived key from a key and a
nonce. It should only be used as part of the XChaCha20 construction.
package chacha20
import (
	"crypto/cipher"
	"encoding/binary"
	"github.com/mmcloughlin/cryptofuzz/target/chacha20poly1305/fork/internal/subtle"
)
var _ cipher.Stream = (*Cipher)(nil)
type Cipher struct {
	key     [8]uint32
	counter uint32  
	nonce   [3]uint32
	buf     [bufSize]byte  
	len     int            
}
func New(key [8]uint32, nonce [3]uint32) *Cipher {
	return &Cipher{key: key, nonce: nonce}
}
const (
	j0 uint32 = 0x61707865
	j1 uint32 = 0x3320646e
	j2 uint32 = 0x79622d32
	j3 uint32 = 0x6b206574
)
func quarterRound(a, b, c, d uint32) (uint32, uint32, uint32, uint32) {
	a += b
	d ^= a
	d = (d << 16) | (d >> 16)
	c += d
	b ^= c
	b = (b << 12) | (b >> 20)
	a += b
	d ^= a
	d = (d << 8) | (d >> 24)
	c += d
	b ^= c
	b = (b << 7) | (b >> 25)
	return a, b, c, d
}
func (s *Cipher) XORKeyStream(dst, src []byte) {
	if len(dst) < len(src) {
		panic("chacha20: output smaller than input")
	}
	if subtle.InexactOverlap(dst[:len(src)], src) {
		panic("chacha20: invalid buffer overlap")
	}
	if s.len != 0 {
		buf := s.buf[len(s.buf)-s.len:]
		if len(src) < len(buf) {
			buf = buf[:len(src)]
		}
		td, ts := dst[:len(buf)], src[:len(buf)]  
		for i, b := range buf {
			td[i] = ts[i] ^ b
		}
		s.len -= len(buf)
		if s.len != 0 {
			return
		}
		s.buf = [len(s.buf)]byte{}  
		src = src[len(buf):]
		dst = dst[len(buf):]
	}
	if len(src) == 0 {
		return
	}
	if haveAsm {
		if uint64(len(src))+uint64(s.counter)*64 > (1<<38)-64 {
			panic("chacha20: counter overflow")
		}
		s.xorKeyStreamAsm(dst, src)
		return
	}
	rem := len(src) % 64   
	fin := len(src) - rem  
	if rem > 0 {
		copy(s.buf[len(s.buf)-64:], src[fin:])
	}
	s1, s5, s9, s13 := quarterRound(j1, s.key[1], s.key[5], s.nonce[0])
	s2, s6, s10, s14 := quarterRound(j2, s.key[2], s.key[6], s.nonce[1])
	s3, s7, s11, s15 := quarterRound(j3, s.key[3], s.key[7], s.nonce[2])
	n := len(src)
	src, dst = src[:n:n], dst[:n:n]  
	for i := 0; i < n; i += 64 {
		s0, s4, s8, s12 := quarterRound(j0, s.key[0], s.key[4], s.counter)
		x0, x5, x10, x15 := quarterRound(s0, s5, s10, s15)
		x1, x6, x11, x12 := quarterRound(s1, s6, s11, s12)
		x2, x7, x8, x13 := quarterRound(s2, s7, s8, s13)
		x3, x4, x9, x14 := quarterRound(s3, s4, s9, s14)
		for i := 0; i < 9; i++ {
			x0, x4, x8, x12 = quarterRound(x0, x4, x8, x12)
			x1, x5, x9, x13 = quarterRound(x1, x5, x9, x13)
			x2, x6, x10, x14 = quarterRound(x2, x6, x10, x14)
			x3, x7, x11, x15 = quarterRound(x3, x7, x11, x15)
			x0, x5, x10, x15 = quarterRound(x0, x5, x10, x15)
			x1, x6, x11, x12 = quarterRound(x1, x6, x11, x12)
			x2, x7, x8, x13 = quarterRound(x2, x7, x8, x13)
			x3, x4, x9, x14 = quarterRound(x3, x4, x9, x14)
		}
		x0 += j0
		x1 += j1
		x2 += j2
		x3 += j3
		x4 += s.key[0]
		x5 += s.key[1]
		x6 += s.key[2]
		x7 += s.key[3]
		x8 += s.key[4]
		x9 += s.key[5]
		x10 += s.key[6]
		x11 += s.key[7]
		x12 += s.counter
		x13 += s.nonce[0]
		x14 += s.nonce[1]
		x15 += s.nonce[2]
		s.counter += 1
		if s.counter == 0 {
			panic("chacha20: counter overflow")
		}
		in, out := src[i:], dst[i:]
		if i == fin {
			in, out = s.buf[len(s.buf)-64:], s.buf[len(s.buf)-64:]
		}
		in, out = in[:64], out[:64]  
		xor(out[0:], in[0:], x0)
		xor(out[4:], in[4:], x1)
		xor(out[8:], in[8:], x2)
		xor(out[12:], in[12:], x3)
		xor(out[16:], in[16:], x4)
		xor(out[20:], in[20:], x5)
		xor(out[24:], in[24:], x6)
		xor(out[28:], in[28:], x7)
		xor(out[32:], in[32:], x8)
		xor(out[36:], in[36:], x9)
		xor(out[40:], in[40:], x10)
		xor(out[44:], in[44:], x11)
		xor(out[48:], in[48:], x12)
		xor(out[52:], in[52:], x13)
		xor(out[56:], in[56:], x14)
		xor(out[60:], in[60:], x15)
	}
	if rem != 0 {
		s.len = 64 - rem
		copy(dst[fin:], s.buf[len(s.buf)-64:])
	}
}
func (s *Cipher) Advance() {
	s.len -= s.len % 64
	if s.len == 0 {
		s.buf = [len(s.buf)]byte{}
	}
}
func XORKeyStream(out, in []byte, counter *[16]byte, key *[32]byte) {
	s := Cipher{
		key: [8]uint32{
			binary.LittleEndian.Uint32(key[0:4]),
			binary.LittleEndian.Uint32(key[4:8]),
			binary.LittleEndian.Uint32(key[8:12]),
			binary.LittleEndian.Uint32(key[12:16]),
			binary.LittleEndian.Uint32(key[16:20]),
			binary.LittleEndian.Uint32(key[20:24]),
			binary.LittleEndian.Uint32(key[24:28]),
			binary.LittleEndian.Uint32(key[28:32]),
		},
		nonce: [3]uint32{
			binary.LittleEndian.Uint32(counter[4:8]),
			binary.LittleEndian.Uint32(counter[8:12]),
			binary.LittleEndian.Uint32(counter[12:16]),
		},
		counter: binary.LittleEndian.Uint32(counter[0:4]),
	}
	s.XORKeyStream(out, in)
}