Skip to content

Instantly share code, notes, and snippets.

@pcaversaccio
Last active September 19, 2025 15:05
Show Gist options
  • Save pcaversaccio/710bee6cc4e760eadb76770ac17610a6 to your computer and use it in GitHub Desktop.
Save pcaversaccio/710bee6cc4e760eadb76770ac17610a6 to your computer and use it in GitHub Desktop.
Ensure a hardware wallet's message signature uses an RFC-6979-compliant nonce for secure, deterministic signing.
mnemonic==0.21
eth_account==0.13.7
#!/usr/bin/env python
from mnemonic import Mnemonic
from eth_account import Account
from eth_account.messages import encode_defunct
##############
# TEST SETUP #
##############
def generate_test_seed_24_words() -> str:
"""Generate a 24-word BIP39 seed phrase for testing.
Returns
-------
seed_phrase: str
The randomly generated 24-word seed phrase.
"""
mnemo = Mnemonic("english")
seed_phrase = mnemo.generate(strength=256)
return seed_phrase
def derive_with_eth_account() -> str:
"""Derive an Ethereum private key from a random mnemonic phrase.
Returns
-------
private_key: str
The 32-byte private key as hex string.
"""
mnemonic_phrase = generate_test_seed_24_words()
Account.enable_unaudited_hdwallet_features()
# Use the standard Ethereum derivation path: `m/44'/60'/0'/0/0`.
account = Account.from_mnemonic(mnemonic_phrase, account_path="m/44'/60'/0'/0/0")
return account.key.hex()
########
# MAIN #
########
if __name__ == "__main__":
"""An illustrative signature verification.
You can import the first account from your hardware wallet's dummy seed
and sign a message here: https://etherscan.io/verifiedSignatures. Use the
message and signature below for verification.
"""
msg = "Vyper is awesome!"
msghash = encode_defunct(text=msg)
# Use here a derived private key from a dummy seed that you generated on your hardware wallet.
# You can use the `derive_with_eth_account` function to get the private key for the test account.
private_key = derive_with_eth_account()
# Generate an RFC-6979-compliant ECDSA signature.
signature = Account.sign_message(msghash, private_key)
r_check = signature.r
# Set here your original signature in bytes. You can convert from hex to bytes by using `bytes.fromhex(...)`.
original_sig = signature.signature
r_original = int(original_sig[:32].hex(), 16)
# If `r_original == r_check`, your signature used an RFC-6979-compliant nonce.
print(f"Original `r`: {r_original}")
print(f"Recomputed `r`: {r_check}")
assert (
r_original == r_check
), "Original `r` is not using an RFC-6979-compliant nonce!"
@pcaversaccio
Copy link
Author

This script relies on the assumption that eth_account itself is compliant with RFC 6979.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment