Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ekrem/tree number #2

Open
wants to merge 11 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
pragma circom 2.0.6;
include "../node_modules/circomlib/circuits/poseidon.circom";
include "../node_modules/circomlib/circuits/bitify.circom";
include "../node_modules/circomlib/circuits/switcher.circom";
include "../node_modules/circomlib/circuits/comparators.circom";
include "../../node_modules/circomlib/circuits/poseidon.circom";
include "../../node_modules/circomlib/circuits/bitify.circom";
include "../../node_modules/circomlib/circuits/switcher.circom";
include "../../node_modules/circomlib/circuits/comparators.circom";

template MerkleProofVerifier(MerkleTreeDepth) {
signal input leaf;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
pragma circom 2.0.6;
include "../node_modules/circomlib/circuits/poseidon.circom";
include "../node_modules/circomlib/circuits/comparators.circom";
include "../../node_modules/circomlib/circuits/poseidon.circom";
include "../../node_modules/circomlib/circuits/comparators.circom";

template NullifierCheck() {
signal input nullifier;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,49 +1,49 @@
pragma circom 2.0.6;

include "../node_modules/circomlib/circuits/poseidon.circom";
include "../node_modules/circomlib/circuits/bitify.circom";
include "../node_modules/circomlib/circuits/switcher.circom";
include "../node_modules/circomlib/circuits/comparators.circom";
include "../../node_modules/circomlib/circuits/poseidon.circom";
include "../../node_modules/circomlib/circuits/bitify.circom";
include "../../node_modules/circomlib/circuits/switcher.circom";
include "../../node_modules/circomlib/circuits/comparators.circom";
include "./merkle-proof-verifier.circom";
include "./nullifier-check.circom";

template Step(MerkleTreeDepth, maxInputs, maxOutputs, zeroLeaf) {
template Step(MerkleTreeDepth, nInputs, nOutputs, maxInputs, maxOutputs, zeroLeaf) {
//********************** Public Signals *********************************
signal input anyRailgunTxidMerklerootAfterTransaction;
signal input poiMerkleroots[maxInputs];
signal output blindedCommitmentsOut[maxOutputs];
signal input railgunTxidIfHasUnshield;
signal input poiMerkleroots[nInputs];
signal output blindedCommitmentsOut[nOutputs];
//***********************************************************************

//********************** Private Signals ********************************
// Railgun Transaction info
signal input boundParamsHash; // hash of ciphertext and adapterParameters
signal input nullifiers[maxInputs]; // Nullifiers for input notes
signal input commitmentsOut[maxOutputs]; // hash of output notes
signal input nullifiers[nInputs]; // Nullifiers for input notes
signal input commitmentsOut[nOutputs]; // hash of output notes

// Spender wallet info
signal input spendingPublicKey[2]; // Public key for signature verification denoted to as PK
signal input nullifyingKey;

// Nullified notes data
signal input token;
signal input randomsIn[maxInputs];
signal input valuesIn[maxInputs];
signal input utxoPositionsIn[maxInputs];
signal input blindedCommitmentsIn[maxInputs];
signal input creationTxidsIn[maxInputs];
signal input utxoTreesIn;
signal input randomsIn[nInputs];
signal input valuesIn[nInputs];
signal input utxoPositionsIn[nInputs];
signal input utxoTreeIn;

// Commitment notes data
signal input npksOut[maxOutputs]; // Recipients' NPK
signal input valuesOut[maxOutputs];
signal input npksOut[nOutputs]; // Recipients' NPK
signal input valuesOut[nOutputs];
signal input utxoBatchGlobalStartPositionOut;

// Railgun txid tree
signal input railgunTxidMerkleProofIndices;
signal input railgunTxidMerkleProofPathElements[MerkleTreeDepth];

// POI tree
signal input poiInMerkleProofIndices[maxInputs];
signal input poiInMerkleProofPathElements[maxInputs][MerkleTreeDepth];
signal input poiInMerkleProofIndices[nInputs];
signal input poiInMerkleProofPathElements[nInputs][MerkleTreeDepth];
//***********************************************************************


Expand All @@ -53,18 +53,29 @@ template Step(MerkleTreeDepth, maxInputs, maxOutputs, zeroLeaf) {

// 1 - Calculate railgunTxid
component nullifiersHasher = Poseidon(maxInputs);
for(var i = 0; i < maxInputs; i++) {
for(var i = 0; i < nInputs; i++) {
nullifiersHasher.inputs[i] <== nullifiers[i];
}
for(var i = nInputs; i < maxInputs; i++){
nullifiersHasher.inputs[i] <== zeroLeaf;
}
component commitmentsHasher = Poseidon(maxOutputs);
for(var i = 0; i < maxOutputs; i++) {
for(var i = 0; i < nOutputs; i++) {
commitmentsHasher.inputs[i] <== commitmentsOut[i];
}
for(var i = nOutputs; i < maxOutputs; i++){
commitmentsHasher.inputs[i] <== zeroLeaf;
}
component railgunTxidHasher = Poseidon(3);
railgunTxidHasher.inputs[0] <== nullifiersHasher.out;
railgunTxidHasher.inputs[1] <== commitmentsHasher.out;
railgunTxidHasher.inputs[2] <== boundParamsHash;

component txidTreeLeafHasher = Poseidon(3);
txidTreeLeafHasher.inputs[0] <== railgunTxidHasher.out;
txidTreeLeafHasher.inputs[1] <== utxoTreeIn;
txidTreeLeafHasher.inputs[2] <== utxoBatchGlobalStartPositionOut;

//***********************************************************************

// 2 - Check if railgunTxid is in the merkle tree
Expand All @@ -74,22 +85,28 @@ template Step(MerkleTreeDepth, maxInputs, maxOutputs, zeroLeaf) {
railgunTxidVerifier.pathElements[j] <== railgunTxidMerkleProofPathElements[j];
}
railgunTxidVerifier.leafIndex <== railgunTxidMerkleProofIndices;
railgunTxidVerifier.leaf <== railgunTxidHasher.out;
railgunTxidVerifier.leaf <== txidTreeLeafHasher.out;
railgunTxidVerifier.enabled <== 1;
//***********************************************************************

// 2.1 enforce railgunTxidIfHasUnshield is either 0 or txid
component railgunTxidIfHasUnshieldCheck = ForceEqualIfEnabled();
railgunTxidIfHasUnshieldCheck.in[0] <== railgunTxidIfHasUnshield;
railgunTxidIfHasUnshieldCheck.in[1] <== railgunTxidHasher.out;
railgunTxidIfHasUnshieldCheck.enabled <== railgunTxidIfHasUnshield;



// 3. Check dummy inputs (i.e., with zero value)
component isDummy[maxInputs];
for(var i=0; i<maxInputs; i++) {
component isDummy[nInputs];
for(var i=0; i<nInputs; i++) {
isDummy[i] = IsZero();
isDummy[i].in <== valuesIn[i];
}

// 3. Verify nullifiers
component nullifiersHash[maxInputs];
for(var i=0; i<maxInputs; i++) {
component nullifiersHash[nInputs];
for(var i=0; i<nInputs; i++) {
nullifiersHash[i] = NullifierCheck();
nullifiersHash[i].nullifyingKey <== nullifyingKey;
nullifiersHash[i].leafIndex <== utxoPositionsIn[i];
Expand All @@ -104,14 +121,12 @@ template Step(MerkleTreeDepth, maxInputs, maxOutputs, zeroLeaf) {
mpk.inputs[2] <== nullifyingKey;

// 5. Verify Merkle proofs of membership
component noteCommitmentsIn[maxInputs];
component npkIn[maxInputs]; // note public keys
component merkleVerifier[maxInputs];
component inBlindedCommitment1[maxInputs];
component inBlindedCommitment2[maxInputs];
component checkInBlindedCommitment[maxInputs];

for(var i=0; i<maxInputs; i++) {
component noteCommitmentsIn[nInputs];
component npkIn[nInputs]; // note public keys
component merkleVerifier[nInputs];
component inBlindedCommitment[nInputs];

for(var i=0; i<nInputs; i++) {
// Compute NPK
npkIn[i] = Poseidon(2);
npkIn[i].inputs[0] <== mpk.out;
Expand All @@ -122,43 +137,26 @@ template Step(MerkleTreeDepth, maxInputs, maxOutputs, zeroLeaf) {
noteCommitmentsIn[i].inputs[1] <== token;
noteCommitmentsIn[i].inputs[2] <== valuesIn[i];

inBlindedCommitment1[i] = Poseidon(3);
inBlindedCommitment1[i].inputs[0] <== noteCommitmentsIn[i].out;
inBlindedCommitment1[i].inputs[1] <== npkIn[i].out;
inBlindedCommitment1[i].inputs[2] <== utxoTreesIn * 65536 + utxoPositionsIn[i];

inBlindedCommitment2[i] = Poseidon(3);
inBlindedCommitment2[i].inputs[0] <== noteCommitmentsIn[i].out;
inBlindedCommitment2[i].inputs[1] <== npkIn[i].out;
inBlindedCommitment2[i].inputs[2] <== creationTxidsIn[i];


checkInBlindedCommitment[i] = ForceEqualIfEnabled();
checkInBlindedCommitment[i].in[0] <== (inBlindedCommitment1[i].out - blindedCommitmentsIn[i]) * (inBlindedCommitment2[i].out - blindedCommitmentsIn[i]);
checkInBlindedCommitment[i].in[1] <== 0;
checkInBlindedCommitment[i].enabled <== 1 - isDummy[i].out;

inBlindedCommitment[i] = Poseidon(3);
inBlindedCommitment[i].inputs[0] <== noteCommitmentsIn[i].out;
inBlindedCommitment[i].inputs[1] <== npkIn[i].out;
inBlindedCommitment[i].inputs[2] <== utxoTreeIn * 65536 + utxoPositionsIn[i];

merkleVerifier[i] = MerkleProofVerifier(MerkleTreeDepth);
merkleVerifier[i].leaf <== blindedCommitmentsIn[i];
merkleVerifier[i].leaf <== inBlindedCommitment[i].out;
merkleVerifier[i].leafIndex <== poiInMerkleProofIndices[i];
for(var j=0; j<MerkleTreeDepth; j++) {
merkleVerifier[i].pathElements[j] <== poiInMerkleProofPathElements[i][j];
}
merkleVerifier[i].merkleRoot <== poiMerkleroots[i];
merkleVerifier[i].enabled <== 1 - isDummy[i].out;

// We don't need to range check input amounts, since all inputs are valid UTXOs that
// were already checked as in railgunTxid
}

component n2b[maxOutputs];
component outNoteHash[maxOutputs];
component outNoteChecker[maxOutputs];
component outBlindedCommitmentHasher[maxOutputs];
component isValueOutZero[maxOutputs];
// var sumOut = 0;
for(var i=0; i<maxOutputs; i++){
component outNoteHash[nOutputs];
component outNoteChecker[nOutputs];
component outBlindedCommitmentHasher[nOutputs];
component isValueOutZero[nOutputs];
for(var i=0; i<nOutputs; i++){

// We don't need to range check output amounts, since all outputs are valid UTXOs that
// were already checked as in railgunTxid
Expand All @@ -181,11 +179,9 @@ template Step(MerkleTreeDepth, maxInputs, maxOutputs, zeroLeaf) {
outBlindedCommitmentHasher[i] = Poseidon(3);
outBlindedCommitmentHasher[i].inputs[0] <== commitmentsOut[i];
outBlindedCommitmentHasher[i].inputs[1] <== npksOut[i];
outBlindedCommitmentHasher[i].inputs[2] <== railgunTxidHasher.out;
outBlindedCommitmentHasher[i].inputs[2] <== utxoBatchGlobalStartPositionOut + i;


blindedCommitmentsOut[i] <== outBlindedCommitmentHasher[i].out*(1 - isValueOutZero[i].out);
}
}

component main{public [anyRailgunTxidMerklerootAfterTransaction, poiMerkleroots]} = Step(16, 13, 13, 2051258411002736885948763699317990061539314419500486054347250703186609807356); // bytes32(uint256(keccak256("Railgun")) % SNARK_SCALAR_FIELD);
}
4 changes: 4 additions & 0 deletions circuits/poi-transaction-13x13.circom
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
pragma circom 2.0.6;
include "./library/poi-transaction.circom";

component main{public [anyRailgunTxidMerklerootAfterTransaction, railgunTxidIfHasUnshield, poiMerkleroots]} = Step(16, 13, 13, 13, 13, 2051258411002736885948763699317990061539314419500486054347250703186609807356); // bytes32(uint256(keccak256("Railgun")) % SNARK_SCALAR_FIELD);
4 changes: 4 additions & 0 deletions circuits/poi-transaction-3x3.circom
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
pragma circom 2.0.6;
include "./library/poi-transaction.circom";

component main{public [anyRailgunTxidMerklerootAfterTransaction, railgunTxidIfHasUnshield, poiMerkleroots]} = Step(16, 3, 3, 13, 13, 2051258411002736885948763699317990061539314419500486054347250703186609807356); // bytes32(uint256(keccak256("Railgun")) % SNARK_SCALAR_FIELD);
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@
"version": "2.0.0",
"description": "ZK-SNARK circuits for RAILGUN Proof of Innocene",
"scripts": {
"test": " mocha --exit --timeout 30000",
"test": " mocha --exit --timeout 30000000",
"compile": "circom circuits/poi-transaction.circom --r1cs --wasm -o artifacts/circuits",
"launch": "circom circuits/poi-launch.circom --r1cs --wasm -o artifacts/circuits",
"build": "bash scripts/buildCircuit.sh",
"build": "bash scripts/buildCircuit.sh 13;bash scripts/buildCircuit.sh 3",
"build3": "bash scripts/buildCircuit.sh 3",
"postinstall": "patch-package"
},
"devDependencies": {
Expand Down
56 changes: 44 additions & 12 deletions scripts/buildCircuit.sh
Original file line number Diff line number Diff line change
@@ -1,18 +1,50 @@
#!/bin/bash -e
POWERS_OF_TAU=17 # circuit will support max 2^POWERS_OF_TAU constraints

# Check circom version
CIRCOM_VERSION=$(circom --version)
if [[ ! $CIRCOM_VERSION =~ "2.0.6" ]]; then
echo "Error: circom version is not 2.0.6 or not installed"
exit 1
fi

# Check brotli version
BROTLI_VERSION=$(brotli --version)
if [[ ! $BROTLI_VERSION =~ "1.0.9" ]]; then
echo "Error: brotli version is not 1.0.9 or not installed"
exit 1
fi

# Create folder for artifacts
mkdir -p artifacts/circuits
if [ ! -f artifacts/circuits/ptau$POWERS_OF_TAU ]; then

if [ ! -f "artifacts/circuits/ptau$POWERS_OF_TAU" ]; then
echo "Downloading powers of tau file"
curl -L https://hermez.s3-eu-west-1.amazonaws.com/powersOfTau28_hez_final_$POWERS_OF_TAU.ptau --create-dirs -o artifacts/circuits/ptau$POWERS_OF_TAU
fi
circom circuits/poi-transaction.circom --r1cs --wasm --c --json --sym --wat -o artifacts/circuits
npx snarkjs groth16 setup artifacts/circuits/poi-transaction.r1cs artifacts/circuits/ptau$POWERS_OF_TAU artifacts/circuits/tmp_poi-transaction.zkey
echo "qwe" | npx snarkjs zkey contribute artifacts/circuits/tmp_poi-transaction.zkey artifacts/circuits/poi-transaction.zkey
# npx snarkjs zkey export solidityverifier artifacts/circuits/poi-transaction.zkey artifacts/circuits/Verifier.sol
# sed -i.bak "s/contract Verifier/contract Verifier${1}/g" artifacts/circuits/Verifier$1.sol
#zkutil setup -c artifacts/circuits/poi-transaction$1.r1cs -p artifacts/circuits/poi-transaction$1.params
#zkutil generate-verifier -p artifacts/circuits/poi-transaction$1.params -v artifacts/circuits/Verifier.sol
npx snarkjs info -r artifacts/circuits/poi-transaction.r1cs
npx snarkjs zkey export verificationkey artifacts/circuits/poi-transaction.zkey artifacts/circuits/verification_key.json

mv artifacts/circuits/poi-transaction_js/poi-transaction.wasm artifacts/circuits/poi-transaction.wasm

# Compile circuit
circom circuits/poi-transaction-$1x$1.circom --r1cs --wasm --c --json --sym --wat -o artifacts/circuits

# Setup SNARK
npx snarkjs groth16 setup artifacts/circuits/poi-transaction-$1x$1.r1cs artifacts/circuits/ptau$POWERS_OF_TAU artifacts/circuits/tmp_poi-transaction-$1x$1.zkey

# Contribute to zkey
echo "qwe" | npx snarkjs zkey contribute artifacts/circuits/tmp_poi-transaction-$1x$1.zkey artifacts/circuits/poi-transaction-$1x$1.zkey

# Get circuit info
npx snarkjs info -r artifacts/circuits/poi-transaction-$1x$1.r1cs

# Export verification key
npx snarkjs zkey export verificationkey artifacts/circuits/poi-transaction-$1x$1.zkey artifacts/circuits/vkey-$1x$1.json
# Create folder for final files
mkdir -p artifacts/circuits/POI_$1x$1

# Move and compress final files
brotli artifacts/circuits/poi-transaction-$1x$1.zkey
mv artifacts/circuits/poi-transaction-$1x$1.zkey.br artifacts/circuits/POI_$1x$1/zkey.br
brotli artifacts/circuits/poi-transaction-$1x$1_js/poi-transaction-$1x$1.wasm
mv artifacts/circuits/poi-transaction-$1x$1_js/poi-transaction-$1x$1.wasm.br artifacts/circuits/POI_$1x$1/wasm.br
brotli artifacts/circuits/poi-transaction-$1x$1_cpp/poi-transaction-$1x$1.dat
mv artifacts/circuits/poi-transaction-$1x$1_cpp/poi-transaction-$1x$1.dat.br artifacts/circuits/POI_$1x$1/dat.br
mv artifacts/circuits/vkey-$1x$1.json artifacts/circuits/POI_$1x$1/vkey.json
4 changes: 2 additions & 2 deletions test/proof-of-innocence-formatters.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -114,8 +114,8 @@ const formatInputs = (proofInputs) => {
};

describe('Proof of Innocence formatters', async () => {
it('Should test POI circuit with mock formatted inputs', async () => {
const circuit = await tester('./circuits/poi-transaction.circom', {
xit('Should test POI circuit with mock formatted inputs', async () => {
const circuit = await tester('./circuits/poi-transaction-13x13.circom', {
reduceConstraints: false,
});

Expand Down
Loading