ecrecover指令
2021-04-20 本文已影响0人
雪落无留痕
Solidity有一个ecrecover
指令,可以根据消息hash
和签名,返回签名者的地址:
ecrecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) returns (address)
具体代码实现为:
func (s *PrivateAccountAPI) EcRecover(ctx context.Context, data, sig hexutil.Bytes) (common.Address, error) {
if len(sig) != 65 {
return common.Address{}, fmt.Errorf("signature must be 65 bytes long")
}
if sig[64] != 27 && sig[64] != 28 {
return common.Address{}, fmt.Errorf("invalid Ethereum signature (V is not 27 or 28)")
}
sig[64] -= 27 // Transform yellow paper V from 27/28 to 0/1
rpk, err := crypto.Ecrecover(signHash(data), sig)
if err != nil {
return common.Address{}, err
}
pubKey := crypto.ToECDSAPub(rpk)
recoveredAddr := crypto.PubkeyToAddress(*pubKey)
return recoveredAddr, nil
}
vbuterin指出可以使用该指令进行点乘运算的验证,其Solidity 代码实现为:
function ecmulVerify(uint256[2] memory multiplicand, uint256 scalar,
uint256[2] memory product) internal pure returns(bool verifies)
{
require(scalar != 0); // Rules out an ecrecover failure case
uint256 x = multiplicand[0]; // x ordinate of multiplicand
uint8 v = multiplicand[1] % 2 == 0 ? 27 : 28; // parity of y ordinate
// https://ethresear.ch/t/you-can-kinda-abuse-ecrecover-to-do-ecmul-in-secp256k1-today/2384/9
// Point corresponding to address ecrecover(0, v, x, s=scalar*x) is
// (x⁻¹ mod GROUP_ORDER) * (scalar * x * multiplicand - 0 * g), i.e.
// scalar*multiplicand. See https://crypto.stackexchange.com/a/18106
bytes32 scalarTimesX = bytes32(mulmod(scalar, x, GROUP_ORDER));
address actual = ecrecover(bytes32(0), v, bytes32(x), scalarTimesX);
// Explicit conversion to address takes bottom 160 bits
address expected = address(uint256(keccak256(abi.encodePacked(product))));
return (actual == expected);
}
该函数可以检查product==scalar*multiplicand
, 其中product
和 multiplicand
为secp256k1
曲线上的点。
参考
https://github.com/protofire/zeppelin-solidity/blob/master/contracts/ECRecovery.sol
https://www.cnblogs.com/wanghui-garcia/p/9664559.html
https://ethresear.ch/t/you-can-kinda-abuse-ecrecover-to-do-ecmul-in-secp256k1-today/2384