Skip to content

Sync Aggregator SMT bit ordering with Yellowpaper big-endian bit strings #169

Description

@ristik

Summary

The Yellowpaper RSMT/RSMST specification now defines keys, regions, and inclusion bitmaps using big-endian bit-string notation:

  • SMT keys are 32-byte values read as 256-bit big-endian bit strings.
  • Depth d addresses bit d of that big-endian bit string.
  • rsmt_sort_key(k) = k; ordinary unsigned lexicographic byte order is the tree traversal order.
  • Inclusion certificate bitmaps are 256-bit big-endian bit vectors.
  • Regions are packed as 256-bit big-endian bit strings: the first d bits are the key prefix and the suffix is zero.

The Go Aggregator still has explicit LSB-in-byte assumptions in the SMT implementation, proof verification, sharding prefix checks, and disk SMT encoding. Update the implementation and tests to match the spec.

Why

The change should make Go follow the natural bit order used by ordinary byte comparisons and big-endian bit-string notation.

Current Hotspots

Likely places that need changes:

  • pkg/api/state_id.go

    • PathToFixedBytes and FixedBytesToPath currently reverse byte order for an LSB-first SMT key layout.
    • Comments explicitly say key bit d is bit (d%8) of key[d/8].
  • pkg/api/state_id_bitorder_test.go

    • Tests pin LSB-first semantics (TestFixedBytesToPath_UsesLSBFirstBitAddressing, RoundtripLSBFirst).
  • pkg/api/inclusion_cert.go

    • verifyBitmapPath tests bitmap bits using (bitmap[d/8] >> (d%8)) & 1.
    • keyBitAt uses LSB-in-byte.
    • RegionFromKeyBytes packs prefixes by copying low-order bits in each byte and masking with (1 << rem) - 1.
    • Comments mention LSB-first layout.
  • pkg/api/inclusion_cert_compose.go

    • bitmapDepthRange uses LSB-in-byte bitmap indexing.
  • pkg/api/smt.go

    • RegionFromPathBits packs path.Bit(i) into region[i/8] |= 1 << (i % 8).
    • Comments describe v6a region bits as LSB-in-byte.
  • pkg/api/shard_match.go

    • MatchesShardPrefix checks LSB-first key bits and reads expected shard bits from the low bits of shardBitmask.
    • This should be reconciled with the spec's shard-prefix interpretation.
  • internal/smt/smt.go

    • populate sets region bits with rightRegion[depth/8] |= 1 << (depth % 8).
    • Parent-mode shard tree construction depends on this bit convention.
  • internal/smt/disk/hash.go

    • HashNode comment says region is packed LSB-in-byte.
    • RegionFromKey and KeyBit use LSB-in-byte.
  • internal/smt/disk/path.go

    • CompressedPath construction, BitAt, and unused-bit canonicalization use LSB-in-byte packing.
  • internal/smt/disk/node_key.go

    • clearUnusedPrefixBits masks unused bits as if prefix bits are LSB-in-byte.
    • Persisted node keys include prefix bytes, so this affects disk compatibility and migration decisions.
  • internal/smt/disk/persist/tree.go

    • Inclusion certificate generation sets bitmap bits with 1 << (depth % 8).
    • setPrefixBit uses LSB-in-byte prefix packing.
  • Test/vector files

    • internal/smt/golden_vectors_test.go
    • internal/smt/v6a_interop_vectors_test.go
    • internal/smt/yellowpaper_hash_semantics_test.go
    • pkg/api/inclusion_cert_test.go
    • internal/smt/disk/*_test.go
    • Any golden roots or certificates generated under the old convention must be regenerated or explicitly marked legacy.

Implementation Notes

Prefer introducing small shared helpers instead of repeating shifts everywhere:

  • KeyBit(key []byte, d int) byte: return (key[d/8] >> (7 - uint(d%8))) & 1
  • SetBitBE(bits []byte, d int): bits[d/8] |= 0x80 >> uint(d%8)
  • ClearSuffixBE(prefix []byte, bitLen int) for region/bitmap/path canonicalization.
  • RegionFromKeyBytes(key []byte, depth int) should copy the prefix bytes and keep the high depth % 8 bits in the boundary byte.

For non-byte-aligned prefixes, the old LSB mask (1 << rem) - 1 becomes a high-bit mask, e.g. 0xff << (8 - rem) when rem != 0.

Migration / Compatibility

Changing bit order changes:

  • SMT root hashes.
  • Inclusion certificate bitmap bytes.
  • Internal-node region bytes, hence node hashes.
  • Shard routing and split behavior.
  • Persisted disk SMT node keys and stored roots.
  • Existing golden vectors.

No backwards compatibility needed. Old-format disk-backed SMT data can be deleted.

Acceptance Criteria

  • All SMT key-bit access, bitmap access, region packing, and prefix packing in Aggregator use big-endian bit-string semantics.
  • FixedBytesToPath / PathToFixedBytes round-trip without reversing the 32-byte key order relative to spec key bytes.
  • Inclusion certificate verification and generation use big-endian bitmap bits.
  • RSMT node hashes match the updated Yellowpaper region packing.
  • Batch/traversal ordering is ordinary unsigned lexicographic byte order (rsmt_sort_key(k)=k).
  • Shard-prefix matching and shard split/parent proof logic are aligned with the same bit convention.
  • Disk SMT metadata/versioning prevents old-layout persisted data from being silently interpreted as new-layout data.
  • Tests cover boundary depths: 0, 1, 7, 8, 200, 255.
  • Golden vectors are regenerated for the new convention, with any retained old vectors clearly labeled legacy.

Out of Scope

  • Changing CBOR serialization structure or public proof envelope shapes.
  • Changing hash domain separators.
  • Changing key byte order on the wire; only bit indexing within the existing byte string changes.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions