BytesLib.sol
1 /* 2 * @title Solidity Bytes Arrays Utils 3 * @author Gonçalo Sá <goncalo.sa@consensys.net> 4 * 5 * @dev Bytes tightly packed arrays utility library for ethereum contracts written in Solidity. 6 * The library lets you concatenate, slice and type cast bytes arrays both in memory and storage. 7 */ 8 pragma solidity >=0.5.0 <0.7.0; 9 10 11 library BytesLib { 12 function concat( 13 bytes memory _preBytes, 14 bytes memory _postBytes 15 ) 16 internal 17 pure 18 returns (bytes memory) 19 { 20 bytes memory tempBytes; 21 22 assembly { 23 // Get a location of some free memory and store it in tempBytes as 24 // Solidity does for memory variables. 25 tempBytes := mload(0x40) 26 27 // Store the length of the first bytes array at the beginning of 28 // the memory for tempBytes. 29 let length := mload(_preBytes) 30 mstore(tempBytes, length) 31 32 // Maintain a memory counter for the current write location in the 33 // temp bytes array by adding the 32 bytes for the array length to 34 // the starting location. 35 let mc := add(tempBytes, 0x20) 36 // Stop copying when the memory counter reaches the length of the 37 // first bytes array. 38 let end := add(mc, length) 39 40 for { 41 // Initialize a copy counter to the start of the _preBytes data, 42 // 32 bytes into its memory. 43 let cc := add(_preBytes, 0x20) 44 } lt(mc, end) { 45 // Increase both counters by 32 bytes each iteration. 46 mc := add(mc, 0x20) 47 cc := add(cc, 0x20) 48 } { 49 // Write the _preBytes data into the tempBytes memory 32 bytes 50 // at a time. 51 mstore(mc, mload(cc)) 52 } 53 54 // Add the length of _postBytes to the current length of tempBytes 55 // and store it as the new length in the first 32 bytes of the 56 // tempBytes memory. 57 length := mload(_postBytes) 58 mstore(tempBytes, add(length, mload(tempBytes))) 59 60 // Move the memory counter back from a multiple of 0x20 to the 61 // actual end of the _preBytes data. 62 mc := end 63 // Stop copying when the memory counter reaches the new combined 64 // length of the arrays. 65 end := add(mc, length) 66 67 for { 68 let cc := add(_postBytes, 0x20) 69 } lt(mc, end) { 70 mc := add(mc, 0x20) 71 cc := add(cc, 0x20) 72 } { 73 mstore(mc, mload(cc)) 74 } 75 76 // Update the free-memory pointer by padding our last write location 77 // to 32 bytes: add 31 bytes to the end of tempBytes to move to the 78 // next 32 byte block, then round down to the nearest multiple of 79 // 32. If the sum of the length of the two arrays is zero then add 80 // one before rounding down to leave a blank 32 bytes (the length block with 0). 81 mstore(0x40, and( 82 add(add(end, iszero(add(length, mload(_preBytes)))), 31), 83 not(31) // Round down to the nearest 32 bytes. 84 )) 85 } 86 87 return tempBytes; 88 } 89 90 function concatStorage(bytes storage _preBytes, bytes memory _postBytes) internal { 91 assembly { 92 // Read the first 32 bytes of _preBytes storage, which is the length 93 // of the array. (We don't need to use the offset into the slot 94 // because arrays use the entire slot.) 95 let fslot := sload(_preBytes_slot) 96 // Arrays of 31 bytes or less have an even value in their slot, 97 // while longer arrays have an odd value. The actual length is 98 // the slot divided by two for odd values, and the lowest order 99 // byte divided by two for even values. 100 // If the slot is even, bitwise and the slot with 255 and divide by 101 // two to get the length. If the slot is odd, bitwise and the slot 102 // with -1 and divide by two. 103 let slength := div(and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2) 104 let mlength := mload(_postBytes) 105 let newlength := add(slength, mlength) 106 // slength can contain both the length and contents of the array 107 // if length < 32 bytes so let's prepare for that 108 // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage 109 switch add(lt(slength, 32), lt(newlength, 32)) 110 case 2 { 111 // Since the new array still fits in the slot, we just need to 112 // update the contents of the slot. 113 // uint256(bytes_storage) = uint256(bytes_storage) + uint256(bytes_memory) + new_length 114 sstore( 115 _preBytes_slot, 116 // all the modifications to the slot are inside this 117 // next block 118 add( 119 // we can just add to the slot contents because the 120 // bytes we want to change are the LSBs 121 fslot, 122 add( 123 mul( 124 div( 125 // load the bytes from memory 126 mload(add(_postBytes, 0x20)), 127 // zero all bytes to the right 128 exp(0x100, sub(32, mlength)) 129 ), 130 // and now shift left the number of bytes to 131 // leave space for the length in the slot 132 exp(0x100, sub(32, newlength)) 133 ), 134 // increase length by the double of the memory 135 // bytes length 136 mul(mlength, 2) 137 ) 138 ) 139 ) 140 } 141 case 1 { 142 // The stored value fits in the slot, but the combined value 143 // will exceed it. 144 // get the keccak hash to get the contents of the array 145 mstore(0x0, _preBytes_slot) 146 let sc := add(keccak256(0x0, 0x20), div(slength, 32)) 147 148 // save new length 149 sstore(_preBytes_slot, add(mul(newlength, 2), 1)) 150 151 // The contents of the _postBytes array start 32 bytes into 152 // the structure. Our first read should obtain the `submod` 153 // bytes that can fit into the unused space in the last word 154 // of the stored array. To get this, we read 32 bytes starting 155 // from `submod`, so the data we read overlaps with the array 156 // contents by `submod` bytes. Masking the lowest-order 157 // `submod` bytes allows us to add that value directly to the 158 // stored value. 159 160 let submod := sub(32, slength) 161 let mc := add(_postBytes, submod) 162 let end := add(_postBytes, mlength) 163 let mask := sub(exp(0x100, submod), 1) 164 165 sstore( 166 sc, 167 add( 168 and( 169 fslot, 170 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00 171 ), 172 and(mload(mc), mask) 173 ) 174 ) 175 176 for { 177 mc := add(mc, 0x20) 178 sc := add(sc, 1) 179 } lt(mc, end) { 180 sc := add(sc, 1) 181 mc := add(mc, 0x20) 182 } { 183 sstore(sc, mload(mc)) 184 } 185 186 mask := exp(0x100, sub(mc, end)) 187 188 sstore(sc, mul(div(mload(mc), mask), mask)) 189 } 190 default { 191 // get the keccak hash to get the contents of the array 192 mstore(0x0, _preBytes_slot) 193 // Start copying to the last used word of the stored array. 194 let sc := add(keccak256(0x0, 0x20), div(slength, 32)) 195 196 // save new length 197 sstore(_preBytes_slot, add(mul(newlength, 2), 1)) 198 199 // Copy over the first `submod` bytes of the new data as in 200 // case 1 above. 201 let slengthmod := mod(slength, 32) 202 let mlengthmod := mod(mlength, 32) 203 let submod := sub(32, slengthmod) 204 let mc := add(_postBytes, submod) 205 let end := add(_postBytes, mlength) 206 let mask := sub(exp(0x100, submod), 1) 207 208 sstore(sc, add(sload(sc), and(mload(mc), mask))) 209 210 for { 211 sc := add(sc, 1) 212 mc := add(mc, 0x20) 213 } lt(mc, end) { 214 sc := add(sc, 1) 215 mc := add(mc, 0x20) 216 } { 217 sstore(sc, mload(mc)) 218 } 219 220 mask := exp(0x100, sub(mc, end)) 221 222 sstore(sc, mul(div(mload(mc), mask), mask)) 223 } 224 } 225 } 226 227 function slice( 228 bytes memory _bytes, 229 uint _start, 230 uint _length 231 ) 232 internal 233 pure 234 returns (bytes memory) 235 { 236 require(_bytes.length >= (_start + _length)); 237 238 bytes memory tempBytes; 239 240 assembly { 241 switch iszero(_length) 242 case 0 { 243 // Get a location of some free memory and store it in tempBytes as 244 // Solidity does for memory variables. 245 tempBytes := mload(0x40) 246 247 // The first word of the slice result is potentially a partial 248 // word read from the original array. To read it, we calculate 249 // the length of that partial word and start copying that many 250 // bytes into the array. The first word we copy will start with 251 // data we don't care about, but the last `lengthmod` bytes will 252 // land at the beginning of the contents of the new array. When 253 // we're done copying, we overwrite the full first word with 254 // the actual length of the slice. 255 let lengthmod := and(_length, 31) 256 257 // The multiplication in the next line is necessary 258 // because when slicing multiples of 32 bytes (lengthmod == 0) 259 // the following copy loop was copying the origin's length 260 // and then ending prematurely not copying everything it should. 261 let mc := add(add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod))) 262 let end := add(mc, _length) 263 264 for { 265 // The multiplication in the next line has the same exact purpose 266 // as the one above. 267 let cc := add(add(add(_bytes, lengthmod), mul(0x20, iszero(lengthmod))), _start) 268 } lt(mc, end) { 269 mc := add(mc, 0x20) 270 cc := add(cc, 0x20) 271 } { 272 mstore(mc, mload(cc)) 273 } 274 275 mstore(tempBytes, _length) 276 277 //update free-memory pointer 278 //allocating the array padded to 32 bytes like the compiler does now 279 mstore(0x40, and(add(mc, 31), not(31))) 280 } 281 //if we want a zero-length slice let's just return a zero-length array 282 default { 283 tempBytes := mload(0x40) 284 285 mstore(0x40, add(tempBytes, 0x20)) 286 } 287 } 288 289 return tempBytes; 290 } 291 292 function toAddress(bytes memory _bytes, uint _start) internal pure returns (address) { 293 require(_bytes.length >= (_start + 20)); 294 address tempAddress; 295 296 assembly { 297 tempAddress := div(mload(add(add(_bytes, 0x20), _start)), 0x1000000000000000000000000) 298 } 299 300 return tempAddress; 301 } 302 303 function toUint8(bytes memory _bytes, uint _start) internal pure returns (uint8) { 304 require(_bytes.length >= (_start + 1)); 305 uint8 tempUint; 306 307 assembly { 308 tempUint := mload(add(add(_bytes, 0x1), _start)) 309 } 310 311 return tempUint; 312 } 313 314 function toUint16(bytes memory _bytes, uint _start) internal pure returns (uint16) { 315 require(_bytes.length >= (_start + 2)); 316 uint16 tempUint; 317 318 assembly { 319 tempUint := mload(add(add(_bytes, 0x2), _start)) 320 } 321 322 return tempUint; 323 } 324 325 function toUint32(bytes memory _bytes, uint _start) internal pure returns (uint32) { 326 require(_bytes.length >= (_start + 4)); 327 uint32 tempUint; 328 329 assembly { 330 tempUint := mload(add(add(_bytes, 0x4), _start)) 331 } 332 333 return tempUint; 334 } 335 336 function toUint64(bytes memory _bytes, uint _start) internal pure returns (uint64) { 337 require(_bytes.length >= (_start + 8)); 338 uint64 tempUint; 339 340 assembly { 341 tempUint := mload(add(add(_bytes, 0x8), _start)) 342 } 343 344 return tempUint; 345 } 346 347 function toUint96(bytes memory _bytes, uint _start) internal pure returns (uint96) { 348 require(_bytes.length >= (_start + 12)); 349 uint96 tempUint; 350 351 assembly { 352 tempUint := mload(add(add(_bytes, 0xc), _start)) 353 } 354 355 return tempUint; 356 } 357 358 function toUint128(bytes memory _bytes, uint _start) internal pure returns (uint128) { 359 require(_bytes.length >= (_start + 16)); 360 uint128 tempUint; 361 362 assembly { 363 tempUint := mload(add(add(_bytes, 0x10), _start)) 364 } 365 366 return tempUint; 367 } 368 369 function toUint(bytes memory _bytes, uint _start) internal pure returns (uint256) { 370 require(_bytes.length >= (_start + 32)); 371 uint256 tempUint; 372 373 assembly { 374 tempUint := mload(add(add(_bytes, 0x20), _start)) 375 } 376 377 return tempUint; 378 } 379 380 function toBytes32(bytes memory _bytes, uint _start) internal pure returns (bytes32) { 381 require(_bytes.length >= (_start + 32)); 382 bytes32 tempBytes32; 383 384 assembly { 385 tempBytes32 := mload(add(add(_bytes, 0x20), _start)) 386 } 387 388 return tempBytes32; 389 } 390 391 function equal(bytes memory _preBytes, bytes memory _postBytes) internal pure returns (bool) { 392 bool success = true; 393 394 assembly { 395 let length := mload(_preBytes) 396 397 // if lengths don't match the arrays are not equal 398 switch eq(length, mload(_postBytes)) 399 case 1 { 400 // cb is a circuit breaker in the for loop since there's 401 // no said feature for inline assembly loops 402 // cb = 1 - don't breaker 403 // cb = 0 - break 404 let cb := 1 405 406 let mc := add(_preBytes, 0x20) 407 let end := add(mc, length) 408 409 for { 410 let cc := add(_postBytes, 0x20) 411 // the next line is the loop condition: 412 // while(uint(mc < end) + cb == 2) 413 } eq(add(lt(mc, end), cb), 2) { 414 mc := add(mc, 0x20) 415 cc := add(cc, 0x20) 416 } { 417 // if any of these checks fails then arrays are not equal 418 if iszero(eq(mload(mc), mload(cc))) { 419 // unsuccess: 420 success := 0 421 cb := 0 422 } 423 } 424 } 425 default { 426 // unsuccess: 427 success := 0 428 } 429 } 430 431 return success; 432 } 433 434 function equalStorage( 435 bytes storage _preBytes, 436 bytes memory _postBytes 437 ) 438 internal 439 view 440 returns (bool) 441 { 442 bool success = true; 443 444 assembly { 445 // we know _preBytes_offset is 0 446 let fslot := sload(_preBytes_slot) 447 // Decode the length of the stored array like in concatStorage(). 448 let slength := div(and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2) 449 let mlength := mload(_postBytes) 450 451 // if lengths don't match the arrays are not equal 452 switch eq(slength, mlength) 453 case 1 { 454 // slength can contain both the length and contents of the array 455 // if length < 32 bytes so let's prepare for that 456 // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage 457 if iszero(iszero(slength)) { 458 switch lt(slength, 32) 459 case 1 { 460 // blank the last byte which is the length 461 fslot := mul(div(fslot, 0x100), 0x100) 462 463 if iszero(eq(fslot, mload(add(_postBytes, 0x20)))) { 464 // unsuccess: 465 success := 0 466 } 467 } 468 default { 469 // cb is a circuit breaker in the for loop since there's 470 // no said feature for inline assembly loops 471 // cb = 1 - don't breaker 472 // cb = 0 - break 473 let cb := 1 474 475 // get the keccak hash to get the contents of the array 476 mstore(0x0, _preBytes_slot) 477 let sc := keccak256(0x0, 0x20) 478 479 let mc := add(_postBytes, 0x20) 480 let end := add(mc, mlength) 481 482 // the next line is the loop condition: 483 // while(uint(mc < end) + cb == 2) 484 for {} eq(add(lt(mc, end), cb), 2) { 485 sc := add(sc, 1) 486 mc := add(mc, 0x20) 487 } { 488 if iszero(eq(sload(sc), mload(mc))) { 489 // unsuccess: 490 success := 0 491 cb := 0 492 } 493 } 494 } 495 } 496 } 497 default { 498 // unsuccess: 499 success := 0 500 } 501 } 502 503 return success; 504 } 505 }