0

I want to split bytes32 into multiples of 8 (in assembly). I have the following code(After referring here):

function testAssembly(bytes32 _msg) public pure returns (bytes8 i, bytes8 j, bytes8 k, uint256 m, bytes memory size){
      assembly {
        let i_ptr := mload(0x40)
        let j_ptr := mload(0x62)
        let k_ptr := mload(0x92)

        m := calldataload(4)
        //size := msize
        calldatacopy(i_ptr,0x4,8)
        calldatacopy(j_ptr,0x9,8)
        calldatacopy(k_ptr,0x11,8)

        i := mload(i_ptr)
        j := mload(j_ptr)
        k := mload(k_ptr)
      }
      return (i,j,k,m,size);
    }

 function testAssemblyArr(bytes32 _msg) public pure returns (bytes8 i, bytes8 j, bytes8 k, uint256 m, bytes memory size){

      bytes8[3] memory y = [bytes8(0), 0,0];

      assembly {

        m := calldataload(4)
        //size := msize         //(*)
        mstore(y,_msg)
        mstore(add(y,0x8),_msg)
        mstore(add(y,0x10),_msg)
      }
      return (y[0],y[1],y[2],m,size);
    }  

I have following input (Remix): "0x1212121212121212343434343434343456565656565656567878787878787878"

Expected output(for both):

0: bytes8: i 0x1212121212121212
1: bytes8: j 0x3434343434343434
2: bytes8: k 0x5656565656565656

Observed output:

testAssembly:
0: bytes8: i 0x1212121212121212
1: bytes8: j 0x3434345656565656
2: bytes8: k 0x3434345656565656
3: uint256: m 8173559240281143207206663486900115636630769273905500857318033424334900983928
4: bytes: size 0x

testAssemblyArr:
0: bytes8: i 0x1212121212121212
1: bytes8: j 0x5656565656565656
2: bytes8: k 0x0000000000000000
3: uint256: m 8173559240281143207206663486900115636630769273905500857318033424334900983928
4: bytes: size 0x

If i change function parameter of testAssemblyArr to bytes then it gives the following output:

0: bytes8: i 0x0000000000000000
1: bytes8: j 0x0000000000000000
2: bytes8: k 0x0000000000000000
3: uint256: m 32
4: bytes: size 0x

In the above output, (Ignore m, it gives correct output if its return type is changed to bytes32). For calldatacopy() function, I used both integer and hexadecimal values but it gives incorrect values. How should i go about this to get expected results?

Also when you uncomment line *(msize), it gives "out of gas" error in ganache and crashes the browser(tab) in Remix.

1

1 Answer 1

2

You do not have to complicate it using assembly, using shift and type cast should work.

pragma solidity >=0.4.22 <0.6.0;

contract A {

    function test(bytes32 r) public pure returns (bytes8 i, bytes8 j, bytes8 k, bytes8 m) {
        uint256 rr = uint256(r);
        i = bytes8(uint64(rr >> 64*3));
        j = bytes8(uint64(rr >> 64*2));
        k = bytes8(uint64(rr >> 64*1));
        m = bytes8(uint64(rr >> 64*0));
    }

    function bar(bytes32 r) public pure returns (bytes8 i, bytes8 j, bytes8 k, bytes8 m) {
        i = bytes8(r);
        j = bytes8(r << 64*1);
        k = bytes8(r << 64*2);
        m = bytes8(r << 64*3);
    }

    function foo(bytes32 r) public pure returns (bytes8 i, bytes8 j, bytes8 k, bytes8 m) {
        assembly {
            i := r
            j := shl(64, r)
            k := shl(128, r)
            m := shl(192, r)
        }
    }
}
4
  • Your solution works, but i need an assembly solution since I am learning the language. I saw a code here, which uses assembly to get r,s,v values.
    – pebble
    Commented Feb 27, 2019 at 9:30
  • It should be straightforward to port the code to assembly, you do not need cast types because everything is 32 bytes.
    – Ismael
    Commented Feb 27, 2019 at 16:00
  • I tried this: assembly{ i := shr(192,r) j := shr(128,r) k := shr(64,r) m := shr(0,r) } But it gives zero value for i,j,k
    – pebble
    Commented Mar 7, 2019 at 5:22
  • @pebble I've included two new implementations. The problem with the previous implementation is how assignment works: uintXXX uses the rightmost bytes, and bytesXXX uses the leftmost bytes. Assembly treat all data as bytes32/uint256, so to cast to bytes8/uint64 you need to do extra operations.
    – Ismael
    Commented Mar 8, 2019 at 2:55

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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