7

I want to split a 32 Byte source: first half in Bytes16 half1; second half in Bytes16 half2. My code works, however only for dynamic array, not with fixed size 16.

pragma solidity ^0.4.8;

contract cut {

    function cutSha(bytes32 source) constant returns (bytes, bytes) {
        bytes memory half1 = new bytes(16);
        bytes memory half2 = new bytes(16);
        for (uint j = 0; j < 16; j++) {
                half1[j] = source[j];
                half2[j] = source[j+16];
        }
        return (half1, half2);
    }
}
  • Since the halfs are just the first / last 16 bytes there should be an efficient way, like using inline assembly and mload? – floyd Mar 16 '17 at 15:16
6

It is possible to do this with assembly:

pragma solidity ^0.4.8;

contract c {
    event trace(bytes32 x, bytes16 a, bytes16 b);

    function foo(bytes32 source) {
        bytes16[2] memory y = [bytes16(0), 0];
        assembly {
            mstore(y, source)
            mstore(add(y, 16), source)
        }
        trace(source, y[0], y[1]);
    }
}

For example, converting bytes from the string "what a wonderful world!", produces this after using 2245 gas:

trace[
  "0x77686174206120776f6e64657266756c20776f726c6421000000000000000000",
  "0x77686174206120776f6e64657266756c",
  "0x20776f726c6421000000000000000000"
]

NB: the code relies on the internal data representation that may be subject to change in later versions of Solidity or interfere with Solidity optimizer in an unpredictable ways.

  • Just saw this now. Thank you very much, will compare now to my own solution posted below. – floyd Mar 16 '17 at 20:19
  • How do we change your code so that I can take input of 56 characters and split them into two bytes32? – Curt Aug 20 '17 at 23:00
3

I found a solution using inline assembly:

contract cutByte32 {

  //"0xa9c40ddcb43ebbc83add97b8f9f361f12b19bceff2f76b68f66b5bb1812365a9"
  //use this as remix command

  function cut(bytes32 sha) constant returns (bytes16 half1, bytes16 half2) {
    assembly {
      let freemem_pointer := mload(0x40)
      mstore(add(freemem_pointer,0x00), sha)
      half1 := mload(add(freemem_pointer,0x00))
      half2 := mload(add(freemem_pointer,0x10))
    }
  }
}
  • +1, that is nice. but can you explain a bit what mload(0x40) means? – max taldykin Mar 16 '17 at 22:56
  • Thank you, at the address 0x40 (solidity definition) the pointer (/address) for the next free slot on the memory is stored. Loading it first into the freemem_pointer variable makes sure I don't overwrite anything in memory. However I assume there are even better solutions. If I would new at what address the parameter value "bytes32 sha" is stored I don't need to store it again and can directly start to read it out 16byte wise. – floyd Mar 18 '17 at 17:45
  • How do we change your code so that I can take input of 56 characters and split them into two bytes32? – Curt Aug 20 '17 at 23:00
0

Try to do it with uints

   function bytesChunck(bytes32 source, uint start, uint numBytes) constant returns(uint _result){
                uint counter = 0;
                uint result;

                for(uint i = 0; i < numBytes; i++) {
                    result += uint8(source[start + i]);
                }
                return result;
        }

but Reading bytes from bytes32 returns zero value (except first one)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.