1

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
7
  • 1
    How long is byte array? If it is less or equal to 32 you could use bytes32 instead of bytes and the shift should work.
    – Ismael
    Commented Jan 21, 2022 at 12:35
  • I am considering this actually, split my bytes into chunks of bytes32 Commented Jan 21, 2022 at 16:27
  • Why do you have to shift a bytes array? What are the possible values for the shift length? It has a bad smell shifting a bytes array of arbitrary length.
    – Ismael
    Commented Jan 21, 2022 at 17:15
  • it's a custom encoding of data for on-chain NFTs, I didn't mean to advertise here but you can find out more on our page chaindreamers.xyz/on-chain-storage Commented Jan 21, 2022 at 18:51
  • It sounds like a bad idea shifting byte arrays. If necessary I'd do it off-chain or use some kind of DSL.
    – Ismael
    Commented Jan 21, 2022 at 19:06

1 Answer 1

3

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.

1
  • I do have a working solution with a for loops but I am looking for some gas saving and I thought that assembly could be a good start. thanks for the link Commented Jan 18, 2022 at 21:59

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.