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 }