使用例
署名の検証コントラクトに以下のような形で使用されます
contract VerifySignature {
/* Get message hash to sign */
function getMessageHash(string memory _message) public pure returns (bytes32) {
return keccak256(abi.encodePacked(_message));
}
/* Sign message hash */
function getEthSignedMessageHash(bytes32 _messageHash) public pure returns (bytes32) {
// ここ
return keccak256(
abi.encodePacked("\x19Ethereum Signed Message:\n32", _messageHash)
);
}
function verify(
address _signer,
string memory _message,
bytes memory _sig // Signature that was created using MetaMask
) public pure returns (bool) {
bytes32 messageHash = getMessageHash(_message); // Message hash
bytes32 ethSignedMessageHash = getEthSignedMessageHash(messageHash); // Prefixed message hash
return recoverSigner(ethSignedMessageHash, _sig) == _signer; // Compare signrer addresses
}
function recoverSigner(
bytes32 _ethSignedMessageHash,
bytes memory _sig
) public pure returns (address) {
(bytes32 r, bytes32 s, uint8 v) = splitSignature(_sig);
return ecrecover(_ethSignedMessageHash, v, r, s);
}
function splitSignature(bytes memory sig) public pure returns (bytes32 r, bytes32 s, uint8 v) {
require(sig.length == 65, "invalid signature length");
assembly {
r := mload(add(sig, 32))
s := mload(add(sig, 64))
v := byte(0, mload(add(sig, 96)))
}
}
}
解説
"\\x19Ethereum Signed Message:\\n32"
はEthereumでメッセージを署名する際の標準的なプレフィックス(接頭辞)です。これはEthereumクライアントによってメッセージに自動的に追加されます。
-
\\x19
は単一のバイトで、数値の25を表します。これは署名されるメッセージがただのデータであることを示すために追加されます。 -
Ethereum Signed Message:
は明示的なテキストで、署名されるメッセージがEthereumの署名メッセージであることを示します。 -
\\n32
は改行文字と32を示します。この32は、次に続くメッセージの長さ(バイト数)を表します。この場合、32バイトの長さは、Keccak256ハッシュ関数(EthereumのSHA3バージョン)によって生成されたハッシュの長さと一致します。
このプレフィックスは、ユーザーが署名するデータが偽造されたトランザクションではないことを確認するためのものです。つまり、Ethereumクライアントは、データがトランザクションではなく、単なるメッセージであることを示すためにこのプレフィックスを追加します。
そのため、keccak256(abi.encodePacked("\\x19Ethereum Signed Message:\\n32", _messageHash));
のコードは、署名を検証する際に、Ethereumクライアントによって追加されたプレフィックスを考慮に入れるために使用されます。
See also: