1- """Defines the data containers for the Generalized XMSS signature scheme."""
1+ """
2+ Data containers for the Generalized XMSS signature scheme.
3+
4+ This module defines the high-level containers: PublicKey, Signature, and SecretKey.
5+ Base types (HashDigestVector, Parameter, etc.) are defined in types.py.
6+ """
27
38from __future__ import annotations
49
510from typing import TYPE_CHECKING
611
7- from lean_spec .subspecs .koalabear import Fp
8-
912from ...types import Uint64
10- from ...types .byte_arrays import BaseBytes
11- from ...types .collections import SSZList , SSZVector
1213from ...types .container import Container
13- from .constants import PRF_KEY_LENGTH , PROD_CONFIG
14+ from .subtree import HashSubTree
15+ from .types import (
16+ HashDigestList ,
17+ HashDigestVector ,
18+ HashTreeOpening ,
19+ Parameter ,
20+ PRFKey ,
21+ Randomness ,
22+ )
1423
1524if TYPE_CHECKING :
1625 from .interface import GeneralizedXmssScheme
17- from .subtree import HashSubTree
18-
19-
20- class PRFKey (BaseBytes ):
21- """
22- The PRF master secret key.
23-
24- This is a high-entropy byte string that acts as the single root secret from
25- which all one-time signing keys are deterministically derived.
26- """
27-
28- LENGTH = PRF_KEY_LENGTH
29-
30-
31- HASH_DIGEST_LENGTH = PROD_CONFIG .HASH_LEN_FE
32- """
33- The fixed length of a hash digest in field elements.
34-
35- Derived from `PROD_CONFIG.HASH_LEN_FE`. This corresponds to the output length
36- of the Poseidon2 hash function used in the XMSS scheme.
37-
38- TODO: Make the configuration generic and don't hardcode `PROD_CONFIG`.
39- """
40-
41- # Calculate the maximum number of nodes in a sparse Merkle tree layer:
42- # - A bottom tree has at most 2^(LOG_LIFETIME/2) leaves
43- # - With padding, we may add up to 2 additional nodes
44- # - To be generous and future-proof, we use 2^(LOG_LIFETIME/2 + 1)
45- NODE_LIST_LIMIT = 1 << (PROD_CONFIG .LOG_LIFETIME // 2 + 1 )
46- """
47- The maximum number of nodes that can be stored in a sparse Merkle tree layer.
48-
49- Calculated as `2^(LOG_LIFETIME/2 + 1)` from PROD_CONFIG to accommodate:
50- - Bottom trees with up to `2^(LOG_LIFETIME/2)` nodes
51- - Padding overhead (up to 2 additional nodes)
52- - Future-proofing with 2x margin
53-
54- TODO: Make the configuration generic and don't hardcode `PROD_CONFIG`.
55- """
56-
57-
58- class HashDigestVector (SSZVector ):
59- """
60- A single hash digest represented as a fixed-size vector of field elements.
61-
62- This is the SSZ-compliant representation of a Poseidon2 hash output.
63- In SSZ notation: `Vector[Fp, HASH_DIGEST_LENGTH]`
64-
65- The fixed size enables efficient serialization when used in collections,
66- as SSZ can pack these back-to-back without per-element offsets.
67- """
68-
69- ELEMENT_TYPE = Fp
70- LENGTH = HASH_DIGEST_LENGTH
71-
72-
73- class HashDigestList (SSZList ):
74- """
75- Variable-length list of hash digests.
76-
77- In SSZ notation: `List[Vector[Fp, HASH_DIGEST_LENGTH], NODE_LIST_LIMIT]`
78-
79- This type is used to represent collections of hash digests in the XMSS scheme.
80- """
81-
82- ELEMENT_TYPE = HashDigestVector
83- LIMIT = NODE_LIST_LIMIT
84-
85-
86- class Parameter (SSZVector ):
87- """
88- The public parameter P.
89-
90- This is a unique, randomly generated value associated with a single key pair. It
91- is mixed into every hash computation to "personalize" the hash function, preventing
92- certain cross-key attacks. It is public knowledge.
93-
94- TODO: Make the configuration generic and don't hardcode `PROD_CONFIG`.
95- """
96-
97- ELEMENT_TYPE = Fp
98- LENGTH = PROD_CONFIG .PARAMETER_LEN
99-
100-
101- class Randomness (SSZVector ):
102- """
103- The randomness `rho` (ρ) used during signing.
104-
105- This value provides a variable input to the message hash, allowing the signer to
106- repeatedly try hashing until a valid "codeword" is found. It must be included in
107- the final signature for the verifier to reproduce the same hash.
108-
109- SSZ notation: `Vector[Fp, RAND_LEN_FE]`
110-
111- TODO: Make the configuration generic and don't hardcode `PROD_CONFIG`.
112- """
113-
114- ELEMENT_TYPE = Fp
115- LENGTH = PROD_CONFIG .RAND_LEN_FE
116-
117-
118- class HashTreeOpening (Container ):
119- """
120- A Merkle authentication path.
121-
122- This object contains the minimal proof required to connect a specific leaf
123- to the Merkle root. It consists of the list of all sibling nodes along the
124- path from the leaf to the top of the tree.
125-
126- SSZ Container with fields:
127- - siblings: List[Vector[Fp, HASH_DIGEST_LENGTH], NODE_LIST_LIMIT]
128- """
129-
130- siblings : HashDigestList
131- """SSZ-compliant list of sibling hashes, from bottom to top."""
132-
133-
134- class HashTreeLayer (Container ):
135- """
136- Represents a single horizontal "slice" of the sparse Merkle tree.
137-
138- Because the tree is sparse, we only store the nodes that are actually computed
139- for the active range of leaves, not the entire conceptual layer.
140- """
141-
142- start_index : Uint64
143- """The starting index of the first node in this layer."""
144- nodes : HashDigestList
145- """SSZ-compliant list of hash digests stored for this layer."""
146-
147-
148- LAYERS_LIMIT = PROD_CONFIG .LOG_LIFETIME + 1
149- """
150- The maximum number of layers in a subtree.
151-
152- This is `LOG_LIFETIME + 1` to accommodate all layers from 0 (leaves) to LOG_LIFETIME (root),
153- inclusive. For PROD_CONFIG with LOG_LIFETIME=32, this allows up to 33 layers.
154-
155- TODO: Make the configuration generic and don't hardcode `PROD_CONFIG`.
156- """
157-
158-
159- class HashTreeLayers (SSZList ):
160- """
161- Variable-length list of Merkle tree layers.
162-
163- In SSZ notation: `List[HashTreeLayer, LAYERS_LIMIT]`
164-
165- This type represents the layers of a subtree, from the lowest layer up to the root.
166-
167- The number of layers varies based on the subtree structure:
168- - Bottom trees: `LOG_LIFETIME/2` layers
169- - Top trees: `LOG_LIFETIME/2` layers
170- - Maximum: `LOG_LIFETIME + 1` layers
171- """
172-
173- ELEMENT_TYPE = HashTreeLayer
174- LIMIT = LAYERS_LIMIT
17526
17627
17728class PublicKey (Container ):
@@ -277,7 +128,7 @@ class SecretKey(Container):
277128 `sqrt(LIFETIME)`, with a minimum of `2 * sqrt(LIFETIME)`.
278129 """
279130
280- top_tree : " HashSubTree"
131+ top_tree : HashSubTree
281132 """
282133 The top tree containing the root and top `LOG_LIFETIME/2` layers.
283134
@@ -297,15 +148,15 @@ class SecretKey(Container):
297148
298149 """
299150
300- left_bottom_tree : " HashSubTree"
151+ left_bottom_tree : HashSubTree
301152 """
302153 The left bottom tree in the sliding window.
303154
304155 This covers epochs:
305156 [left_bottom_tree_index * sqrt(LIFETIME), (left_bottom_tree_index + 1) * sqrt(LIFETIME))
306157 """
307158
308- right_bottom_tree : " HashSubTree"
159+ right_bottom_tree : HashSubTree
309160 """
310161 The right bottom tree in the sliding window.
311162
0 commit comments