Skip to content

Commit

Permalink
Mark assembly blocks as safe (#521)
Browse files Browse the repository at this point in the history
* Mark assembly blocks as safe

* Fix linter
  • Loading branch information
vtleonardo committed Nov 22, 2022
1 parent d361959 commit 225e477
Show file tree
Hide file tree
Showing 13 changed files with 83 additions and 127 deletions.
15 changes: 8 additions & 7 deletions bridge/contracts/Dynamics.sol
Original file line number Diff line number Diff line change
Expand Up @@ -165,13 +165,14 @@ contract Dynamics is Initializable, IDynamics, ImmutableSnapshots {
function _deployStorage(bytes memory data) internal returns (address) {
bytes memory deployCode = abi.encodePacked(_UNIVERSAL_DEPLOY_CODE, data);
address addr;
assembly {
assembly ("memory-safe") {
addr := create(0, add(deployCode, 0x20), mload(deployCode))
if iszero(addr) {
//if contract creation fails, we want to return any err messages
returndatacopy(0x00, 0x00, returndatasize())
//revert and return errors
revert(0x00, returndatasize())
let ptr := mload(0x40)
mstore(0x40, add(ptr, returndatasize()))
returndatacopy(ptr, 0x00, returndatasize())
revert(ptr, returndatasize())
}
}
emit DeployedStorageContract(addr);
Expand Down Expand Up @@ -280,7 +281,7 @@ contract Dynamics is Initializable, IDynamics, ImmutableSnapshots {
uint8[8] memory sizes = [8, 24, 32, 32, 32, 64, 64, 128];
uint256 dynamicValuesTotalSize = 48;
uint256 extCodeSize;
assembly {
assembly ("memory-safe") {
ptr := mload(0x40)
retPtr := values
extCodeSize := extcodesize(addr)
Expand All @@ -292,7 +293,7 @@ contract Dynamics is Initializable, IDynamics, ImmutableSnapshots {

for (uint8 i = 0; i < sizes.length; i++) {
uint8 size = sizes[i];
assembly {
assembly ("memory-safe") {
mstore(retPtr, shr(sub(256, size), mload(ptr)))
ptr := add(ptr, div(size, 8))
retPtr := add(retPtr, 0x20)
Expand Down Expand Up @@ -330,7 +331,7 @@ contract Dynamics is Initializable, IDynamics, ImmutableSnapshots {
uint256 minorVersion,
uint256 patch
) internal pure returns (uint256 fullVersion) {
assembly {
assembly ("memory-safe") {
fullVersion := or(or(shl(64, majorVersion), shl(32, minorVersion)), patch)
}
}
Expand Down
17 changes: 8 additions & 9 deletions bridge/contracts/Foundation.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ pragma solidity ^0.8.16;

import "@openzeppelin/contracts-upgradeable/token/ERC721/ERC721Upgradeable.sol";
import "@openzeppelin/contracts-upgradeable/token/ERC721/IERC721Upgradeable.sol";
import "@openzeppelin/contracts/utils/Address.sol";
import "contracts/utils/auth/ImmutableFactory.sol";
import "contracts/utils/auth/ImmutableAToken.sol";
import "contracts/utils/EthSafeTransfer.sol";
Expand All @@ -19,6 +20,8 @@ contract Foundation is
ImmutableFactory,
ImmutableAToken
{
using Address for address;

constructor() ImmutableFactory(msg.sender) ImmutableAToken() {}

function initialize() public initializer onlyFactory {}
Expand Down Expand Up @@ -52,14 +55,10 @@ contract Foundation is
/// Delegates a call to the specified contract with any set of parameters encoded
/// @param target_ The address of the contract to be delagated to
/// @param cdata_ The encoded parameters of the delegate call encoded
function delegateCallAny(address target_, bytes memory cdata_) public payable onlyFactory {
assembly {
let size := mload(cdata_)
let ptr := add(0x20, cdata_)
if iszero(delegatecall(gas(), target_, ptr, size, 0x00, 0x00)) {
returndatacopy(0x00, 0x00, returndatasize())
revert(0x00, returndatasize())
}
}
function delegateCallAny(
address target_,
bytes memory cdata_
) public payable onlyFactory returns (bytes memory) {
return target_.functionDelegateCall(cdata_);
}
}
56 changes: 7 additions & 49 deletions bridge/contracts/Proxy.sol
Original file line number Diff line number Diff line change
Expand Up @@ -64,14 +64,14 @@ contract Proxy {
case 0xca11c0de11 {
// revert in case user is not factory/admin
if iszero(eq(caller(), factory)) {
revertUnauthorized()
revertASM("unauthorized", 12)
}
// if caller is factory, and has 0xca11c0de00<address> as calldata,
// run admin logic and return
setImplementationAddress()
}
default {
revertIncorrectDataOrFunctionSignature()
revertASM("function not found", 18)
}
}
}
Expand All @@ -80,58 +80,16 @@ contract Proxy {

///////////// Functions ///////////////

function revertUnauthorized() {
function revertASM(str, len) {
let ptr := mload(0x40)
let startPtr := ptr
mstore(ptr, hex"08c379a0") // keccak256('Error(string)')[0:4]
ptr := add(ptr, 0x4)
mstore(ptr, 0x20)
ptr := add(ptr, 0x20)
mstore(ptr, 12) // string length = 13
mstore(ptr, len) // string length
ptr := add(ptr, 0x20)
mstore(ptr, "unauthorized")
ptr := add(ptr, 0x20)
revert(startPtr, sub(ptr, startPtr))
}

function revertImplementationLock() {
let ptr := mload(0x40)
let startPtr := ptr
mstore(ptr, hex"08c379a0") // keccak256('Error(string)')[0:4]
ptr := add(ptr, 0x4)
mstore(ptr, 0x20)
ptr := add(ptr, 0x20)
mstore(ptr, 13) // string length = 13
ptr := add(ptr, 0x20)
mstore(ptr, "update locked")
ptr := add(ptr, 0x20)
revert(startPtr, sub(ptr, startPtr))
}

function revertImplementationNotSetYet() {
let ptr := mload(0x40)
let startPtr := ptr
mstore(ptr, hex"08c379a0") // keccak256('Error(string)')[0:4]
ptr := add(ptr, 0x4)
mstore(ptr, 0x20)
ptr := add(ptr, 0x20)
mstore(ptr, 13) // string length = 13
ptr := add(ptr, 0x20)
mstore(ptr, "logic not set")
ptr := add(ptr, 0x20)
revert(startPtr, sub(ptr, startPtr))
}

function revertIncorrectDataOrFunctionSignature() {
let ptr := mload(0x40)
let startPtr := ptr
mstore(ptr, hex"08c379a0") // keccak256('Error(string)')[0:4]
ptr := add(ptr, 0x4)
mstore(ptr, 0x20)
ptr := add(ptr, 0x20)
mstore(ptr, 18) // string length = 18
ptr := add(ptr, 0x20)
mstore(ptr, "function not found")
mstore(ptr, str)
ptr := add(ptr, 0x20)
revert(startPtr, sub(ptr, startPtr))
}
Expand All @@ -150,7 +108,7 @@ contract Proxy {
function setImplementationAddress() {
// check if the upgrade functionality is locked.
if eq(shr(160, sload(not(0x00))), 0xca11c0de15dead10deadc0de) {
revertImplementationLock()
revertASM("update locked", 13)
}
// this is an assignment to implementation
let newImpl := shr(96, shl(96, calldataload(0x05)))
Expand All @@ -164,7 +122,7 @@ contract Proxy {
function passthrough() {
let logicAddress := sload(not(0x00))
if iszero(logicAddress) {
revertImplementationNotSetYet()
revertASM("logic not set", 13)
}
// load free memory pointer
let ptr := mload(0x40)
Expand Down
8 changes: 4 additions & 4 deletions bridge/contracts/libraries/factory/BridgePoolFactoryBase.sol
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ abstract contract BridgePoolFactoryBase is ImmutableFactory {
// solhint-disable-next-line
fallback() external {
address implementation_ = _implementation;
assembly {
assembly ("memory-safe") {
let ptr := mload(0x40)
mstore(ptr, shl(176, 0x363d3d373d3d3d363d73)) //10
mstore(add(ptr, 10), shl(96, implementation_)) //20
Expand Down Expand Up @@ -84,7 +84,7 @@ abstract contract BridgePoolFactoryBase is ImmutableFactory {
bytes memory alicenetFactoryAddress = abi.encodePacked(
bytes32(uint256(uint160(_factoryAddress())))
);
assembly {
assembly ("memory-safe") {
let ptr := mload(0x40)
calldatacopy(ptr, deployCode_.offset, deployCode_.length)
// add bytes32 alicenet factory address as parameter to constructor
Expand Down Expand Up @@ -141,7 +141,7 @@ abstract contract BridgePoolFactoryBase is ImmutableFactory {
_implementation = implementation;
//check if the logic exists for the specified pool
uint256 implementationSize;
assembly {
assembly ("memory-safe") {
implementationSize := extcodesize(implementation)
}
if (implementationSize == 0) {
Expand All @@ -159,7 +159,7 @@ abstract contract BridgePoolFactoryBase is ImmutableFactory {
*/
function _deployStaticPool(bytes32 salt_) internal returns (address contractAddr) {
uint256 contractSize;
assembly {
assembly ("memory-safe") {
let ptr := mload(0x40)
mstore(ptr, shl(136, 0x5880818283335afa3d82833e3d82f3))
contractAddr := create2(0, ptr, 15, salt_)
Expand Down
60 changes: 30 additions & 30 deletions bridge/contracts/libraries/math/CryptoLibrary.sol
Original file line number Diff line number Diff line change
Expand Up @@ -165,8 +165,7 @@ library CryptoLibrary {
// *) y-coordinate of point Q

bool success;
assembly {
// solium-disable-line
assembly ("memory-safe") {
// 0x06 id of precompiled bn256Add contract
// 0 number of ether to transfer
// 128 size of call parameters, i.e. 128 bytes total
Expand All @@ -189,8 +188,7 @@ library CryptoLibrary {
// *) scalar x

bool success;
assembly {
// solium-disable-line
assembly ("memory-safe") {
// 0x07 id of precompiled bn256ScalarMul contract
// 0 number of ether to transfer
// 96 size of call parameters, i.e. 96 bytes total (256 bit for x, 256 bit for y, 256 bit for scalar)
Expand All @@ -205,8 +203,7 @@ library CryptoLibrary {
function bn128CheckPairing(uint256[12] memory input) internal view returns (bool) {
uint256[1] memory result;
bool success;
assembly {
// solium-disable-line
assembly ("memory-safe") {
// 0x08 id of precompiled bn256Pairing contract (checking the elliptic curve pairings)
// 0 number of ether to transfer
// 384 size of call parameters, i.e. 12*256 bits == 384 bytes
Expand All @@ -228,8 +225,7 @@ library CryptoLibrary {
// and slightly modified
function expmod(uint256 base, uint256 e, uint256 m) internal view returns (uint256 result) {
bool success;
assembly {
// solium-disable-line
assembly ("memory-safe") {
// define pointer
let p := mload(0x40)
// store data assembly-favouring ways
Expand Down Expand Up @@ -369,11 +365,24 @@ library CryptoLibrary {
/// HashToG1 takes byte slice message and outputs an element of G1. Optimized version of `hashToG1`
/// written in EVM assembly.
function hashToG1ASM(bytes memory message) internal view returns (uint256[2] memory h) {
assembly {
assembly ("memory-safe") {
function revertASM(str, len) {
let ptr := mload(0x40)
let startPtr := ptr
mstore(ptr, hex"08c379a0") // keccak256('Error(string)')[0:4]
ptr := add(ptr, 0x4)
mstore(ptr, 0x20)
ptr := add(ptr, 0x20)
mstore(ptr, len) // string length
ptr := add(ptr, 0x20)
mstore(ptr, str)
ptr := add(ptr, 0x20)
revert(startPtr, sub(ptr, startPtr))
}

function memCopy(dest, src, len) {
if lt(len, 32) {
mstore(0, "invalid len")
revert(0, 32)
revertASM("invalid length", 18)
}
// Copy word-length chunks while possible
for {
Expand Down Expand Up @@ -404,7 +413,7 @@ library CryptoLibrary {
memCopy(ptr, paramPtr, 0xb0)
let success := staticcall(gas(), 0x08, ptr, 384, ptr, 32)
if iszero(success) {
revert(0, 0)
revertASM("invalid bn128 pairing", 21)
}
result := mload(ptr)
}
Expand All @@ -426,8 +435,7 @@ library CryptoLibrary {
mstore(add(ptr, 0x60), alpha)
mstore(add(ptr, 0x80), P_MINUS2)
if iszero(staticcall(gas(), 0x05, ptr, 0xc0, fp, 0x20)) {
mstore(0, "exp mod failed at 1")
revert(0, 0x20)
revertASM("exp mod failed at 1", 19)
}
alpha := mload(fp)

Expand All @@ -445,8 +453,7 @@ library CryptoLibrary {
mstore(add(ptr, 0x80), P_PLUS1_OVER4)
mstore(add(ptr, 0x60), x_three)
if iszero(staticcall(gas(), 0x05, ptr, 0xc0, fp, 0x20)) {
mstore(0, "exp mod failed at 2")
revert(0, 0x20)
revertASM("exp mod failed at 2", 19)
}

let ymul := 1
Expand All @@ -467,8 +474,7 @@ library CryptoLibrary {
x_three := addmod(x_three, 3, FIELD_MODULUS)
mstore(add(ptr, 0x60), x_three)
if iszero(staticcall(gas(), 0x05, ptr, 0xc0, fp, 0x20)) {
mstore(0, "exp mod failed at 3")
revert(0, 0x20)
revertASM("exp mod failed at 3", 19)
}
y := mulmod(mload(fp), ymul, FIELD_MODULUS)
y_two := mulmod(y, y, FIELD_MODULUS)
Expand All @@ -489,8 +495,7 @@ library CryptoLibrary {
x_three := addmod(x_three, 3, FIELD_MODULUS)
mstore(add(ptr, 0x60), x_three)
if iszero(staticcall(gas(), 0x05, ptr, 0xc0, fp, 0x20)) {
mstore(0, "exp mod failed at 4")
revert(0, 0x20)
revertASM("exp mod failed at 4", 19)
}
y := mulmod(mload(fp), ymul, FIELD_MODULUS)
mstore(output, x)
Expand Down Expand Up @@ -519,35 +524,30 @@ library CryptoLibrary {
let y1 := mload(add(output, 0x20))
let success := bn128IsOnCurve(x1, y1)
if iszero(success) {
mstore(0, "x1 y1 not in curve")
revert(0, 0x20)
revertASM("x1 y1 not in curve", 18)
}
baseToG1(ptr, h2, output)
let x2 := mload(output)
let y2 := mload(add(output, 0x20))
success := bn128IsOnCurve(x2, y2)
if iszero(success) {
mstore(0, "x2 y2 not in curve")
revert(0, 0x20)
revertASM("x2 y2 not in curve", 18)
}
mstore(ptr, x1)
mstore(add(ptr, 0x20), y1)
mstore(add(ptr, 0x40), x2)
mstore(add(ptr, 0x60), y2)
if iszero(staticcall(gas(), 0x06, ptr, 128, ptr, 64)) {
mstore(0, "bn256 add failed")
revert(0, 0x20)
revertASM("bn256 add failed", 16)
}
let x := mload(ptr)
let y := mload(add(ptr, 0x20))
success := bn128IsOnCurve(x, y)
if iszero(success) {
mstore(0, "x2 y2 not in curve")
revert(0, 0x20)
revertASM("x y not in curve", 16)
}
if or(iszero(x), eq(y, 1)) {
mstore(0, "point not safe to sign")
revert(0, 0x20)
revertASM("point not safe to sign", 22)
}
mstore(output, x)
mstore(add(output, 0x20), y)
Expand Down
Loading

0 comments on commit 225e477

Please sign in to comment.