Solidity Assembly – How to Bit Shift Bytes in Solidity/Assembly

assemblybit-manipulationsolidity

I can bit shift uint_n_ easily but I don't manage to bit shift a bytes memory myBytes.

When doing myBytes << i I have a compile error and when using assembly I receive 0.

See my MWE for assembly and test:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

library BytesShift {
    function shiftLeft(bytes memory x, uint256 n)
        public
        pure
        returns (bytes memory)
    {
        bytes memory tmp;
        assembly {
            tmp := shl(n, x)
        }
        return tmp;
    }
}
describe("BytesShift", function () {
  describe("shiftLeft", () => {
    it(`Should shift bytes to the left`, async function () {
      const BytesShift = await ethers.getContract("BytesShift");
      const res = await BytesShift.shiftLeft("0xff", 1);
      expect(res).to.equal("0xfe");
    });
  });
});

failing with received value :

      AssertionError: expected '0x' to equal '0xfe'
      + expected - actual

      -0x
      +0xfe

Best Answer

The shift operation is only available for value types not for reference types (see https://docs.soliditylang.org/en/v0.8.11/types.html#value-types)

Value types exist on stack and there can be passed to the shift opcode.

The bytes memory only stores the location of the data in memory on stack. So in you assembly example you tmp just points to an invalid memory location and therefore returns 0.

If you want to shift a bytes you need to process the whole bytes data word by word and also handle overflows between the words.