mirror of
https://github.com/tornadocash/tornado-core.git
synced 2025-01-20 17:21:29 -05:00
poseidon in merkle tree
This commit is contained in:
parent
c7f0ca9dfa
commit
71f6fce20e
@ -18,8 +18,8 @@ You can read more about it in [this medium article](https://medium.com/@tornado.
|
||||
![mixer image](./mixer.png)
|
||||
|
||||
## Security risks
|
||||
* Cryptographic tools used by mixer (zkSNARKS, Pedersen commitment, MiMC hash) are not yet extensively audited by cryptographic experts and may be vulnerable
|
||||
* Note: we use MiMC hash only for merkle tree, so even if a preimage attack on MiMC is discovered, it will not allow to deanonymize users. To drain funds attacker needs to be able to generate arbitrary hash collisions, which is a pretty strong assumption.
|
||||
* Cryptographic tools used by mixer (zkSNARKS, Pedersen commitment, Poseidon hash) are not yet extensively audited by cryptographic experts and may be vulnerable
|
||||
* Note: we use Poseidon hash only for merkle tree, so even if a preimage attack on Poseidon is discovered, it will not allow to deanonymize users. To drain funds attacker needs to be able to generate arbitrary hash collisions, which is a pretty strong assumption.
|
||||
* Bugs in contract. Even though we have an extensive experience in smart contract security audits, we can still make mistakes. An external audit is needed to reduce probablility of bugs. Our mixer is currently being audited, stay tuned.
|
||||
* Relayer is frontrunnable. When relayer submits a transaction someone can see it in tx pool and frontrun it with higher gas price to get the fee and drain relayer funds.
|
||||
* Workaround: we can set high gas price so that (almost) all fee is used on gas
|
||||
|
@ -1,18 +1,17 @@
|
||||
include "../node_modules/circomlib/circuits/mimcsponge.circom";
|
||||
include "../node_modules/circomlib/circuits/poseidon.circom";
|
||||
|
||||
// Computes MiMC(left + right)
|
||||
// Computes Poseidon(left + right)
|
||||
template HashLeftRight(rounds) {
|
||||
signal input left;
|
||||
signal input right;
|
||||
|
||||
signal output hash;
|
||||
|
||||
component hasher = MiMCSponge(2, rounds, 1);
|
||||
hasher.ins[0] <== left;
|
||||
hasher.ins[1] <== right;
|
||||
hasher.k <== 0;
|
||||
component hasher = Poseidon(2, 6, 8, 57);
|
||||
hasher.inputs[0] <== left;
|
||||
hasher.inputs[1] <== right;
|
||||
|
||||
hash <== hasher.outs[0];
|
||||
hash <== hasher.out;
|
||||
}
|
||||
|
||||
// if pathIndex == 0 returns (left = inputElement, right = pathElement)
|
||||
|
8
cli.js
8
cli.js
@ -40,7 +40,7 @@ async function deposit() {
|
||||
const deposit = createDeposit(rbigint(31), rbigint(31))
|
||||
|
||||
console.log('Submitting deposit transaction')
|
||||
await mixer.methods.deposit('0x' + deposit.commitment.toString(16)).send({ value: ETH_AMOUNT, from: (await web3.eth.getAccounts())[0], gas:1e6 })
|
||||
await mixer.methods.deposit('0x' + deposit.commitment.toString(16)).send({ value: ETH_AMOUNT, from: (await web3.eth.getAccounts())[0], gas:4e6 })
|
||||
|
||||
const note = '0x' + deposit.preimage.toString('hex')
|
||||
console.log('Your note:', note)
|
||||
@ -57,7 +57,7 @@ async function depositErc20() {
|
||||
console.log('erc20mixer allowance', allowance.toString(10))
|
||||
|
||||
const deposit = createDeposit(rbigint(31), rbigint(31))
|
||||
await erc20mixer.methods.deposit('0x' + deposit.commitment.toString(16)).send({ value: ETH_AMOUNT, from: account, gas:1e6 })
|
||||
await erc20mixer.methods.deposit('0x' + deposit.commitment.toString(16)).send({ value: ETH_AMOUNT, from: account, gas:4e6 })
|
||||
|
||||
const balance = await erc20.methods.balanceOf(erc20mixer.address).call()
|
||||
console.log('erc20mixer balance', balance.toString(10))
|
||||
@ -116,7 +116,7 @@ async function withdrawErc20(note, receiver, relayer) {
|
||||
console.timeEnd('Proof time')
|
||||
|
||||
console.log('Submitting withdraw transaction')
|
||||
await erc20mixer.methods.withdraw(proof, publicSignals).send({ from: (await web3.eth.getAccounts())[0], gas: 1e6 })
|
||||
await erc20mixer.methods.withdraw(proof, publicSignals).send({ from: (await web3.eth.getAccounts())[0], gas: 4e6 })
|
||||
console.log('Done')
|
||||
}
|
||||
|
||||
@ -190,7 +190,7 @@ async function withdraw(note, receiver) {
|
||||
console.timeEnd('Proof time')
|
||||
|
||||
console.log('Submitting withdraw transaction')
|
||||
await mixer.methods.withdraw(proof, publicSignals).send({ from: (await web3.eth.getAccounts())[0], gas: 1e6 })
|
||||
await mixer.methods.withdraw(proof, publicSignals).send({ from: (await web3.eth.getAccounts())[0], gas: 4e6 })
|
||||
console.log('Done')
|
||||
}
|
||||
|
||||
|
@ -12,7 +12,7 @@
|
||||
pragma solidity ^0.5.8;
|
||||
|
||||
library Hasher {
|
||||
function MiMCSponge(uint256 in_xL, uint256 in_xR, uint256 in_k) public pure returns (uint256 xL, uint256 xR);
|
||||
function poseidon(uint256[] memory input) public pure returns (uint256);
|
||||
}
|
||||
|
||||
contract MerkleTreeWithHistory {
|
||||
@ -43,17 +43,10 @@ contract MerkleTreeWithHistory {
|
||||
}
|
||||
|
||||
function hashLeftRight(uint256 left, uint256 right) public pure returns (uint256 hash) {
|
||||
uint256 k = 21888242871839275222246405745257275088548364400416034343698204186575808495617;
|
||||
uint256 R = 0;
|
||||
uint256 C = 0;
|
||||
|
||||
R = addmod(R, left, k);
|
||||
(R, C) = Hasher.MiMCSponge(R, C, 0);
|
||||
|
||||
R = addmod(R, right, k);
|
||||
(R, C) = Hasher.MiMCSponge(R, C, 0);
|
||||
|
||||
hash = R;
|
||||
uint256[] memory data = new uint256[](2);
|
||||
data[0] = left;
|
||||
data[1] = right;
|
||||
hash = MiMC.poseidon(data);
|
||||
}
|
||||
|
||||
function _insert(uint256 leaf) internal {
|
||||
|
@ -1,5 +1,5 @@
|
||||
const jsStorage = require('./Storage')
|
||||
const hasherImpl = require('./MiMC')
|
||||
const hasherImpl = require('./Poseidon')
|
||||
|
||||
class MerkleTree {
|
||||
|
||||
|
13
lib/Poseidon.js
Normal file
13
lib/Poseidon.js
Normal file
@ -0,0 +1,13 @@
|
||||
const poseidon = require('circomlib/src/poseidon')
|
||||
const snarkjs = require('snarkjs')
|
||||
|
||||
const bigInt = snarkjs.bigInt
|
||||
|
||||
class PoseidonHasher {
|
||||
hash(level, left, right) {
|
||||
const hash = poseidon.createHash(6, 8, 57)
|
||||
return hash([bigInt(left), bigInt(right)]).toString()
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = PoseidonHasher
|
@ -1,7 +1,7 @@
|
||||
/* global artifacts */
|
||||
const path = require('path')
|
||||
|
||||
const genContract = require('circomlib/src/mimcsponge_gencontract.js')
|
||||
const genContract = require('circomlib/src/poseidon_gencontract.js')
|
||||
const Artifactor = require('truffle-artifactor')
|
||||
|
||||
module.exports = function(deployer) {
|
||||
@ -12,7 +12,7 @@ module.exports = function(deployer) {
|
||||
await artifactor.save({
|
||||
contractName,
|
||||
abi: genContract.abi,
|
||||
unlinked_binary: genContract.createCode('mimcsponge', 220),
|
||||
unlinked_binary: genContract.createCode(),
|
||||
}).then(async () => {
|
||||
const hasherContract = artifacts.require(contractName)
|
||||
await deployer.deploy(hasherContract)
|
||||
|
@ -10,7 +10,7 @@ const MerkleTreeWithHistory = artifacts.require('./MerkleTreeWithHistoryMock.sol
|
||||
const hasherContract = artifacts.require('./Hasher.sol')
|
||||
|
||||
const MerkleTree = require('../lib/MerkleTree')
|
||||
const hasherImpl = require('../lib/MiMC')
|
||||
const hasherImpl = require('../lib/Poseidon')
|
||||
|
||||
const { ETH_AMOUNT, MERKLE_TREE_HEIGHT, EMPTY_ELEMENT } = process.env
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user