test: add offline integrity test suite with frozen vectors
This commit is contained in:
104
tests/bootstrap_vectors.py
Normal file
104
tests/bootstrap_vectors.py
Normal file
@@ -0,0 +1,104 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Bootstrap script to generate tests/vectors.json.
|
||||
Run this ONCE (online allowed if needed, though this logic is offline)
|
||||
to freeze the expected outputs of the current pyhdwallet implementation.
|
||||
"""
|
||||
import sys
|
||||
import json
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
# Add src to path so we can import pyhdwallet
|
||||
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "../src")))
|
||||
|
||||
import pyhdwallet
|
||||
from bip_utils import Bip39SeedGenerator
|
||||
|
||||
def main():
|
||||
print("Bootstrapping test vectors...")
|
||||
vectors = {}
|
||||
|
||||
# 1. PGP Fingerprint Vector
|
||||
recipient_path = Path(__file__).parent / "data" / "recipient.asc"
|
||||
if not recipient_path.exists():
|
||||
print(f"Error: {recipient_path} not found. Please create it first.")
|
||||
sys.exit(1)
|
||||
|
||||
with open(recipient_path, "r", encoding="utf-8") as f:
|
||||
armored = f.read()
|
||||
|
||||
# Calculate expected fingerprint using current code logic
|
||||
expected_fpr = pyhdwallet.pgp_fingerprint(armored)
|
||||
|
||||
vectors["pgp"] = {
|
||||
"recipient_file": "recipient.asc",
|
||||
"expected_fingerprint": expected_fpr
|
||||
}
|
||||
print(f"PGP: Pinned fingerprint {expected_fpr}")
|
||||
|
||||
# 2. BIP39 & Derivation Vectors
|
||||
mnemonic = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"
|
||||
|
||||
vectors["bip39"] = []
|
||||
|
||||
# Case A: No Passphrase
|
||||
seed_bytes = Bip39SeedGenerator(mnemonic).Generate("")
|
||||
seed_hex = seed_bytes.hex()
|
||||
|
||||
# Generate addresses for all supported chains/profiles
|
||||
chains = ["ethereum", "bitcoin", "solana"]
|
||||
# Fixed profile names to use underscores instead of hyphens
|
||||
sol_profiles = ["phantom_bip44change", "phantom_bip44", "solana_bip39_first32"]
|
||||
|
||||
derived_data = {}
|
||||
|
||||
# Run derivation for each sol profile logic
|
||||
for profile in sol_profiles:
|
||||
res = pyhdwallet.derive_all(
|
||||
seed_bytes,
|
||||
chains,
|
||||
count=5,
|
||||
sol_profile=profile,
|
||||
export_private=False
|
||||
)
|
||||
derived_data[profile] = res["addresses"]
|
||||
|
||||
vectors["bip39"].append({
|
||||
"mnemonic": mnemonic,
|
||||
"passphrase": "",
|
||||
"expected_seed_hex": seed_hex,
|
||||
"derived_addresses": derived_data
|
||||
})
|
||||
|
||||
# Case B: With Passphrase (Regression test)
|
||||
passphrase = "TREZOR"
|
||||
seed_bytes_p = Bip39SeedGenerator(mnemonic).Generate(passphrase)
|
||||
seed_hex_p = seed_bytes_p.hex()
|
||||
|
||||
res_p = pyhdwallet.derive_all(
|
||||
seed_bytes_p,
|
||||
chains,
|
||||
count=1,
|
||||
sol_profile="phantom_bip44change",
|
||||
export_private=False
|
||||
)
|
||||
|
||||
vectors["bip39"].append({
|
||||
"mnemonic": mnemonic,
|
||||
"passphrase": passphrase,
|
||||
"expected_seed_hex": seed_hex_p,
|
||||
"derived_addresses": {"phantom_bip44change": res_p["addresses"]}
|
||||
})
|
||||
|
||||
print("Derivation: Generated vectors for empty and non-empty passphrases.")
|
||||
|
||||
# 3. Save
|
||||
out_path = Path(__file__).parent / "vectors.json"
|
||||
with open(out_path, "w", encoding="utf-8") as f:
|
||||
json.dump(vectors, f, indent=2)
|
||||
|
||||
print(f"Success! Vectors written to {out_path}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user