Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Solidity Assembly, the mstore function, and the width of a word in bytes

I'm learning Solidity Assembly and I'm confused about something. I'm looking at this library called Seriality. Specifically, this function: https://github.com/pouladzade/Seriality/blob/master/src/TypesToBytes.sol#L21

function bytes32ToBytes(uint _offst, bytes32 _input, bytes memory _output) internal pure {
    assembly {
        mstore(add(_output, _offst), _input)
        mstore(add(add(_output, _offst),32), add(_input,32))
    }
}

That function bytes32ToBytes takes a bytes32 variable and stores it in a dynamically sized bytes array, starting at the offset passed in.

The thing that confuses me is that it uses the mstore function twice. But the mstore function stores a word, which is 32 bytes, right? So why is it called twice, given that the input is 32 bytes? Wouldn't calling it twice store 2 words, which is 64 bytes?

Thanks!

like image 438
user1558646 Avatar asked Oct 29 '25 13:10

user1558646


1 Answers

Solidity arrays are stored by writing out the size of the array to the first storage slot then writing out the data to the subsequent slots.

Knowing that mstore has the following parameters: mstore(START_LOCATION, ITEM_TO_STORE), the first mstore statement is written as follows:

mstore(add(_output, _offst), _input)

Since the first slot of the array points to the size of the array, this statement is setting the size of _output. You should be able to get the same result by replacing it with mstore(add(_output, _offst), 32) (since the size is of _input is static).

The second statement (mstore(add(add(_output, _offst),32), add(_input,32))) is the one that writes the data itself. Here, we are shifting the position of both pointers by 32 bytes (as the first 32 bytes for both arrays are pointing to the size) and storing the value of _input to where the data is stored for _output.

Chances are, _output will already be initialized before calling this method (so the length will already be set), so it will usually be unnecessary. But, it doesn't hurt. Note that a similar implementation making this assumption would look like this:

function test() public pure returns (bytes) {
    bytes32 i = "some message";
    bytes memory o = new bytes(32); // Initializing this way sets the length to the location "o" points to. This replaces mstore(add(_output, _offst), _input).
    bytes32ToBytes(0, i, o);
    
    return o;
}

function bytes32ToBytes(uint _offst, bytes32 _input, bytes memory _output) internal pure {
    assembly {
        mstore(add(add(_output, _offst),32), add(_input,32))
    }
}
like image 155
Adam Kipnis Avatar answered Nov 01 '25 13:11

Adam Kipnis



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!