Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 15 additions & 38 deletions std/std.solc
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -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()
Comment on lines +2133 to +2134

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now it would be nice having gas comparison tests, as I do wonder what is the overhead of require. Ideally nothing.

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 ---
Expand All @@ -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);
}
12 changes: 12 additions & 0 deletions test/examples/dispatch/ecrecover.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,18 @@
"returndata": "0000000000000000000000007e5f4552091a69125d5dfcb7b8c2659029395bdf",
"status": "success"
}
},
{
"input": {
"text-calldata": "recoverFail()(address)",
"calldata": "75ebe7ac",
"value": "0"
},
"kind": "call",
"output": {
"returndata": "4fbfae63",
"status": "failure"
}
}
]
}
Expand Down
12 changes: 12 additions & 0 deletions test/examples/dispatch/ecrecover.solc
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
12 changes: 12 additions & 0 deletions test/testrunner/EVMHost.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 */);
Expand Down
Loading