无法可靠地验证签名消息
unable to verify a signed message in solidity
我正在使用本教程:https://web3py.readthedocs.io/en/stable/web3.eth.account.html#sign-a-message
## in web3py
sig = Web3.soliditySha3( [uint256, address], [tokens, contractaddress] ) ## used below also
output: HexBytes('0x3efb3cf4e41109f6f1f998401d02dbe894719a8806f45e79a5fab7d4799f00bb')
from eth_account.messages import encode_defunct
msg = sig.hex()
message = encode_defunct(text=msg)
signed_message = w3.eth.account.sign_message(message, private_key=private_key)
signed_message
SignedMessage(messageHash=HexBytes('0x4c0c7077f770069785167e8b7451d63fad1e858ef5251b239eb0781c314000d2'), r=5665764915496639843348851536709769469640799172147461427941649091688603148258, s=48121517563314450138554207713326165180739298862566159641495137088718857193470, v=27, signature=HexBytes('0x0c86b594baa5bb06a0f4054ffdf3896377cfb757d42dcaeacf0241d96a4d5fe26a63d0514338ec600c89ee808dc088e7b3aadc55b9f5d86685d3ff212e2e47fe1b'))
当我将 signed_message.messageHash
和 signed_message.signature
这些参数传递给智能合约中的 recoversigner(下面提到的)函数时。它给出了正确的地址。但是当我将参数 tokens, contractaddress
(上面使用)传递给 solidity keccak256(abi.encodePacked(token,address(this)))
时,生成的消息与 signed_message.messageHash
不同,反过来我得到一个不同的地址作为 [= 的输出19=].
我检查了 keccak256(abi.encodePacked(..))
的输出是什么。
我发现它与 sig 值相同
我做了什么:
创建一个 ERC20 代币。
设置频道
我的目标:
签名消息(使用 web3py)
用可靠性验证签名消息。
像这样:
用户将传递一些参数:比如合约地址和代币数量以及签名消息。我会用
验证它
function splitSignature(bytes memory sig)
pure
internal
returns (uint8 v, bytes32 r, bytes32 s)
{
require(sig.length == 65 , "invalid length");
assembly {
r := mload(add(sig, 32))
s := mload(add(sig, 64))
v := byte(0, mload(add(sig, 96)))
}
if (v < 27) {
v += 27;
}
require(v == 27 || v == 28 , "value of v ");
return (v, r, s);
}
function recoverSigner(bytes32 message, bytes memory sig)
internal
pure
returns (address)
{
(uint8 v, bytes32 r, bytes32 s) = splitSignature(sig);
return ecrecover(message, v, r, s);
}
bytes32 message = prefixed(keccak256(abi.encodePacked(token,address(this))));
这无法正常工作。我没有得到正确的地址作为输出。
请帮忙..
我不完全清楚你想做什么,但这里要澄清的一个重要问题是 Web3 的 eth.sign
(及其底层的 JSON-RPC 调用 eth_sign
) 不要签署简单的散列。它添加了一个前缀字符串,嵌入了一个长度。
参见 eth_sign
docs:
The sign method calculates an Ethereum specific signature with: sign(keccak256("\x19Ethereum Signed Message:\n" + len(message) + message)))
.
通过向传递的消息添加前缀,您的客户端可以确保您没有使用 eth_sign
来签署交易(可能是意外或由于攻击)。
调用 recoverHash(sig, ...)
有点荒谬。尽管该变量名为“sig
”,但它只是一些数据的哈希值——它还没有被任何东西签名。
如果您正在设计新的消息签名方案,我强烈建议使用某种标准。如果您想要最简单的选项,可以使用 EIP-191 的 "Version 0" 消息。
为此,您可以使用 eth-account 的 encode_intended_validator()
,它看起来像:
from eth_account.messages import encode_intended_validator
message = encode_intended_validator(YOUR_CONTRACT_ADDR, sig)
signed_message = w3.eth.account.sign_message(message, private_key=private_key)
我正在使用本教程:https://web3py.readthedocs.io/en/stable/web3.eth.account.html#sign-a-message
## in web3py
sig = Web3.soliditySha3( [uint256, address], [tokens, contractaddress] ) ## used below also
output: HexBytes('0x3efb3cf4e41109f6f1f998401d02dbe894719a8806f45e79a5fab7d4799f00bb')
from eth_account.messages import encode_defunct
msg = sig.hex()
message = encode_defunct(text=msg)
signed_message = w3.eth.account.sign_message(message, private_key=private_key)
signed_message
SignedMessage(messageHash=HexBytes('0x4c0c7077f770069785167e8b7451d63fad1e858ef5251b239eb0781c314000d2'), r=5665764915496639843348851536709769469640799172147461427941649091688603148258, s=48121517563314450138554207713326165180739298862566159641495137088718857193470, v=27, signature=HexBytes('0x0c86b594baa5bb06a0f4054ffdf3896377cfb757d42dcaeacf0241d96a4d5fe26a63d0514338ec600c89ee808dc088e7b3aadc55b9f5d86685d3ff212e2e47fe1b'))
当我将 signed_message.messageHash
和 signed_message.signature
这些参数传递给智能合约中的 recoversigner(下面提到的)函数时。它给出了正确的地址。但是当我将参数 tokens, contractaddress
(上面使用)传递给 solidity keccak256(abi.encodePacked(token,address(this)))
时,生成的消息与 signed_message.messageHash
不同,反过来我得到一个不同的地址作为 [= 的输出19=].
我检查了 keccak256(abi.encodePacked(..))
的输出是什么。
我发现它与 sig 值相同
我做了什么:
创建一个 ERC20 代币。
设置频道
我的目标:
签名消息(使用 web3py)
用可靠性验证签名消息。
像这样:
用户将传递一些参数:比如合约地址和代币数量以及签名消息。我会用
验证它 function splitSignature(bytes memory sig)
pure
internal
returns (uint8 v, bytes32 r, bytes32 s)
{
require(sig.length == 65 , "invalid length");
assembly {
r := mload(add(sig, 32))
s := mload(add(sig, 64))
v := byte(0, mload(add(sig, 96)))
}
if (v < 27) {
v += 27;
}
require(v == 27 || v == 28 , "value of v ");
return (v, r, s);
}
function recoverSigner(bytes32 message, bytes memory sig)
internal
pure
returns (address)
{
(uint8 v, bytes32 r, bytes32 s) = splitSignature(sig);
return ecrecover(message, v, r, s);
}
bytes32 message = prefixed(keccak256(abi.encodePacked(token,address(this))));
这无法正常工作。我没有得到正确的地址作为输出。
请帮忙..
我不完全清楚你想做什么,但这里要澄清的一个重要问题是 Web3 的 eth.sign
(及其底层的 JSON-RPC 调用 eth_sign
) 不要签署简单的散列。它添加了一个前缀字符串,嵌入了一个长度。
参见 eth_sign
docs:
The sign method calculates an Ethereum specific signature with:
sign(keccak256("\x19Ethereum Signed Message:\n" + len(message) + message)))
.
通过向传递的消息添加前缀,您的客户端可以确保您没有使用 eth_sign
来签署交易(可能是意外或由于攻击)。
调用 recoverHash(sig, ...)
有点荒谬。尽管该变量名为“sig
”,但它只是一些数据的哈希值——它还没有被任何东西签名。
如果您正在设计新的消息签名方案,我强烈建议使用某种标准。如果您想要最简单的选项,可以使用 EIP-191 的 "Version 0" 消息。
为此,您可以使用 eth-account 的 encode_intended_validator()
,它看起来像:
from eth_account.messages import encode_intended_validator
message = encode_intended_validator(YOUR_CONTRACT_ADDR, sig)
signed_message = w3.eth.account.sign_message(message, private_key=private_key)