func newHandshakeState(initiator bool, prologue []byte,
	localStatic *koblitz.PrivateKey) handshakeState {
	h := handshakeState{
		initiator:   initiator,
		localStatic: localStatic,
	}
	h.InitializeSymmetric([]byte(protocolName))
	h.mixHash(prologue)
	return h
}
newHandshakeState returns a new instance of the handshake state initialized
with the prologue and protocol name. If this is the responder's handshake
state, then the remotePub can be nil.
package cxnoise
import (
	"crypto/cipher"
	"crypto/sha256"
	"encoding/binary"
	"errors"
	"fmt"
	"io"
	"math"
	"time"
	"golang.org/x/crypto/chacha20poly1305"
	"golang.org/x/crypto/hkdf"
	"github.com/mit-dci/lit/crypto/koblitz"
)
const (
	protocolName = "Noise_XX_secp256k1_ChaChaPoly_SHA256"
	macSize = 16
	lengthHeaderSize = 2
	keyRotationInterval = 1000
	handshakeReadTimeout = time.Second * 5  
)
func ecdh(pub *koblitz.PublicKey, priv *koblitz.PrivateKey) []byte {
	s := &koblitz.PublicKey{}
	x, y := koblitz.S256().ScalarMult(pub.X, pub.Y, priv.D.Bytes())
	s.X = x
	s.Y = y
	h := sha256.Sum256(s.SerializeCompressed())
	return h[:]
}
type cipherState struct {
	nonce uint64
	secretKey [32]byte
	salt [32]byte
	cipher cipher.AEAD
}
func (c *cipherState) Encrypt(associatedData, cipherText, plainText []byte) []byte {
	defer func() {
		c.nonce++
		if c.nonce == keyRotationInterval {
			c.rotateKey()
		}
	}()
	var nonce [12]byte
	binary.LittleEndian.PutUint64(nonce[4:], c.nonce)
	return c.cipher.Seal(cipherText, nonce[:], plainText, associatedData)
}
func (c *cipherState) Decrypt(associatedData, plainText, cipherText []byte) ([]byte, error) {
	defer func() {
		c.nonce++
		if c.nonce == keyRotationInterval {
			c.rotateKey()
		}
	}()
	var nonce [12]byte
	binary.LittleEndian.PutUint64(nonce[4:], c.nonce)
	return c.cipher.Open(plainText, nonce[:], cipherText, associatedData)
}
func (c *cipherState) InitializeKey(key [32]byte) {
	c.secretKey = key
	c.nonce = 0
	c.cipher, _ = chacha20poly1305.New(c.secretKey[:])
}
func (c *cipherState) InitializeKeyWithSalt(salt, key [32]byte) {
	c.salt = salt
	c.InitializeKey(key)
}
func (c *cipherState) rotateKey() {
	var (
		info    []byte
		nextKey [32]byte
	)
	oldKey := c.secretKey
	h := hkdf.New(sha256.New, oldKey[:], c.salt[:], info)
	h.Read(c.salt[:])
	h.Read(nextKey[:])
	c.InitializeKey(nextKey)
}
type symmetricState struct {
	cipherState
	chainingKey [32]byte
	tempKey [32]byte
	handshakeDigest [32]byte
}
func (s *symmetricState) mixKey(input []byte) {
	var info []byte
	secret := input
	salt := s.chainingKey
	h := hkdf.New(sha256.New, secret, salt[:], info)
	h.Read(s.chainingKey[:])
	h.Read(s.tempKey[:])
	s.InitializeKey(s.tempKey)
}
func (s *symmetricState) mixHash(data []byte) {
	h := sha256.New()
	h.Write(s.handshakeDigest[:])
	h.Write(data)
	copy(s.handshakeDigest[:], h.Sum(nil))
}
func (s *symmetricState) EncryptAndHash(plaintext []byte) []byte {
	ciphertext := s.Encrypt(s.handshakeDigest[:], nil, plaintext)
	s.mixHash(ciphertext)
	return ciphertext
}
func (s *symmetricState) DecryptAndHash(ciphertext []byte) ([]byte, error) {
	plaintext, err := s.Decrypt(s.handshakeDigest[:], nil, ciphertext)
	if err != nil {
		return nil, err
	}
	s.mixHash(ciphertext)
	return plaintext, nil
}
func (s *symmetricState) InitializeSymmetric(protocolName []byte) {
	var empty [32]byte
	s.handshakeDigest = sha256.Sum256(protocolName)
	s.chainingKey = s.handshakeDigest
	s.InitializeKey(empty)  
}
type handshakeState struct {
	symmetricState
	initiator bool
	localStatic    *koblitz.PrivateKey
	localEphemeral *koblitz.PrivateKey
	remoteStatic    *koblitz.PublicKey
	remoteEphemeral *koblitz.PublicKey
}