@@ -126,8 +126,17 @@ def parse_args() -> argparse.Namespace:
126126def build_scenarios (lifetimes : list [str ], seed_hex : str ) -> list [ScenarioConfig ]:
127127 scenarios : list [ScenarioConfig ] = []
128128 for lifetime in lifetimes :
129- # Use 1024 active epochs for 2^32 lifetime, 256 for others
130- num_active_epochs = 1024 if lifetime == "2^32" else 256
129+ # Use appropriate active epochs for each lifetime
130+ # Note: Zig/Rust multiply by 128 internally, so actual = input * 128
131+ # 2^8: max 256 signatures, so max input = 256/128 = 2
132+ # 2^18: max 262,144 signatures, so we can use 256 (256*128=32,768)
133+ # 2^32: max 4B+ signatures, so we can use 1024 (1024*128=131,072)
134+ if lifetime == "2^32" :
135+ num_active_epochs = 1024
136+ elif lifetime == "2^18" :
137+ num_active_epochs = 256
138+ else : # 2^8
139+ num_active_epochs = 2
131140 scenarios .append (
132141 ScenarioConfig (
133142 lifetime = lifetime ,
@@ -262,6 +271,8 @@ def run_rust_sign(cfg: ScenarioConfig, paths: Dict[str, Path]) -> OperationResul
262271 tmp_dir .mkdir (exist_ok = True )
263272
264273 # Save active epochs to file for the tool to read
274+ # Note: Rust leansig multiplies by 128 internally, Zig now does the same
275+ # So we pass the same value to both
265276 (tmp_dir / "rust_active_epochs.txt" ).write_text (str (cfg .num_active_epochs ))
266277
267278 # Generate keypair first
@@ -416,6 +427,68 @@ def run_rust_verify(
416427 return OperationResult (success , duration , result .stdout , result .stderr )
417428
418429
430+ def compare_file_sizes (cfg : ScenarioConfig , paths : Dict [str , Path ]) -> bool :
431+ """Compare file sizes between Rust and Zig generated files"""
432+ print (f"\n -- Comparing file sizes --" )
433+
434+ discrepancies = []
435+
436+ # Compare public keys
437+ rust_pk_size = paths ["rust_pk" ].stat ().st_size if paths ["rust_pk" ].exists () else 0
438+ zig_pk_size = paths ["zig_pk" ].stat ().st_size if paths ["zig_pk" ].exists () else 0
439+
440+ print (f"Public key sizes:" )
441+ print (f" Rust: { rust_pk_size } bytes" )
442+ print (f" Zig: { zig_pk_size } bytes" )
443+
444+ if rust_pk_size != zig_pk_size :
445+ discrepancies .append (f"Public key size mismatch: Rust={ rust_pk_size } vs Zig={ zig_pk_size } " )
446+ print (f" ⚠️ WARNING: Public key sizes differ!" )
447+ else :
448+ print (f" ✅ Public key sizes match" )
449+
450+ # Compare signatures
451+ rust_sig_size = paths ["rust_sig" ].stat ().st_size if paths ["rust_sig" ].exists () else 0
452+ zig_sig_size = paths ["zig_sig" ].stat ().st_size if paths ["zig_sig" ].exists () else 0
453+
454+ print (f"Signature sizes:" )
455+ print (f" Rust: { rust_sig_size } bytes" )
456+ print (f" Zig: { zig_sig_size } bytes" )
457+
458+ if rust_sig_size != zig_sig_size :
459+ discrepancies .append (f"Signature size mismatch: Rust={ rust_sig_size } vs Zig={ zig_sig_size } " )
460+ print (f" ⚠️ WARNING: Signature sizes differ!" )
461+ else :
462+ print (f" ✅ Signature sizes match" )
463+
464+ # Compare secret keys (check both project tmp and rust_benchmark tmp)
465+ rust_sk_path = REPO_ROOT / "benchmark" / "rust_benchmark" / "tmp" / "rust_sk.ssz"
466+ zig_sk_path = REPO_ROOT / "tmp" / "zig_sk.ssz"
467+
468+ if rust_sk_path .exists () and zig_sk_path .exists ():
469+ rust_sk_size = rust_sk_path .stat ().st_size
470+ zig_sk_size = zig_sk_path .stat ().st_size
471+
472+ print (f"Secret key sizes:" )
473+ print (f" Rust: { rust_sk_size :,} bytes" )
474+ print (f" Zig: { zig_sk_size :,} bytes" )
475+
476+ if rust_sk_size != zig_sk_size :
477+ discrepancies .append (f"Secret key size mismatch: Rust={ rust_sk_size :,} vs Zig={ zig_sk_size :,} " )
478+ print (f" ⚠️ WARNING: Secret key sizes differ!" )
479+ print (f" This indicates incompatible SSZ serialization formats!" )
480+ print (f" Rust includes full trees, Zig may only save metadata." )
481+ else :
482+ print (f" ✅ Secret key sizes match" )
483+
484+ if discrepancies :
485+ print (f"\n ⚠️ { len (discrepancies )} size discrepanc{ 'y' if len (discrepancies ) == 1 else 'ies' } detected:" )
486+ for disc in discrepancies :
487+ print (f" - { disc } " )
488+ return False
489+
490+ return True
491+
419492def run_scenario (cfg : ScenarioConfig , timeout_2_32 : int ) -> tuple [Dict [str , OperationResult ], Dict [str , Path ]]:
420493 print (f"\n === Scenario: { cfg .label } ===" )
421494 paths = scenario_paths (cfg )
@@ -438,6 +511,11 @@ def run_scenario(cfg: ScenarioConfig, timeout_2_32: int) -> tuple[Dict[str, Oper
438511 # signature must be accepted by the Rust verifier.
439512 results ["zig_to_rust" ] = run_rust_verify (cfg , paths ["zig_pk" ], paths ["zig_sig" ], "Zig sign → Rust verify" )
440513
514+ # Compare file sizes to detect serialization format mismatches
515+ sizes_match = compare_file_sizes (cfg , paths )
516+ if not sizes_match :
517+ print ("\n ⚠️ WARNING: File size mismatches detected. This may indicate serialization format issues." )
518+
441519 return results , paths
442520
443521
0 commit comments