encoding specification

how bytes map to tower field elements and back. this encoding is shared by every system that moves data across the byte/field boundary.

bytes to tower elements

F₂⁸ (byte-aligned)

each byte maps directly to one F₂⁸ element. the byte's bit layout matches the tower representation:

byte b = [b₇ b₆ b₅ b₄ b₃ b₂ b₁ b₀]

F₂⁸ element = b₀ + b₁·x₀ + b₂·x₁ + b₃·x₁x₀ + b₄·x₂ + b₅·x₂x₀ + b₆·x₂x₁ + b₇·x₂x₁x₀

tower decomposition:
  lo = F₂⁴(b & 0x0F)     // lower nibble
  hi = F₂⁴(b >> 4)       // upper nibble
  element = lo + hi * x₂   // in F₂⁴[x₂]/(x₂² + x₂ + alpha)

no conversion needed. bytes are F₂⁸ elements. the identity encoding.

F₂¹⁶ (2 bytes)

two bytes in little-endian order map to one F₂¹⁶ element:

bytes [b₀, b₁]:
  element = F₂¹⁶(b₀ as u16 | (b₁ as u16) << 8)
  lo = F₂⁸(b₀)
  hi = F₂⁸(b₁)

F₂¹²⁸ (16 bytes)

sixteen bytes in little-endian order map to one F₂¹²⁸ element:

bytes [b₀, b₁, ..., b₁₅]:
  element = F₂¹²⁸(b₀ | b₁<<8 | b₂<<16 | ... | b₁₅<<120)

equivalent to u128::from_le_bytes([b₀, ..., b₁₅]).

tower elements to bytes

canonical representation

every tower element has exactly one canonical byte representation: the little-endian encoding of its integer representation.

F₂⁸(v)   -> [v]                              1 byte
F₂¹⁶(v)  -> [v & 0xFF, v >> 8]              2 bytes
F₂³²(v)  -> v.to_le_bytes()                  4 bytes
F₂⁶⁴(v)  -> v.to_le_bytes()                  8 bytes
F₂¹²⁸(v) -> v.to_le_bytes()                 16 bytes

sub-byte elements

F₂, F₂², and F₂⁴ are smaller than one byte. they are encoded in the low bits of a single byte with high bits zeroed:

F₂(v)   -> [v & 0x01]     1 byte, bits [1:8) = 0
F₂²(v)  -> [v & 0x03]     1 byte, bits [2:8) = 0
F₂⁴(v)  -> [v & 0x0F]     1 byte, bits [4:8) = 0

this matches the repr(transparent) struct layout in Rust: the element's u8 is the canonical byte.

encoding table

field element bytes total bytes encoding
F₂ 1 (padded) 1 bit 0 of byte
F₂² 1 (padded) 1 bits 0-1 of byte
F₂⁴ 1 (padded) 1 bits 0-3 of byte
F₂⁸ 1 1 identity
F₂¹⁶ 2 2 little-endian u16
F₂³² 4 4 little-endian u32
F₂⁶⁴ 8 8 little-endian u64
F₂¹²⁸ 16 16 little-endian u128

bulk encoding

for absorbing arbitrary byte streams into tower field elements:

encode_stream(bytes) -> Vec<F₂¹²⁸>:
  // pad to multiple of 16 bytes with zeros
  padded = bytes ++ [0; 16 - (len % 16)]
  for each 16-byte chunk:
    elements.push(F₂¹²⁸(u128::from_le_bytes(chunk)))

rate: 16 bytes per F₂¹²⁸ element. no conditional reduction needed (every 128-bit value is a valid field element). this is unlike prime field encoding where overflow checking is required.

comparison with nebu encoding

property nebu (Goldilocks) kuro (F₂ tower)
input width 7 bytes per element 16 bytes per element
overflow check not needed (7 < 8 byte prime) not needed (all 2^128 values valid)
output width 8 bytes per element 16 bytes per element
asymmetry yes (7 in, 8 out) no (16 in, 16 out)
padding zero-pad last chunk zero-pad last chunk

kuro has a simpler encoding story: every bit pattern is a valid element. no reduction, no conditional branches, no constant-time concerns from encoding.

see also

  • field -- field element definitions
  • vectors -- encoding test vectors

Dimensions

encoding
jali/specs/encoding
encoding — RingElement serialization how ring elements are serialized to bytes and deserialized back. two forms exist: coefficient encoding and NTT encoding. coefficient form encoding a RingElement in coefficient form is n Goldilocks field elements. each coefficient is 8 bytes little-endian: total…
genies/specs/encoding
encoding serialization formats for genies types. F_q element an element x in F_q is serialized as 64 bytes, little-endian. each x_i is a 64-bit limb stored in little-endian byte order. the value x must satisfy 0 <= x < q. **canonical form**: on deserialization, reject if the decoded value >= q.…
nox/specs/encoding
noun encoding specification version: 0.3 status: canonical overview this document specifies three encoding layers for nox nouns: 1. **storage encoding** — canonical binary serialization of individual nouns 2. **content-addressed identity** — how noun identity is derived from encoded content 3.…
trop/specs/encoding
F_p encoding how tropical elements and matrices are represented over the Goldilocks field F_p (p = 2⁶⁴ - 2³² + 1). element encoding a tropical element is a single F_p value with the following interpretation: | F_p value | tropical meaning | |-----------|-----------------| | 0 | tropical…
hemera/specs/encoding
encoding specification Input Encoding (Bytes → Field Elements) Pack input bytes into 7-byte little-endian chunks. Each 7-byte chunk is zero-extended to 8 bytes and interpreted as a u64 in little-endian order, producing one Goldilocks field element. Why 7 bytes, not 8: The maximum 7-byte value is…
nebu/specs/encoding
encoding specification how bytes map to field elements and back. this encoding is shared by every system that moves data across the byte↔field boundary. bytes to field elements input bytes are packed into field elements using 7-byte little-endian chunks. the maximum 7-byte value is 2⁵⁶ − 1 =…

Local Graph