package
4.3.0-stable+incompatible
Repository: https://github.com/algorand/go-algorand.git
Documentation: pkg.go.dev

# README

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 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.


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)

OffsetDescription
0Presence flags for optional values (LSB first, see table).
1Reserved, currently zero.

2.1 Bit‑mask layout (byte 0)

BitFlagField enabledEncoded size
0bitPerr.per (varuint)1 - 9 bytes
1bitDigr.prop.dig (digest)32 bytes
2bitEncDigr.prop.encdig (digest)32 bytes
3bitOperr.prop.oper (varuint)1 - 9 bytes
4bitOpropr.prop.oprop (address)32 bytes
5bitStepr.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:

FieldTypeEncoded sizePresence flag
pfVRF credential80 bytesRequired
r.perPeriodvaruintbitPer
r.prop.digProposal digest32 bytesbitDig
r.prop.encdigDigest of encoded proposal32 bytesbitEncDig
r.prop.operProposal's original periodvaruintbitOper
r.prop.opropProposal's original proposer32 bytesbitOprop
r.rndRound numbervaruintRequired
r.sndVoter's (sender) address32 bytesRequired
r.stepStepvaruintbitStep
sig.pEd25519 public key32 bytesRequired
sig.p1sSignature over offset ID64 bytesRequired
sig.p2Second-tier Ed25519 public key32 bytesRequired
sig.p2sSignature over batch ID64 bytesRequired
sig.sSignature over vote using p64 bytesRequired