viem は、Ethereum のクライアント、アカウント、コントラクト、ABI のエンコードとデコードを扱う、型付きでツリーシェイキング可能なライブラリで、wagmi の基盤でもあります。privateKeyToAccount() で作るローカルアカウントは @noble/curves で署名します(viem 2.57.7 はそのバージョン 1.9.1 に依存しています)。そのため署名は RFC 6979 による決定的な low-S 署名で、同じ鍵とメッセージなら ethers が生成するものと同一です。
account.signMessage() は EIP-191 のプレフィックスを付けて keccak-256 でハッシュし、末尾が v = 27 または 28 の 65 バイトを返します。hash パラメーターを指定した sign() は 32 バイトのダイジェストにそのまま署名します。EIP-712 のダイジェストやトランザクションハッシュはこの方法で署名します。チェックでは、どちらも独立した別の実装と照合して確認しました。
検証は ethers より寛容です。recoverMessageAddress() とユーティリティ関数の verifyMessage は、s を n − s に置き換えた high-S 署名を受け入れました。数学的には有効ですが、ethers は non-canonical s で拒否する形式です。署名の重複排除や保存を行うシステムでは、自分で s を正規化してください。そうしないと、同じメッセージに対して見た目の異なる 2 つ目の署名が受け入れられてしまいます。逆に、64 バイトの EIP-2098 コンパクト形式は、どちらの関数でも invalid signature length で失敗しました。先に parseCompactSignature と compactSignatureToSignature で展開してください。
単体のユーティリティ関数 verifyMessage が確認できるのは、外部所有アカウントだけです。スマートコントラクトウォレット(Safe、アカウント抽象化ウォレット、パスキーウォレット)は ERC-1271 または ERC-6492 で署名し、コントラクトに問い合わせるのはパブリッククライアントの verifyMessage アクションだけです。型付きデータは EIP-712 インスペクターで、ログインメッセージは SIWE 検証ツールで、生の署名は Ethereum 署名検証ツールで確認してください。
サンプルはログインメッセージに署名し、アドレスに対する検証と署名者の復元という 2 つの方法で確認します。