Ethernaut Puzzle 12 Privacy

This task is about how we store the varaibles in Solidity, how solidity allocates space for these variables.

In Solidity, variables are stored in different storage slots, and the specific rules are as follows:

  • The size of a slot is 32 bytes (256 bits).
  • If the size of a variable is less than or equal to 32 bytes, it will share a storage slot with other variables.
  • If the size of a variable is greater than 32 bytes, it will occupy an independent storage slot.
  • The order of variables affects the position of their storage slots.

Given this contract, the allocation of storage slots for variables is as follows:

  • “locked” occupies one 32-byte storage slot, and it is a boolean type.
  • “ID” occupies one 32-byte storage slot, and it is a uint256 type.
  • “flattening” and “denomination” are two 8-bit unsigned integers, so they will share one 32-byte storage slot.
  • “awkwardness” is a 16-bit unsigned integer, and it will also share a 32-byte storage slot with “flattening” and “denomination”.
  • “data” is an array containing 3 elements of type bytes32, each element occupying one 32-byte storage slot. Therefore, it will occupy 3 storage slots of 32 bytes each (i.e. 96 bytes).

Therefore, the storage slot allocation for the variables is as follows:

Slot 1: bool public locked = true;
Slot 2: uint256 public ID = block.timestamp;
Slot 3: uint8 private flattening = 10;
uint8 private denomination = 255;
uint16 private awkwardness = uint16(block.timestamp);
Slot 4: bytes32[0] private data;
Slot 5: bytes32[1] private data;
Slot 6: bytes32[2] private data;

So first, we can get the value of data[2], the index starts from 0:

1
key = await web3.eth.getStorageAt(contract.address, 5)

Then we notice that the parameter of key is a byte16 varaiable, so we need to get the first half of the whole string.

1
2
key = key.slice(0,34)
'0x3984f2645f6a24237d048268a9429f76'

The reason why I slice from 0 to 34 instead of 32 is because the first two characters are “0x”.

Finally, it’s done.

1
await contract.unlock(key)