> loading_
# Walkthrough: Verifying an ML-DSA-44 signature (EIP-8164 direction)
# This uses the `pqcrypto` Python bindings as a reference.
# Production implementations should use audited, FIPS 204-compliant libraries.
# Step 0: Install the post-quantum crypto library
# pip install pqcrypto
from pqcrypto.sign.dilithium2 import generate_keypair, sign, verify
# Step 1: Generate an ML-DSA-44 (Dilithium2 / NIST Security Level 2) keypair
# Note: ML-DSA-44 maps to Dilithium2 in most libraries.
# Public keys are ~1,312 bytes; secret keys are ~2,528 bytes.
public_key, secret_key = generate_keypair()
print(f"Public key size: {len(public_key)} bytes") # ~1,312 bytes
print(f"Secret key size: {len(secret_key)} bytes") # ~2,528 bytes
# Step 2: Sign a message
# In the context of EIP-8164, this message would be the
# transaction hash or EIP-712 structured data hash.
message = b"EIP-8164 post-quantum test payload"
signature = sign(message, secret_key)
print(f"Signature size: {len(signature)} bytes") # ~2,420 bytes
# Step 3: Verify the signature using ONLY the public key
# This is where EIP-7932's separation matters: the public key
# is passed independently, not extracted from the signature.
try:
verify(message, signature, public_key)
print("Signature valid under ML-DSA-44")
except Exception as e:
print(f"Verification failed: {e}")
# Step 4: Demonstrate EIP-7932 separation pattern
# Under the new model, keys and signatures are discrete fields.
# This mirrors how a future Ethereum transaction type might structure them.
tx_envelope = {
"type": "0x8164",
"payload": message.hex(),
# EIP-7932: public_key is a first-class, separate field
"public_key": public_key.hex(),
# Signature is its own field — no embedded key material
"signature": signature.hex(),
}
print(f"Envelope public_key field: {len(tx_envelope['public_key']) // 2} bytes")
print(f"Envelope signature field: {len(tx_envelope['signature']) // 2} bytes")
# Key takeaway for developers:
# - Ed25519 paths in EIP-8164 are now deprecated. Migrate to ML-DSA-44.
# - Expect ~38x larger signatures (2,420 vs 64 bytes). Plan gas accordingly.
# - EIP-7932 separation means: never assume key material is inside the sig.
# - Use FIPS 204-compliant implementations only — not raw Dilithium ports.