web3.py es el cliente de Python para nodos de Ethereum; la firma de mensajes y de transacciones se delega en el paquete eth-account (0.14.0 con web3 8.0.0), que a su vez usa eth-keys para la aritmética de la curva. La mayor parte del código de firma importa eth_account directamente, como hace el ejemplo.
Account.sign_message(encode_defunct(text=...)) implementa personal_sign: el prefijo EIP-191 con la longitud en bytes en decimal, keccak-256, un nonce RFC 6979 (contrastado con un firmante de referencia independiente) y s en la mitad inferior, con el resultado devuelto como 65 bytes que terminan en v = 27 o 28. encode_defunct es la pieza que se suele olvidar: firmar bytes en bruto con unsafe_sign_hash omite el prefijo, y eso es precisamente lo que hace que una firma no sirva como prueba de inicio de sesión en otros sistemas.
Account.recover_message() recuperó al firmante tanto a partir de la firma high-S reflejada como de v = 0/1, así que acepta más formas que ethers: normaliza s por tu cuenta si las firmas se almacenan o se deduplican. La forma compacta EIP-2098 de 64 bytes se rechazó con Unexpected recoverable signature length: Expected 65, but got 64 bytes; expándela antes de la recuperación.
Para los datos tipados, usa encode_typed_data (EIP-712) en lugar de calcular tú mismo el hash del JSON, y comprueba con el inspector de EIP-712 qué se le pide firmar a una billetera. Las billeteras de contrato inteligente necesitan una llamada ERC-1271 al contrato en lugar de recover_message; los mensajes de inicio de sesión se depuran más fácilmente en el verificador de SIWE.
El ejemplo firma un mensaje de inicio de sesión y compara la dirección recuperada, que es la comparación que debería sustituir a cualquier comprobación byte a byte de las firmas.