-
Notifications
You must be signed in to change notification settings - Fork 29
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
MessageHarness #30
Merged
Merged
MessageHarness #30
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,11 +1,7 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity >=0.5.10 <0.8.14; | ||
|
||
import { SafeMath } from "@openzeppelin/contracts/utils/math/SafeMath.sol"; | ||
// SPDX-License-Identifier: MIT OR Apache-2.0 | ||
pragma solidity >=0.8.12; | ||
|
||
library TypedMemView { | ||
using SafeMath for uint256; | ||
|
||
// Why does this exist? | ||
// the solidity `bytes memory` type has a few weaknesses. | ||
// 1. You can't index ranges effectively | ||
|
@@ -147,21 +143,27 @@ library TypedMemView { | |
* @return second - The bottom 16 bytes | ||
*/ | ||
function encodeHex(uint256 _b) internal pure returns (uint256 first, uint256 second) { | ||
for (uint8 i = 31; i > 15; i -= 1) { | ||
for (uint8 i = 31; i > 15; ) { | ||
uint8 _byte = uint8(_b >> (i * 8)); | ||
first |= byteHex(_byte); | ||
if (i != 16) { | ||
first <<= 16; | ||
} | ||
unchecked { | ||
i -= 1; | ||
} | ||
} | ||
|
||
// abusing underflow here =_= | ||
for (uint8 i = 15; i < 255; i -= 1) { | ||
for (uint8 i = 15; i < 255; ) { | ||
uint8 _byte = uint8(_b >> (i * 8)); | ||
second |= byteHex(_byte); | ||
if (i != 0) { | ||
second <<= 16; | ||
} | ||
unchecked { | ||
i -= 1; | ||
} | ||
} | ||
} | ||
|
||
|
@@ -202,7 +204,7 @@ library TypedMemView { | |
function leftMask(uint8 _len) private pure returns (uint256 mask) { | ||
// ugly. redo without assembly? | ||
assembly { | ||
// solium-disable-previous-line security/no-inline-assembly | ||
// solhint-disable-previous-line no-inline-assembly | ||
mask := sar( | ||
sub(_len, 1), | ||
0x8000000000000000000000000000000000000000000000000000000000000000 | ||
|
@@ -248,7 +250,7 @@ library TypedMemView { | |
} | ||
uint256 _end = end(memView); | ||
assembly { | ||
// solium-disable-previous-line security/no-inline-assembly | ||
// solhint-disable-previous-line no-inline-assembly | ||
ret := not(gt(_end, mload(0x40))) | ||
} | ||
} | ||
|
@@ -307,7 +309,7 @@ library TypedMemView { | |
function castTo(bytes29 memView, uint40 _newType) internal pure returns (bytes29 newView) { | ||
// then | in the new type | ||
assembly { | ||
// solium-disable-previous-line security/no-inline-assembly | ||
// solhint-disable-previous-line no-inline-assembly | ||
// shift off the top 5 bytes | ||
newView := or(newView, shr(40, shl(40, memView))) | ||
newView := or(newView, shl(216, _newType)) | ||
|
@@ -330,7 +332,7 @@ library TypedMemView { | |
uint256 _len | ||
) private pure returns (bytes29 newView) { | ||
assembly { | ||
// solium-disable-previous-line security/no-inline-assembly | ||
// solhint-disable-previous-line no-inline-assembly | ||
newView := shl(96, or(newView, _type)) // insert type | ||
newView := shl(96, or(newView, _loc)) // insert loc | ||
newView := shl(24, or(newView, _len)) // empty bottom 3 bytes | ||
|
@@ -352,9 +354,9 @@ library TypedMemView { | |
uint256 _loc, | ||
uint256 _len | ||
) internal pure returns (bytes29 newView) { | ||
uint256 _end = _loc.add(_len); | ||
uint256 _end = _loc + _len; | ||
assembly { | ||
// solium-disable-previous-line security/no-inline-assembly | ||
// solhint-disable-previous-line no-inline-assembly | ||
if gt(_end, mload(0x40)) { | ||
_end := 0 | ||
} | ||
|
@@ -378,7 +380,7 @@ library TypedMemView { | |
|
||
uint256 _loc; | ||
assembly { | ||
// solium-disable-previous-line security/no-inline-assembly | ||
// solhint-disable-previous-line no-inline-assembly | ||
_loc := add(arr, 0x20) // our view is of the data, not the struct | ||
} | ||
|
||
|
@@ -392,7 +394,7 @@ library TypedMemView { | |
*/ | ||
function typeOf(bytes29 memView) internal pure returns (uint40 _type) { | ||
assembly { | ||
// solium-disable-previous-line security/no-inline-assembly | ||
// solhint-disable-previous-line no-inline-assembly | ||
// 216 == 256 - 40 | ||
_type := shr(216, memView) // shift out lower 24 bytes | ||
} | ||
|
@@ -416,7 +418,7 @@ library TypedMemView { | |
function loc(bytes29 memView) internal pure returns (uint96 _loc) { | ||
uint256 _mask = LOW_12_MASK; // assembly can't use globals | ||
assembly { | ||
// solium-disable-previous-line security/no-inline-assembly | ||
// solhint-disable-previous-line no-inline-assembly | ||
// 120 bits = 12 bytes (the encoded loc) + 3 bytes (empty low space) | ||
_loc := and(shr(120, memView), _mask) | ||
} | ||
|
@@ -428,7 +430,7 @@ library TypedMemView { | |
* @return uint256 - The number of memory words | ||
*/ | ||
function words(bytes29 memView) internal pure returns (uint256) { | ||
return uint256(len(memView)).add(32) / 32; | ||
return (uint256(len(memView)) + 32) / 32; | ||
} | ||
|
||
/** | ||
|
@@ -448,7 +450,7 @@ library TypedMemView { | |
function len(bytes29 memView) internal pure returns (uint96 _len) { | ||
uint256 _mask = LOW_12_MASK; // assembly can't use globals | ||
assembly { | ||
// solium-disable-previous-line security/no-inline-assembly | ||
// solhint-disable-previous-line no-inline-assembly | ||
_len := and(shr(24, memView), _mask) | ||
} | ||
} | ||
|
@@ -459,7 +461,9 @@ library TypedMemView { | |
* @return uint256 - The endpoint of `memView` | ||
*/ | ||
function end(bytes29 memView) internal pure returns (uint256) { | ||
return loc(memView) + len(memView); | ||
unchecked { | ||
return loc(memView) + len(memView); | ||
} | ||
} | ||
|
||
/** | ||
|
@@ -479,11 +483,11 @@ library TypedMemView { | |
uint256 _loc = loc(memView); | ||
|
||
// Ensure it doesn't overrun the view | ||
if (_loc.add(_index).add(_len) > end(memView)) { | ||
if (_loc + _index + _len > end(memView)) { | ||
return NULL; | ||
} | ||
|
||
_loc = _loc.add(_index); | ||
_loc = _loc + _index; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. if |
||
return build(newType, _loc, _len); | ||
} | ||
|
||
|
@@ -514,7 +518,7 @@ library TypedMemView { | |
uint256 _len, | ||
uint40 newType | ||
) internal pure returns (bytes29) { | ||
return slice(memView, uint256(len(memView)).sub(_len), _len, newType); | ||
return slice(memView, uint256(len(memView)) - _len, _len, newType); | ||
} | ||
|
||
/** | ||
|
@@ -568,16 +572,19 @@ library TypedMemView { | |
if (_bytes == 0) { | ||
return bytes32(0); | ||
} | ||
if (_index.add(_bytes) > len(memView)) { | ||
if (_index + _bytes > len(memView)) { | ||
revert(indexErrOverrun(loc(memView), len(memView), _index, uint256(_bytes))); | ||
} | ||
require(_bytes <= 32, "TypedMemView/index - Attempted to index more than 32 bytes"); | ||
|
||
uint8 bitLength = _bytes * 8; | ||
uint8 bitLength; | ||
unchecked { | ||
bitLength = _bytes * 8; | ||
} | ||
uint256 _loc = loc(memView); | ||
uint256 _mask = leftMask(bitLength); | ||
assembly { | ||
// solium-disable-previous-line security/no-inline-assembly | ||
// solhint-disable-previous-line no-inline-assembly | ||
result := and(mload(add(_loc, _index)), _mask) | ||
} | ||
} | ||
|
@@ -633,7 +640,7 @@ library TypedMemView { | |
uint256 _loc = loc(memView); | ||
uint256 _len = len(memView); | ||
assembly { | ||
// solium-disable-previous-line security/no-inline-assembly | ||
// solhint-disable-previous-line no-inline-assembly | ||
digest := keccak256(_loc, _len) | ||
} | ||
} | ||
|
@@ -648,7 +655,7 @@ library TypedMemView { | |
uint256 _loc = loc(memView); | ||
uint256 _len = len(memView); | ||
assembly { | ||
// solium-disable-previous-line security/no-inline-assembly | ||
// solhint-disable-previous-line no-inline-assembly | ||
let ptr := mload(0x40) | ||
pop(staticcall(gas(), 2, _loc, _len, ptr, 0x20)) // sha2 #1 | ||
digest := mload(ptr) | ||
|
@@ -664,7 +671,7 @@ library TypedMemView { | |
uint256 _loc = loc(memView); | ||
uint256 _len = len(memView); | ||
assembly { | ||
// solium-disable-previous-line security/no-inline-assembly | ||
// solhint-disable-previous-line no-inline-assembly | ||
let ptr := mload(0x40) | ||
pop(staticcall(gas(), 2, _loc, _len, ptr, 0x20)) // sha2 | ||
pop(staticcall(gas(), 3, ptr, 0x20, ptr, 0x20)) // rmd160 | ||
|
@@ -681,7 +688,7 @@ library TypedMemView { | |
uint256 _loc = loc(memView); | ||
uint256 _len = len(memView); | ||
assembly { | ||
// solium-disable-previous-line security/no-inline-assembly | ||
// solhint-disable-previous-line no-inline-assembly | ||
let ptr := mload(0x40) | ||
pop(staticcall(gas(), 2, _loc, _len, ptr, 0x20)) // sha2 #1 | ||
pop(staticcall(gas(), 2, ptr, 0x20, ptr, 0x20)) // sha2 #2 | ||
|
@@ -751,7 +758,7 @@ library TypedMemView { | |
|
||
uint256 ptr; | ||
assembly { | ||
// solium-disable-previous-line security/no-inline-assembly | ||
// solhint-disable-previous-line no-inline-assembly | ||
ptr := mload(0x40) | ||
// revert if we're writing in occupied memory | ||
if gt(ptr, _newLoc) { | ||
|
@@ -777,13 +784,15 @@ library TypedMemView { | |
uint256 ptr; | ||
uint256 _len = len(memView); | ||
assembly { | ||
// solium-disable-previous-line security/no-inline-assembly | ||
// solhint-disable-previous-line no-inline-assembly | ||
ptr := mload(0x40) // load unused memory pointer | ||
ret := ptr | ||
} | ||
unsafeCopyTo(memView, ptr + 0x20); | ||
unchecked { | ||
unsafeCopyTo(memView, ptr + 0x20); | ||
} | ||
assembly { | ||
// solium-disable-previous-line security/no-inline-assembly | ||
// solhint-disable-previous-line no-inline-assembly | ||
mstore(0x40, add(add(ptr, _len), 0x20)) // write new unused pointer | ||
mstore(ptr, _len) // write len of new array (in bytes) | ||
} | ||
|
@@ -805,7 +814,7 @@ library TypedMemView { | |
returns (bytes29 unsafeView) | ||
{ | ||
assembly { | ||
// solium-disable-previous-line security/no-inline-assembly | ||
// solhint-disable-previous-line no-inline-assembly | ||
let ptr := mload(0x40) | ||
// revert if we're writing in occupied memory | ||
if gt(ptr, _location) { | ||
|
@@ -816,8 +825,10 @@ library TypedMemView { | |
uint256 _offset = 0; | ||
for (uint256 i = 0; i < memViews.length; i++) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
bytes29 memView = memViews[i]; | ||
unsafeCopyTo(memView, _location + _offset); | ||
_offset += len(memView); | ||
unchecked { | ||
unsafeCopyTo(memView, _location + _offset); | ||
_offset += len(memView); | ||
} | ||
} | ||
unsafeView = unsafeBuildUnchecked(0, _location, _offset); | ||
} | ||
|
@@ -830,7 +841,7 @@ library TypedMemView { | |
function joinKeccak(bytes29[] memory memViews) internal view returns (bytes32) { | ||
uint256 ptr; | ||
assembly { | ||
// solium-disable-previous-line security/no-inline-assembly | ||
// solhint-disable-previous-line no-inline-assembly | ||
ptr := mload(0x40) // load unused memory pointer | ||
} | ||
return keccak(unsafeJoin(memViews, ptr)); | ||
|
@@ -844,7 +855,7 @@ library TypedMemView { | |
function joinSha2(bytes29[] memory memViews) internal view returns (bytes32) { | ||
uint256 ptr; | ||
assembly { | ||
// solium-disable-previous-line security/no-inline-assembly | ||
// solhint-disable-previous-line no-inline-assembly | ||
ptr := mload(0x40) // load unused memory pointer | ||
} | ||
return sha2(unsafeJoin(memViews, ptr)); | ||
|
@@ -858,16 +869,19 @@ library TypedMemView { | |
function join(bytes29[] memory memViews) internal view returns (bytes memory ret) { | ||
uint256 ptr; | ||
assembly { | ||
// solium-disable-previous-line security/no-inline-assembly | ||
// solhint-disable-previous-line no-inline-assembly | ||
ptr := mload(0x40) // load unused memory pointer | ||
} | ||
|
||
bytes29 _newView = unsafeJoin(memViews, ptr + 0x20); | ||
bytes29 _newView; | ||
unchecked { | ||
_newView = unsafeJoin(memViews, ptr + 0x20); | ||
} | ||
uint256 _written = len(_newView); | ||
uint256 _footprint = footprint(_newView); | ||
|
||
assembly { | ||
// solium-disable-previous-line security/no-inline-assembly | ||
// solhint-disable-previous-line no-inline-assembly | ||
// store the legnth | ||
mstore(ptr, _written) | ||
// new pointer is old + 0x20 + the footprint of the body | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
// SPDX-License-Identifier: MIT | ||
|
||
pragma solidity 0.8.13; | ||
|
||
import "forge-std/Test.sol"; | ||
import "forge-std/console2.sol"; | ||
|
||
import { MessageHarness } from "./harnesses/MessageHarness.sol"; | ||
import { TypedMemView } from "../contracts/libs/TypedMemView.sol"; | ||
|
||
contract MessageTest is Test { | ||
MessageHarness messageHarness; | ||
using TypedMemView for bytes; | ||
using TypedMemView for bytes29; | ||
|
||
uint32 originDomain; | ||
bytes32 sender; | ||
uint32 nonce; | ||
uint32 destinationDomain; | ||
bytes32 recipient; | ||
bytes messageBody; | ||
|
||
function setUp() public { | ||
messageHarness = new MessageHarness(); | ||
originDomain = 1000; | ||
sender = bytes32("AAAA THE SENDOOOOOR"); | ||
nonce = 0; | ||
destinationDomain = 2000; | ||
recipient = bytes32("AAAA THE RECEIVOOOR"); | ||
messageBody = bytes("Messagoooor"); | ||
} | ||
|
||
function test_formatMessage() public { | ||
bytes memory message = messageHarness.formatMessage( | ||
originDomain, | ||
sender, | ||
nonce, | ||
destinationDomain, | ||
recipient, | ||
messageBody | ||
); | ||
|
||
console2.log(messageHarness.origin(message)); | ||
assertEq(messageHarness.origin(message), originDomain); | ||
assertEq(messageHarness.sender(message), sender); | ||
assertEq(messageHarness.nonce(message), nonce); | ||
assertEq(messageHarness.destination(message), destinationDomain); | ||
assertEq(messageHarness.recipient(message), recipient); | ||
assertEq(messageHarness.body(message), (messageBody)); | ||
assertEq(messageHarness.leaf(message), keccak256(message)); | ||
} | ||
|
||
function test_messageHash() public { | ||
bytes memory message = messageHarness.formatMessage( | ||
originDomain, | ||
sender, | ||
nonce, | ||
destinationDomain, | ||
recipient, | ||
messageBody | ||
); | ||
|
||
bytes32 messageHash = messageHarness.messageHash( | ||
originDomain, | ||
sender, | ||
nonce, | ||
destinationDomain, | ||
recipient, | ||
messageBody | ||
); | ||
|
||
assertEq(messageHash, keccak256(message)); | ||
} | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
len(memView)
isuint96
, so this never overflows, safe touncheck
itThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
footprint
will never overflow as well