mirror of
https://github.com/tornadocash/tornado-core.git
synced 2024-11-22 01:37:07 +01:00
optimize sloads
This commit is contained in:
parent
127a61e21f
commit
3ad634594e
@ -20,36 +20,35 @@ contract MerkleTreeWithHistory {
|
|||||||
uint256 public constant FIELD_SIZE = 21888242871839275222246405745257275088548364400416034343698204186575808495617;
|
uint256 public constant FIELD_SIZE = 21888242871839275222246405745257275088548364400416034343698204186575808495617;
|
||||||
uint256 public constant ZERO_VALUE = 21663839004416932945382355908790599225266501822907911457504978515578255421292; // = keccak256("tornado") % FIELD_SIZE
|
uint256 public constant ZERO_VALUE = 21663839004416932945382355908790599225266501822907911457504978515578255421292; // = keccak256("tornado") % FIELD_SIZE
|
||||||
|
|
||||||
uint32 public levels;
|
IHasher public immutable hasher;
|
||||||
|
uint32 public immutable levels;
|
||||||
|
|
||||||
// the following variables are made public for easier testing and debugging and
|
// the following variables are made public for easier testing and debugging and
|
||||||
// are not supposed to be accessed in regular code
|
// are not supposed to be accessed in regular code
|
||||||
bytes32[] public filledSubtrees;
|
|
||||||
bytes32[] public zeros;
|
// filledSubtrees, zeros, and roots could be bytes32[size], but using mappings makes it cheaper because
|
||||||
|
// it removes index range check on every interaction
|
||||||
|
mapping(uint256 => bytes32) public filledSubtrees;
|
||||||
|
mapping(uint256 => bytes32) public zeros;
|
||||||
|
mapping(uint256 => bytes32) public roots;
|
||||||
|
uint32 public constant ROOT_HISTORY_SIZE = 30;
|
||||||
uint32 public currentRootIndex = 0;
|
uint32 public currentRootIndex = 0;
|
||||||
uint32 public nextIndex = 0;
|
uint32 public nextIndex = 0;
|
||||||
uint32 public constant ROOT_HISTORY_SIZE = 100;
|
|
||||||
bytes32[ROOT_HISTORY_SIZE] public roots;
|
|
||||||
IHasher public immutable hasher;
|
|
||||||
|
|
||||||
constructor(uint32 _treeLevels, IHasher _hasher) public {
|
|
||||||
require(_treeLevels > 0, "_treeLevels should be greater than zero");
|
|
||||||
require(_treeLevels < 32, "_treeLevels should be less than 32");
|
|
||||||
levels = _treeLevels;
|
|
||||||
|
|
||||||
|
constructor(uint32 _levels, IHasher _hasher) public {
|
||||||
|
require(_levels > 0, "_levels should be greater than zero");
|
||||||
|
require(_levels < 32, "_levels should be less than 32");
|
||||||
|
levels = _levels;
|
||||||
hasher = _hasher;
|
hasher = _hasher;
|
||||||
|
|
||||||
bytes32 currentZero = bytes32(ZERO_VALUE);
|
bytes32 currentZero = bytes32(ZERO_VALUE);
|
||||||
zeros.push(currentZero);
|
for (uint32 i = 0; i < _levels; i++) {
|
||||||
filledSubtrees.push(currentZero);
|
zeros[i] = currentZero;
|
||||||
|
filledSubtrees[i] = currentZero;
|
||||||
for (uint32 i = 1; i < levels; i++) {
|
|
||||||
currentZero = hashLeftRight(_hasher, currentZero, currentZero);
|
currentZero = hashLeftRight(_hasher, currentZero, currentZero);
|
||||||
zeros.push(currentZero);
|
|
||||||
filledSubtrees.push(currentZero);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
roots[0] = hashLeftRight(_hasher, currentZero, currentZero);
|
roots[0] = currentZero;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -71,9 +70,9 @@ contract MerkleTreeWithHistory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function _insert(bytes32 _leaf) internal returns (uint32 index) {
|
function _insert(bytes32 _leaf) internal returns (uint32 index) {
|
||||||
uint32 currentIndex = nextIndex;
|
uint32 _nextIndex = nextIndex;
|
||||||
require(currentIndex != uint32(2)**levels, "Merkle tree is full. No more leafs can be added");
|
require(_nextIndex != uint32(2)**levels, "Merkle tree is full. No more leaves can be added");
|
||||||
nextIndex += 1;
|
uint32 currentIndex = _nextIndex;
|
||||||
bytes32 currentLevelHash = _leaf;
|
bytes32 currentLevelHash = _leaf;
|
||||||
bytes32 left;
|
bytes32 left;
|
||||||
bytes32 right;
|
bytes32 right;
|
||||||
@ -82,21 +81,20 @@ contract MerkleTreeWithHistory {
|
|||||||
if (currentIndex % 2 == 0) {
|
if (currentIndex % 2 == 0) {
|
||||||
left = currentLevelHash;
|
left = currentLevelHash;
|
||||||
right = zeros[i];
|
right = zeros[i];
|
||||||
|
|
||||||
filledSubtrees[i] = currentLevelHash;
|
filledSubtrees[i] = currentLevelHash;
|
||||||
} else {
|
} else {
|
||||||
left = filledSubtrees[i];
|
left = filledSubtrees[i];
|
||||||
right = currentLevelHash;
|
right = currentLevelHash;
|
||||||
}
|
}
|
||||||
|
|
||||||
currentLevelHash = hashLeftRight(hasher, left, right);
|
currentLevelHash = hashLeftRight(hasher, left, right);
|
||||||
|
|
||||||
currentIndex /= 2;
|
currentIndex /= 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
currentRootIndex = (currentRootIndex + 1) % ROOT_HISTORY_SIZE;
|
uint32 newRootIndex = (currentRootIndex + 1) % ROOT_HISTORY_SIZE;
|
||||||
roots[currentRootIndex] = currentLevelHash;
|
currentRootIndex = newRootIndex;
|
||||||
return nextIndex - 1;
|
roots[newRootIndex] = currentLevelHash;
|
||||||
|
nextIndex = _nextIndex + 1;
|
||||||
|
return _nextIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -106,7 +104,8 @@ contract MerkleTreeWithHistory {
|
|||||||
if (_root == 0) {
|
if (_root == 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
uint32 i = currentRootIndex;
|
uint32 _currentRootIndex = currentRootIndex;
|
||||||
|
uint32 i = _currentRootIndex;
|
||||||
do {
|
do {
|
||||||
if (_root == roots[i]) {
|
if (_root == roots[i]) {
|
||||||
return true;
|
return true;
|
||||||
@ -115,7 +114,7 @@ contract MerkleTreeWithHistory {
|
|||||||
i = ROOT_HISTORY_SIZE;
|
i = ROOT_HISTORY_SIZE;
|
||||||
}
|
}
|
||||||
i--;
|
i--;
|
||||||
} while (i != currentRootIndex);
|
} while (i != _currentRootIndex);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,19 +20,12 @@ interface IVerifier {
|
|||||||
}
|
}
|
||||||
|
|
||||||
abstract contract Tornado is MerkleTreeWithHistory, ReentrancyGuard {
|
abstract contract Tornado is MerkleTreeWithHistory, ReentrancyGuard {
|
||||||
uint256 public denomination;
|
IVerifier public immutable verifier;
|
||||||
|
uint256 public immutable denomination;
|
||||||
|
|
||||||
mapping(bytes32 => bool) public nullifierHashes;
|
mapping(bytes32 => bool) public nullifierHashes;
|
||||||
// we store all commitments just to prevent accidental deposits with the same commitment
|
// we store all commitments just to prevent accidental deposits with the same commitment
|
||||||
mapping(bytes32 => bool) public commitments;
|
mapping(bytes32 => bool) public commitments;
|
||||||
IVerifier public immutable verifier;
|
|
||||||
|
|
||||||
// operator can update snark verification key
|
|
||||||
// after the final trusted setup ceremony operator rights are supposed to be transferred to zero address
|
|
||||||
address public operator;
|
|
||||||
modifier onlyOperator {
|
|
||||||
require(msg.sender == operator, "Only operator can call this function.");
|
|
||||||
_;
|
|
||||||
}
|
|
||||||
|
|
||||||
event Deposit(bytes32 indexed commitment, uint32 leafIndex, uint256 timestamp);
|
event Deposit(bytes32 indexed commitment, uint32 leafIndex, uint256 timestamp);
|
||||||
event Withdrawal(address to, bytes32 nullifierHash, address indexed relayer, uint256 fee);
|
event Withdrawal(address to, bytes32 nullifierHash, address indexed relayer, uint256 fee);
|
||||||
|
@ -159,10 +159,10 @@ contract('MerkleTreeWithHistory', (accounts) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let error = await merkleTreeWithHistory.insert(toFixedHex(1337)).should.be.rejected
|
let error = await merkleTreeWithHistory.insert(toFixedHex(1337)).should.be.rejected
|
||||||
error.reason.should.be.equal('Merkle tree is full. No more leafs can be added')
|
error.reason.should.be.equal('Merkle tree is full. No more leaves can be added')
|
||||||
|
|
||||||
error = await merkleTreeWithHistory.insert(toFixedHex(1)).should.be.rejected
|
error = await merkleTreeWithHistory.insert(toFixedHex(1)).should.be.rejected
|
||||||
error.reason.should.be.equal('Merkle tree is full. No more leafs can be added')
|
error.reason.should.be.equal('Merkle tree is full. No more leaves can be added')
|
||||||
})
|
})
|
||||||
|
|
||||||
it.skip('hasher gas', async () => {
|
it.skip('hasher gas', async () => {
|
||||||
|
Loading…
Reference in New Issue
Block a user