Commit e4693481 authored by smartcontracts's avatar smartcontracts Committed by GitHub

fix(ctb): clean up BytesUtils (#2964)

Cleans up BytesUtils and properly attributes the slice code (although
it's licensed as Unlicense so I don't think strictly necessary, but
attribution is always nice and I think we just missed it the first time
around).
Co-authored-by: default avatarmergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
parent 9d435aec
---
'@eth-optimism/contracts-bedrock': patch
---
Clean up BytesUtils
This diff is collapsed.
...@@ -3,20 +3,31 @@ pragma solidity ^0.8.9; ...@@ -3,20 +3,31 @@ pragma solidity ^0.8.9;
/** /**
* @title BytesUtils * @title BytesUtils
* @notice BytesUtils is a library for manipulating byte arrays.
*/ */
library BytesUtils { library BytesUtils {
/********************** /**
* Internal Functions * * @custom:attribution https://github.com/GNSPS/solidity-bytes-utils
**********************/ * @notice Slices a byte array with a given starting index and length. Returns a new byte array
* as opposed to a pointer to the original array. Will throw if trying to slice more
* bytes than exist in the array.
*
* @param _bytes Byte array to slice.
* @param _start Starting index of the slice.
* @param _length Length of the slice.
*
* @return Slice of the input byte array.
*/
function slice( function slice(
bytes memory _bytes, bytes memory _bytes,
uint256 _start, uint256 _start,
uint256 _length uint256 _length
) internal pure returns (bytes memory) { ) internal pure returns (bytes memory) {
unchecked {
require(_length + 31 >= _length, "slice_overflow"); require(_length + 31 >= _length, "slice_overflow");
require(_start + _length >= _start, "slice_overflow"); require(_start + _length >= _start, "slice_overflow");
require(_bytes.length >= _start + _length, "slice_outOfBounds"); require(_bytes.length >= _start + _length, "slice_outOfBounds");
}
bytes memory tempBytes; bytes memory tempBytes;
...@@ -76,51 +87,63 @@ library BytesUtils { ...@@ -76,51 +87,63 @@ library BytesUtils {
return tempBytes; return tempBytes;
} }
/**
* @notice Slices a byte array with a given starting index up to the end of the original byte
* array. Returns a new array rathern than a pointer to the original.
*
* @param _bytes Byte array to slice.
* @param _start Starting index of the slice.
*
* @return Slice of the input byte array.
*/
function slice(bytes memory _bytes, uint256 _start) internal pure returns (bytes memory) { function slice(bytes memory _bytes, uint256 _start) internal pure returns (bytes memory) {
if (_start >= _bytes.length) { if (_start >= _bytes.length) {
return bytes(""); return bytes("");
} }
return slice(_bytes, _start, _bytes.length - _start); return slice(_bytes, _start, _bytes.length - _start);
} }
function toBytes32(bytes memory _bytes) internal pure returns (bytes32) { /**
if (_bytes.length < 32) { * @notice Converts a byte array into a nibble array by splitting each byte into two nibbles.
bytes32 ret; * Resulting nibble array will be exactly twice as long as the input byte array.
assembly { *
ret := mload(add(_bytes, 32)) * @param _bytes Input byte array to convert.
} *
return ret; * @return Resulting nibble array.
} */
return abi.decode(_bytes, (bytes32)); // will truncate if input length > 32 bytes
}
function toUint256(bytes memory _bytes) internal pure returns (uint256) {
return uint256(toBytes32(_bytes));
}
function toNibbles(bytes memory _bytes) internal pure returns (bytes memory) { function toNibbles(bytes memory _bytes) internal pure returns (bytes memory) {
bytes memory nibbles = new bytes(_bytes.length * 2); bytes memory nibbles = new bytes(_bytes.length * 2);
for (uint256 i = 0; i < _bytes.length; i++) { for (uint256 i = 0; i < _bytes.length; i++) {
nibbles[i * 2] = _bytes[i] >> 4; nibbles[i * 2] = _bytes[i] >> 4;
nibbles[i * 2 + 1] = bytes1(uint8(_bytes[i]) % 16); nibbles[i * 2 + 1] = bytes1(uint8(_bytes[i]) % 16);
} }
return nibbles; return nibbles;
} }
/**
* @notice Generates a byte array from a nibble array by joining each set of two nibbles into a
* single byte. Resulting byte array will be half as long as the input byte array.
*
* @param _bytes Input nibble array to convert.
*
* @return Resulting byte array.
*/
function fromNibbles(bytes memory _bytes) internal pure returns (bytes memory) { function fromNibbles(bytes memory _bytes) internal pure returns (bytes memory) {
bytes memory ret = new bytes(_bytes.length / 2); bytes memory ret = new bytes(_bytes.length / 2);
for (uint256 i = 0; i < ret.length; i++) { for (uint256 i = 0; i < ret.length; i++) {
ret[i] = (_bytes[i * 2] << 4) | (_bytes[i * 2 + 1]); ret[i] = (_bytes[i * 2] << 4) | (_bytes[i * 2 + 1]);
} }
return ret; return ret;
} }
/**
* @notice Compares two byte arrays by comparing their keccak256 hashes.
*
* @param _bytes First byte array to compare.
* @param _other Second byte array to compare.
*
* @return True if the two byte arrays are equal, false otherwise.
*/
function equal(bytes memory _bytes, bytes memory _other) internal pure returns (bool) { function equal(bytes memory _bytes, bytes memory _other) internal pure returns (bool) {
return keccak256(_bytes) == keccak256(_other); return keccak256(_bytes) == keccak256(_other);
} }
......
...@@ -167,7 +167,7 @@ library MerkleTrie { ...@@ -167,7 +167,7 @@ library MerkleTrie {
} else { } else {
// Nodes smaller than 31 bytes aren't hashed. // Nodes smaller than 31 bytes aren't hashed.
require( require(
BytesUtils.toBytes32(currentNode.encoded) == currentNodeID, bytes32(currentNode.encoded) == currentNodeID,
"Invalid internal node hash" "Invalid internal node hash"
); );
} }
...@@ -272,7 +272,7 @@ library MerkleTrie { ...@@ -272,7 +272,7 @@ library MerkleTrie {
nodeID = RLPReader.readBytes(_node); nodeID = RLPReader.readBytes(_node);
} }
return BytesUtils.toBytes32(nodeID); return bytes32(nodeID);
} }
/** /**
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment