1

I have a bytes32 that I plan to pack with 10 bytes3 at specific indexes without affecting the other bytes already set. So for instance if I had a bytes3 of 0xABCDEF into bytes32 at the index 3, it will go from this:

0x0000000000000000000000000000000000000000000000000000000000000000
  ^0    ^1    ^2    ^3    ^4    ^5    ^6    ^7    ^8    ^9    ^ignore last 4 bits

to this:

0x000000000000000000ABCDEF0000000000000000000000000000000000000000
  ^0    ^1    ^2    ^3    ^4    ^5    ^6    ^7    ^8    ^9    ^ignore last 4 bits

I believe this could be achieved with some bitwise magic but I'm not too familiar with it. I found an example that sets individual bits and tried to tweak it to set more than just individual bits:

bytes32 currentBytesGroup;
currentBytesGroup = currentBytesGroup | bytes3(number) << (positionWithinGroup * 24);//3 bytes = 24 bits

however this doesn't appear to be working. What am I doing wrong?

1 Answer 1

2

This should work.

contract ShiftDemo {
    bytes32 public s;

    function execute(bytes3 d, uint256 idx)public {
        s = s | (bytes32(d) >> (idx*8));
    }
}

A few thing to note:

  • If you shift bytes3 for more than 24 bits you will get three zero bytes. The shift operators (<< and >>) don't change the base type. To properly shift you first have to cast to a larger type like bytes32.

  • bytesXX are left aligned, bytes32(0xAABBCC) results in 0xAABBCC000000..00. If you apply << for more than 24 bits you will get zero bytes. You have to use >> right shift instead.

2
  • Thank for you answer! It seems to work, but only if the bytes are all zeroes - if there's existing bytes where the data needs to go it doesn't overwrite correctly. I saw in another question in C here stackoverflow.com/questions/10132906/… they "mask" the bits before writing, i assume that needs to be done here somehow? Also, I have to multiply idx by 3 to take into account my chosen indexes are every 3 bytes. Feb 13, 2020 at 8:44
  • 1
    I've taken what you said and applied it with masking and now it works great for me: function replaceBytesAtIndex(bytes32 original, uint position, bytes3 toInsert) public pure returns (bytes32) { bytes3 maskBytes = 0xffffff; bytes32 mask = bytes32(maskBytes) >> ((position*3) * 8); return (~mask & original) | (bytes32(toInsert) >> ((position*3) * 8)); } Feb 13, 2020 at 8:54

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.