// Copyright 2009 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 tls

import (
	
	

	
)

// The marshalingFunction type is an adapter to allow the use of ordinary
// functions as cryptobyte.MarshalingValue.
type marshalingFunction func(b *cryptobyte.Builder) error

func ( marshalingFunction) ( *cryptobyte.Builder) error {
	return ()
}

// addBytesWithLength appends a sequence of bytes to the cryptobyte.Builder. If
// the length of the sequence is not the value specified, it produces an error.
func addBytesWithLength( *cryptobyte.Builder,  []byte,  int) {
	.AddValue(marshalingFunction(func( *cryptobyte.Builder) error {
		if len() !=  {
			return fmt.Errorf("invalid value length: expected %d, got %d", , len())
		}
		.AddBytes()
		return nil
	}))
}

// addUint64 appends a big-endian, 64-bit value to the cryptobyte.Builder.
func addUint64( *cryptobyte.Builder,  uint64) {
	.AddUint32(uint32( >> 32))
	.AddUint32(uint32())
}

// readUint64 decodes a big-endian, 64-bit value into out and advances over it.
// It reports whether the read was successful.
func readUint64( *cryptobyte.String,  *uint64) bool {
	var ,  uint32
	if !.ReadUint32(&) || !.ReadUint32(&) {
		return false
	}
	* = uint64()<<32 | uint64()
	return true
}

// readUint8LengthPrefixed acts like s.ReadUint8LengthPrefixed, but targets a
// []byte instead of a cryptobyte.String.
func readUint8LengthPrefixed( *cryptobyte.String,  *[]byte) bool {
	return .ReadUint8LengthPrefixed((*cryptobyte.String)())
}

// readUint16LengthPrefixed acts like s.ReadUint16LengthPrefixed, but targets a
// []byte instead of a cryptobyte.String.
func readUint16LengthPrefixed( *cryptobyte.String,  *[]byte) bool {
	return .ReadUint16LengthPrefixed((*cryptobyte.String)())
}

// readUint24LengthPrefixed acts like s.ReadUint24LengthPrefixed, but targets a
// []byte instead of a cryptobyte.String.
func readUint24LengthPrefixed( *cryptobyte.String,  *[]byte) bool {
	return .ReadUint24LengthPrefixed((*cryptobyte.String)())
}

type clientHelloMsg struct {
	raw                              []byte
	vers                             uint16
	random                           []byte
	sessionId                        []byte
	cipherSuites                     []uint16
	compressionMethods               []uint8
	serverName                       string
	ocspStapling                     bool
	supportedCurves                  []CurveID
	supportedPoints                  []uint8
	ticketSupported                  bool
	sessionTicket                    []uint8
	supportedSignatureAlgorithms     []SignatureScheme
	supportedSignatureAlgorithmsCert []SignatureScheme
	secureRenegotiationSupported     bool
	secureRenegotiation              []byte
	alpnProtocols                    []string
	scts                             bool
	supportedVersions                []uint16
	cookie                           []byte
	keyShares                        []keyShare
	earlyData                        bool
	pskModes                         []uint8
	pskIdentities                    []pskIdentity
	pskBinders                       [][]byte
}

func ( *clientHelloMsg) () []byte {
	if .raw != nil {
		return .raw
	}

	var  cryptobyte.Builder
	.AddUint8(typeClientHello)
	.AddUint24LengthPrefixed(func( *cryptobyte.Builder) {
		.AddUint16(.vers)
		addBytesWithLength(, .random, 32)
		.AddUint8LengthPrefixed(func( *cryptobyte.Builder) {
			.AddBytes(.sessionId)
		})
		.AddUint16LengthPrefixed(func( *cryptobyte.Builder) {
			for ,  := range .cipherSuites {
				.AddUint16()
			}
		})
		.AddUint8LengthPrefixed(func( *cryptobyte.Builder) {
			.AddBytes(.compressionMethods)
		})

		// If extensions aren't present, omit them.
		var  bool
		 := *

		.AddUint16LengthPrefixed(func( *cryptobyte.Builder) {
			if len(.serverName) > 0 {
				// RFC 6066, Section 3
				.AddUint16(extensionServerName)
				.AddUint16LengthPrefixed(func( *cryptobyte.Builder) {
					.AddUint16LengthPrefixed(func( *cryptobyte.Builder) {
						.AddUint8(0) // name_type = host_name
						.AddUint16LengthPrefixed(func( *cryptobyte.Builder) {
							.AddBytes([]byte(.serverName))
						})
					})
				})
			}
			if .ocspStapling {
				// RFC 4366, Section 3.6
				.AddUint16(extensionStatusRequest)
				.AddUint16LengthPrefixed(func( *cryptobyte.Builder) {
					.AddUint8(1)  // status_type = ocsp
					.AddUint16(0) // empty responder_id_list
					.AddUint16(0) // empty request_extensions
				})
			}
			if len(.supportedCurves) > 0 {
				// RFC 4492, sections 5.1.1 and RFC 8446, Section 4.2.7
				.AddUint16(extensionSupportedCurves)
				.AddUint16LengthPrefixed(func( *cryptobyte.Builder) {
					.AddUint16LengthPrefixed(func( *cryptobyte.Builder) {
						for ,  := range .supportedCurves {
							.AddUint16(uint16())
						}
					})
				})
			}
			if len(.supportedPoints) > 0 {
				// RFC 4492, Section 5.1.2
				.AddUint16(extensionSupportedPoints)
				.AddUint16LengthPrefixed(func( *cryptobyte.Builder) {
					.AddUint8LengthPrefixed(func( *cryptobyte.Builder) {
						.AddBytes(.supportedPoints)
					})
				})
			}
			if .ticketSupported {
				// RFC 5077, Section 3.2
				.AddUint16(extensionSessionTicket)
				.AddUint16LengthPrefixed(func( *cryptobyte.Builder) {
					.AddBytes(.sessionTicket)
				})
			}
			if len(.supportedSignatureAlgorithms) > 0 {
				// RFC 5246, Section 7.4.1.4.1
				.AddUint16(extensionSignatureAlgorithms)
				.AddUint16LengthPrefixed(func( *cryptobyte.Builder) {
					.AddUint16LengthPrefixed(func( *cryptobyte.Builder) {
						for ,  := range .supportedSignatureAlgorithms {
							.AddUint16(uint16())
						}
					})
				})
			}
			if len(.supportedSignatureAlgorithmsCert) > 0 {
				// RFC 8446, Section 4.2.3
				.AddUint16(extensionSignatureAlgorithmsCert)
				.AddUint16LengthPrefixed(func( *cryptobyte.Builder) {
					.AddUint16LengthPrefixed(func( *cryptobyte.Builder) {
						for ,  := range .supportedSignatureAlgorithmsCert {
							.AddUint16(uint16())
						}
					})
				})
			}
			if .secureRenegotiationSupported {
				// RFC 5746, Section 3.2
				.AddUint16(extensionRenegotiationInfo)
				.AddUint16LengthPrefixed(func( *cryptobyte.Builder) {
					.AddUint8LengthPrefixed(func( *cryptobyte.Builder) {
						.AddBytes(.secureRenegotiation)
					})
				})
			}
			if len(.alpnProtocols) > 0 {
				// RFC 7301, Section 3.1
				.AddUint16(extensionALPN)
				.AddUint16LengthPrefixed(func( *cryptobyte.Builder) {
					.AddUint16LengthPrefixed(func( *cryptobyte.Builder) {
						for ,  := range .alpnProtocols {
							.AddUint8LengthPrefixed(func( *cryptobyte.Builder) {
								.AddBytes([]byte())
							})
						}
					})
				})
			}
			if .scts {
				// RFC 6962, Section 3.3.1
				.AddUint16(extensionSCT)
				.AddUint16(0) // empty extension_data
			}
			if len(.supportedVersions) > 0 {
				// RFC 8446, Section 4.2.1
				.AddUint16(extensionSupportedVersions)
				.AddUint16LengthPrefixed(func( *cryptobyte.Builder) {
					.AddUint8LengthPrefixed(func( *cryptobyte.Builder) {
						for ,  := range .supportedVersions {
							.AddUint16()
						}
					})
				})
			}
			if len(.cookie) > 0 {
				// RFC 8446, Section 4.2.2
				.AddUint16(extensionCookie)
				.AddUint16LengthPrefixed(func( *cryptobyte.Builder) {
					.AddUint16LengthPrefixed(func( *cryptobyte.Builder) {
						.AddBytes(.cookie)
					})
				})
			}
			if len(.keyShares) > 0 {
				// RFC 8446, Section 4.2.8
				.AddUint16(extensionKeyShare)
				.AddUint16LengthPrefixed(func( *cryptobyte.Builder) {
					.AddUint16LengthPrefixed(func( *cryptobyte.Builder) {
						for ,  := range .keyShares {
							.AddUint16(uint16(.group))
							.AddUint16LengthPrefixed(func( *cryptobyte.Builder) {
								.AddBytes(.data)
							})
						}
					})
				})
			}
			if .earlyData {
				// RFC 8446, Section 4.2.10
				.AddUint16(extensionEarlyData)
				.AddUint16(0) // empty extension_data
			}
			if len(.pskModes) > 0 {
				// RFC 8446, Section 4.2.9
				.AddUint16(extensionPSKModes)
				.AddUint16LengthPrefixed(func( *cryptobyte.Builder) {
					.AddUint8LengthPrefixed(func( *cryptobyte.Builder) {
						.AddBytes(.pskModes)
					})
				})
			}
			if len(.pskIdentities) > 0 { // pre_shared_key must be the last extension
				// RFC 8446, Section 4.2.11
				.AddUint16(extensionPreSharedKey)
				.AddUint16LengthPrefixed(func( *cryptobyte.Builder) {
					.AddUint16LengthPrefixed(func( *cryptobyte.Builder) {
						for ,  := range .pskIdentities {
							.AddUint16LengthPrefixed(func( *cryptobyte.Builder) {
								.AddBytes(.label)
							})
							.AddUint32(.obfuscatedTicketAge)
						}
					})
					.AddUint16LengthPrefixed(func( *cryptobyte.Builder) {
						for ,  := range .pskBinders {
							.AddUint8LengthPrefixed(func( *cryptobyte.Builder) {
								.AddBytes()
							})
						}
					})
				})
			}

			 = len(.BytesOrPanic()) > 2
		})

		if ! {
			* = 
		}
	})

	.raw = .BytesOrPanic()
	return .raw
}

// marshalWithoutBinders returns the ClientHello through the
// PreSharedKeyExtension.identities field, according to RFC 8446, Section
// 4.2.11.2. Note that m.pskBinders must be set to slices of the correct length.
func ( *clientHelloMsg) () []byte {
	 := 2 // uint16 length prefix
	for ,  := range .pskBinders {
		 += 1 // uint8 length prefix
		 += len()
	}

	 := .marshal()
	return [:len()-]
}

// updateBinders updates the m.pskBinders field, if necessary updating the
// cached marshaled representation. The supplied binders must have the same
// length as the current m.pskBinders.
func ( *clientHelloMsg) ( [][]byte) {
	if len() != len(.pskBinders) {
		panic("tls: internal error: pskBinders length mismatch")
	}
	for  := range .pskBinders {
		if len([]) != len(.pskBinders[]) {
			panic("tls: internal error: pskBinders length mismatch")
		}
	}
	.pskBinders = 
	if .raw != nil {
		 := len(.marshalWithoutBinders())
		// TODO(filippo): replace with NewFixedBuilder once CL 148882 is imported.
		 := cryptobyte.NewBuilder(.raw[:])
		.AddUint16LengthPrefixed(func( *cryptobyte.Builder) {
			for ,  := range .pskBinders {
				.AddUint8LengthPrefixed(func( *cryptobyte.Builder) {
					.AddBytes()
				})
			}
		})
		if len(.BytesOrPanic()) != len(.raw) {
			panic("tls: internal error: failed to update binders")
		}
	}
}

func ( *clientHelloMsg) ( []byte) bool {
	* = clientHelloMsg{raw: }
	 := cryptobyte.String()

	if !.Skip(4) || // message type and uint24 length field
		!.ReadUint16(&.vers) || !.ReadBytes(&.random, 32) ||
		!readUint8LengthPrefixed(&, &.sessionId) {
		return false
	}

	var  cryptobyte.String
	if !.ReadUint16LengthPrefixed(&) {
		return false
	}
	.cipherSuites = []uint16{}
	.secureRenegotiationSupported = false
	for !.Empty() {
		var  uint16
		if !.ReadUint16(&) {
			return false
		}
		if  == scsvRenegotiation {
			.secureRenegotiationSupported = true
		}
		.cipherSuites = append(.cipherSuites, )
	}

	if !readUint8LengthPrefixed(&, &.compressionMethods) {
		return false
	}

	if .Empty() {
		// ClientHello is optionally followed by extension data
		return true
	}

	var  cryptobyte.String
	if !.ReadUint16LengthPrefixed(&) || !.Empty() {
		return false
	}

	for !.Empty() {
		var  uint16
		var  cryptobyte.String
		if !.ReadUint16(&) ||
			!.ReadUint16LengthPrefixed(&) {
			return false
		}

		switch  {
		case extensionServerName:
			// RFC 6066, Section 3
			var  cryptobyte.String
			if !.ReadUint16LengthPrefixed(&) || .Empty() {
				return false
			}
			for !.Empty() {
				var  uint8
				var  cryptobyte.String
				if !.ReadUint8(&) ||
					!.ReadUint16LengthPrefixed(&) ||
					.Empty() {
					return false
				}
				if  != 0 {
					continue
				}
				if len(.serverName) != 0 {
					// Multiple names of the same name_type are prohibited.
					return false
				}
				.serverName = string()
				// An SNI value may not include a trailing dot.
				if strings.HasSuffix(.serverName, ".") {
					return false
				}
			}
		case extensionStatusRequest:
			// RFC 4366, Section 3.6
			var  uint8
			var  cryptobyte.String
			if !.ReadUint8(&) ||
				!.ReadUint16LengthPrefixed(&) ||
				!.ReadUint16LengthPrefixed(&) {
				return false
			}
			.ocspStapling =  == statusTypeOCSP
		case extensionSupportedCurves:
			// RFC 4492, sections 5.1.1 and RFC 8446, Section 4.2.7
			var  cryptobyte.String
			if !.ReadUint16LengthPrefixed(&) || .Empty() {
				return false
			}
			for !.Empty() {
				var  uint16
				if !.ReadUint16(&) {
					return false
				}
				.supportedCurves = append(.supportedCurves, CurveID())
			}
		case extensionSupportedPoints:
			// RFC 4492, Section 5.1.2
			if !readUint8LengthPrefixed(&, &.supportedPoints) ||
				len(.supportedPoints) == 0 {
				return false
			}
		case extensionSessionTicket:
			// RFC 5077, Section 3.2
			.ticketSupported = true
			.ReadBytes(&.sessionTicket, len())
		case extensionSignatureAlgorithms:
			// RFC 5246, Section 7.4.1.4.1
			var  cryptobyte.String
			if !.ReadUint16LengthPrefixed(&) || .Empty() {
				return false
			}
			for !.Empty() {
				var  uint16
				if !.ReadUint16(&) {
					return false
				}
				.supportedSignatureAlgorithms = append(
					.supportedSignatureAlgorithms, SignatureScheme())
			}
		case extensionSignatureAlgorithmsCert:
			// RFC 8446, Section 4.2.3
			var  cryptobyte.String
			if !.ReadUint16LengthPrefixed(&) || .Empty() {
				return false
			}
			for !.Empty() {
				var  uint16
				if !.ReadUint16(&) {
					return false
				}
				.supportedSignatureAlgorithmsCert = append(
					.supportedSignatureAlgorithmsCert, SignatureScheme())
			}
		case extensionRenegotiationInfo:
			// RFC 5746, Section 3.2
			if !readUint8LengthPrefixed(&, &.secureRenegotiation) {
				return false
			}
			.secureRenegotiationSupported = true
		case extensionALPN:
			// RFC 7301, Section 3.1
			var  cryptobyte.String
			if !.ReadUint16LengthPrefixed(&) || .Empty() {
				return false
			}
			for !.Empty() {
				var  cryptobyte.String
				if !.ReadUint8LengthPrefixed(&) || .Empty() {
					return false
				}
				.alpnProtocols = append(.alpnProtocols, string())
			}
		case extensionSCT:
			// RFC 6962, Section 3.3.1
			.scts = true
		case extensionSupportedVersions:
			// RFC 8446, Section 4.2.1
			var  cryptobyte.String
			if !.ReadUint8LengthPrefixed(&) || .Empty() {
				return false
			}
			for !.Empty() {
				var  uint16
				if !.ReadUint16(&) {
					return false
				}
				.supportedVersions = append(.supportedVersions, )
			}
		case extensionCookie:
			// RFC 8446, Section 4.2.2
			if !readUint16LengthPrefixed(&, &.cookie) ||
				len(.cookie) == 0 {
				return false
			}
		case extensionKeyShare:
			// RFC 8446, Section 4.2.8
			var  cryptobyte.String
			if !.ReadUint16LengthPrefixed(&) {
				return false
			}
			for !.Empty() {
				var  keyShare
				if !.ReadUint16((*uint16)(&.group)) ||
					!readUint16LengthPrefixed(&, &.data) ||
					len(.data) == 0 {
					return false
				}
				.keyShares = append(.keyShares, )
			}
		case extensionEarlyData:
			// RFC 8446, Section 4.2.10
			.earlyData = true
		case extensionPSKModes:
			// RFC 8446, Section 4.2.9
			if !readUint8LengthPrefixed(&, &.pskModes) {
				return false
			}
		case extensionPreSharedKey:
			// RFC 8446, Section 4.2.11
			if !.Empty() {
				return false // pre_shared_key must be the last extension
			}
			var  cryptobyte.String
			if !.ReadUint16LengthPrefixed(&) || .Empty() {
				return false
			}
			for !.Empty() {
				var  pskIdentity
				if !readUint16LengthPrefixed(&, &.label) ||
					!.ReadUint32(&.obfuscatedTicketAge) ||
					len(.label) == 0 {
					return false
				}
				.pskIdentities = append(.pskIdentities, )
			}
			var  cryptobyte.String
			if !.ReadUint16LengthPrefixed(&) || .Empty() {
				return false
			}
			for !.Empty() {
				var  []byte
				if !readUint8LengthPrefixed(&, &) ||
					len() == 0 {
					return false
				}
				.pskBinders = append(.pskBinders, )
			}
		default:
			// Ignore unknown extensions.
			continue
		}

		if !.Empty() {
			return false
		}
	}

	return true
}

type serverHelloMsg struct {
	raw                          []byte
	vers                         uint16
	random                       []byte
	sessionId                    []byte
	cipherSuite                  uint16
	compressionMethod            uint8
	ocspStapling                 bool
	ticketSupported              bool
	secureRenegotiationSupported bool
	secureRenegotiation          []byte
	alpnProtocol                 string
	scts                         [][]byte
	supportedVersion             uint16
	serverShare                  keyShare
	selectedIdentityPresent      bool
	selectedIdentity             uint16
	supportedPoints              []uint8

	// HelloRetryRequest extensions
	cookie        []byte
	selectedGroup CurveID
}

func ( *serverHelloMsg) () []byte {
	if .raw != nil {
		return .raw
	}

	var  cryptobyte.Builder
	.AddUint8(typeServerHello)
	.AddUint24LengthPrefixed(func( *cryptobyte.Builder) {
		.AddUint16(.vers)
		addBytesWithLength(, .random, 32)
		.AddUint8LengthPrefixed(func( *cryptobyte.Builder) {
			.AddBytes(.sessionId)
		})
		.AddUint16(.cipherSuite)
		.AddUint8(.compressionMethod)

		// If extensions aren't present, omit them.
		var  bool
		 := *

		.AddUint16LengthPrefixed(func( *cryptobyte.Builder) {
			if .ocspStapling {
				.AddUint16(extensionStatusRequest)
				.AddUint16(0) // empty extension_data
			}
			if .ticketSupported {
				.AddUint16(extensionSessionTicket)
				.AddUint16(0) // empty extension_data
			}
			if .secureRenegotiationSupported {
				.AddUint16(extensionRenegotiationInfo)
				.AddUint16LengthPrefixed(func( *cryptobyte.Builder) {
					.AddUint8LengthPrefixed(func( *cryptobyte.Builder) {
						.AddBytes(.secureRenegotiation)
					})
				})
			}
			if len(.alpnProtocol) > 0 {
				.AddUint16(extensionALPN)
				.AddUint16LengthPrefixed(func( *cryptobyte.Builder) {
					.AddUint16LengthPrefixed(func( *cryptobyte.Builder) {
						.AddUint8LengthPrefixed(func( *cryptobyte.Builder) {
							.AddBytes([]byte(.alpnProtocol))
						})
					})
				})
			}
			if len(.scts) > 0 {
				.AddUint16(extensionSCT)
				.AddUint16LengthPrefixed(func( *cryptobyte.Builder) {
					.AddUint16LengthPrefixed(func( *cryptobyte.Builder) {
						for ,  := range .scts {
							.AddUint16LengthPrefixed(func( *cryptobyte.Builder) {
								.AddBytes()
							})
						}
					})
				})
			}
			if .supportedVersion != 0 {
				.AddUint16(extensionSupportedVersions)
				.AddUint16LengthPrefixed(func( *cryptobyte.Builder) {
					.AddUint16(.supportedVersion)
				})
			}
			if .serverShare.group != 0 {
				.AddUint16(extensionKeyShare)
				.AddUint16LengthPrefixed(func( *cryptobyte.Builder) {
					.AddUint16(uint16(.serverShare.group))
					.AddUint16LengthPrefixed(func( *cryptobyte.Builder) {
						.AddBytes(.serverShare.data)
					})
				})
			}
			if .selectedIdentityPresent {
				.AddUint16(extensionPreSharedKey)
				.AddUint16LengthPrefixed(func( *cryptobyte.Builder) {
					.AddUint16(.selectedIdentity)
				})
			}

			if len(.cookie) > 0 {
				.AddUint16(extensionCookie)
				.AddUint16LengthPrefixed(func( *cryptobyte.Builder) {
					.AddUint16LengthPrefixed(func( *cryptobyte.Builder) {
						.AddBytes(.cookie)
					})
				})
			}
			if .selectedGroup != 0 {
				.AddUint16(extensionKeyShare)
				.AddUint16LengthPrefixed(func( *cryptobyte.Builder) {
					.AddUint16(uint16(.selectedGroup))
				})
			}
			if len(.supportedPoints) > 0 {
				.AddUint16(extensionSupportedPoints)
				.AddUint16LengthPrefixed(func( *cryptobyte.Builder) {
					.AddUint8LengthPrefixed(func( *cryptobyte.Builder) {
						.AddBytes(.supportedPoints)
					})
				})
			}

			 = len(.BytesOrPanic()) > 2
		})

		if ! {
			* = 
		}
	})

	.raw = .BytesOrPanic()
	return .raw
}

func ( *serverHelloMsg) ( []byte) bool {
	* = serverHelloMsg{raw: }
	 := cryptobyte.String()

	if !.Skip(4) || // message type and uint24 length field
		!.ReadUint16(&.vers) || !.ReadBytes(&.random, 32) ||
		!readUint8LengthPrefixed(&, &.sessionId) ||
		!.ReadUint16(&.cipherSuite) ||
		!.ReadUint8(&.compressionMethod) {
		return false
	}

	if .Empty() {
		// ServerHello is optionally followed by extension data
		return true
	}

	var  cryptobyte.String
	if !.ReadUint16LengthPrefixed(&) || !.Empty() {
		return false
	}

	for !.Empty() {
		var  uint16
		var  cryptobyte.String
		if !.ReadUint16(&) ||
			!.ReadUint16LengthPrefixed(&) {
			return false
		}

		switch  {
		case extensionStatusRequest:
			.ocspStapling = true
		case extensionSessionTicket:
			.ticketSupported = true
		case extensionRenegotiationInfo:
			if !readUint8LengthPrefixed(&, &.secureRenegotiation) {
				return false
			}
			.secureRenegotiationSupported = true
		case extensionALPN:
			var  cryptobyte.String
			if !.ReadUint16LengthPrefixed(&) || .Empty() {
				return false
			}
			var  cryptobyte.String
			if !.ReadUint8LengthPrefixed(&) ||
				.Empty() || !.Empty() {
				return false
			}
			.alpnProtocol = string()
		case extensionSCT:
			var  cryptobyte.String
			if !.ReadUint16LengthPrefixed(&) || .Empty() {
				return false
			}
			for !.Empty() {
				var  []byte
				if !readUint16LengthPrefixed(&, &) ||
					len() == 0 {
					return false
				}
				.scts = append(.scts, )
			}
		case extensionSupportedVersions:
			if !.ReadUint16(&.supportedVersion) {
				return false
			}
		case extensionCookie:
			if !readUint16LengthPrefixed(&, &.cookie) ||
				len(.cookie) == 0 {
				return false
			}
		case extensionKeyShare:
			// This extension has different formats in SH and HRR, accept either
			// and let the handshake logic decide. See RFC 8446, Section 4.2.8.
			if len() == 2 {
				if !.ReadUint16((*uint16)(&.selectedGroup)) {
					return false
				}
			} else {
				if !.ReadUint16((*uint16)(&.serverShare.group)) ||
					!readUint16LengthPrefixed(&, &.serverShare.data) {
					return false
				}
			}
		case extensionPreSharedKey:
			.selectedIdentityPresent = true
			if !.ReadUint16(&.selectedIdentity) {
				return false
			}
		case extensionSupportedPoints:
			// RFC 4492, Section 5.1.2
			if !readUint8LengthPrefixed(&, &.supportedPoints) ||
				len(.supportedPoints) == 0 {
				return false
			}
		default:
			// Ignore unknown extensions.
			continue
		}

		if !.Empty() {
			return false
		}
	}

	return true
}

type encryptedExtensionsMsg struct {
	raw          []byte
	alpnProtocol string
}

func ( *encryptedExtensionsMsg) () []byte {
	if .raw != nil {
		return .raw
	}

	var  cryptobyte.Builder
	.AddUint8(typeEncryptedExtensions)
	.AddUint24LengthPrefixed(func( *cryptobyte.Builder) {
		.AddUint16LengthPrefixed(func( *cryptobyte.Builder) {
			if len(.alpnProtocol) > 0 {
				.AddUint16(extensionALPN)
				.AddUint16LengthPrefixed(func( *cryptobyte.Builder) {
					.AddUint16LengthPrefixed(func( *cryptobyte.Builder) {
						.AddUint8LengthPrefixed(func( *cryptobyte.Builder) {
							.AddBytes([]byte(.alpnProtocol))
						})
					})
				})
			}
		})
	})

	.raw = .BytesOrPanic()
	return .raw
}

func ( *encryptedExtensionsMsg) ( []byte) bool {
	* = encryptedExtensionsMsg{raw: }
	 := cryptobyte.String()

	var  cryptobyte.String
	if !.Skip(4) || // message type and uint24 length field
		!.ReadUint16LengthPrefixed(&) || !.Empty() {
		return false
	}

	for !.Empty() {
		var  uint16
		var  cryptobyte.String
		if !.ReadUint16(&) ||
			!.ReadUint16LengthPrefixed(&) {
			return false
		}

		switch  {
		case extensionALPN:
			var  cryptobyte.String
			if !.ReadUint16LengthPrefixed(&) || .Empty() {
				return false
			}
			var  cryptobyte.String
			if !.ReadUint8LengthPrefixed(&) ||
				.Empty() || !.Empty() {
				return false
			}
			.alpnProtocol = string()
		default:
			// Ignore unknown extensions.
			continue
		}

		if !.Empty() {
			return false
		}
	}

	return true
}

type endOfEarlyDataMsg struct{}

func ( *endOfEarlyDataMsg) () []byte {
	 := make([]byte, 4)
	[0] = typeEndOfEarlyData
	return 
}

func ( *endOfEarlyDataMsg) ( []byte) bool {
	return len() == 4
}

type keyUpdateMsg struct {
	raw             []byte
	updateRequested bool
}

func ( *keyUpdateMsg) () []byte {
	if .raw != nil {
		return .raw
	}

	var  cryptobyte.Builder
	.AddUint8(typeKeyUpdate)
	.AddUint24LengthPrefixed(func( *cryptobyte.Builder) {
		if .updateRequested {
			.AddUint8(1)
		} else {
			.AddUint8(0)
		}
	})

	.raw = .BytesOrPanic()
	return .raw
}

func ( *keyUpdateMsg) ( []byte) bool {
	.raw = 
	 := cryptobyte.String()

	var  uint8
	if !.Skip(4) || // message type and uint24 length field
		!.ReadUint8(&) || !.Empty() {
		return false
	}
	switch  {
	case 0:
		.updateRequested = false
	case 1:
		.updateRequested = true
	default:
		return false
	}
	return true
}

type newSessionTicketMsgTLS13 struct {
	raw          []byte
	lifetime     uint32
	ageAdd       uint32
	nonce        []byte
	label        []byte
	maxEarlyData uint32
}

func ( *newSessionTicketMsgTLS13) () []byte {
	if .raw != nil {
		return .raw
	}

	var  cryptobyte.Builder
	.AddUint8(typeNewSessionTicket)
	.AddUint24LengthPrefixed(func( *cryptobyte.Builder) {
		.AddUint32(.lifetime)
		.AddUint32(.ageAdd)
		.AddUint8LengthPrefixed(func( *cryptobyte.Builder) {
			.AddBytes(.nonce)
		})
		.AddUint16LengthPrefixed(func( *cryptobyte.Builder) {
			.AddBytes(.label)
		})

		.AddUint16LengthPrefixed(func( *cryptobyte.Builder) {
			if .maxEarlyData > 0 {
				.AddUint16(extensionEarlyData)
				.AddUint16LengthPrefixed(func( *cryptobyte.Builder) {
					.AddUint32(.maxEarlyData)
				})
			}
		})
	})

	.raw = .BytesOrPanic()
	return .raw
}

func ( *newSessionTicketMsgTLS13) ( []byte) bool {
	* = newSessionTicketMsgTLS13{raw: }
	 := cryptobyte.String()

	var  cryptobyte.String
	if !.Skip(4) || // message type and uint24 length field
		!.ReadUint32(&.lifetime) ||
		!.ReadUint32(&.ageAdd) ||
		!readUint8LengthPrefixed(&, &.nonce) ||
		!readUint16LengthPrefixed(&, &.label) ||
		!.ReadUint16LengthPrefixed(&) ||
		!.Empty() {
		return false
	}

	for !.Empty() {
		var  uint16
		var  cryptobyte.String
		if !.ReadUint16(&) ||
			!.ReadUint16LengthPrefixed(&) {
			return false
		}

		switch  {
		case extensionEarlyData:
			if !.ReadUint32(&.maxEarlyData) {
				return false
			}
		default:
			// Ignore unknown extensions.
			continue
		}

		if !.Empty() {
			return false
		}
	}

	return true
}

type certificateRequestMsgTLS13 struct {
	raw                              []byte
	ocspStapling                     bool
	scts                             bool
	supportedSignatureAlgorithms     []SignatureScheme
	supportedSignatureAlgorithmsCert []SignatureScheme
	certificateAuthorities           [][]byte
}

func ( *certificateRequestMsgTLS13) () []byte {
	if .raw != nil {
		return .raw
	}

	var  cryptobyte.Builder
	.AddUint8(typeCertificateRequest)
	.AddUint24LengthPrefixed(func( *cryptobyte.Builder) {
		// certificate_request_context (SHALL be zero length unless used for
		// post-handshake authentication)
		.AddUint8(0)

		.AddUint16LengthPrefixed(func( *cryptobyte.Builder) {
			if .ocspStapling {
				.AddUint16(extensionStatusRequest)
				.AddUint16(0) // empty extension_data
			}
			if .scts {
				// RFC 8446, Section 4.4.2.1 makes no mention of
				// signed_certificate_timestamp in CertificateRequest, but
				// "Extensions in the Certificate message from the client MUST
				// correspond to extensions in the CertificateRequest message
				// from the server." and it appears in the table in Section 4.2.
				.AddUint16(extensionSCT)
				.AddUint16(0) // empty extension_data
			}
			if len(.supportedSignatureAlgorithms) > 0 {
				.AddUint16(extensionSignatureAlgorithms)
				.AddUint16LengthPrefixed(func( *cryptobyte.Builder) {
					.AddUint16LengthPrefixed(func( *cryptobyte.Builder) {
						for ,  := range .supportedSignatureAlgorithms {
							.AddUint16(uint16())
						}
					})
				})
			}
			if len(.supportedSignatureAlgorithmsCert) > 0 {
				.AddUint16(extensionSignatureAlgorithmsCert)
				.AddUint16LengthPrefixed(func( *cryptobyte.Builder) {
					.AddUint16LengthPrefixed(func( *cryptobyte.Builder) {
						for ,  := range .supportedSignatureAlgorithmsCert {
							.AddUint16(uint16())
						}
					})
				})
			}
			if len(.certificateAuthorities) > 0 {
				.AddUint16(extensionCertificateAuthorities)
				.AddUint16LengthPrefixed(func( *cryptobyte.Builder) {
					.AddUint16LengthPrefixed(func( *cryptobyte.Builder) {
						for ,  := range .certificateAuthorities {
							.AddUint16LengthPrefixed(func( *cryptobyte.Builder) {
								.AddBytes()
							})
						}
					})
				})
			}
		})
	})

	.raw = .BytesOrPanic()
	return .raw
}

func ( *certificateRequestMsgTLS13) ( []byte) bool {
	* = certificateRequestMsgTLS13{raw: }
	 := cryptobyte.String()

	var ,  cryptobyte.String
	if !.Skip(4) || // message type and uint24 length field
		!.ReadUint8LengthPrefixed(&) || !.Empty() ||
		!.ReadUint16LengthPrefixed(&) ||
		!.Empty() {
		return false
	}

	for !.Empty() {
		var  uint16
		var  cryptobyte.String
		if !.ReadUint16(&) ||
			!.ReadUint16LengthPrefixed(&) {
			return false
		}

		switch  {
		case extensionStatusRequest:
			.ocspStapling = true
		case extensionSCT:
			.scts = true
		case extensionSignatureAlgorithms:
			var  cryptobyte.String
			if !.ReadUint16LengthPrefixed(&) || .Empty() {
				return false
			}
			for !.Empty() {
				var  uint16
				if !.ReadUint16(&) {
					return false
				}
				.supportedSignatureAlgorithms = append(
					.supportedSignatureAlgorithms, SignatureScheme())
			}
		case extensionSignatureAlgorithmsCert:
			var  cryptobyte.String
			if !.ReadUint16LengthPrefixed(&) || .Empty() {
				return false
			}
			for !.Empty() {
				var  uint16
				if !.ReadUint16(&) {
					return false
				}
				.supportedSignatureAlgorithmsCert = append(
					.supportedSignatureAlgorithmsCert, SignatureScheme())
			}
		case extensionCertificateAuthorities:
			var  cryptobyte.String
			if !.ReadUint16LengthPrefixed(&) || .Empty() {
				return false
			}
			for !.Empty() {
				var  []byte
				if !readUint16LengthPrefixed(&, &) || len() == 0 {
					return false
				}
				.certificateAuthorities = append(.certificateAuthorities, )
			}
		default:
			// Ignore unknown extensions.
			continue
		}

		if !.Empty() {
			return false
		}
	}

	return true
}

type certificateMsg struct {
	raw          []byte
	certificates [][]byte
}

func ( *certificateMsg) () ( []byte) {
	if .raw != nil {
		return .raw
	}

	var  int
	for ,  := range .certificates {
		 += len()
	}

	 := 3 + 3*len(.certificates) + 
	 = make([]byte, 4+)
	[0] = typeCertificate
	[1] = uint8( >> 16)
	[2] = uint8( >> 8)
	[3] = uint8()

	 :=  - 3
	[4] = uint8( >> 16)
	[5] = uint8( >> 8)
	[6] = uint8()

	 := [7:]
	for ,  := range .certificates {
		[0] = uint8(len() >> 16)
		[1] = uint8(len() >> 8)
		[2] = uint8(len())
		copy([3:], )
		 = [3+len():]
	}

	.raw = 
	return
}

func ( *certificateMsg) ( []byte) bool {
	if len() < 7 {
		return false
	}

	.raw = 
	 := uint32([4])<<16 | uint32([5])<<8 | uint32([6])
	if uint32(len()) != +7 {
		return false
	}

	 := 0
	 := [7:]
	for  > 0 {
		if len() < 4 {
			return false
		}
		 := uint32([0])<<16 | uint32([1])<<8 | uint32([2])
		if uint32(len()) < 3+ {
			return false
		}
		 = [3+:]
		 -= 3 + 
		++
	}

	.certificates = make([][]byte, )
	 = [7:]
	for  := 0;  < ; ++ {
		 := uint32([0])<<16 | uint32([1])<<8 | uint32([2])
		.certificates[] = [3 : 3+]
		 = [3+:]
	}

	return true
}

type certificateMsgTLS13 struct {
	raw          []byte
	certificate  Certificate
	ocspStapling bool
	scts         bool
}

func ( *certificateMsgTLS13) () []byte {
	if .raw != nil {
		return .raw
	}

	var  cryptobyte.Builder
	.AddUint8(typeCertificate)
	.AddUint24LengthPrefixed(func( *cryptobyte.Builder) {
		.AddUint8(0) // certificate_request_context

		 := .certificate
		if !.ocspStapling {
			.OCSPStaple = nil
		}
		if !.scts {
			.SignedCertificateTimestamps = nil
		}
		marshalCertificate(, )
	})

	.raw = .BytesOrPanic()
	return .raw
}

func marshalCertificate( *cryptobyte.Builder,  Certificate) {
	.AddUint24LengthPrefixed(func( *cryptobyte.Builder) {
		for ,  := range .Certificate {
			.AddUint24LengthPrefixed(func( *cryptobyte.Builder) {
				.AddBytes()
			})
			.AddUint16LengthPrefixed(func( *cryptobyte.Builder) {
				if  > 0 {
					// This library only supports OCSP and SCT for leaf certificates.
					return
				}
				if .OCSPStaple != nil {
					.AddUint16(extensionStatusRequest)
					.AddUint16LengthPrefixed(func( *cryptobyte.Builder) {
						.AddUint8(statusTypeOCSP)
						.AddUint24LengthPrefixed(func( *cryptobyte.Builder) {
							.AddBytes(.OCSPStaple)
						})
					})
				}
				if .SignedCertificateTimestamps != nil {
					.AddUint16(extensionSCT)
					.AddUint16LengthPrefixed(func( *cryptobyte.Builder) {
						.AddUint16LengthPrefixed(func( *cryptobyte.Builder) {
							for ,  := range .SignedCertificateTimestamps {
								.AddUint16LengthPrefixed(func( *cryptobyte.Builder) {
									.AddBytes()
								})
							}
						})
					})
				}
			})
		}
	})
}

func ( *certificateMsgTLS13) ( []byte) bool {
	* = certificateMsgTLS13{raw: }
	 := cryptobyte.String()

	var  cryptobyte.String
	if !.Skip(4) || // message type and uint24 length field
		!.ReadUint8LengthPrefixed(&) || !.Empty() ||
		!unmarshalCertificate(&, &.certificate) ||
		!.Empty() {
		return false
	}

	.scts = .certificate.SignedCertificateTimestamps != nil
	.ocspStapling = .certificate.OCSPStaple != nil

	return true
}

func unmarshalCertificate( *cryptobyte.String,  *Certificate) bool {
	var  cryptobyte.String
	if !.ReadUint24LengthPrefixed(&) {
		return false
	}
	for !.Empty() {
		var  []byte
		var  cryptobyte.String
		if !readUint24LengthPrefixed(&, &) ||
			!.ReadUint16LengthPrefixed(&) {
			return false
		}
		.Certificate = append(.Certificate, )
		for !.Empty() {
			var  uint16
			var  cryptobyte.String
			if !.ReadUint16(&) ||
				!.ReadUint16LengthPrefixed(&) {
				return false
			}
			if len(.Certificate) > 1 {
				// This library only supports OCSP and SCT for leaf certificates.
				continue
			}

			switch  {
			case extensionStatusRequest:
				var  uint8
				if !.ReadUint8(&) ||  != statusTypeOCSP ||
					!readUint24LengthPrefixed(&, &.OCSPStaple) ||
					len(.OCSPStaple) == 0 {
					return false
				}
			case extensionSCT:
				var  cryptobyte.String
				if !.ReadUint16LengthPrefixed(&) || .Empty() {
					return false
				}
				for !.Empty() {
					var  []byte
					if !readUint16LengthPrefixed(&, &) ||
						len() == 0 {
						return false
					}
					.SignedCertificateTimestamps = append(
						.SignedCertificateTimestamps, )
				}
			default:
				// Ignore unknown extensions.
				continue
			}

			if !.Empty() {
				return false
			}
		}
	}
	return true
}

type serverKeyExchangeMsg struct {
	raw []byte
	key []byte
}

func ( *serverKeyExchangeMsg) () []byte {
	if .raw != nil {
		return .raw
	}
	 := len(.key)
	 := make([]byte, +4)
	[0] = typeServerKeyExchange
	[1] = uint8( >> 16)
	[2] = uint8( >> 8)
	[3] = uint8()
	copy([4:], .key)

	.raw = 
	return 
}

func ( *serverKeyExchangeMsg) ( []byte) bool {
	.raw = 
	if len() < 4 {
		return false
	}
	.key = [4:]
	return true
}

type certificateStatusMsg struct {
	raw      []byte
	response []byte
}

func ( *certificateStatusMsg) () []byte {
	if .raw != nil {
		return .raw
	}

	var  cryptobyte.Builder
	.AddUint8(typeCertificateStatus)
	.AddUint24LengthPrefixed(func( *cryptobyte.Builder) {
		.AddUint8(statusTypeOCSP)
		.AddUint24LengthPrefixed(func( *cryptobyte.Builder) {
			.AddBytes(.response)
		})
	})

	.raw = .BytesOrPanic()
	return .raw
}

func ( *certificateStatusMsg) ( []byte) bool {
	.raw = 
	 := cryptobyte.String()

	var  uint8
	if !.Skip(4) || // message type and uint24 length field
		!.ReadUint8(&) ||  != statusTypeOCSP ||
		!readUint24LengthPrefixed(&, &.response) ||
		len(.response) == 0 || !.Empty() {
		return false
	}
	return true
}

type serverHelloDoneMsg struct{}

func ( *serverHelloDoneMsg) () []byte {
	 := make([]byte, 4)
	[0] = typeServerHelloDone
	return 
}

func ( *serverHelloDoneMsg) ( []byte) bool {
	return len() == 4
}

type clientKeyExchangeMsg struct {
	raw        []byte
	ciphertext []byte
}

func ( *clientKeyExchangeMsg) () []byte {
	if .raw != nil {
		return .raw
	}
	 := len(.ciphertext)
	 := make([]byte, +4)
	[0] = typeClientKeyExchange
	[1] = uint8( >> 16)
	[2] = uint8( >> 8)
	[3] = uint8()
	copy([4:], .ciphertext)

	.raw = 
	return 
}

func ( *clientKeyExchangeMsg) ( []byte) bool {
	.raw = 
	if len() < 4 {
		return false
	}
	 := int([1])<<16 | int([2])<<8 | int([3])
	if  != len()-4 {
		return false
	}
	.ciphertext = [4:]
	return true
}

type finishedMsg struct {
	raw        []byte
	verifyData []byte
}

func ( *finishedMsg) () []byte {
	if .raw != nil {
		return .raw
	}

	var  cryptobyte.Builder
	.AddUint8(typeFinished)
	.AddUint24LengthPrefixed(func( *cryptobyte.Builder) {
		.AddBytes(.verifyData)
	})

	.raw = .BytesOrPanic()
	return .raw
}

func ( *finishedMsg) ( []byte) bool {
	.raw = 
	 := cryptobyte.String()
	return .Skip(1) &&
		readUint24LengthPrefixed(&, &.verifyData) &&
		.Empty()
}

type certificateRequestMsg struct {
	raw []byte
	// hasSignatureAlgorithm indicates whether this message includes a list of
	// supported signature algorithms. This change was introduced with TLS 1.2.
	hasSignatureAlgorithm bool

	certificateTypes             []byte
	supportedSignatureAlgorithms []SignatureScheme
	certificateAuthorities       [][]byte
}

func ( *certificateRequestMsg) () ( []byte) {
	if .raw != nil {
		return .raw
	}

	// See RFC 4346, Section 7.4.4.
	 := 1 + len(.certificateTypes) + 2
	 := 0
	for ,  := range .certificateAuthorities {
		 += 2 + len()
	}
	 += 

	if .hasSignatureAlgorithm {
		 += 2 + 2*len(.supportedSignatureAlgorithms)
	}

	 = make([]byte, 4+)
	[0] = typeCertificateRequest
	[1] = uint8( >> 16)
	[2] = uint8( >> 8)
	[3] = uint8()

	[4] = uint8(len(.certificateTypes))

	copy([5:], .certificateTypes)
	 := [5+len(.certificateTypes):]

	if .hasSignatureAlgorithm {
		 := len(.supportedSignatureAlgorithms) * 2
		[0] = uint8( >> 8)
		[1] = uint8()
		 = [2:]
		for ,  := range .supportedSignatureAlgorithms {
			[0] = uint8( >> 8)
			[1] = uint8()
			 = [2:]
		}
	}

	[0] = uint8( >> 8)
	[1] = uint8()
	 = [2:]
	for ,  := range .certificateAuthorities {
		[0] = uint8(len() >> 8)
		[1] = uint8(len())
		 = [2:]
		copy(, )
		 = [len():]
	}

	.raw = 
	return
}

func ( *certificateRequestMsg) ( []byte) bool {
	.raw = 

	if len() < 5 {
		return false
	}

	 := uint32([1])<<16 | uint32([2])<<8 | uint32([3])
	if uint32(len())-4 !=  {
		return false
	}

	 := int([4])
	 = [5:]
	if  == 0 || len() <=  {
		return false
	}

	.certificateTypes = make([]byte, )
	if copy(.certificateTypes, ) !=  {
		return false
	}

	 = [:]

	if .hasSignatureAlgorithm {
		if len() < 2 {
			return false
		}
		 := uint16([0])<<8 | uint16([1])
		 = [2:]
		if &1 != 0 {
			return false
		}
		if len() < int() {
			return false
		}
		 :=  / 2
		.supportedSignatureAlgorithms = make([]SignatureScheme, )
		for  := range .supportedSignatureAlgorithms {
			.supportedSignatureAlgorithms[] = SignatureScheme([0])<<8 | SignatureScheme([1])
			 = [2:]
		}
	}

	if len() < 2 {
		return false
	}
	 := uint16([0])<<8 | uint16([1])
	 = [2:]
	if len() < int() {
		return false
	}
	 := make([]byte, )
	copy(, )
	 = [:]

	.certificateAuthorities = nil
	for len() > 0 {
		if len() < 2 {
			return false
		}
		 := uint16([0])<<8 | uint16([1])
		 = [2:]

		if len() < int() {
			return false
		}

		.certificateAuthorities = append(.certificateAuthorities, [:])
		 = [:]
	}

	return len() == 0
}

type certificateVerifyMsg struct {
	raw                   []byte
	hasSignatureAlgorithm bool // format change introduced in TLS 1.2
	signatureAlgorithm    SignatureScheme
	signature             []byte
}

func ( *certificateVerifyMsg) () ( []byte) {
	if .raw != nil {
		return .raw
	}

	var  cryptobyte.Builder
	.AddUint8(typeCertificateVerify)
	.AddUint24LengthPrefixed(func( *cryptobyte.Builder) {
		if .hasSignatureAlgorithm {
			.AddUint16(uint16(.signatureAlgorithm))
		}
		.AddUint16LengthPrefixed(func( *cryptobyte.Builder) {
			.AddBytes(.signature)
		})
	})

	.raw = .BytesOrPanic()
	return .raw
}

func ( *certificateVerifyMsg) ( []byte) bool {
	.raw = 
	 := cryptobyte.String()

	if !.Skip(4) { // message type and uint24 length field
		return false
	}
	if .hasSignatureAlgorithm {
		if !.ReadUint16((*uint16)(&.signatureAlgorithm)) {
			return false
		}
	}
	return readUint16LengthPrefixed(&, &.signature) && .Empty()
}

type newSessionTicketMsg struct {
	raw    []byte
	ticket []byte
}

func ( *newSessionTicketMsg) () ( []byte) {
	if .raw != nil {
		return .raw
	}

	// See RFC 5077, Section 3.3.
	 := len(.ticket)
	 := 2 + 4 + 
	 = make([]byte, 4+)
	[0] = typeNewSessionTicket
	[1] = uint8( >> 16)
	[2] = uint8( >> 8)
	[3] = uint8()
	[8] = uint8( >> 8)
	[9] = uint8()
	copy([10:], .ticket)

	.raw = 

	return
}

func ( *newSessionTicketMsg) ( []byte) bool {
	.raw = 

	if len() < 10 {
		return false
	}

	 := uint32([1])<<16 | uint32([2])<<8 | uint32([3])
	if uint32(len())-4 !=  {
		return false
	}

	 := int([8])<<8 + int([9])
	if len()-10 !=  {
		return false
	}

	.ticket = [10:]

	return true
}

type helloRequestMsg struct {
}

func (*helloRequestMsg) () []byte {
	return []byte{typeHelloRequest, 0, 0, 0}
}

func (*helloRequestMsg) ( []byte) bool {
	return len() == 4
}