Skip to content

Commit

Permalink
fix: fix memory read
Browse files Browse the repository at this point in the history
  • Loading branch information
GCdePaula committed Aug 5, 2024
1 parent ef68cdd commit a1923bf
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 66 deletions.
72 changes: 35 additions & 37 deletions src/AccessLogs.sol
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,8 @@ library AccessLogs {
return end2;
}

/// @dev bytes buffer layout is the different for `readWord` and `writeWord`,
/// readWord: [32 bytes as read data], [59 * 32 bytes as sibling hashes]
/// writeWord [32 bytes as written hash] [32 bytes as read data], [59 * 32 bytes as sibling hashes]
/// @dev bytes buffer layout is the same for `readWord` and `writeWord`,
/// [32 bytes as read data], [59 * 32 bytes as sibling hashes]

//
// Read methods
Expand Down Expand Up @@ -96,18 +95,17 @@ library AccessLogs {
Memory.PhysicalAddress readAddress
) internal pure returns (uint64) {
bytes32 readData = a.buffer.consumeBytes32();
bytes32 computedReadHash = keccak256(abi.encodePacked(readData));
(Memory.PhysicalAddress leafAddress, uint64 wordOffset) =
bytes32 valHash = keccak256(abi.encodePacked(readData));

(Memory.PhysicalAddress leafAddress, uint64 offset) =
readAddress.truncateToLeaf();
bytes8 word = getBytes8FromBytes32AtOffset(readData, wordOffset);
bytes8 readValue = getBytes8FromBytes32AtOffset(readData, offset);

bytes32 expectedReadHash =
bytes32 expectedValHash =
readLeaf(a, Memory.strideFromLeafAddress(leafAddress));

require(
computedReadHash == expectedReadHash, "Read value doesn't match"
);
return machineWordToSolidityUint64(word);
require(valHash == expectedValHash, "Read value doesn't match");
return machineWordToSolidityUint64(readValue);
}

//
Expand Down Expand Up @@ -145,28 +143,27 @@ library AccessLogs {
Memory.PhysicalAddress writeAddress,
uint64 newValue
) internal pure {
(Memory.PhysicalAddress leafAddress, uint64 wordOffset) =
(Memory.PhysicalAddress leafAddress, uint64 offset) =
writeAddress.truncateToLeaf();
bytes32 writtenHash = a.buffer.consumeBytes32();
bytes32 readData = a.buffer.consumeBytes32();

// check if read data hashes to the same read hash that is next in the buffer
bytes32 computedReadHash = keccak256(abi.encodePacked(readData));
bytes32 loggedReadHash = a.buffer.peekBytes32();
require(
computedReadHash == loggedReadHash,
"logged and computed read hashes mismatch"
Memory.Region memory region = Memory.regionFromStride(
Memory.strideFromLeafAddress(leafAddress),
Memory.alignedSizeFromLog2(0)
);

// construct the written data by patching the verified read data
bytes32 computedWrittenData = setBytes8InBytes32AtOffset(
readData, wordOffset, solidityUint64ToMachineWord(newValue)
bytes32 oldLeaf = a.buffer.consumeBytes32();
(bytes32 rootHash,) =
a.buffer.peekRoot(region, keccak256(abi.encodePacked(oldLeaf)));

require(a.currentRootHash == rootHash, "Write word root doesn't match");

bytes32 newLeaf = setBytes8ToBytes32AtOffset(
solidityUint64ToMachineWord(newValue), oldLeaf, offset
);
bytes32 computedWrittenHash =
keccak256(abi.encodePacked(computedWrittenData));
require(computedWrittenHash == writtenHash, "Written hash mismatch");

writeLeaf(a, Memory.strideFromLeafAddress(leafAddress), writtenHash);
bytes32 newRootHash =
a.buffer.getRoot(region, keccak256(abi.encodePacked(newLeaf)));
a.currentRootHash = newRootHash;
}

function getBytes8FromBytes32AtOffset(bytes32 source, uint64 offset)
Expand All @@ -177,16 +174,17 @@ library AccessLogs {
return bytes8(source << (offset << Memory.LOG2_WORD));
}

function setBytes8InBytes32AtOffset(
bytes32 target,
uint64 offset,
bytes8 source
function setBytes8ToBytes32AtOffset(
bytes8 word,
bytes32 leaf,
uint64 offset
) internal pure returns (bytes32) {
bytes32 erase_mask = bytes32(bytes8(type(uint64).max));
erase_mask = erase_mask >> (offset << Memory.LOG2_WORD);
erase_mask = ~erase_mask;
bytes32 result = target & erase_mask;
result = result | (bytes32(source) >> (offset << Memory.LOG2_WORD));
return result;
uint256 wordOffset = offset << Memory.LOG2_WORD;
bytes32 toWrite = bytes32(word) >> wordOffset;

bytes32 wordMask = bytes32(~bytes8(0));
bytes32 mask = ~(wordMask >> wordOffset);

return (leaf & mask) | toWrite;
}
}
66 changes: 37 additions & 29 deletions templates/AccessLogs.sol.template
Original file line number Diff line number Diff line change
Expand Up @@ -75,9 +75,8 @@ library AccessLogs {

//:#ifndef test

/// @dev bytes buffer layout is the different for `readWord` and `writeWord`,
/// readWord: [32 bytes as read data], [59 * 32 bytes as sibling hashes]
/// writeWord [32 bytes as written hash] [32 bytes as read data], [59 * 32 bytes as sibling hashes]
/// @dev bytes buffer layout is the same for `readWord` and `writeWord`,
/// [32 bytes as read data], [59 * 32 bytes as sibling hashes]

//
// Read methods
Expand Down Expand Up @@ -109,15 +108,16 @@ library AccessLogs {
Memory.PhysicalAddress readAddress
) internal pure returns (uint64) {
bytes32 readData = a.buffer.consumeBytes32();
bytes32 computedReadHash = keccak256(abi.encodePacked(readData));
(Memory.PhysicalAddress leafAddress, uint64 wordOffset) = readAddress.truncateToLeaf();
bytes8 word = getBytes8FromBytes32AtOffset(readData, wordOffset);
bytes32 valHash = keccak256(abi.encodePacked(readData));

bytes32 expectedReadHash =
(Memory.PhysicalAddress leafAddress, uint64 offset) = readAddress.truncateToLeaf();
bytes8 readValue = getBytes8FromBytes32AtOffset(readData, offset);

bytes32 expectedValHash =
readLeaf(a, Memory.strideFromLeafAddress(leafAddress));

require(computedReadHash == expectedReadHash, "Read value doesn't match");
return machineWordToSolidityUint64(word);
require(valHash == expectedValHash, "Read value doesn't match");
return machineWordToSolidityUint64(readValue);
}

//
Expand Down Expand Up @@ -155,21 +155,27 @@ library AccessLogs {
Memory.PhysicalAddress writeAddress,
uint64 newValue
) internal pure {
(Memory.PhysicalAddress leafAddress, uint64 wordOffset) = writeAddress.truncateToLeaf();
bytes32 writtenHash = a.buffer.consumeBytes32();
bytes32 readData = a.buffer.consumeBytes32();
(Memory.PhysicalAddress leafAddress, uint64 offset) =
writeAddress.truncateToLeaf();

// check if read data hashes to the same read hash that is next in the buffer
bytes32 computedReadHash = keccak256(abi.encodePacked(readData));
bytes32 loggedReadHash = a.buffer.peekBytes32();
require(computedReadHash ==loggedReadHash, "logged and computed read hashes mismatch");
Memory.Region memory region = Memory.regionFromStride(
Memory.strideFromLeafAddress(leafAddress),
Memory.alignedSizeFromLog2(0)
);

// construct the written data by patching the verified read data
bytes32 computedWrittenData = setBytes8InBytes32AtOffset(readData, wordOffset, solidityUint64ToMachineWord(newValue));
bytes32 computedWrittenHash = keccak256(abi.encodePacked(computedWrittenData));
require(computedWrittenHash == writtenHash, "Written hash mismatch");
bytes32 oldLeaf = a.buffer.consumeBytes32();
(bytes32 rootHash,) = a.buffer.peekRoot(region, keccak256(abi.encodePacked(oldLeaf)));

writeLeaf(a, Memory.strideFromLeafAddress(leafAddress), writtenHash);
require(
a.currentRootHash == rootHash, "Write word root doesn't match"
);

bytes32 newLeaf = setBytes8ToBytes32AtOffset(
solidityUint64ToMachineWord(newValue), oldLeaf, offset
);

bytes32 newRootHash = a.buffer.getRoot(region, keccak256(abi.encodePacked(newLeaf)));
a.currentRootHash = newRootHash;
}

function getBytes8FromBytes32AtOffset(bytes32 source, uint64 offset)
Expand All @@ -179,20 +185,22 @@ library AccessLogs {
{
return bytes8(source << (offset << Memory.LOG2_WORD));
}
function setBytes8InBytes32AtOffset(bytes32 target, uint64 offset, bytes8 source)

function setBytes8ToBytes32AtOffset(bytes8 word, bytes32 leaf, uint64 offset)
internal
pure
returns (bytes32)
{
bytes32 erase_mask = bytes32(bytes8(type(uint64).max));
erase_mask = erase_mask >> (offset << Memory.LOG2_WORD);
erase_mask = ~erase_mask;
bytes32 result = target & erase_mask;
result = result | (bytes32(source) >> (offset << Memory.LOG2_WORD));
return result;
uint256 wordOffset = offset << Memory.LOG2_WORD;
bytes32 toWrite = bytes32(word) >> wordOffset;

bytes32 wordMask = bytes32(~bytes8(0));
bytes32 mask = ~(wordMask >> wordOffset);

return (leaf & mask) | toWrite;
}


//:#else

/// @dev This library mocks the `templates/AccessLogs.sol` yet with a very different implementation.
Expand Down

0 comments on commit a1923bf

Please sign in to comment.