Skip to content

Commit e4098c8

Browse files
committed
xmss: add cross test with ream signature
1 parent 44f896a commit e4098c8

1 file changed

Lines changed: 209 additions & 0 deletions

File tree

Lines changed: 209 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,209 @@
1+
"""Cross-client XMSS signature compatibility tests."""
2+
3+
from __future__ import annotations
4+
5+
import pytest
6+
7+
from lean_spec.subspecs.containers.slot import Slot
8+
from lean_spec.subspecs.xmss.constants import PROD_CONFIG
9+
from lean_spec.subspecs.xmss.containers import PublicKey
10+
from lean_spec.subspecs.xmss.interface import PROD_SIGNATURE_SCHEME
11+
from lean_spec.subspecs.xmss.types import HashDigestVector, Randomness
12+
from lean_spec.types import Bytes32
13+
from lean_spec.types.collections import SSZList
14+
from lean_spec.types.container import Container
15+
16+
PROD_NODE_LIST_LIMIT = 1 << (PROD_CONFIG.LOG_LIFETIME // 2 + 1)
17+
18+
19+
class ProdHashDigestList(SSZList[HashDigestVector]):
20+
"""Hash digest list with prod-sized limit (works under any LEAN_ENV)."""
21+
22+
LIMIT = PROD_NODE_LIST_LIMIT
23+
24+
25+
class ProdHashTreeOpening(Container):
26+
"""Merkle authentication path using prod-sized sibling list."""
27+
28+
siblings: ProdHashDigestList
29+
30+
31+
class ProdSignature(Container):
32+
"""Signature container using prod-sized list limits for decoding."""
33+
34+
path: ProdHashTreeOpening
35+
rho: Randomness
36+
hashes: ProdHashDigestList
37+
38+
39+
PUBLIC_KEY_HEX = (
40+
"7bbaf95bd653c827b5775e00b973b24d50ab4743db3373244f29c95fdf4ccc62"
41+
"8788ba2b5b9d635acdb25770e8ceef66bfdecd0a"
42+
)
43+
44+
SIGNATURE_HEX = (
45+
"240000006590c5180f52a57ef4d12153ace9dd1bb346ea1299402d32978bd56f"
46+
"2804000004000000903b927d2ee9cf14087b2164dd418115962e322a6da10a58"
47+
"821ee20dd54f3c6a3f6dba14ebc2340b1aa7cc5647e08d0151024229312973331f"
48+
"669e1a268c8a2429d2353393f0d67a6b02da35e589da5bb099ea1ef931e9770c"
49+
"cae83a31f1454b359a4f4227fa1f17895918649115f3416bfa4e7976c5736170"
50+
"bc4e2acaf58342bf8e7472a2d6871e93bbbd01ebb6f30d51ccc3150e1d1e6c7b"
51+
"bfe15ea42cac218a8b94745184ce1f1098d62a9ea7a20662de0464f588225010"
52+
"84da7cbb58833ef9adfe59c17ac121676d92103a52903fbb70c1694717c46951"
53+
"40411977dfcb0e3da29612e27c590ef56967046817cb3727def54b4544f40314"
54+
"27be0a056ba7633334fd4104b0ba550521b61e16ecad72b5fda17de3e7a03bf6"
55+
"83f55ecefd215235c6481b5a6f873bc8134373f9fafc3053164e5f435c3d2ad7"
56+
"90221601ce274a4117f3104cadb00feb8baf79dd48904c5c1e0c1627c17c41ee"
57+
"7ca3760051ec163eee3e38a7bffa5779570a6cc078a630f5494f4917214954f1"
58+
"da636decff784335944a0674aa82096e5136063ef59c6962e95308074fed4bf6"
59+
"a81301d38a7919149bb24d221e5c44c12f82127c551413fef4f40b6f5ad646f4"
60+
"ca4578baf6f11d3325fe356168925b1f75690c17dbfd74d0d39756106c8a6d10"
61+
"c3bd355f27de621c72ca76734e523ebb8e647ef9fd216093f6bf086f075e4dcc"
62+
"607b5f6ff0603ca71787665a504621bdaf9e0b2924516972dc9c0ee1198f4ae3"
63+
"d6f7109c0c0f4b1708262685c7850709275e6e7f14cf4b74647a04005c501c37"
64+
"6d3a179014dc69d26716199b3811773d77800948ad6a6c620d1d2cd0d038283e"
65+
"10c659bd6c3635fa8634482cc14c1d476fa23a40f94d0dcb542b2230bb4f0283"
66+
"3713357b8f783b9ffaa50c32ef9933265a072bbc34b671800a8807fae7b235d3"
67+
"f2cc62804a4e3efecbb420122e6a6b62154976faff37329de17d7691a5213d54"
68+
"75b92132e48d657993d12c5eb5d0164f6af8589c199c1b61cf4619c60d723580"
69+
"97e43e5c5a676914748541e8d705626ac3654342f749361577056efe50e65e23"
70+
"2fd91c8588576db75cd96e004994278441bc2abac25a51cbdc095764bf7a64ff"
71+
"e05b06cea7bb446f6de72149bf850d795ddd15e464bf7377985f422e937e4ad0"
72+
"0563360340c93fd8d0c2695aaac71776f9476c4e574a7645285f5ca714cc021d"
73+
"88eb317d9c0177305bfa06f35622433447803322bf3833b617852b5cbd1d7abb"
74+
"ca563f124886792d0133298de40c6d4a8c802faa83da52211bdd5f13c1a14404"
75+
"16b40acc044774e083394d5e803a6a4a3123549d208c340448655b633d434784"
76+
"88717ebc9f3a09b514852c709cc77ace7bba083cc3826d3542ec663a55750838"
77+
"b83369521b40683a268413a302f90adb9a2954466d8d432b316021228f9763e7"
78+
"6e7a704866b66d0471626ae5f19c345147b64233266b7a58c7db0c246f370b91"
79+
"b490297ce07130166c424624d96b2adcb3a460fb0cce015f9e33194cc4a128f9"
80+
"153e1ddb24e1509e21793796b5b11fadc22218db97f3650ca8ec0e6003086fab"
81+
"38cf251b71ae2dece3716f3d50e26873ef8346c9951742953e0f720420af17b5"
82+
"30c1720f8f606e19a0c223d7059b6da670d12fd555313205312f7c151af068bb"
83+
"0b3d0f80333f2f73159e63a9c7cb46a88ede5ac4ddc20700bee377ec01f568cc"
84+
"179a6ccfc2e86d03912b779e2c4e5cc3d73d3b53f18001dee0032b276d456b82"
85+
"2d8b242d6d5e27b794ed14a2478e1c13eb5d0866990e4d75a27b1cca956737ca"
86+
"c4b16813ca29191720f632f9826e5cd2d32216a9580646bdcc1f0ff114e00661"
87+
"65f1368a324f27a97c3032a697f3317229782dfe053445921286144fbe7d7e68"
88+
"ac441a91c5cc2543ac6908cc171a67cdb0a638e19bb32f3dc6576b8b4aeb5aa4"
89+
"866a18a458972c1521345fbf885238afa6862b0ee4eb62b1c7b94026b8926f2f"
90+
"ae2f469b8bd02a6706995733b9321edaff6c429311f72ec541c65fccf9646f4e"
91+
"2ceb7c58d7f26e8280641dde221f0cb38cee6ccb9bd7238641fb11c576b02a2b"
92+
"47553858208a7ac9b6805a80474c38e3295d00f147ed3deb3d30503ec4076b25"
93+
"43bf307194b2787be3d53f3227ca3b815541709bbbc77a11eff92f5cccca7c76"
94+
"17e303c1b430799018aa0a94c7b152b154956a7e874507895e1735edc2683bb3"
95+
"28dd576ff11a2e3fc07f1ba086831e534dab1c0320920156155f72cc7e90795c"
96+
"268c2486d1dc4921204c53082dfb1b830bd9238794881c985ab247274990541c"
97+
"fa8f0e5e582e2caf44f7598f068272eb4ee81c5c04663504b745194c8c570169"
98+
"de83626063e20a6847b82c77931f321cd3ac5cbac802476969255a13a2fe6070"
99+
"7f960f5df8095c89cc786ffbe1b86a3e0b7f607f98982b9f10591c9c7bd14d21"
100+
"6bac36de88254da273a3601048cb47cb5c2954f34bae09d33d814162bf3d6da2"
101+
"de8c7a51331d437a8012420f6c1323b063e4085e32ee4d2864a14a66bffc29ef"
102+
"bca2328416901fe998be14033cb00b104d6732bdc8a963357b9d1290043229e3"
103+
"21c25f549c467415472e4061a30b616b23700cc930597e117438293330de628b"
104+
"7c465a8d79b150f0cf913a43e92e6c87e8e644412d0815c0086c46e3028b74d7"
105+
"967a6cf6f5332c4fea10320e90061dc0df4b3f01d0934772291c0cc9b8622b1e"
106+
"e9e120a0178613586b1370f71ef508bcc70c0728894621146a707a9c802321cc"
107+
"f7e50d5d4f8a21c5ced8480117bb11404cbc6eac8ec928507e912474c3fa4ba7"
108+
"dbd22781c28761d19e736f63e0c659c94f243b87271e2424505c2118c30c0dcf"
109+
"d7b719d2a6a549f28da317e1cbeb5748da595c86ada266aed25d18575368"
110+
"6e94914c68af6f4c5b833bd91033bbcb6b89cad52b9b65e110683dc96be38d69"
111+
"0780253c49bf454d783aa25c0838e00929155c943d7c80c83d0a22c65e6e49c7"
112+
"60f50b0623f074ee19138c08671cd6a846faf4237cbc4cee192106ed24545165"
113+
"2c591b5a04fd6537255f54a261f7df231fe13a803f617a4719ba15831c4fa848"
114+
"64f581772539091726fd0d3112a55781440796562a9324936110004039a3e3ec"
115+
"26078f76243e1be93df0166270055dcb65a94f2c14c5813145f4bd680c02c33e"
116+
"042d98d17e1c5a9c22d095ed30ad754144ae7f5150ac0df842d4e9415f849f1b"
117+
"36f2c1ff520be3d0721aab9b31c249df28aac8d9378326184262f53307bc77bc"
118+
"6ca59c3349bb29b90b7464ab666f563e5ac741a6390e6d634620fbb33182f958"
119+
"482746ff1138f53e55b9d1a119800e8d6fe04a46044781f813817514338a60a8"
120+
"044b3333249cc9c93cdf6c8537de140943f4907f7926f5a81ed20f1526fd9447"
121+
"412d81e75a05d93b7610e2e27d851b1163cb96e242c08796493f564e0e51a45e"
122+
"17e74b2619dafa0855922b714b84f1266bfc094e494c29175298d9a44eb5cf2d"
123+
"3a696c744f15a1f21d737fb45ed8af333157e88b1c89018d6322f91e751827c0"
124+
"30a6fb9d03554dee606a39cc6b79147906c18b376b1a39c20249a64c2b0b95e6"
125+
"26204ee24dcfa2665bd5ca0405df11391d15b8604130c3de32f7c43726c10bd5"
126+
"334b16df17f17456605008cb3cf926f0166209bc358562f32293073012bc7425"
127+
"0445e39e6cc14aa2613d77de1143e15c2e101cca14b9543d44b248a17c72279b"
128+
"743b0e18483a2331228bd57a3d5ecfa03f9318d269cbf992765ea15678046038"
129+
"749a04c35638c7984cbb90c40b7b94e657bc70a6760520fb4cbe1bbe62f5f7c1"
130+
"21268168361963cf3bf032f71e01d9555655faeb58e995c916d7b0850f681383"
131+
"0583717d36e9b4a319ccc4797386f072485834f4772d291a3976f1fa799ba0d0"
132+
"07822c011ad959895a4b29c11f3f9f07277a1ce94d1c5d9b0150a1e919528c17"
133+
"340031a204be28ff69ad90c13e4b81f354ef8ec11df62e9c62c1de715981bd4f"
134+
"4095a72d2eb68a5811bc059f0f58a5fa539a9a857e68604248d2fd5c28cabdf1"
135+
"1ae4a4692218a18d49d38ff76a6e2b8956b884ac0a5af9cc6680bfb62cf3d83a"
136+
"14d031f0404cc8930898bda055a934624650064e40665ce21754c72b6be81526"
137+
"62b5e29571be85b01cb7728045c92a5a37764a99062abb535c21260612b3026d"
138+
"1145be6c1b3d5e917ee457102fcfc8c5771d011d61f591271220a01e1dc11d1b"
139+
"441217577a5b5cc113421cd740bbe47556719bb51375eda8173d54706cafe98b"
140+
"6b9ad0f9639708e87e77fcbb2bb822ce59f0bdba7746ca286c5b98447d4ca2f0"
141+
"27b827ea4c7987e96a0429696bf9cfa21d6add9b79f2eddf2e6fe1c23c118ce2"
142+
"035ca0e3022270b628"
143+
)
144+
145+
EPOCH = 5
146+
MESSAGE = Bytes32(b"\x00" * 32)
147+
148+
149+
@pytest.fixture()
150+
def ream_public_key() -> PublicKey:
151+
"""Decode the ream-generated public key from raw SSZ bytes."""
152+
return PublicKey.decode_bytes(bytes.fromhex(PUBLIC_KEY_HEX))
153+
154+
155+
@pytest.fixture()
156+
def ream_signature() -> ProdSignature:
157+
"""Decode the ream-generated signature from raw SSZ bytes."""
158+
return ProdSignature.decode_bytes(bytes.fromhex(SIGNATURE_HEX))
159+
160+
161+
class TestCrossClientCompat:
162+
"""Verify ream-produced XMSS artifacts decode and verify in leanSpec."""
163+
164+
def test_decode_ream_public_key(self, ream_public_key: PublicKey) -> None:
165+
"""SSZ decode + re-encode roundtrip for the public key."""
166+
raw = bytes.fromhex(PUBLIC_KEY_HEX)
167+
assert len(raw) == PROD_CONFIG.PUBLIC_KEY_LEN_BYTES
168+
assert ream_public_key.encode_bytes() == raw
169+
170+
def test_decode_ream_signature(self, ream_signature: ProdSignature) -> None:
171+
"""SSZ decode + re-encode roundtrip for the signature."""
172+
raw = bytes.fromhex(SIGNATURE_HEX)
173+
assert len(raw) == PROD_CONFIG.SIGNATURE_LEN_BYTES
174+
assert ream_signature.encode_bytes() == raw
175+
176+
def test_verify_ream_signature(
177+
self, ream_public_key: PublicKey, ream_signature: ProdSignature
178+
) -> None:
179+
"""Full XMSS verification of a ream-produced signature."""
180+
assert PROD_SIGNATURE_SCHEME.verify(
181+
ream_public_key,
182+
Slot(EPOCH),
183+
MESSAGE,
184+
ream_signature, # type: ignore[arg-type]
185+
)
186+
187+
def test_ream_signature_rejects_wrong_message(
188+
self, ream_public_key: PublicKey, ream_signature: ProdSignature
189+
) -> None:
190+
"""Signature must not verify against a different message."""
191+
wrong_message = Bytes32(b"\xff" * 32)
192+
assert not PROD_SIGNATURE_SCHEME.verify(
193+
ream_public_key,
194+
Slot(EPOCH),
195+
wrong_message,
196+
ream_signature, # type: ignore[arg-type]
197+
)
198+
199+
def test_ream_signature_rejects_wrong_slot(
200+
self, ream_public_key: PublicKey, ream_signature: ProdSignature
201+
) -> None:
202+
"""Signature must not verify for a different slot."""
203+
wrong_slot = Slot(EPOCH + 1)
204+
assert not PROD_SIGNATURE_SCHEME.verify(
205+
ream_public_key,
206+
wrong_slot,
207+
MESSAGE,
208+
ream_signature, # type: ignore[arg-type]
209+
)

0 commit comments

Comments
 (0)