Skip to content

Commit

Permalink
Make H(0, 0) = 0
Browse files Browse the repository at this point in the history
  • Loading branch information
TimDaub committed Dec 17, 2021
1 parent 1b2026b commit eacc9e4
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 120 deletions.
44 changes: 13 additions & 31 deletions src/StateTree.sol
@@ -1,43 +1,17 @@
pragma solidity ^0.8.6;

function hashes(uint256 _level) pure returns (bytes32) {
if(_level == 0) {
return 0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563;
} else if(_level == 1) {
return 0x633dc4d7da7256660a892f8f1604a44b5432649cc8ec5cb3ced4c4e6ac94dd1d;
} else if(_level == 2) {
return 0x890740a8eb06ce9be422cb8da5cdafc2b58c0a5e24036c578de2a433c828ff7d;
} else if(_level == 3) {
return 0x3b8ec09e026fdc305365dfc94e189a81b38c7597b3d941c279f042e8206e0bd8;
} else if(_level == 4) {
return 0xecd50eee38e386bd62be9bedb990706951b65fe053bd9d8a521af753d139e2da;
} else if(_level == 5) {
return 0xdefff6d330bb5403f63b14f33b578274160de3a50df4efecf0e0db73bcdd3da5;
} else if(_level == 6) {
return 0x617bdd11f7c0a11f49db22f629387a12da7596f9d1704d7465177c63d88ec7d7;
} else if(_level == 7) {
return 0x292c23a9aa1d8bea7e2435e555a4a60e379a5a35f3f452bae60121073fb6eead;
} else if(_level == 8) {
return 0xe1cea92ed99acdcb045a6726b2f87107e8a61620a232cf4d7d5b5766b3952e10;
}
}

uint256 constant SIZE = 255;
uint256 constant BUFFER_LENGTH = 1;
uint256 constant DEPTH = 8;

library StateTree {
function get(uint256 _level) internal pure returns (bytes32) {
return hashes(_level);
}

function bitmap(uint256 index) internal pure returns (uint8) {
uint8 bytePos = (uint8(BUFFER_LENGTH) - 1) - (uint8(index) / 8);
return bytePos + 1 << (uint8(index) % 8);
}

function empty() internal pure returns (bytes32) {
return hashes(DEPTH);
return 0;
}

function validate(
Expand Down Expand Up @@ -65,6 +39,14 @@ library StateTree {
return compute(_proofs, _bits, _index, _nextLeaf);
}

function hash(bytes32 a, bytes32 b) internal pure returns (bytes32) {
if (a == 0 && b == 0) {
return 0;
} else {
return keccak256(abi.encode(a, b));
}
}

function compute(
bytes32[] memory _proofs,
uint8 _bits,
Expand All @@ -77,15 +59,15 @@ library StateTree {
for (uint256 d = 0; d < DEPTH; d++) {
if ((_index & 1) == 1) {
if ((_bits & 1) == 1) {
_leaf = keccak256(abi.encode(_proofs[d], _leaf));
_leaf = hash(_proofs[d], _leaf);
} else {
_leaf = keccak256(abi.encode(hashes(d), _leaf));
_leaf = hash(0, _leaf);
}
} else {
if ((_bits & 1) == 1) {
_leaf = keccak256(abi.encode(_leaf, _proofs[d]));
_leaf = hash(_leaf, _proofs[d]);
} else {
_leaf = keccak256(abi.encode(_leaf, hashes(d)));
_leaf = hash(_leaf, 0);
}
}

Expand Down
101 changes: 12 additions & 89 deletions src/StateTree.t.sol
Expand Up @@ -7,13 +7,6 @@ import "./StateTree.sol";
contract StateTreeTest is DSTest {
function setUp() public {}

function testGasOfGet() public {
uint startGas = gasleft();
StateTree.get(0);
uint endGas = gasleft();
emit log_named_uint("gas calling get(uint256 _level)", startGas - endGas);
}

function testGasOfCompute() public {
bytes32 LEAF = 0x0000000000000000000000000000000000000000000000000000000000000000;
bytes32 LEAF_HASH = keccak256(abi.encode(LEAF));
Expand Down Expand Up @@ -62,24 +55,16 @@ contract StateTreeTest is DSTest {
assertEq(value % 2, 0);
}

function testGetHash() public {
bytes32 hash = StateTree.get(0);
assertEq(hash, 0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563);
}

function testGettingZero() public {
bytes32 empty = StateTree.empty();
assertEq(empty, 0xe1cea92ed99acdcb045a6726b2f87107e8a61620a232cf4d7d5b5766b3952e10);
assertEq(empty, 0);
}

function testComputeEmpty() public {
bytes32[] memory proofs = new bytes32[](0);

bytes32 LEAF = 0x0000000000000000000000000000000000000000000000000000000000000000;
bytes32 LEAF_HASH = keccak256(abi.encode(LEAF));

bytes32 expectedRoot = StateTree.empty();
assertEq(StateTree.compute(proofs, 0, 0, LEAF_HASH), expectedRoot);
assertEq(StateTree.compute(proofs, 0, 0, 0), expectedRoot);
}

function testValidateEmpty() public {
Expand All @@ -89,10 +74,7 @@ contract StateTreeTest is DSTest {
bytes32 LEAF_HASH = keccak256(abi.encode(LEAF));

bytes32 expectedRoot = StateTree.empty();
assertTrue(
StateTree.validate(proofs, 0, 0, LEAF_HASH,
expectedRoot
));
assertTrue(StateTree.validate(proofs, 0, 0, 0, expectedRoot));
}

function testComputeInsertFirst() public {
Expand All @@ -104,7 +86,7 @@ contract StateTreeTest is DSTest {
bytes32 expectedRoot = LEAF_HASH;
uint DEPTH = 8;
for (uint256 i = 0; i < DEPTH; i++) {
expectedRoot = keccak256(abi.encode(expectedRoot, StateTree.get(i)));
expectedRoot = keccak256(abi.encode(expectedRoot, 0));
}

assertEq(StateTree.compute(proofs, 0, 0, LEAF_HASH), expectedRoot);
Expand All @@ -116,19 +98,16 @@ contract StateTreeTest is DSTest {
bytes32 NEXT_LEAF = 0x0000000000000000000000000000000000000000000000000000000000000001;
bytes32 NEXT_LEAF_HASH = keccak256(abi.encode(NEXT_LEAF));

bytes32 PREV_LEAF = 0x0000000000000000000000000000000000000000000000000000000000000000;
bytes32 PREV_LEAF_HASH = keccak256(abi.encode(PREV_LEAF));

bytes32 PREV_ROOT = StateTree.empty();
uint startGas = gasleft();
bytes32 NEXT_ROOT = StateTree.write(proofs, 0, 0, NEXT_LEAF_HASH, PREV_LEAF_HASH, PREV_ROOT);
bytes32 NEXT_ROOT = StateTree.write(proofs, 0, 0, NEXT_LEAF_HASH, 0, PREV_ROOT);
uint endGas = gasleft();
emit log_named_uint("gas calling first write()", startGas - endGas);

bytes32 expectedRoot = NEXT_LEAF_HASH;
uint DEPTH = 8;
for (uint256 i = 0; i < DEPTH; i++) {
expectedRoot = keccak256(abi.encode(expectedRoot, StateTree.get(i)));
expectedRoot = keccak256(abi.encode(expectedRoot, 0));
}
assertEq(NEXT_ROOT, expectedRoot);
}
Expand All @@ -139,24 +118,19 @@ contract StateTreeTest is DSTest {
bytes32 NEXT_LEAF = 0x0000000000000000000000000000000000000000000000000000000000000001;
bytes32 NEXT_LEAF_HASH = keccak256(abi.encode(NEXT_LEAF));

bytes32 PREV_LEAF = 0x0000000000000000000000000000000000000000000000000000000000000000;
bytes32 PREV_LEAF_HASH = keccak256(abi.encode(PREV_LEAF));

bytes32 ROOT1 = StateTree.empty();
bytes32 ROOT2 = StateTree.write(proofs, 0, 0, NEXT_LEAF_HASH, PREV_LEAF_HASH, ROOT1);
bytes32 ROOT2 = StateTree.write(proofs, 0, 0, NEXT_LEAF_HASH, 0, ROOT1);

uint8 bits = StateTree.bitmap(0);
bytes32[] memory proofs1 = new bytes32[](1);
proofs1[0] = NEXT_LEAF_HASH;
bytes32 ROOT3 = StateTree.write(proofs1, bits, 1, NEXT_LEAF_HASH, PREV_LEAF_HASH, ROOT2);
bytes32 ROOT3 = StateTree.write(proofs1, bits, 1, NEXT_LEAF_HASH, 0, ROOT2);
}

function testFillUpTree() public {
uint256 DEPTH = 8;
bytes32 LEAF = 0x0000000000000000000000000000000000000000000000000000000000000001;
bytes32 LEAF_HASH = keccak256(abi.encode(LEAF));
bytes32 ZERO_LEAF = 0x0000000000000000000000000000000000000000000000000000000000000000;
bytes32 ZERO_LEAF_HASH = keccak256(abi.encode(ZERO_LEAF));

bytes32[] memory ones = new bytes32[](DEPTH);
bytes32 hashOnes = LEAF_HASH;
Expand Down Expand Up @@ -185,67 +159,19 @@ contract StateTreeTest is DSTest {
pointer = pointer / 2;
}

prevRoot = StateTree.write(proofs, bits, i, LEAF_HASH, ZERO_LEAF_HASH, prevRoot);
prevRoot = StateTree.write(proofs, bits, i, LEAF_HASH, 0, prevRoot);
}

}


function testFillUp() public {
uint256 DEPTH = 8;
bytes32 LEAF = 0x0000000000000000000000000000000000000000000000000000000000000001;
bytes32 LEAF_HASH = keccak256(abi.encode(LEAF));
bytes32 ZERO_LEAF = 0x0000000000000000000000000000000000000000000000000000000000000000;
bytes32 ZERO_LEAF_HASH = keccak256(abi.encode(ZERO_LEAF));

bytes32[] memory ones = new bytes32[](DEPTH);
bytes32 hashOnes = LEAF_HASH;
ones[0] = LEAF_HASH;
ones[1] = keccak256(abi.encode(ones[0], ones[0]));
ones[2] = keccak256(abi.encode(ones[1], ones[1]));
ones[3] = keccak256(abi.encode(ones[2], ones[2]));
ones[4] = keccak256(abi.encode(ones[3], ones[3]));
ones[5] = keccak256(abi.encode(ones[4], ones[4]));
ones[6] = keccak256(abi.encode(ones[5], ones[5]));
ones[7] = keccak256(abi.encode(ones[6], ones[6]));

bytes32 prevRoot = StateTree.empty();
for(uint256 i = 0; i < 5; i++) {
bytes32[] memory proofs = new bytes32[](DEPTH);

uint8 bits;
if (i == 0) {
bits = 0;
} else if (i == 1) {
bits = StateTree.bitmap(0);
proofs[0] = ones[0];
} else if (i == 2) {
bits = StateTree.bitmap(1);
proofs[1] = ones[1];
} else if (i == 3) {
bits = StateTree.bitmap(0);
bits += StateTree.bitmap(1);
proofs[0] = ones[0];
proofs[1] = ones[1];
} else if (i == 4) {
bits = StateTree.bitmap(2);
proofs[2] = ones[2];
}

prevRoot = StateTree.write(proofs, bits, i, LEAF_HASH, ZERO_LEAF_HASH, prevRoot);
}
}

function testFailHijackingHash() public {
bytes32[] memory proofs = new bytes32[](0);
uint8 bits = StateTree.bitmap(0);

bytes32 LEAF = 0x0000000000000000000000000000000000000000000000000000000000001337;
bytes32 LEAF_HASH = keccak256(abi.encode(LEAF));
bytes32 ZERO_LEAF = 0x0000000000000000000000000000000000000000000000000000000000000000;
bytes32 ZERO_LEAF_HASH = keccak256(abi.encode(ZERO_LEAF));

bytes32 newRoot = StateTree.write(proofs, bits, 0, LEAF_HASH, ZERO_LEAF_HASH, ZERO_LEAF_HASH);
bytes32 newRoot = StateTree.write(proofs, bits, 0, LEAF_HASH, 0, 0);
assertEq(newRoot, LEAF_HASH);
}

Expand All @@ -255,16 +181,13 @@ contract StateTreeTest is DSTest {
bytes32 NEXT_LEAF = 0x0000000000000000000000000000000000000000000000000000000000000001;
bytes32 NEXT_LEAF_HASH = keccak256(abi.encode(NEXT_LEAF));

bytes32 PREV_LEAF = 0x0000000000000000000000000000000000000000000000000000000000000000;
bytes32 PREV_LEAF_HASH = keccak256(abi.encode(PREV_LEAF));

bytes32 ROOT1 = StateTree.empty();
bytes32 ROOT2 = StateTree.write(proofs, 0, 0, NEXT_LEAF_HASH, PREV_LEAF_HASH, ROOT1);
bytes32 ROOT2 = StateTree.write(proofs, 0, 0, NEXT_LEAF_HASH, 0, ROOT1);

uint8 bits = StateTree.bitmap(0);
bytes32[] memory proofs1 = new bytes32[](1);
proofs1[0] = NEXT_LEAF_HASH;
bytes32 ROOT3 = StateTree.write(proofs1, bits, 1, NEXT_LEAF_HASH, PREV_LEAF_HASH, ROOT2);
bytes32 ROOT3 = StateTree.write(proofs1, bits, 1, NEXT_LEAF_HASH, 0, ROOT2);

bytes32 UPDATE_LEAF = 0x0000000000000000000000000000000000000000000000000000000000000002;
bytes32 UPDATE_LEAF_HASH = keccak256(abi.encode(UPDATE_LEAF));
Expand Down

0 comments on commit eacc9e4

Please sign in to comment.