被签名的数据是 0x19 ‖ version ‖ version-specific data ‖ data。版本包括:0x00(附带预期验证器地址的数据)、0x01(结构化数据,即 EIP-712),以及 0x45(字母 E),用于 personal_sign:0x19 后接 Ethereum Signed Message: 和一个换行符,然后是以十进制 ASCII 表示的消息长度,最后是消息本身。RLP 编码的交易不可能以 0x19 开头,这正是加这个前缀的目的。
钱包用 Keccak-256 对结果计算哈希,再用 secp256k1 签名;签名为 65 字节的 r ‖ s ‖ v,其中 v 为 27 或 28。对于消息 hello,摘要为 0x50b2c43fd39106bafbba0da34fc430e1f91e3c96ea2acee2bc34119f92b37750。验证者用 ecrecover(或库提供的 verifyMessage)恢复出地址,再与预期地址比较;智能账户则需要改用 ERC-1271。
personal_sign 向用户展示的是含义不透明的文本,也不提供域或链的绑定,因此应用应该把这些信息写进消息(以太坊登录就是这样做的),或者在内容有结构或涉及价值时优先使用 EIP-712。