前言
以太坊的签名与验签可以用来metamask钱包登录,多签钱包等应用。但没有全面的文档进行相关的解释,这里笔者整理了相关的方法
签名
metamask的ethereum签名
const msg = '0x553d52098a30d90afbae2f14f7872b8ede6c2eb7020661813b9f75df14cb8da7'
const account = await signer.getAddress()
const signedMessage = await ethereum.request({ method: "personal_sign", params: [account, msg] })
ethers签名
const msg = '0x553d52098a30d90afbae2f14f7872b8ede6c2eb7020661813b9f75df14cb8da7'
// 亦可以用私钥来构建signer
const provider = new ethers.providers.Web3Provider(window.ethereum)
const signer = provider.getSigner()
// 这里一定要把msg通过arrayify方法,功能类似于下文中solidity中的getEthSignedMessageHash方法
const signedMessage = await signer.signMessage(ethers.utils.arrayify(msg))
验签
solidity验签
function getEthSignedMessageHash(bytes32 _messageHash)
public
pure
returns (bytes32)
{
/*
Signature is produced by signing a keccak256 hash with the following format:
"\x19Ethereum Signed Message\n" + len(msg) + msg
*/
return
keccak256(
abi.encodePacked("\x19Ethereum Signed Message:\n32", _messageHash)
);
}
function splitSignature(bytes memory sig)
public
pure
returns (
bytes32 r,
bytes32 s,
uint8 v
)
{
require(sig.length == 65, "invalid signature length");
assembly {
/*
First 32 bytes stores the length of the signature
add(sig, 32) = pointer of sig + 32
effectively, skips first 32 bytes of signature
mload(p) loads next 32 bytes starting at the memory address p into memory
*/
// first 32 bytes, after the length prefix
r := mload(add(sig, 32))
// second 32 bytes
s := mload(add(sig, 64))
// final byte (first byte of the next 32 bytes)
v := byte(0, mload(add(sig, 96)))
}
// implicitly return (r, s, v)
}
// !!!_ethSignedMessageHash需要把msg传入getEthSignedMessageHash再次hash
function recoverSigner(bytes32 _ethSignedMessageHash, bytes memory _signature)
public
pure
returns (address)
{
(bytes32 r, bytes32 s, uint8 v) = splitSignature(_signature);
return ecrecover(_ethSignedMessageHash, v, r, s);
}
ethers验签
// 理论上可以签名和验签都不加ethers.utils.arrayify(),但是为了和solidity验签签名保持一致,最好如此
const signerAddr = await ethers.utils.verifyMessage(ethers.utils.arrayify(msg), signedMessage)
参考
solidity-by-example
Sign Message with Ethers.js and Verify with Solidity Contract