tornado-core/contracts/MerkleTreeWithHistory.sol

129 lines
4.1 KiB
Solidity
Raw Normal View History

2019-08-02 19:12:30 +02:00
// https://tornado.cash
/*
2021-02-11 07:23:18 +01:00
* d888888P dP a88888b. dP
* 88 88 d8' `88 88
* 88 .d8888b. 88d888b. 88d888b. .d8888b. .d888b88 .d8888b. 88 .d8888b. .d8888b. 88d888b.
* 88 88' `88 88' `88 88' `88 88' `88 88' `88 88' `88 88 88' `88 Y8ooooo. 88' `88
* 88 88. .88 88 88 88 88. .88 88. .88 88. .88 dP Y8. .88 88. .88 88 88 88
* dP `88888P' dP dP dP `88888P8 `88888P8 `88888P' 88 Y88888P' `88888P8 `88888P' dP dP
* ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo
*/
2019-08-02 19:12:30 +02:00
2021-02-11 07:03:43 +01:00
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;
2019-07-09 15:05:30 +02:00
2021-02-11 06:37:18 +01:00
interface Hasher {
2021-02-11 07:03:43 +01:00
function MiMCSponge(uint256 in_xL, uint256 in_xR) external pure returns (uint256 xL, uint256 xR);
2019-07-09 15:05:30 +02:00
}
contract MerkleTreeWithHistory {
2019-11-02 13:35:22 +01:00
uint256 public constant FIELD_SIZE = 21888242871839275222246405745257275088548364400416034343698204186575808495617;
2019-11-15 09:42:48 +01:00
uint256 public constant ZERO_VALUE = 21663839004416932945382355908790599225266501822907911457504978515578255421292; // = keccak256("tornado") % FIELD_SIZE
2019-07-09 15:05:30 +02:00
uint32 public levels;
2019-11-04 20:45:56 +01:00
// the following variables are made public for easier testing and debugging and
// are not supposed to be accessed in regular code
2019-11-04 22:04:22 +01:00
bytes32[] public filledSubtrees;
bytes32[] public zeros;
2019-11-06 11:52:00 +01:00
uint32 public currentRootIndex = 0;
uint32 public nextIndex = 0;
uint32 public constant ROOT_HISTORY_SIZE = 100;
bytes32[ROOT_HISTORY_SIZE] public roots;
2021-02-11 06:37:18 +01:00
Hasher public immutable hasher;
2019-07-09 15:05:30 +02:00
2021-02-11 06:37:18 +01:00
constructor(uint32 _treeLevels, Hasher _hasher) public {
2019-11-02 14:04:17 +01:00
require(_treeLevels > 0, "_treeLevels should be greater than zero");
require(_treeLevels < 32, "_treeLevels should be less than 32");
2019-11-02 14:04:17 +01:00
levels = _treeLevels;
2019-07-09 15:05:30 +02:00
2021-02-11 06:37:18 +01:00
hasher = _hasher;
2019-11-04 22:04:22 +01:00
bytes32 currentZero = bytes32(ZERO_VALUE);
2019-11-03 09:45:54 +01:00
zeros.push(currentZero);
2019-11-02 14:04:17 +01:00
filledSubtrees.push(currentZero);
2019-07-09 15:05:30 +02:00
for (uint32 i = 1; i < levels; i++) {
2021-02-11 07:03:43 +01:00
currentZero = hashLeftRight(_hasher, currentZero, currentZero);
2019-11-02 14:04:17 +01:00
zeros.push(currentZero);
filledSubtrees.push(currentZero);
2019-07-09 15:05:30 +02:00
}
2021-02-11 07:03:43 +01:00
roots[0] = hashLeftRight(_hasher, currentZero, currentZero);
2019-07-09 15:05:30 +02:00
}
2019-11-04 20:45:56 +01:00
/**
@dev Hash 2 tree leaves, returns MiMC(_left, _right)
*/
2021-02-11 07:23:18 +01:00
function hashLeftRight(
Hasher _hasher,
bytes32 _left,
bytes32 _right
) public pure returns (bytes32) {
2019-11-04 22:04:22 +01:00
require(uint256(_left) < FIELD_SIZE, "_left should be inside the field");
require(uint256(_right) < FIELD_SIZE, "_right should be inside the field");
uint256 R = uint256(_left);
2019-07-09 15:05:30 +02:00
uint256 C = 0;
2021-02-11 07:03:43 +01:00
(R, C) = _hasher.MiMCSponge(R, C);
2019-11-04 22:04:22 +01:00
R = addmod(R, uint256(_right), FIELD_SIZE);
2021-02-11 07:03:43 +01:00
(R, C) = _hasher.MiMCSponge(R, C);
2019-11-04 22:04:22 +01:00
return bytes32(R);
2019-07-09 15:05:30 +02:00
}
2021-02-11 07:23:18 +01:00
function _insert(bytes32 _leaf) internal returns (uint32 index) {
2019-11-02 14:04:17 +01:00
uint32 currentIndex = nextIndex;
require(currentIndex != uint32(2)**levels, "Merkle tree is full. No more leafs can be added");
2019-11-02 14:04:17 +01:00
nextIndex += 1;
2019-11-04 22:04:22 +01:00
bytes32 currentLevelHash = _leaf;
bytes32 left;
bytes32 right;
2019-07-09 15:05:30 +02:00
for (uint32 i = 0; i < levels; i++) {
2019-11-02 14:04:17 +01:00
if (currentIndex % 2 == 0) {
left = currentLevelHash;
right = zeros[i];
2019-07-09 15:05:30 +02:00
2019-11-02 14:04:17 +01:00
filledSubtrees[i] = currentLevelHash;
2019-07-09 15:05:30 +02:00
} else {
2019-11-02 14:04:17 +01:00
left = filledSubtrees[i];
right = currentLevelHash;
2019-07-09 15:05:30 +02:00
}
2021-02-11 07:03:43 +01:00
currentLevelHash = hashLeftRight(hasher, left, right);
2019-07-09 15:05:30 +02:00
2019-11-02 14:04:17 +01:00
currentIndex /= 2;
2019-07-09 15:05:30 +02:00
}
2019-11-02 14:04:17 +01:00
currentRootIndex = (currentRootIndex + 1) % ROOT_HISTORY_SIZE;
roots[currentRootIndex] = currentLevelHash;
return nextIndex - 1;
2019-07-09 15:05:30 +02:00
}
2019-11-04 20:45:56 +01:00
/**
@dev Whether the root is present in the root history
*/
2021-02-11 07:23:18 +01:00
function isKnownRoot(bytes32 _root) public view returns (bool) {
2019-11-02 14:04:17 +01:00
if (_root == 0) {
2019-07-09 15:05:30 +02:00
return false;
}
uint32 i = currentRootIndex;
2019-11-03 10:06:58 +01:00
do {
2019-12-13 22:18:16 +01:00
if (_root == roots[i]) {
return true;
}
if (i == 0) {
i = ROOT_HISTORY_SIZE;
}
i--;
2019-11-03 10:06:58 +01:00
} while (i != currentRootIndex);
2019-07-09 15:05:30 +02:00
return false;
}
2019-11-04 20:45:56 +01:00
/**
@dev Returns the last root
*/
2021-02-11 07:23:18 +01:00
function getLastRoot() public view returns (bytes32) {
2019-11-02 14:04:17 +01:00
return roots[currentRootIndex];
2019-07-09 15:05:30 +02:00
}
}