web3.py ist der Python-Client für Ethereum-Knoten; das Signieren von Nachrichten und Transaktionen übernimmt das Paket eth-account (0.14.0 mit web3 8.0.0), das für die Kurvenarithmetik wiederum eth-keys verwendet. Der meiste Signiercode importiert eth_account direkt, so wie das Beispiel.
Account.sign_message(encode_defunct(text=...)) implementiert personal_sign: das Präfix nach EIP-191 mit der dezimalen Bytelänge, keccak-256, eine Nonce nach RFC 6979 (abgeglichen mit einem unabhängigen Referenz-Signierer) und s in der unteren Hälfte, zurückgegeben als 65 Byte, die auf v = 27 oder 28 enden. encode_defunct ist der Teil, den viele vergessen: Wer rohe Bytes mit unsafe_sign_hash signiert, lässt das Präfix weg – und genau das macht eine Signatur anderswo als Anmeldenachweis unbrauchbar.
Account.recover_message() stellte den Signierer aus der gespiegelten High-S-Signatur ebenso wieder her wie aus v = 0/1 und akzeptiert damit mehr Formen als ethers – normalisiere s selbst, wenn Signaturen gespeichert oder dedupliziert werden. Die kompakte 64-Byte-Form nach EIP-2098 wurde mit Unexpected recoverable signature length: Expected 65, but got 64 bytes abgelehnt; expandiere sie vor der Wiederherstellung.
Für Typed Data verwende encode_typed_data (EIP-712), statt das JSON selbst zu hashen, und prüfe mit dem EIP-712-Inspektor, was eine Wallet signieren soll. Smart-Contract-Wallets brauchen statt recover_message einen Aufruf des Contracts nach ERC-1271; Fehler in Anmeldenachrichten findest du am einfachsten mit dem SIWE-Verifizierer.
Das Beispiel signiert eine Anmeldenachricht und vergleicht die wiederhergestellte Adresse – der Vergleich, der jeden byteweisen Abgleich von Signaturen ersetzen sollte.