transaaction circuit with custom input count

This commit is contained in:
poma 2021-06-15 14:25:06 +03:00
parent a19a226277
commit 960b6adb30
No known key found for this signature in database
GPG Key ID: BA20CB01FE165657
10 changed files with 69 additions and 47 deletions

View File

@ -14,7 +14,7 @@ commitment = hash(amount, blinding, pubKey)
nullifier = hash(commitment, privKey, merklePath) nullifier = hash(commitment, privKey, merklePath)
*/ */
// Universal JoinSplit transaction with 2 inputs and 2 outputs // Universal JoinSplit transaction with nIns inputs and 2 outputs
template Transaction(levels, nIns, nOuts, zeroLeaf) { template Transaction(levels, nIns, nOuts, zeroLeaf) {
signal input root; signal input root;
signal input newRoot; signal input newRoot;
@ -107,10 +107,18 @@ template Transaction(levels, nIns, nOuts, zeroLeaf) {
component feeCheck = Num2Bits(248); component feeCheck = Num2Bits(248);
feeCheck.in <== fee; feeCheck.in <== fee;
component sameNullifiers = IsEqual(); // check that there are no same nullifiers among all inputs
sameNullifiers.in[0] <== inputNullifier[0]; component sameNullifiers[nIns * (nIns - 1) / 2];
sameNullifiers.in[1] <== inputNullifier[1]; var index = 0;
sameNullifiers.out === 0; for (var i = 0; i < nIns - 1; i++) {
for (var j = i + 1; j < nIns; j++) {
sameNullifiers[index] = IsEqual();
sameNullifiers[index].in[0] <== inputNullifier[i];
sameNullifiers[index].in[1] <== inputNullifier[j];
sameNullifiers[index].out === 0;
index++;
}
}
// verify amount invariant // verify amount invariant
sumIns + extAmount === sumOuts + fee; sumIns + extAmount === sumOuts + fee;
@ -119,8 +127,9 @@ template Transaction(levels, nIns, nOuts, zeroLeaf) {
component treeUpdater = TreeUpdater(levels, zeroLeaf); component treeUpdater = TreeUpdater(levels, zeroLeaf);
treeUpdater.oldRoot <== root; treeUpdater.oldRoot <== root;
treeUpdater.newRoot <== newRoot; treeUpdater.newRoot <== newRoot;
treeUpdater.leaf[0] <== outputCommitment[0]; for (var i = 0; i < nOuts; i++) {
treeUpdater.leaf[1] <== outputCommitment[1]; treeUpdater.leaf[i] <== outputCommitment[i];
}
treeUpdater.pathIndices <== outPathIndices; treeUpdater.pathIndices <== outPathIndices;
for (var i = 0; i < levels - 1; i++) { for (var i = 0; i < levels - 1; i++) {
treeUpdater.pathElements[i] <== outPathElements[i]; treeUpdater.pathElements[i] <== outPathElements[i];

View File

@ -17,6 +17,7 @@ import "@openzeppelin/contracts/utils/ReentrancyGuard.sol"; // todo: maybe remov
interface IVerifier { interface IVerifier {
function verifyProof(bytes memory _proof, uint256[9] memory _input) external returns(bool); function verifyProof(bytes memory _proof, uint256[9] memory _input) external returns(bool);
function verifyProof(bytes memory _proof, uint256[23] memory _input) external returns(bool);
} }
contract TornadoPool is ReentrancyGuard { contract TornadoPool is ReentrancyGuard {
@ -26,7 +27,8 @@ contract TornadoPool is ReentrancyGuard {
mapping(bytes32 => bool) public nullifierHashes; mapping(bytes32 => bool) public nullifierHashes;
bytes32 public currentRoot; bytes32 public currentRoot;
uint public currentCommitmentIndex; uint public currentCommitmentIndex;
IVerifier public verifier; IVerifier public verifier2;
IVerifier public verifier16;
struct ExtData { struct ExtData {
address payable recipient; address payable recipient;
@ -42,10 +44,12 @@ contract TornadoPool is ReentrancyGuard {
/** /**
@dev The constructor @dev The constructor
@param _verifier the address of SNARK verifier for this contract @param _verifier2 the address of SNARK verifier for this contract
@param _verifier16 the address of SNARK verifier for this contract
*/ */
constructor(IVerifier _verifier, bytes32 _currentRoot) public { constructor(IVerifier _verifier2, IVerifier _verifier16, bytes32 _currentRoot) public {
verifier = _verifier; verifier2 = _verifier2;
verifier16 = _verifier16;
currentRoot = _currentRoot; currentRoot = _currentRoot;
} }
@ -66,7 +70,7 @@ contract TornadoPool is ReentrancyGuard {
require(!isSpent(_inputNullifiers[0]), "Input 0 is already spent"); require(!isSpent(_inputNullifiers[0]), "Input 0 is already spent");
require(!isSpent(_inputNullifiers[1]), "Input 1 is already spent"); require(!isSpent(_inputNullifiers[1]), "Input 1 is already spent");
require(uint256(_extDataHash) == uint256(keccak256(abi.encode(_extData))) % FIELD_SIZE, "Incorrect external data hash"); require(uint256(_extDataHash) == uint256(keccak256(abi.encode(_extData))) % FIELD_SIZE, "Incorrect external data hash");
require(verifier.verifyProof(_proof, [ require(verifier2.verifyProof(_proof, [
uint256(_root), uint256(_root),
uint256(_newRoot), uint256(_newRoot),
uint256(_inputNullifiers[0]), uint256(_inputNullifiers[0]),

View File

@ -1 +0,0 @@
../artifacts/circuits/Verifier.sol

1
contracts/Verifier16.sol Symbolic link
View File

@ -0,0 +1 @@
../artifacts/circuits/Verifier16.sol

1
contracts/Verifier2.sol Symbolic link
View File

@ -0,0 +1 @@
../artifacts/circuits/Verifier2.sol

View File

@ -7,11 +7,10 @@
"test": "test" "test": "test"
}, },
"scripts": { "scripts": {
"circuit": "./scripts/buildCircuit.sh transaction2 && ./scripts/buildCircuit.sh transaction16", "circuit": "./scripts/buildCircuit.sh 2 && ./scripts/buildCircuit.sh 16",
"compile": "npx hardhat compile", "compile": "npx hardhat compile",
"build": "npm run circuit && npm run compile", "build": "npm run circuit && npm run compile",
"migrate": "npx hardhat run scripts/deploy.js --network localhost", "test": "npx hardhat test"
"start": "node ./src/index.js"
}, },
"keywords": [], "keywords": [],
"author": "", "author": "",
@ -32,7 +31,7 @@
"ffjavascript": "^0.2.36", "ffjavascript": "^0.2.36",
"fixed-merkle-tree": "^0.5.0", "fixed-merkle-tree": "^0.5.0",
"hardhat": "^2.3.0", "hardhat": "^2.3.0",
"snarkjs": "^0.4.5", "snarkjs": "git+https://github.com/tornadocash/snarkjs.git#c103e3bf10e95e2e9bbf0f7952ed13812f8e39d3",
"tmp-promise": "^3.0.2" "tmp-promise": "^3.0.2"
} }
} }

View File

@ -8,10 +8,11 @@ if [ ! -f artifacts/circuits/ptau$POWERS_OF_TAU ]; then
npx snarkjs powersoftau prepare phase2 artifacts/circuits/tmp2_ptau$POWERS_OF_TAU artifacts/circuits/ptau$POWERS_OF_TAU npx snarkjs powersoftau prepare phase2 artifacts/circuits/tmp2_ptau$POWERS_OF_TAU artifacts/circuits/ptau$POWERS_OF_TAU
rm artifacts/circuits/tmp_ptau$POWERS_OF_TAU artifacts/circuits/tmp2_ptau$POWERS_OF_TAU rm artifacts/circuits/tmp_ptau$POWERS_OF_TAU artifacts/circuits/tmp2_ptau$POWERS_OF_TAU
fi fi
npx circom -v -r artifacts/circuits/$1.r1cs -w artifacts/circuits/$1.wasm -s artifacts/circuits/$1.sym circuits/$1.circom npx circom -v -r artifacts/circuits/transaction$1.r1cs -w artifacts/circuits/transaction$1.wasm -s artifacts/circuits/transaction$1.sym circuits/transaction$1.circom
npx snarkjs groth16 setup artifacts/circuits/$1.r1cs artifacts/circuits/ptau$POWERS_OF_TAU artifacts/circuits/tmp_$1.zkey npx snarkjs groth16 setup artifacts/circuits/transaction$1.r1cs artifacts/circuits/ptau$POWERS_OF_TAU artifacts/circuits/tmp_transaction$1.zkey
npx snarkjs zkey contribute artifacts/circuits/tmp_$1.zkey artifacts/circuits/$1.zkey npx snarkjs zkey contribute artifacts/circuits/tmp_transaction$1.zkey artifacts/circuits/transaction$1.zkey
npx snarkjs zkey export solidityverifier artifacts/circuits/$1.zkey artifacts/circuits/Verifier.sol npx snarkjs zkey export solidityverifier artifacts/circuits/transaction$1.zkey artifacts/circuits/Verifier$1.sol
#zkutil setup -c artifacts/circuits/$1.r1cs -p artifacts/circuits/$1.params sed -i.bak "s/contract Verifier/contract Verifier${1}/g" artifacts/circuits/Verifier$1.sol
#zkutil generate-verifier -p artifacts/circuits/$1.params -v artifacts/circuits/Verifier.sol #zkutil setup -c artifacts/circuits/transaction$1.r1cs -p artifacts/circuits/transaction$1.params
npx snarkjs info -r artifacts/circuits/$1.r1cs #zkutil generate-verifier -p artifacts/circuits/transaction$1.params -v artifacts/circuits/Verifier.sol
npx snarkjs info -r artifacts/circuits/transaction$1.r1cs

View File

@ -14,16 +14,21 @@ const toFixedHex = (number, length = 32) =>
).padStart(length * 2, '0') ).padStart(length * 2, '0')
async function main() { async function main() {
const Verifier = await ethers.getContractFactory('Verifier') const Verifier2 = await ethers.getContractFactory('Verifier2')
const verifier = await Verifier.deploy() const verifier2 = await Verifier2.deploy()
await verifier.deployed() await verifier2.deployed()
console.log(`verifier: ${verifier.address}`) console.log(`verifier2: ${verifier2.address}`)
const Verifier16 = await ethers.getContractFactory('Verifier16')
const verifier16 = await Verifier16.deploy()
await verifier16.deployed()
console.log(`verifier16: ${verifier16.address}`)
const tree = new MerkleTree(MERKLE_TREE_HEIGHT, [], { hashFunction: poseidonHash2 }) const tree = new MerkleTree(MERKLE_TREE_HEIGHT, [], { hashFunction: poseidonHash2 })
const root = await tree.root() const root = await tree.root()
const Pool = await ethers.getContractFactory('TornadoPool') const Pool = await ethers.getContractFactory('TornadoPool')
const tornado = await Pool.deploy(verifier.address, toFixedHex(root)) const tornado = await Pool.deploy(verifier2.address, verifier16.address, toFixedHex(root))
console.log("TornadoPool's address ", tornado.address) console.log("TornadoPool's address ", tornado.address)
} }

View File

@ -14,15 +14,19 @@ describe('TornadoPool', () => {
/* prettier-ignore */ /* prettier-ignore */
before(async function () { before(async function () {
const Verifier = await ethers.getContractFactory('Verifier') const Verifier2 = await ethers.getContractFactory('Verifier2')
const verifier = await Verifier.deploy() const verifier2 = await Verifier2.deploy()
await verifier.deployed() await verifier2.deployed()
const Verifier16 = await ethers.getContractFactory('Verifier16')
const verifier16 = await Verifier16.deploy()
await verifier16.deployed()
const tree = new MerkleTree(MERKLE_TREE_HEIGHT, [], { hashFunction: poseidonHash2 }) const tree = new MerkleTree(MERKLE_TREE_HEIGHT, [], { hashFunction: poseidonHash2 })
const root = await tree.root() const root = await tree.root()
const Pool = await ethers.getContractFactory('TornadoPool') const Pool = await ethers.getContractFactory('TornadoPool')
tornadoPool = await Pool.deploy(verifier.address, toFixedHex(root)) tornadoPool = await Pool.deploy(verifier2.address, verifier16.address, toFixedHex(root))
snapshotId = await takeSnapshot() snapshotId = await takeSnapshot()
}) })

View File

@ -7423,10 +7423,20 @@ snapdragon@^0.8.1:
source-map-resolve "^0.5.0" source-map-resolve "^0.5.0"
use "^3.1.0" use "^3.1.0"
snarkjs@^0.4.5: "snarkjs@git+https://github.com/tornadocash/snarkjs.git#869181cfaf7526fe8972073d31655493a04326d5":
version "0.1.20"
resolved "git+https://github.com/tornadocash/snarkjs.git#869181cfaf7526fe8972073d31655493a04326d5"
dependencies:
big-integer "^1.6.43"
chai "^4.2.0"
escape-string-regexp "^1.0.5"
eslint "^5.16.0"
keccak "^2.0.0"
yargs "^12.0.5"
"snarkjs@git+https://github.com/tornadocash/snarkjs.git#c103e3bf10e95e2e9bbf0f7952ed13812f8e39d3":
version "0.4.5" version "0.4.5"
resolved "https://registry.yarnpkg.com/snarkjs/-/snarkjs-0.4.5.tgz#c7246b0bdcdafd25c67c0ecc395556715b059a14" resolved "git+https://github.com/tornadocash/snarkjs.git#c103e3bf10e95e2e9bbf0f7952ed13812f8e39d3"
integrity sha512-rgxbp3JMhGdPgkhCrssq+a4Bv2vm2QucWwK9QG5cdyRRpx8f5EOpyMPy7pi/U8VUyyyulAaDowKBf7x7chB7zg==
dependencies: dependencies:
"@iden3/binfileutils" "0.0.8" "@iden3/binfileutils" "0.0.8"
blake2b-wasm "https://github.com/jbaylina/blake2b-wasm.git" blake2b-wasm "https://github.com/jbaylina/blake2b-wasm.git"
@ -7439,17 +7449,6 @@ snarkjs@^0.4.5:
r1csfile "0.0.32" r1csfile "0.0.32"
readline "^1.3.0" readline "^1.3.0"
"snarkjs@git+https://github.com/tornadocash/snarkjs.git#869181cfaf7526fe8972073d31655493a04326d5":
version "0.1.20"
resolved "git+https://github.com/tornadocash/snarkjs.git#869181cfaf7526fe8972073d31655493a04326d5"
dependencies:
big-integer "^1.6.43"
chai "^4.2.0"
escape-string-regexp "^1.0.5"
eslint "^5.16.0"
keccak "^2.0.0"
yargs "^12.0.5"
solc@0.7.3: solc@0.7.3:
version "0.7.3" version "0.7.3"
resolved "https://registry.yarnpkg.com/solc/-/solc-0.7.3.tgz#04646961bd867a744f63d2b4e3c0701ffdc7d78a" resolved "https://registry.yarnpkg.com/solc/-/solc-0.7.3.tgz#04646961bd867a744f63d2b4e3c0701ffdc7d78a"