Skip to content

refactor(xmss): hoist 0x-hex JSON serialization into a shared mixin#824

Merged
tcoratger merged 1 commit into
leanEthereum:mainfrom
tcoratger:xmss-hex-serializer
Jun 2, 2026
Merged

refactor(xmss): hoist 0x-hex JSON serialization into a shared mixin#824
tcoratger merged 1 commit into
leanEthereum:mainfrom
tcoratger:xmss-hex-serializer

Conversation

@tcoratger
Copy link
Copy Markdown
Collaborator

Summary

Simplifies XMSS container JSON serialization by hoisting the repeated 0x-prefixed hex serializer into a single shared mixin.

  • Introduces HexSerializedContainer, a Container subclass holding the lone @model_serializer(mode="plain", when_used="json") that emits "0x" + encode_bytes().hex().
  • PublicKey, SecretKey, and Signature now inherit it.
  • Deletes the hand-rolled per-field field_serializer on KeyPair and the duplicate serializer that previously lived on Signature.

The base container already decodes such hex strings on the way in (its existing wrap-validator accepts hex with or without a 0x prefix), so encode/decode roundtrips are unchanged.

Why a mixin and not the base Container

mode="plain" replaces a model's entire JSON representation. Putting it on the base Container would force all 21 subclasses (Block, State, Checkpoint, Attestation, ...) to collapse from structured objects into opaque hex blobs, breaking the human-readable fixture format and the state-transition / fork-choice fixtures. Hex is only the right shape for the opaque cryptographic blobs, so it stays opt-in.

Behavior change

Key halves (public_key / secret_key) now serialize as 0x-prefixed hex; previously KeyPair emitted plain hex. Plain hex is still accepted on input.

Generated SSZ test vectors for PublicKey now emit a 0x hex string for their value field instead of a nested {root, parameter} object — consistent with how Signature already behaved. Regenerate fixtures with uv run fill and review that diff.

Testing

  • uv run pytest tests/lean_spec/spec/crypto/xmss/ → 196 passed
  • just check → passes (lint, format, ty, codespell, mdformat, lock)

🤖 Generated with Claude Code

Introduce HexSerializedContainer holding the single model_serializer
that emits a 0x-prefixed hex SSZ payload in JSON mode. PublicKey,
SecretKey, and Signature now inherit it.

This removes the hand-rolled per-field serializer on KeyPair and the
duplicate serializer on Signature. The container base already decodes
such hex strings on the way in, so roundtrips are unchanged.

Key halves now serialize as 0x-prefixed hex (previously plain hex).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@tcoratger tcoratger merged commit e5e7626 into leanEthereum:main Jun 2, 2026
13 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant