# flare.quic.packet

> A module of flare_mlake's API.

QUIC v1 packet header codec (RFC 9000 §17).

QUIC packets come in two flavours:

- **Long header** (§17.2) — used during the handshake (Initial,
  0-RTT, Handshake, Retry). Carries the QUIC version and both
  Destination + Source Connection IDs explicitly.
- **Short header** (§17.3) — used after the handshake (1-RTT).
  Carries only the Destination Connection ID; the receiver
  already knows the SCID by virtue of the prior handshake.

This module parses the *public* (unprotected) parts of these
headers: the first byte's flag bits, the version, and the
connection IDs. The packet number and the length-prefixed
payload live inside header-protection-protected bytes that
require key material to access; that decryption layer is the
job of a later cycle's TLS adapter.

Connection IDs are 0..20 octet identifiers (§5.1.1). The long
header explicitly carries a length byte for each CID; the short
header relies on the receiver knowing the DCID length out of
band (typically pinned at handshake time).

References:
- RFC 9000 §17 "Packet Formats".
- RFC 9000 §5.1 "Connection IDs".
- aioquic ``packet.PullQuicHeader`` / ``packet.encode_quic_header``.

## Structs

### `ConnectionId`

```mojo
struct ConnectionId
```

A QUIC connection identifier (0..20 octets per §5.1.1).

Implements: `Copyable`, `Movable`

Fields:

- `bytes: List[UInt8]`

#### `length`

```mojo
def length(self) -> Int
```

#### `copy`

```mojo
def copy(self) -> Self
```

Return a deep copy of this CID (so callers can move the original into a parent struct without invalidating downstream references).

### `LongHeader`

```mojo
struct LongHeader
```

Parsed long-header fields.

The ``payload_offset`` is the byte index inside the original
buffer where the (still encrypted) packet payload begins.
Callers that decrypt header protection use this offset as the
starting point. For version negotiation packets the
``packet_type`` field is irrelevant and the payload is the
list of supported versions; the parser leaves it on the caller
to inspect ``version == QUIC_VERSION_NEGOTIATION``.

Implements: `Copyable`, `Movable`

Fields:

- `packet_type: Int`
- `version: UInt32`
- `dcid: ConnectionId`
- `scid: ConnectionId`
- `payload_offset: Int`

### `InitialExtras`

```mojo
struct InitialExtras
```

Initial-specific extras that follow the long-header common prefix (§17.2.2): a length-prefixed token, then a varint declaring the protected payload length.

Implements: `Copyable`, `Movable`

Fields:

- `token: List[UInt8]`
- `payload_length: UInt64`
- `consumed: Int`

### `ShortHeader`

```mojo
struct ShortHeader
```

Parsed short-header (1-RTT) public fields.

The DCID length is *not* on the wire; the caller passes it
in (typically pinned at handshake time). The ``key_phase``
bit is exposed because callers track key updates per
connection.

Implements: `Copyable`, `Movable`

Fields:

- `spin_bit: Bool`
- `key_phase: Bool`
- `dcid: ConnectionId`
- `payload_offset: Int`

## Functions

### `parse_long_header`

```mojo
def parse_long_header(buf: Span[UInt8]) -> LongHeader
```

Parse a long-header packet's public fields.

The first byte's high two bits must be 0b11 (long header
indicator). The next two bits carry the packet type. Bits
0-3 are version-specific (reserved + packet-number length in
QUIC v1, but those are header-protected and not parsed here).

Then a 32-bit version, length-prefixed DCID, length-prefixed
SCID. Initial-specific token + length parsing is split into
:func:`parse_initial_extras` because Retry/Handshake/0-RTT
packets share the same prefix but diverge from here.

### `parse_initial_extras`

```mojo
def parse_initial_extras(buf: Span[UInt8], offset: Int) -> InitialExtras
```

Parse the Initial-specific token + length fields starting at ``offset`` (typically the ``payload_offset`` returned by :func:`parse_long_header` for a packet whose type is Initial).

### `parse_short_header`

```mojo
def parse_short_header(buf: Span[UInt8], dcid_length: Int) -> ShortHeader
```

Parse a short-header (1-RTT) packet's public fields.

The first byte's high two bits must be 0b01 (short header
indicator + fixed bit). Bit 5 is the spin bit (§17.4); bits
3-4 are reserved + key-phase, but the key-phase bit (bit 2)
is header-protected, so callers that need it must apply
header protection first. The parser exposes ``key_phase`` as
a raw bit read for callers that have already deprotected.

### `packet_number_length`

```mojo
def packet_number_length(pn: UInt64, largest_acked: UInt64, any_acked: Bool) -> Int
```

Bytes needed to encode ``pn`` so the peer can recover it (RFC 9000 sec 17.1, appendix A.2): enough bits for twice the distance from the largest acknowledged packet, at least 2 bytes, at most 4.

### `encode_long_header`

```mojo
def encode_long_header(packet_type: Int, version: UInt32, dcid: ConnectionId, scid: ConnectionId, type_specific_bits: Int = Int(0)) -> List[UInt8]
```

Encode the long-header public prefix.

``type_specific_bits`` populates the low 4 bits of the first
byte. For QUIC v1 those bits are reserved bits 2-3 + the
encoded packet-number length in bits 0-1 (a 2-bit value, one
less than the actual length). The caller computes these bits;
the encoder just writes them.

### `encode_short_header`

```mojo
def encode_short_header(dcid: ConnectionId, spin_bit: Bool, key_phase: Bool, pn_length: Int = Int(1)) -> List[UInt8]
```

Encode the short-header public prefix.

``pn_length`` is the encoded packet-number length (1..4);
this is the value the receiver would observe *after* header
protection is removed. The encoder writes it into bits 0-1
(value minus one). Header protection itself is the caller's
job after this prefix is emitted.

### `encode_short_header_into`

```mojo
def encode_short_header_into(dcid: ConnectionId, spin_bit: Bool, key_phase: Bool, pn_length: Int, mut out: List[UInt8])
```

Append the short-header public prefix to ``out``; see :func:`encode_short_header`.

## Aliases

### `QUIC_VERSION_1`

```mojo
comptime QUIC_VERSION_1 = UInt32(1)
```

RFC 9000's "version 1" wire constant. Returned by the parser when the long header carries the standard QUIC v1 version.

### `QUIC_VERSION_NEGOTIATION`

```mojo
comptime QUIC_VERSION_NEGOTIATION = UInt32(0)
```

Version negotiation packets (RFC 9000 §17.2.1) carry version=0 in the long header. The parser exposes this constant so callers can detect VN packets cleanly without magic numbers.

### `PACKET_TYPE_INITIAL`

```mojo
comptime PACKET_TYPE_INITIAL = Int(0)
```

### `PACKET_TYPE_ZERO_RTT`

```mojo
comptime PACKET_TYPE_ZERO_RTT = Int(1)
```

### `PACKET_TYPE_HANDSHAKE`

```mojo
comptime PACKET_TYPE_HANDSHAKE = Int(2)
```

### `PACKET_TYPE_RETRY`

```mojo
comptime PACKET_TYPE_RETRY = Int(3)
```

Long-header packet types (§17.2). The two-bit ``T T`` field in bits 4-5 of the first byte selects one of these four values.

### `MAX_CID_LENGTH`

```mojo
comptime MAX_CID_LENGTH = Int(20)
```

Maximum Connection ID length (§5.1.1). Receivers that observe a CID length greater than 20 octets must reject the packet at the codec boundary.
