ethers couvre tout ce dont une application a besoin pour dialoguer avec Ethereum (fournisseurs, contrats, encodage ABI, ENS), et ses classes Wallet et SigningKey sont ce qu’utilise la plupart du code JavaScript pour signer. L’arithmétique de courbe vient de @noble/curves ; ethers 6.17.0 en fige la version 1.2.0.
wallet.signMessage() implémente personal_sign : elle préfixe le message par \x19Ethereum Signed Message:\n et sa longueur (EIP-191), hache avec keccak-256 et renvoie 65 octets r ‖ s ‖ v avec v = 27 ou 28. Les essais ont confirmé le condensat avec une implémentation indépendante de keccak et la signature avec la sortie RFC 6979 de @noble/curves : une même clé et un même message donnent donc toujours les mêmes octets. Pour signer un condensat déjà calculé (un condensat EIP-712, un hash de transaction), utilisez SigningKey.sign(), qui prend exactement 32 octets et n’ajoute aucun préfixe ; toute autre entrée échoue avec invalid digest length.
En entrée, ethers est tolérant sur le format, mais strict sur la forme. verifyMessage() a récupéré le signataire à partir de v = 27/28, de v = 0/1 et de la forme compacte EIP-2098 de 64 octets, mais a refusé la signature miroir high-S avec non-canonical s; use ._s, bien qu’elle soit mathématiquement valide. Les signatures produites par OpenSSL, un KMS cloud ou des modules matériels qui ne normalisent pas s doivent être converties en low-S (s → n − s, en inversant v) avant qu’ethers les accepte ; le vérificateur de signatures Ethereum indique sous quelle forme se trouve une signature.
La plupart des bugs de vérification dans les connexions par portefeuille ne tiennent pas du tout à la courbe : un message qui diffère par un saut de ligne ou une espace finale, un ID de chaîne différent dans un domaine EIP-712, ou un portefeuille de contrat intelligent dont les signatures exigent ERC-1271 au lieu d’ecrecover. Examinez les données typées avec l’inspecteur EIP-712 et les messages de connexion complets avec le vérificateur SIWE.
L’exemple signe un message de connexion, récupère l’adresse et affiche la forme compacte ; comparez les adresses récupérées, jamais les octets de signature, car une même signature a plusieurs encodages valides.