Skip to content

Commit a769c2a

Browse files
tcoratgerclaude
andauthored
docs(xmss): document the 4-byte epoch packing precondition in the PRF (#1118)
The PRF packs the epoch into four big-endian bytes in both chain-start and randomness derivation. This is sound only because the epoch is bounded by the key lifetime, and every supported config keeps LOG_LIFETIME <= 32, so the value always fits in four bytes. Record that precondition next to each packing site so a future config exceeding the bound is understood as the cause of the resulting overflow at signing time, rather than appearing as an unexplained failure. The wire layout is unchanged. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent e203930 commit a769c2a

1 file changed

Lines changed: 8 additions & 0 deletions

File tree

  • src/lean_spec/spec/crypto/xmss

‎src/lean_spec/spec/crypto/xmss/prf.py‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,10 @@ def derive_chain_start(
7474
# domain_sep || 0x00 || key || epoch (4 bytes) || chain_index (8 bytes)
7575
#
7676
# The 0x00 byte separates chain-start derivation from randomness derivation.
77+
#
78+
# The epoch is bounded by the key lifetime, which fits in four bytes for every
79+
# supported configuration (LOG_LIFETIME <= 32).
80+
# A config beyond that bound would overflow this fixed-width packing.
7781
input_data = (
7882
PRF_DOMAIN_SEP
7983
+ PRF_DOMAIN_SEP_DOMAIN_ELEMENT
@@ -128,6 +132,10 @@ def derive_randomness(
128132
# Layout:
129133
#
130134
# domain_sep || 0x01 || key || epoch || message || counter
135+
#
136+
# The epoch is bounded by the key lifetime, which fits in four bytes for every
137+
# supported configuration (LOG_LIFETIME <= 32).
138+
# A config beyond that bound would overflow this fixed-width packing.
131139
input_data = (
132140
PRF_DOMAIN_SEP
133141
+ PRF_DOMAIN_SEP_RANDOMNESS

0 commit comments

Comments
 (0)