# Stateless *vpack* wire format

This document specifies the byte‑level (on‑wire) layout produced by `StatelessEncoder.CompressVote` and accepted by `StatelessDecoder.DecompressVote`.
The goal is to minimize vote size while retaining a 1‑to‑1, loss‑free mapping to the canonical msgpack representation of `agreement.UnauthenticatedVote`.
The canonical msgpack representation we rely on is provided by agreement/msgp_gen.go, generated by our [custom msgpack code generator](https://github.com/algorand/msgp)
which ensures fields are generated in lexicographic order, omit empty key-value pairs, and use specific formats for certain types as defined in
[our specification](https://github.com/algorandfoundation/specs/blob/c0331123148971e4705f25b9c937cb23e5ee28d1/dev/crypto.md#L22-L40).

---

## 1. High‑level structure

```
+---------+-----------------+---------------------+--------------------------+
| Header  | VrfProof ("pf") | rawVote ("r")       | OneTimeSignature ("sig") |
| 2 bytes | 80 bytes        | variable length     | 256 bytes                |
+---------+-----------------+---------------------+--------------------------+
```

All fields appear exactly once, and in the fixed order above. The presence of optional sub‑fields inside `rawVote` are indicated by a 1‑byte bitmask in the header.
No field names appear, only values.

---

## 2. Header (2 bytes)

| Offset | Description                                                    |
| ------ | -------------------------------------------------------------- |
| `0`    | Presence flags for optional values (LSB first, see table).     |
| `1`    | Reserved, currently zero.                                      |

### 2.1 Bit‑mask layout (byte 0)

| Bit | Flag        | Field enabled                    | Encoded size |
| --- | ----------- | -------------------------------- | ------------ |
| 0   | `bitPer`    | `r.per` (varuint)                | 1 - 9 bytes  |
| 1   | `bitDig`    | `r.prop.dig` (digest)            | 32 bytes     |
| 2   | `bitEncDig` | `r.prop.encdig` (digest)         | 32 bytes     |
| 3   | `bitOper`   | `r.prop.oper` (varuint)          | 1 - 9 bytes  |
| 4   | `bitOprop`  | `r.prop.oprop` (address)         | 32 bytes     |
| 5   | `bitStep`   | `r.step` (varuint)               | 1 - 9 bytes  |

Binary fields are represented by their 32-, 64-, and 80-byte values without markers.
Integers use msgpack's variable-length unsigned integer encoding:
- `fixint` (≤ 127), 1 byte in length (values 0x00-0x7f)
- `uint8` 2 bytes in length (marker byte 0xcc + 1-byte value)
- `uint16` 3 bytes in length (marker byte 0xcd + 2-byte value)
- `uint32` 5 bytes in length (marker byte 0xce + 4-byte value)
- `uint64` 9 bytes in length (marker byte 0xcf + 8-byte value)

---

## 3. Field serialization order

After the 2-byte header, the encoder emits values in the following order:

| Field          | Type                           | Encoded size | Presence flag |
| -------------- | ------------------------------ | ------------ | ------------- |
| `pf`           | VRF credential                 | 80 bytes     | Required      |
| `r.per`        | Period                         | varuint      | `bitPer`      |
| `r.prop.dig`   | Proposal digest                | 32 bytes     | `bitDig`      |
| `r.prop.encdig`| Digest of encoded proposal     | 32 bytes     | `bitEncDig`   |
| `r.prop.oper`  | Proposal's original period     | varuint      | `bitOper`     |
| `r.prop.oprop` | Proposal's original proposer   | 32 bytes     | `bitOprop`    |
| `r.rnd`        | Round number                   | varuint      | Required      |
| `r.snd`        | Voter's (sender) address       | 32 bytes     | Required      |
| `r.step`       | Step                           | varuint      | `bitStep`     |
| `sig.p`        | Ed25519 public key             | 32 bytes     | Required      |
| `sig.p1s`      | Signature over offset ID       | 64 bytes     | Required      |
| `sig.p2`       | Second-tier Ed25519 public key | 32 bytes     | Required      |
| `sig.p2s`      | Signature over batch ID        | 64 bytes     | Required      |
| `sig.s`        | Signature over vote using `p`  | 64 bytes     | Required      |
