viem 是带类型、支持 tree-shaking 的库,用于以太坊客户端、账户、合约和 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 工具函数接受了镜像得到的 high-S 签名——它在数学上有效,但 ethers 会拒绝这种形式,报错 non-canonical s。如果你的系统会对签名去重或存储签名,就要自行规范化 s,否则同一条消息的第二个、看起来不同的签名也会被接受。反过来,64 字节的 EIP-2098 紧凑形式在这两个函数中都报错 invalid signature length;应先用 parseCompactSignature 和 compactSignatureToSignature 将其展开。
独立的 verifyMessage 工具函数只检查外部拥有账户(EOA)。智能合约钱包(Safe、账户抽象钱包、通行密钥钱包)通过 ERC-1271 或 ERC-6492 签名,只有公共客户端(public client)上的 verifyMessage 操作才会向合约查询。可以用 EIP-712 查看器查看类型化数据,用 SIWE 验证工具检查登录消息,用以太坊签名验证工具检查原始签名。
示例对一条登录消息签名,并用两种方式检查:针对地址验证,以及恢复出签名者。