diff --git a/std/std.solc b/std/std.solc index f4321a59..ee8d6179 100644 --- a/std/std.solc +++ b/std/std.solc @@ -1,4 +1,4 @@ -import std.opcodes.{mstore, mload, sstore, sload}; +import std.opcodes.{gas, staticcall, mstore, mload, sstore, sload}; pragma no-patterson-condition ABIEncode, Num; pragma no-coverage-condition ABIDecode, MemoryType; @@ -2129,33 +2129,19 @@ forall a . a:MemorySize, a:MemoryPointer => function keccak256_(input: a) -> byt forall a . a:MemorySize, a:MemoryPointer => function sha256(input: a) -> bytes32 { let len : word = MemorySize.len(input); let ptr : word = MemoryPointer.ptr(input); - let res : word; // We assume the [0, 32] scratch space is reserved. - // TODO: add specific error code - assembly { - let ret := staticcall(gas(), 2, ptr, len, 0, 32) - if iszero(ret) { - revert(0, 0) - } - res := mload(0) - } - return bytes32(res); + let ret = staticcall(gas(), 2, ptr, len, 0, 32); + require(ret != 0, Error(0x68c071bb)); // SHA256CallFailed() + return bytes32(mload(0)); } forall a . a:MemorySize, a:MemoryPointer => function ripemd160(input: a) -> bytes32 { let len : word = MemorySize.len(input); let ptr : word = MemoryPointer.ptr(input); - let res : word; // We assume the [0, 32] scratch space is reserved. - // TODO: add specific error code - assembly { - let ret := staticcall(gas(), 3, ptr, len, 0, 32) - if iszero(ret) { - revert(0, 0) - } - res := mload(0) - } - return bytes32(res); + let ret = staticcall(gas(), 3, ptr, len, 0, 32); + require(ret != 0, Error(0x31a72d92)); // RIPEMD160CallFailed() + return bytes32(mload(0)); } // --- Precompiles --- @@ -2177,23 +2163,14 @@ function ecrecover(hash: bytes32, v: uint256, r: bytes32, s: bytes32) -> address let r_ = Typedef.rep(r); let s_ = Typedef.rep(s); let ptr = get_free_memory(); - let res: word; // We assume the [0, 32] scratch space is reserved. - // TODO: add specific error code - assembly { - mstore(ptr, hash_) - mstore(add(ptr, 32), v_) - mstore(add(ptr, 64), r_) - mstore(add(ptr, 96), s_) - - let ret := staticcall(gas(), 1, ptr, 128, 0, 32) - if iszero(ret) { - revert(0, 0) - } - res := mload(0) - if iszero(res) { - revert(0, 0) - } - } + mstore(ptr, hash_); + mstore(ptr + 32, v_); + mstore(ptr + 64, r_); + mstore(ptr + 96, s_); + let ret = staticcall(gas(), 1, ptr, 128, 0, 32); + require(ret != 0, Error(0x578763f7)); // ECRecoverCallFailed() + let res = mload(0); + require(res != 0, Error(0x4fbfae63)); // ECRecoverFailed() return address(res); } diff --git a/test/examples/dispatch/ecrecover.json b/test/examples/dispatch/ecrecover.json index 3e4a2b13..8d39fff0 100644 --- a/test/examples/dispatch/ecrecover.json +++ b/test/examples/dispatch/ecrecover.json @@ -21,6 +21,18 @@ "returndata": "0000000000000000000000007e5f4552091a69125d5dfcb7b8c2659029395bdf", "status": "success" } + }, + { + "input": { + "text-calldata": "recoverFail()(address)", + "calldata": "75ebe7ac", + "value": "0" + }, + "kind": "call", + "output": { + "returndata": "4fbfae63", + "status": "failure" + } } ] } diff --git a/test/examples/dispatch/ecrecover.solc b/test/examples/dispatch/ecrecover.solc index 49dbfd98..9cb8c790 100644 --- a/test/examples/dispatch/ecrecover.solc +++ b/test/examples/dispatch/ecrecover.solc @@ -9,4 +9,16 @@ contract EcrecoverTest { let s: bytes32 = bytes32(0x3523e7d34da277c59af090e44cebddb10b73be11780f028d02cf5ae5f24109fc); return ecrecover(h, v, r, s); } + + // r = 0 is an invalid signature component: the precompile succeeds (ret != 0) + // but recovers nothing, so it returns empty output and `res` stays 0. This + // exercises the `ECRecoverFailed()` (0x4fbfae63) revert path. `v` and `s` + // are kept well-formed so neither the malleability nor call-failed guards fire. + public function recoverFail() -> address { + let h: bytes32 = bytes32(0xaabbccddeeff00112233445566778899aabbccddeeff00112233445566778899); + let v: uint256 = uint256(27); + let r: bytes32 = bytes32(0x0); + let s: bytes32 = bytes32(0x3523e7d34da277c59af090e44cebddb10b73be11780f028d02cf5ae5f24109fc); + return ecrecover(h, v, r, s); + } } diff --git a/test/testrunner/EVMHost.cpp b/test/testrunner/EVMHost.cpp index 5d15b9d2..eb788df7 100644 --- a/test/testrunner/EVMHost.cpp +++ b/test/testrunner/EVMHost.cpp @@ -541,6 +541,18 @@ evmc::Result EVMHost::precompileECRecover(evmc_message const& _message) noexcept fromHex("0000000000000000000000007e5f4552091a69125d5dfcb7b8c2659029395bdf"), gas_cost } + }, + { + fromHex( + "aabbccddeeff00112233445566778899aabbccddeeff00112233445566778899" + "000000000000000000000000000000000000000000000000000000000000001b" + "0000000000000000000000000000000000000000000000000000000000000000" + "3523e7d34da277c59af090e44cebddb10b73be11780f028d02cf5ae5f24109fc" + ), + { + fromHex(""), + gas_cost + } } }; evmc::Result result = precompileGeneric(_message, inputOutput, true /* _ignoresTrailingInput */);