package handshake

import (
	

	
)

// pathPacketNumberLow62 masks a packet number to the low 62 bits, as the
// draft-ietf-quic-multipath §2.4 path-and-packet-number reserves the two bits
// above the 62-bit packet number. QUIC packet numbers never exceed 2^62-1
// (RFC 9000 §17.1), so this is a no-op for valid packet numbers; it documents
// the invariant the draft relies on.
const pathPacketNumberLow62 = (uint64(1) << 62) - 1

// putPathNonce writes the AEAD nonce for path pid and packet number pn into buf,
// per draft-ietf-quic-multipath §2.4. For PathIDZero the nonce is the 8-byte
// big-endian packet number — byte-identical to the RFC 9001 nonce — so the
// single-path stack is unchanged. For a non-zero path it is the 12-byte
// big-endian path-and-packet-number: the path id in the high 32 bits, then two
// zero bits, then the 62-bit packet number in the low bits. It returns the
// sub-slice of buf that was written. buf must be at least 12 bytes.
func putPathNonce( []byte,  protocol.PathID,  protocol.PacketNumber) []byte {
	if  == protocol.PathIDZero {
		 := [len()-8:]
		binary.BigEndian.PutUint64(, uint64())
		return 
	}
	 := [len()-12:]
	binary.BigEndian.PutUint32([:4], uint32())
	binary.BigEndian.PutUint64([4:], uint64()&pathPacketNumberLow62)
	return 
}

func createAEAD( cipherSuite,  []byte,  protocol.Version) *xorNonceAEAD {
	 := hkdfLabelKeyV1
	 := hkdfLabelIVV1
	if  == protocol.Version2 {
		 = hkdfLabelKeyV2
		 = hkdfLabelIVV2
	}
	 := hkdfExpandLabel(.Hash, , []byte{}, , .KeyLen)
	 := hkdfExpandLabel(.Hash, , []byte{}, , .IVLen())
	return .AEAD(, )
}

type longHeaderSealer struct {
	aead            *xorNonceAEAD
	headerProtector headerProtector
	nonceBuf        [12]byte
}

var _ LongHeaderSealer = &longHeaderSealer{}

func newLongHeaderSealer( *xorNonceAEAD,  headerProtector) LongHeaderSealer {
	if .NonceSize() != 8 {
		panic("unexpected nonce size")
	}
	return &longHeaderSealer{
		aead:            ,
		headerProtector: ,
	}
}

func ( *longHeaderSealer) (,  []byte,  protocol.PathID,  protocol.PacketNumber,  []byte) []byte {
	return .aead.Seal(, putPathNonce(.nonceBuf[:], , ), , )
}

func ( *longHeaderSealer) ( []byte,  *byte,  []byte) {
	.headerProtector.EncryptHeader(, , )
}

func ( *longHeaderSealer) () int {
	return .aead.Overhead()
}

type longHeaderOpener struct {
	aead            *xorNonceAEAD
	headerProtector headerProtector
	highestRcvdPN   protocol.PacketNumber // highest packet number received (which could be successfully unprotected)

	// use a single array to avoid allocations
	nonceBuf [12]byte
}

var _ LongHeaderOpener = &longHeaderOpener{}

func newLongHeaderOpener( *xorNonceAEAD,  headerProtector) LongHeaderOpener {
	if .NonceSize() != 8 {
		panic("unexpected nonce size")
	}
	return &longHeaderOpener{
		aead:            ,
		headerProtector: ,
	}
}

// DecodePacketNumber reconstructs the truncated wire packet number. pid is
// always PathIDZero (long-header packets are never multipath), so a single
// highestRcvdPN suffices.
func ( *longHeaderOpener) ( protocol.PathID,  protocol.PacketNumber,  protocol.PacketNumberLen) protocol.PacketNumber {
	return protocol.DecodePacketNumber(, .highestRcvdPN, )
}

func ( *longHeaderOpener) (,  []byte,  protocol.PathID,  protocol.PacketNumber,  []byte) ([]byte, error) {
	,  := .aead.Open(, putPathNonce(.nonceBuf[:], , ), , )
	if  == nil {
		.highestRcvdPN = max(.highestRcvdPN, )
	} else {
		 = ErrDecryptionFailed
	}
	return , 
}

func ( *longHeaderOpener) ( []byte,  *byte,  []byte) {
	.headerProtector.DecryptHeader(, , )
}