Skip to content

Commit

Permalink
Merge pull request #69 from 0xPolygon/sec/update-rlp
Browse files Browse the repository at this point in the history
Update RLPReader
  • Loading branch information
DhairyaSethi authored Dec 19, 2023
2 parents 296ac8d + 8ca8544 commit 7319592
Showing 1 changed file with 52 additions and 37 deletions.
89 changes: 52 additions & 37 deletions contracts/lib/RLPReader.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@
* @author Hamdi Allam [email protected]
* Please reach out with any questions or concerns
*/

pragma solidity ^0.8.0;
pragma solidity >=0.5.10 <0.9.0;

library RLPReader {
uint8 constant STRING_SHORT_START = 0x80;
Expand Down Expand Up @@ -74,21 +73,33 @@ library RLPReader {
}

/*
* @param item RLP encoded bytes
* @param the RLP item.
*/
function rlpLen(RLPItem memory item) internal pure returns (uint256) {
return item.len;
}

/*
* @param item RLP encoded bytes
* @param the RLP item.
* @return (memPtr, len) pair: location of the item's payload in memory.
*/
function payloadLocation(RLPItem memory item) internal pure returns (uint256, uint256) {
uint256 offset = _payloadOffset(item.memPtr);
uint256 memPtr = item.memPtr + offset;
uint256 len = item.len - offset; // data length
return (memPtr, len);
}

/*
* @param the RLP item.
*/
function payloadLen(RLPItem memory item) internal pure returns (uint256) {
return item.len - _payloadOffset(item.memPtr);
(, uint256 len) = payloadLocation(item);
return len;
}

/*
* @param item RLP encoded list in bytes
* @param the RLP item containing the encoded list.
*/
function toList(RLPItem memory item) internal pure returns (RLPItem[] memory) {
require(isList(item));
Expand Down Expand Up @@ -135,13 +146,6 @@ library RLPReader {
return result;
}

function payloadLocation(RLPItem memory item) internal pure returns (uint256, uint256) {
uint256 offset = _payloadOffset(item.memPtr);
uint256 memPtr = item.memPtr + offset;
uint256 len = item.len - offset; // data length
return (memPtr, len);
}

/*
* @dev A cheaper version of keccak256(toBytes(item)) that avoids copying memory.
* @return keccak256 hash of the item payload.
Expand Down Expand Up @@ -171,7 +175,7 @@ library RLPReader {
return result;
}

// any non-zero byte < 128 is considered true
// any non-zero byte except "0x80" is considered true
function toBoolean(RLPItem memory item) internal pure returns (bool) {
require(item.len == 1);
uint256 result;
Expand All @@ -180,7 +184,15 @@ library RLPReader {
result := byte(0, mload(memPtr))
}

return result == 0 ? false : true;
// SEE Github Issue #5.
// Summary: Most commonly used RLP libraries (i.e Geth) will encode
// "0" as "0x80" instead of as "0". We handle this edge case explicitly
// here.
if (result == 0 || result == STRING_SHORT_START) {
return false;
} else {
return true;
}
}

function toAddress(RLPItem memory item) internal pure returns (address) {
Expand All @@ -193,11 +205,9 @@ library RLPReader {
function toUint(RLPItem memory item) internal pure returns (uint256) {
require(item.len > 0 && item.len <= 33);

uint256 offset = _payloadOffset(item.memPtr);
uint256 len = item.len - offset;
(uint256 memPtr, uint256 len) = payloadLocation(item);

uint256 result;
uint256 memPtr = item.memPtr + offset;
assembly {
result := mload(memPtr)

Expand Down Expand Up @@ -227,16 +237,15 @@ library RLPReader {
function toBytes(RLPItem memory item) internal pure returns (bytes memory) {
require(item.len > 0);

uint256 offset = _payloadOffset(item.memPtr);
uint256 len = item.len - offset; // data length
(uint256 memPtr, uint256 len) = payloadLocation(item);
bytes memory result = new bytes(len);

uint256 destPtr;
assembly {
destPtr := add(0x20, result)
}

copy(item.memPtr + offset, destPtr, len);
copy(memPtr, destPtr, len);
return result;
}

Expand Down Expand Up @@ -267,12 +276,15 @@ library RLPReader {
byte0 := byte(0, mload(memPtr))
}

if (byte0 < STRING_SHORT_START) itemLen = 1;
else if (byte0 < STRING_LONG_START) itemLen = byte0 - STRING_SHORT_START + 1;
else if (byte0 < LIST_SHORT_START) {
if (byte0 < STRING_SHORT_START) {
itemLen = 1;
} else if (byte0 < STRING_LONG_START) {
itemLen = byte0 - STRING_SHORT_START + 1;
} else if (byte0 < LIST_SHORT_START) {
assembly {
let byteLen := sub(byte0, 0xb7) // # of bytes the actual length is
memPtr := add(memPtr, 1) // skip over the first byte

/* 32 byte word size */
let dataLen := div(mload(memPtr), exp(256, sub(32, byteLen))) // right shifting to get the len
itemLen := add(dataLen, add(byteLen, 1))
Expand All @@ -299,12 +311,16 @@ library RLPReader {
byte0 := byte(0, mload(memPtr))
}

if (byte0 < STRING_SHORT_START) return 0;
else if (byte0 < STRING_LONG_START || (byte0 >= LIST_SHORT_START && byte0 < LIST_LONG_START)) return 1;
else if (byte0 < LIST_SHORT_START)
if (byte0 < STRING_SHORT_START) {
return 0;
} else if (byte0 < STRING_LONG_START || (byte0 >= LIST_SHORT_START && byte0 < LIST_LONG_START)) {
return 1;
} else if (byte0 < LIST_SHORT_START) {
// being explicit
return byte0 - (STRING_LONG_START - 1) + 1;
else return byte0 - (LIST_LONG_START - 1) + 1;
} else {
return byte0 - (LIST_LONG_START - 1) + 1;
}
}

/*
Expand All @@ -325,15 +341,14 @@ library RLPReader {
dest += WORD_SIZE;
}

if (len == 0) return;

// left over bytes. Mask is used to remove unwanted bytes from the word
uint256 mask = 256 ** (WORD_SIZE - len) - 1;

assembly {
let srcpart := and(mload(src), not(mask)) // zero out src
let destpart := and(mload(dest), mask) // retrieve the bytes
mstore(dest, or(destpart, srcpart))
if (len > 0) {
// left over bytes. Mask is used to remove unwanted bytes from the word
uint256 mask = 256 ** (WORD_SIZE - len) - 1;
assembly {
let srcpart := and(mload(src), not(mask)) // zero out src
let destpart := and(mload(dest), mask) // retrieve the bytes
mstore(dest, or(destpart, srcpart))
}
}
}
}

0 comments on commit 7319592

Please sign in to comment.