github.com/ethereum-optimism/optimism@v1.7.2/packages/contracts-bedrock/src/libraries/rlp/RLPWriter.sol (about)

     1  // SPDX-License-Identifier: MIT
     2  pragma solidity ^0.8.0;
     3  
     4  /// @custom:attribution https://github.com/bakaoh/solidity-rlp-encode
     5  /// @title RLPWriter
     6  /// @author RLPWriter is a library for encoding Solidity types to RLP bytes. Adapted from Bakaoh's
     7  ///         RLPEncode library (https://github.com/bakaoh/solidity-rlp-encode) with minor
     8  ///         modifications to improve legibility.
     9  library RLPWriter {
    10      /// @notice RLP encodes a byte string.
    11      /// @param _in The byte string to encode.
    12      /// @return out_ The RLP encoded string in bytes.
    13      function writeBytes(bytes memory _in) internal pure returns (bytes memory out_) {
    14          if (_in.length == 1 && uint8(_in[0]) < 128) {
    15              out_ = _in;
    16          } else {
    17              out_ = abi.encodePacked(_writeLength(_in.length, 128), _in);
    18          }
    19      }
    20  
    21      /// @notice RLP encodes a list of RLP encoded byte byte strings.
    22      /// @param _in The list of RLP encoded byte strings.
    23      /// @return list_ The RLP encoded list of items in bytes.
    24      function writeList(bytes[] memory _in) internal pure returns (bytes memory list_) {
    25          list_ = _flatten(_in);
    26          list_ = abi.encodePacked(_writeLength(list_.length, 192), list_);
    27      }
    28  
    29      /// @notice RLP encodes a string.
    30      /// @param _in The string to encode.
    31      /// @return out_ The RLP encoded string in bytes.
    32      function writeString(string memory _in) internal pure returns (bytes memory out_) {
    33          out_ = writeBytes(bytes(_in));
    34      }
    35  
    36      /// @notice RLP encodes an address.
    37      /// @param _in The address to encode.
    38      /// @return out_ The RLP encoded address in bytes.
    39      function writeAddress(address _in) internal pure returns (bytes memory out_) {
    40          out_ = writeBytes(abi.encodePacked(_in));
    41      }
    42  
    43      /// @notice RLP encodes a uint.
    44      /// @param _in The uint256 to encode.
    45      /// @return out_ The RLP encoded uint256 in bytes.
    46      function writeUint(uint256 _in) internal pure returns (bytes memory out_) {
    47          out_ = writeBytes(_toBinary(_in));
    48      }
    49  
    50      /// @notice RLP encodes a bool.
    51      /// @param _in The bool to encode.
    52      /// @return out_ The RLP encoded bool in bytes.
    53      function writeBool(bool _in) internal pure returns (bytes memory out_) {
    54          out_ = new bytes(1);
    55          out_[0] = (_in ? bytes1(0x01) : bytes1(0x80));
    56      }
    57  
    58      /// @notice Encode the first byte and then the `len` in binary form if `length` is more than 55.
    59      /// @param _len    The length of the string or the payload.
    60      /// @param _offset 128 if item is string, 192 if item is list.
    61      /// @return out_ RLP encoded bytes.
    62      function _writeLength(uint256 _len, uint256 _offset) private pure returns (bytes memory out_) {
    63          if (_len < 56) {
    64              out_ = new bytes(1);
    65              out_[0] = bytes1(uint8(_len) + uint8(_offset));
    66          } else {
    67              uint256 lenLen;
    68              uint256 i = 1;
    69              while (_len / i != 0) {
    70                  lenLen++;
    71                  i *= 256;
    72              }
    73  
    74              out_ = new bytes(lenLen + 1);
    75              out_[0] = bytes1(uint8(lenLen) + uint8(_offset) + 55);
    76              for (i = 1; i <= lenLen; i++) {
    77                  out_[i] = bytes1(uint8((_len / (256 ** (lenLen - i))) % 256));
    78              }
    79          }
    80      }
    81  
    82      /// @notice Encode integer in big endian binary form with no leading zeroes.
    83      /// @param _x The integer to encode.
    84      /// @return out_ RLP encoded bytes.
    85      function _toBinary(uint256 _x) private pure returns (bytes memory out_) {
    86          bytes memory b = abi.encodePacked(_x);
    87  
    88          uint256 i = 0;
    89          for (; i < 32; i++) {
    90              if (b[i] != 0) {
    91                  break;
    92              }
    93          }
    94  
    95          out_ = new bytes(32 - i);
    96          for (uint256 j = 0; j < out_.length; j++) {
    97              out_[j] = b[i++];
    98          }
    99      }
   100  
   101      /// @custom:attribution https://github.com/Arachnid/solidity-stringutils
   102      /// @notice Copies a piece of memory to another location.
   103      /// @param _dest Destination location.
   104      /// @param _src  Source location.
   105      /// @param _len  Length of memory to copy.
   106      function _memcpy(uint256 _dest, uint256 _src, uint256 _len) private pure {
   107          uint256 dest = _dest;
   108          uint256 src = _src;
   109          uint256 len = _len;
   110  
   111          for (; len >= 32; len -= 32) {
   112              assembly {
   113                  mstore(dest, mload(src))
   114              }
   115              dest += 32;
   116              src += 32;
   117          }
   118  
   119          uint256 mask;
   120          unchecked {
   121              mask = 256 ** (32 - len) - 1;
   122          }
   123          assembly {
   124              let srcpart := and(mload(src), not(mask))
   125              let destpart := and(mload(dest), mask)
   126              mstore(dest, or(destpart, srcpart))
   127          }
   128      }
   129  
   130      /// @custom:attribution https://github.com/sammayo/solidity-rlp-encoder
   131      /// @notice Flattens a list of byte strings into one byte string.
   132      /// @param _list List of byte strings to flatten.
   133      /// @return out_ The flattened byte string.
   134      function _flatten(bytes[] memory _list) private pure returns (bytes memory out_) {
   135          if (_list.length == 0) {
   136              return new bytes(0);
   137          }
   138  
   139          uint256 len;
   140          uint256 i = 0;
   141          for (; i < _list.length; i++) {
   142              len += _list[i].length;
   143          }
   144  
   145          out_ = new bytes(len);
   146          uint256 flattenedPtr;
   147          assembly {
   148              flattenedPtr := add(out_, 0x20)
   149          }
   150  
   151          for (i = 0; i < _list.length; i++) {
   152              bytes memory item = _list[i];
   153  
   154              uint256 listPtr;
   155              assembly {
   156                  listPtr := add(item, 0x20)
   157              }
   158  
   159              _memcpy(flattenedPtr, listPtr, item.length);
   160              flattenedPtr += _list[i].length;
   161          }
   162      }
   163  }