diff --git a/.vscode/settings.json b/.vscode/settings.json index 87b5da0..5dc800a 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -2,5 +2,35 @@ "yaml.format.singleQuote": false, "prettier.enable": true, "prettier.jsxSingleQuote": false, - "yaml.format.enable": true + "yaml.format.enable": true, + "cSpell.words": [ + "babyjub", + "Babyjubjub", + "circom", + "circomlib", + "circomlibjs", + "Commonlib", + "ECDH", + "fflonk", + "Groth", + "iden", + "izeto", + "Jubjub", + "keypair", + "maci", + "merkletree", + "ptau", + "ptaus", + "rapidsnark", + "snarkjs", + "solidityverifier", + "tokenid", + "UTXO", + "UTXOs", + "UUPS", + "verificationkey", + "vkey", + "WTNS", + "zeto" + ] } \ No newline at end of file diff --git a/zkp/circuits/README.md b/zkp/circuits/README.md index 5a248f2..bc54c4c 100644 --- a/zkp/circuits/README.md +++ b/zkp/circuits/README.md @@ -111,7 +111,7 @@ When using the groth16 proving system, per-circuit set up ceremony must be condu ### Export the verification key -The verification key is used by verifier code (either offchain with a JS library or onchain with Solidity). This can be derived from the proving key above. +The verification key is used by verifier code (either off-chain with a JS library or onchain with Solidity). This can be derived from the proving key above. ```console snarkjs zkey export verificationkey ~/proving-keys/CIRCUIT_FILE_NAME.zkey ~/proving-keys/CIRCUIT_FILE_NAME-vkey.json diff --git a/zkp/circuits/check_hashes_value.circom b/zkp/circuits/check_hashes_value.circom index 25a4e88..2b5fd8a 100644 --- a/zkp/circuits/check_hashes_value.circom +++ b/zkp/circuits/check_hashes_value.circom @@ -15,7 +15,6 @@ // limitations under the License. pragma circom 2.2.1; -include "./lib/check-positive.circom"; include "./lib/check-hashes.circom"; template checkHashesValue(nOutputs) { diff --git a/zkp/circuits/gen-config.json b/zkp/circuits/gen-config.json index 78101f8..d337fac 100644 --- a/zkp/circuits/gen-config.json +++ b/zkp/circuits/gen-config.json @@ -4,81 +4,81 @@ "anon": { "ptau": "powersOfTau28_hez_final_13", "batchPtau": "powersOfTau28_hez_final_15", - "skipSolidityGenaration": false + "skipSolidityGeneration": false }, "anon_enc": { "ptau": "powersOfTau28_hez_final_15", "batchPtau": "powersOfTau28_hez_final_17", - "skipSolidityGenaration": false + "skipSolidityGeneration": false }, "anon_nullifier": { "ptau": "powersOfTau28_hez_final_17", "batchPtau": "powersOfTau28_hez_final_19", - "skipSolidityGenaration": false + "skipSolidityGeneration": false }, "anon_nullifier_kyc": { "ptau": "powersOfTau28_hez_final_17", "batchPtau": "powersOfTau28_hez_final_19", - "skipSolidityGenaration": false + "skipSolidityGeneration": false }, "anon_enc_nullifier_non_repudiation": { "ptau": "powersOfTau28_hez_final_17", "batchPtau": "powersOfTau28_hez_final_19", - "skipSolidityGenaration": false + "skipSolidityGeneration": false }, "anon_enc_nullifier": { "ptau": "powersOfTau28_hez_final_17", "batchPtau": "powersOfTau28_hez_final_19", - "skipSolidityGenaration": false + "skipSolidityGeneration": false }, "anon_enc_nullifier_kyc": { "ptau": "powersOfTau28_hez_final_17", "batchPtau": "powersOfTau28_hez_final_20", - "skipSolidityGenaration": false + "skipSolidityGeneration": false }, "nf_anon": { "ptau": "powersOfTau28_hez_final_13", - "skipSolidityGenaration": false + "skipSolidityGeneration": false }, "nf_anon_nullifier": { "ptau": "powersOfTau28_hez_final_16", - "skipSolidityGenaration": false + "skipSolidityGeneration": false }, "check_hashes_value": { "ptau": "powersOfTau28_hez_final_11", - "skipSolidityGenaration": false + "skipSolidityGeneration": false }, "check_inputs_outputs_value": { "ptau": "powersOfTau28_hez_final_13", "batchPtau": "powersOfTau28_hez_final_14", - "skipSolidityGenaration": false + "skipSolidityGeneration": false }, "check_nullifiers_value": { "ptau": "powersOfTau28_hez_final_17", "batchPtau": "powersOfTau28_hez_final_19", - "skipSolidityGenaration": false + "skipSolidityGeneration": false }, "check_utxos_owner": { "ptau": "powersOfTau28_hez_final_13", "batchPtau": "powersOfTau28_hez_final_14", - "skipSolidityGenaration": false + "skipSolidityGeneration": false }, "check_utxos_nf_owner": { "ptau": "powersOfTau28_hez_final_13", - "skipSolidityGenaration": false + "skipSolidityGeneration": false }, "check_nullifiers_owner": { "ptau": "powersOfTau28_hez_final_11", "batchPtau": "powersOfTau28_hez_final_13", - "skipSolidityGenaration": false + "skipSolidityGeneration": false }, "check_nullifiers_nf_owner": { "ptau": "powersOfTau28_hez_final_11", - "skipSolidityGenaration": false + "skipSolidityGeneration": false }, "check_nullifiers": { "ptau": "powersOfTau28_hez_final_13", - "skipSolidityGenaration": true + "skipSolidityGeneration": true } } } diff --git a/zkp/circuits/gen.js b/zkp/circuits/gen.js index fd3a84d..f511163 100644 --- a/zkp/circuits/gen.js +++ b/zkp/circuits/gen.js @@ -45,7 +45,7 @@ const ptauDownload = process.env.PTAU_DOWNLOAD_PATH || argv.ptauDownloadPath; const specificCircuits = argv.c; const verbose = argv.v; const compileOnly = argv.compileOnly; -const parallelLimit = parseInt(process.env.GEN_CONCURRENCY, 10) || 4; // Default to compile 4 circuits in parallel +const parallelLimit = parseInt(process.env.GEN_CONCURRENCY, 10) || 4; // Default to compile 4 circuits in parallel // check env vars if (!circuitsRoot) { @@ -105,7 +105,7 @@ const log = (circuit, message) => { }; // main circuit process logic -const processCircuit = async (circuit, ptau, skipSolidityGenaration) => { +const processCircuit = async (circuit, ptau, skipSolidityGeneration) => { const circomInput = path.join("./", `${circuit}.circom`); const ptauFile = path.join(ptauDownload, `${ptau}.ptau`); const zkeyOutput = path.join(provingKeysRoot, `${circuit}.zkey`); @@ -184,7 +184,7 @@ const processCircuit = async (circuit, ptau, skipSolidityGenaration) => { } log(circuit, `Exporting verification key`); const { stdout: vkOut, stderr: vkErr } = await execAsync( - `npx snarkjs zkey export verificationkey ${zkeyOutput} ${path.join( + `npx snarkjs zkey export verification key ${zkeyOutput} ${path.join( provingKeysRoot, `${circuit}-vkey.json`, )}`, @@ -197,7 +197,7 @@ const processCircuit = async (circuit, ptau, skipSolidityGenaration) => { log(circuit, "verification key export error:\n" + vkErr); } } - if (skipSolidityGenaration) { + if (skipSolidityGeneration) { log(circuit, `Skipping solidity verifier generation`); return; } @@ -212,7 +212,7 @@ const processCircuit = async (circuit, ptau, skipSolidityGenaration) => { `verifier_${circuit}.sol`, ); const { stdout: svOut, stderr: svErr } = await execAsync( - `npx snarkjs zkey export solidityverifier ${zkeyOutput} ${solidityFile}`, + `npx snarkjs zkey export solidity verifier ${zkeyOutput} ${solidityFile}`, ); if (verbose) { if (svOut) { @@ -257,14 +257,14 @@ const run = async () => { for (const [ circuit, - { ptau, skipSolidityGenaration, batchPtau }, + { ptau, skipSolidityGeneration, batchPtau }, ] of circuitsArray) { if (onlyCircuits && !onlyCircuits.includes(circuit)) { continue; } let snarkjsVersion; - // first check cirom version and snarkjs version matches the one in the package.json + // first check circom version and snarkjs version matches the one in the package.json try { const { stdout: circomVersion } = await execAsync("circom --version"); // Trigger error to get snarkjs version @@ -316,7 +316,7 @@ const run = async () => { process.exit(1); } - const pcPromise = processCircuit(circuit, ptau, skipSolidityGenaration); + const pcPromise = processCircuit(circuit, ptau, skipSolidityGeneration); activePromises.add(pcPromise); if (activePromises.size >= parallelLimit) { @@ -327,7 +327,7 @@ const run = async () => { const pcBatchPromise = processCircuit( circuit + "_batch", batchPtau, - skipSolidityGenaration, + skipSolidityGeneration, ); activePromises.add(pcBatchPromise); diff --git a/zkp/js/integration-test/check_nullifiers_owner.js b/zkp/js/integration-test/check_nullifiers_owner.js index 7ff6dc5..03b33ff 100644 --- a/zkp/js/integration-test/check_nullifiers_owner.js +++ b/zkp/js/integration-test/check_nullifiers_owner.js @@ -14,23 +14,25 @@ // See the License for the specific language governing permissions and // limitations under the License. -const { expect } = require('chai'); -const { groth16 } = require('snarkjs'); -const { genKeypair, formatPrivKeyForBabyJub } = require('maci-crypto'); -const { Poseidon, newSalt, loadCircuit } = require('../index.js'); -const { loadProvingKeys } = require('./utils.js'); +const { expect } = require("chai"); +const { groth16 } = require("snarkjs"); +const { genKeypair, formatPrivKeyForBabyJub } = require("maci-crypto"); +const { Poseidon, newSalt, loadCircuit } = require("../index.js"); +const { loadProvingKeys } = require("./utils.js"); const poseidonHash3 = Poseidon.poseidon3; -describe('check_nullifiers_owner circuit tests', () => { +describe("check_nullifiers_owner circuit tests", () => { let circuit, provingKeyFile, verificationKey; const Alice = {}; let senderPrivateKey; before(async () => { - circuit = await loadCircuit('check_nullifiers_owner'); - ({ provingKeyFile, verificationKey } = loadProvingKeys('check_nullifiers_owner')); + circuit = await loadCircuit("check_nullifiers_owner"); + ({ provingKeyFile, verificationKey } = loadProvingKeys( + "check_nullifiers_owner", + )); let keypair = genKeypair(); Alice.privKey = keypair.privKey; @@ -38,7 +40,7 @@ describe('check_nullifiers_owner circuit tests', () => { senderPrivateKey = formatPrivKeyForBabyJub(Alice.privKey); }); - it('should generate a valid proof that can be verified successfully and fail when public signals are tampered', async () => { + it("should generate a valid proof that can be verified successfully and fail when public signals are tampered", async () => { const values = [15, 100]; // create two input UTXOs, each has their own salt, but same owner @@ -47,8 +49,16 @@ describe('check_nullifiers_owner circuit tests', () => { const salt2 = newSalt(); // create the nullifiers for the input UTXOs - const nullifier1 = poseidonHash3([BigInt(values[0]), salt1, senderPrivateKey]); - const nullifier2 = poseidonHash3([BigInt(values[1]), salt2, senderPrivateKey]); + const nullifier1 = poseidonHash3([ + BigInt(values[0]), + salt1, + senderPrivateKey, + ]); + const nullifier2 = poseidonHash3([ + BigInt(values[1]), + salt2, + senderPrivateKey, + ]); const nullifiers = [nullifier1, nullifier2]; const startTime = Date.now(); @@ -59,18 +69,35 @@ describe('check_nullifiers_owner circuit tests', () => { salts: [salt1, salt2], ownerPrivateKey: senderPrivateKey, }, - true + true, ); - const { proof, publicSignals } = await groth16.prove(provingKeyFile, witness); - console.log('Proving time: ', (Date.now() - startTime) / 1000, 's'); + const { proof, publicSignals } = await groth16.prove( + provingKeyFile, + witness, + ); + console.log("Proving time: ", (Date.now() - startTime) / 1000, "s"); - let verifyResult = await groth16.verify(verificationKey, publicSignals, proof); + let verifyResult = await groth16.verify( + verificationKey, + publicSignals, + proof, + ); expect(verifyResult).to.be.true; - const tamperedNullifier = poseidonHash3([BigInt(values[0] + 1), salt1, senderPrivateKey]); - let tamperedPublicSignals = publicSignals.map((ps) => (ps.toString() === nullifiers[0].toString() ? tamperedNullifier : ps)); + const tamperedNullifier = poseidonHash3([ + BigInt(values[0] + 1), + salt1, + senderPrivateKey, + ]); + let tamperedPublicSignals = publicSignals.map((ps) => + ps.toString() === nullifiers[0].toString() ? tamperedNullifier : ps, + ); - verifyResult = await groth16.verify(verificationKey, tamperedPublicSignals, proof); + verifyResult = await groth16.verify( + verificationKey, + tamperedPublicSignals, + proof, + ); expect(verifyResult).to.be.false; }).timeout(600000); }); diff --git a/zkp/js/integration-test/check_utxos_owner.js b/zkp/js/integration-test/check_utxos_owner.js index a2a27b4..5028a56 100644 --- a/zkp/js/integration-test/check_utxos_owner.js +++ b/zkp/js/integration-test/check_utxos_owner.js @@ -21,8 +21,6 @@ const { Poseidon, newSalt, loadCircuit } = require("../index.js"); const { loadProvingKeys } = require("./utils.js"); const poseidonHash = Poseidon.poseidon4; -const poseidonHash3 = Poseidon.poseidon3; - describe("check_utxos_owner circuit tests", () => { let circuit, provingKeyFile, verificationKey, smtAlice; @@ -31,9 +29,8 @@ describe("check_utxos_owner circuit tests", () => { before(async () => { circuit = await loadCircuit("check_utxos_owner"); - ({ provingKeyFile, verificationKey } = loadProvingKeys( - "check_utxos_owner", - )); + ({ provingKeyFile, verificationKey } = + loadProvingKeys("check_utxos_owner")); let keypair = genKeypair(); Alice.privKey = keypair.privKey; @@ -47,17 +44,9 @@ describe("check_utxos_owner circuit tests", () => { // create two input UTXOs, each has their own salt, but same owner const senderPrivateKey = formatPrivKeyForBabyJub(Alice.privKey); const salt1 = newSalt(); - const input1 = poseidonHash([ - BigInt(values[0]), - salt1, - ...Alice.pubKey, - ]); + const input1 = poseidonHash([BigInt(values[0]), salt1, ...Alice.pubKey]); const salt2 = newSalt(); - const input2 = poseidonHash([ - BigInt(values[1]), - salt2, - ...Alice.pubKey, - ]); + const input2 = poseidonHash([BigInt(values[1]), salt2, ...Alice.pubKey]); const commitments = [input1, input2]; const startTime = Date.now(); @@ -94,9 +83,7 @@ describe("check_utxos_owner circuit tests", () => { ...Alice.pubKey, ]); let tamperedPublicSignals = publicSignals.map((ps) => - ps.toString() === commitments[0].toString() - ? tamperedCommitment - : ps, + ps.toString() === commitments[0].toString() ? tamperedCommitment : ps, ); verifyResult = await groth16.verify( diff --git a/zkp/js/test/check_hashes_value.js b/zkp/js/test/check_hashes_value.js index 1bff94f..74a1921 100644 --- a/zkp/js/test/check_hashes_value.js +++ b/zkp/js/test/check_hashes_value.js @@ -60,9 +60,14 @@ describe("check_hashes_value circuit tests", () => { let witness = await circuit.calculateWitness( { outputCommitments, - outputValues, - outputSalts: [salt1, salt2], - outputOwnerPublicKeys: [sender.pubKey, sender.pubKey], + outputCommitmentInputs: [ + BigInt(outputValues[0]), + salt1, + ...sender.pubKey, + BigInt(outputValues[1]), + salt2, + ...sender.pubKey, + ], }, true, ); @@ -91,9 +96,14 @@ describe("check_hashes_value circuit tests", () => { let witness = await circuit.calculateWitness( { outputCommitments, - outputValues, - outputSalts: [salt1, salt2], - outputOwnerPublicKeys: [sender.pubKey, sender.pubKey], + outputCommitmentInputs: [ + BigInt(outputValues[0]), + salt1, + ...sender.pubKey, + BigInt(outputValues[1]), + salt2, + ...sender.pubKey, + ], }, true, ); @@ -123,9 +133,14 @@ describe("check_hashes_value circuit tests", () => { await circuit.calculateWitness( { outputCommitments, - outputValues, - outputSalts: [salt1, salt1], - outputOwnerPublicKeys: [sender.pubKey, sender.pubKey], + outputCommitmentInputs: [ + BigInt(outputValues[0]), + salt1, + ...sender.pubKey, + BigInt(outputValues[1]), + salt1, + ...sender.pubKey, + ], }, true, ); @@ -133,11 +148,11 @@ describe("check_hashes_value circuit tests", () => { error = e; } // console.log(error); - expect(error).to.match(/Error in template CheckHashes_80 line: 47/); // hash check failed + expect(error).to.match(/Error in template CheckHashes_80 line: 62/); // hash check failed }); it("should fail to generate a witness because of negative values in output commitments", async () => { - // in the finite field used in the Poseidion hash implementation, -100n is equivalent to + // in the finite field used in the Poseidon hash implementation, -100n is equivalent to // 21888242871839275222246405745257275088548364400416034343698204186575808495517n const outputValues = [-100, 200]; @@ -160,9 +175,14 @@ describe("check_hashes_value circuit tests", () => { await circuit.calculateWitness( { outputCommitments, - outputValues, - outputSalts: [salt1, salt1], - outputOwnerPublicKeys: [sender.pubKey, sender.pubKey], + outputCommitmentInputs: [ + BigInt(outputValues[0]), + salt1, + ...sender.pubKey, + BigInt(outputValues[1]), + salt1, + ...sender.pubKey, + ], }, true, ); @@ -170,11 +190,11 @@ describe("check_hashes_value circuit tests", () => { error = e; } // console.log(error); - expect(error).to.match(/Error in template CheckPositive_3 line: 36/); // positive range check failed + expect(error).to.match(/Error in template CheckPositiveValues_3 line: 34/); // positive range check failed }); it("should fail to generate a witness because of using the inverse of a negative value in output commitments", async () => { - // in the finite field used in the Poseidion hash implementation, -100n is equivalent to + // in the finite field used in the Poseidon hash implementation, -100n is equivalent to // 21888242871839275222246405745257275088548364400416034343698204186575808495517n. This number // is considered negative by the circuit, because we allow the range of 0 to (2**40 - 1) const outputValues = [ @@ -201,9 +221,14 @@ describe("check_hashes_value circuit tests", () => { await circuit.calculateWitness( { outputCommitments, - outputValues, - outputSalts: [salt1, salt1], - outputOwnerPublicKeys: [sender.pubKey, sender.pubKey], + outputCommitmentInputs: [ + BigInt(outputValues[0]), + salt1, + ...sender.pubKey, + BigInt(outputValues[1]), + salt1, + ...sender.pubKey, + ], }, true, ); @@ -211,7 +236,7 @@ describe("check_hashes_value circuit tests", () => { error = e; } // console.log(error); - expect(error).to.match(/Error in template CheckPositive_3 line: 36/); // positive range check failed + expect(error).to.match(/Error in template CheckPositiveValues_3 line: 34/); // positive range check failed }); it("should fail to generate a witness because a larger than MAX_VALUE is used in output", async () => { @@ -236,9 +261,14 @@ describe("check_hashes_value circuit tests", () => { await circuit.calculateWitness( { outputCommitments, - outputValues, - outputSalts: [salt1, salt1], - outputOwnerPublicKeys: [sender.pubKey, sender.pubKey], + outputCommitmentInputs: [ + BigInt(outputValues[0]), + salt1, + ...sender.pubKey, + BigInt(outputValues[1]), + salt1, + ...sender.pubKey, + ], }, true, ); @@ -246,6 +276,6 @@ describe("check_hashes_value circuit tests", () => { error = e; } // console.log(error); - expect(error).to.match(/Error in template CheckPositive_3 line: 36/); // positive range check failed + expect(error).to.match(/Error in template CheckPositiveValues_3 line: 34/); // positive range check failed }); }); diff --git a/zkp/js/test/check_inputs_outputs_value.js b/zkp/js/test/check_inputs_outputs_value.js index 1a0f2b1..31a7b74 100644 --- a/zkp/js/test/check_inputs_outputs_value.js +++ b/zkp/js/test/check_inputs_outputs_value.js @@ -42,7 +42,7 @@ describe("check_inputs_outputs_value circuit tests", () => { Alice.pubKey = keypair.pubKey; senderPrivateKey = formatPrivKeyForBabyJub(Alice.privKey); - // initialize the local storage for Alice to manage her UTXOs in the Spart Merkle Tree + // initialize the local storage for Alice to manage her UTXOs in the Spark Merkle Tree const storage1 = new InMemoryDB(str2Bytes("")); smtAlice = new Merkletree(storage1, true, SMT_HEIGHT); }); diff --git a/zkp/js/test/check_nullifiers_nf_owner.js b/zkp/js/test/check_nullifiers_nf_owner.js index ca62e5d..f0bbca4 100644 --- a/zkp/js/test/check_nullifiers_nf_owner.js +++ b/zkp/js/test/check_nullifiers_nf_owner.js @@ -14,16 +14,15 @@ // See the License for the specific language governing permissions and // limitations under the License. -const { expect } = require('chai'); -const { join } = require('path'); -const { wasm: wasm_tester } = require('circom_tester'); -const { genKeypair, formatPrivKeyForBabyJub } = require('maci-crypto'); -const { Poseidon, newSalt, tokenUriHash } = require('../index.js'); -const { Merkletree, InMemoryDB, str2Bytes, ZERO_HASH } = require('@iden3/js-merkletree'); +const { expect } = require("chai"); +const { join } = require("path"); +const { wasm: wasm_tester } = require("circom_tester"); +const { genKeypair, formatPrivKeyForBabyJub } = require("maci-crypto"); +const { Poseidon, newSalt, tokenUriHash } = require("../index.js"); const poseidonHash4 = Poseidon.poseidon4; -describe('check_nullifiers_nf_owner circuit tests', () => { +describe("check_nullifiers_nf_owner circuit tests", () => { let circuit; const sender = {}; const receiver = {}; @@ -32,7 +31,9 @@ describe('check_nullifiers_nf_owner circuit tests', () => { before(async function () { this.timeout(60000); - circuit = await wasm_tester(join(__dirname, '../../circuits/check_nullifiers_nf_owner.circom')); + circuit = await wasm_tester( + join(__dirname, "../../circuits/check_nullifiers_nf_owner.circom"), + ); let keypair = genKeypair(); sender.privKey = keypair.privKey; @@ -44,12 +45,17 @@ describe('check_nullifiers_nf_owner circuit tests', () => { receiver.pubKey = keypair.pubKey; }); - it('should return true for valid witness', async () => { + it("should return true for valid witness", async () => { const tokenId = 1001; - const tokenUri = tokenUriHash('http://ipfs.io/some-file-hash'); + const tokenUri = tokenUriHash("http://ipfs.io/some-file-hash"); const salt1 = newSalt(); - const nullifier1 = poseidonHash4([BigInt(tokenId), tokenUri, salt1, senderPrivateKey]); + const nullifier1 = poseidonHash4([ + BigInt(tokenId), + tokenUri, + salt1, + senderPrivateKey, + ]); const witness = await circuit.calculateWitness( { @@ -59,7 +65,7 @@ describe('check_nullifiers_nf_owner circuit tests', () => { salts: [salt1, 0], ownerPrivateKey: senderPrivateKey, }, - true + true, ); // console.log('tokenUri', tokenUri); @@ -73,12 +79,17 @@ describe('check_nullifiers_nf_owner circuit tests', () => { expect(witness[7]).to.equal(salt1); }); - it('should fail to calculate witness due to invalid nullifier', async () => { + it("should fail to calculate witness due to invalid nullifier", async () => { const tokenId = 1001; - const tokenUri = tokenUriHash('http://ipfs.io/some-file-hash'); + const tokenUri = tokenUriHash("http://ipfs.io/some-file-hash"); const salt1 = newSalt(); - const nullifier1 = poseidonHash4([BigInt(tokenId), tokenUri, salt1, senderPrivateKey]); + const nullifier1 = poseidonHash4([ + BigInt(tokenId), + tokenUri, + salt1, + senderPrivateKey, + ]); let error; try { @@ -90,12 +101,14 @@ describe('check_nullifiers_nf_owner circuit tests', () => { salts: [salt1, 0], ownerPrivateKey: senderPrivateKey, }, - true + true, ); } catch (e) { error = e; } // console.log(error); - expect(error).to.match(/Error in template CheckNullifiersForTokenIdAndUri_76 line: 52/); + expect(error).to.match( + /Error in template CheckNullifiersForTokenIdAndUri_76 line: 52/, + ); }); }); diff --git a/zkp/js/test/check_nullifiers_owner.js b/zkp/js/test/check_nullifiers_owner.js index 8bce438..3cfd7ec 100644 --- a/zkp/js/test/check_nullifiers_owner.js +++ b/zkp/js/test/check_nullifiers_owner.js @@ -14,15 +14,15 @@ // See the License for the specific language governing permissions and // limitations under the License. -const { expect } = require('chai'); -const { join } = require('path'); -const { wasm: wasm_tester } = require('circom_tester'); -const { genKeypair, formatPrivKeyForBabyJub } = require('maci-crypto'); -const { Poseidon, newSalt } = require('../index.js'); +const { expect } = require("chai"); +const { join } = require("path"); +const { wasm: wasm_tester } = require("circom_tester"); +const { genKeypair, formatPrivKeyForBabyJub } = require("maci-crypto"); +const { Poseidon, newSalt } = require("../index.js"); const poseidonHash3 = Poseidon.poseidon3; -describe('check_nullifiers_owner circuit tests', () => { +describe("check_nullifiers_owner circuit tests", () => { let circuit; const sender = {}; const receiver = {}; @@ -31,7 +31,9 @@ describe('check_nullifiers_owner circuit tests', () => { before(async function () { this.timeout(60000); - circuit = await wasm_tester(join(__dirname, '../../circuits/check_nullifiers_owner.circom')); + circuit = await wasm_tester( + join(__dirname, "../../circuits/check_nullifiers_owner.circom"), + ); let keypair = genKeypair(); sender.privKey = keypair.privKey; @@ -43,14 +45,22 @@ describe('check_nullifiers_owner circuit tests', () => { receiver.pubKey = keypair.pubKey; }); - it('should return true for valid witness', async () => { + it("should return true for valid witness", async () => { const values = [32, 40]; const salt1 = newSalt(); const salt2 = newSalt(); // create two input nullifiers, corresponding to the input UTXOs - const nullifier1 = poseidonHash3([BigInt(values[0]), salt1, senderPrivateKey]); - const nullifier2 = poseidonHash3([BigInt(values[1]), salt2, senderPrivateKey]); + const nullifier1 = poseidonHash3([ + BigInt(values[0]), + salt1, + senderPrivateKey, + ]); + const nullifier2 = poseidonHash3([ + BigInt(values[1]), + salt2, + senderPrivateKey, + ]); const nullifiers = [nullifier1, nullifier2]; const witness = await circuit.calculateWitness( @@ -60,7 +70,7 @@ describe('check_nullifiers_owner circuit tests', () => { salts: [salt1, salt2], ownerPrivateKey: senderPrivateKey, }, - true + true, ); // console.log('nullifiers', nullifiers); @@ -76,14 +86,22 @@ describe('check_nullifiers_owner circuit tests', () => { expect(witness[7]).to.equal(senderPrivateKey); }); - it('should fail to generate a witness because incorrect values are not used', async () => { + it("should fail to generate a witness because incorrect values are not used", async () => { const values = [15, 100]; const salt1 = newSalt(); const salt2 = newSalt(); // create two input nullifiers, corresponding to the input UTXOs - const nullifier1 = poseidonHash3([BigInt(values[0]), salt1, senderPrivateKey]); - const nullifier2 = poseidonHash3([BigInt(values[1] + 1), salt2, senderPrivateKey]); + const nullifier1 = poseidonHash3([ + BigInt(values[0]), + salt1, + senderPrivateKey, + ]); + const nullifier2 = poseidonHash3([ + BigInt(values[1] + 1), + salt2, + senderPrivateKey, + ]); const nullifiers = [nullifier1, nullifier2]; let err; @@ -95,7 +113,7 @@ describe('check_nullifiers_owner circuit tests', () => { salts: [salt1, salt2], ownerPrivateKey: senderPrivateKey, }, - true + true, ); } catch (e) { err = e; diff --git a/zkp/js/test/check_utxos_nf_owner.js b/zkp/js/test/check_utxos_nf_owner.js index c433d5d..55a16e5 100644 --- a/zkp/js/test/check_utxos_nf_owner.js +++ b/zkp/js/test/check_utxos_nf_owner.js @@ -14,15 +14,15 @@ // See the License for the specific language governing permissions and // limitations under the License. -const { expect } = require('chai'); -const { join } = require('path'); -const { wasm: wasm_tester } = require('circom_tester'); -const { genKeypair, formatPrivKeyForBabyJub } = require('maci-crypto'); -const { Poseidon, newSalt, tokenUriHash } = require('../index.js'); +const { expect } = require("chai"); +const { join } = require("path"); +const { wasm: wasm_tester } = require("circom_tester"); +const { genKeypair, formatPrivKeyForBabyJub } = require("maci-crypto"); +const { Poseidon, newSalt, tokenUriHash } = require("../index.js"); const poseidonHash = Poseidon.poseidon5; -describe('check_utxos_nf_owner circuit tests', () => { +describe("check_utxos_nf_owner circuit tests", () => { let circuit; const sender = {}; let senderPrivateKey; @@ -30,7 +30,9 @@ describe('check_utxos_nf_owner circuit tests', () => { before(async function () { this.timeout(60000); - circuit = await wasm_tester(join(__dirname, '../../circuits/check_utxos_nf_owner.circom')); + circuit = await wasm_tester( + join(__dirname, "../../circuits/check_utxos_nf_owner.circom"), + ); let keypair = genKeypair(); sender.privKey = keypair.privKey; @@ -38,13 +40,18 @@ describe('check_utxos_nf_owner circuit tests', () => { senderPrivateKey = formatPrivKeyForBabyJub(sender.privKey); }); - it('should return true for valid witness', async () => { + it("should return true for valid witness", async () => { const tokenIds = [1001, 0]; - const tokenUris = [tokenUriHash('http://ipfs.io/some-file-hash'), 0]; + const tokenUris = [tokenUriHash("http://ipfs.io/some-file-hash"), 0]; // create two input UTXOs, each has their own salt, but same owner const salt1 = newSalt(); - const input1 = poseidonHash([BigInt(tokenIds[0]), tokenUris[0], salt1, ...sender.pubKey]); + const input1 = poseidonHash([ + BigInt(tokenIds[0]), + tokenUris[0], + salt1, + ...sender.pubKey, + ]); const commitments = [input1, 0]; const witness = await circuit.calculateWitness( @@ -55,7 +62,7 @@ describe('check_utxos_nf_owner circuit tests', () => { salts: [salt1, 0], ownerPrivateKey: senderPrivateKey, }, - true + true, ); // console.log(witness.slice(0, 10)); @@ -68,13 +75,18 @@ describe('check_utxos_nf_owner circuit tests', () => { expect(witness[11]).to.equal(BigInt(sender.pubKey[1])); }); - it('should fail to generate a witness because of invalid owner private key', async () => { + it("should fail to generate a witness because of invalid owner private key", async () => { const tokenIds = [1001, 0]; - const tokenUris = [tokenUriHash('http://ipfs.io/some-file-hash'), 0]; + const tokenUris = [tokenUriHash("http://ipfs.io/some-file-hash"), 0]; // create two input UTXOs, each has their own salt, but same owner const salt1 = newSalt(); - const input1 = poseidonHash([BigInt(tokenIds[0]), tokenUris[0], salt1, ...sender.pubKey]); + const input1 = poseidonHash([ + BigInt(tokenIds[0]), + tokenUris[0], + salt1, + ...sender.pubKey, + ]); const commitments = [input1, 0]; let error; @@ -87,12 +99,14 @@ describe('check_utxos_nf_owner circuit tests', () => { salts: [salt1, 0], ownerPrivateKey: senderPrivateKey + BigInt(1), }, - true + true, ); } catch (e) { error = e; } // console.log(error); - expect(error).to.match(/Error in template CheckHashesForTokenIdAndUri_88 line: 51/); // hash check failed + expect(error).to.match( + /Error in template CheckHashesForTokenIdAndUri_88 line: 51/, + ); // hash check failed }); }); diff --git a/zkp/js/test/check_utxos_owner.js b/zkp/js/test/check_utxos_owner.js index 17fba51..8c07fbc 100644 --- a/zkp/js/test/check_utxos_owner.js +++ b/zkp/js/test/check_utxos_owner.js @@ -14,16 +14,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -const { expect } = require('chai'); -const { join } = require('path'); -const { wasm: wasm_tester } = require('circom_tester'); -const { genKeypair, formatPrivKeyForBabyJub } = require('maci-crypto'); -const { Poseidon, newSalt } = require('../index.js'); +const { expect } = require("chai"); +const { join } = require("path"); +const { wasm: wasm_tester } = require("circom_tester"); +const { genKeypair, formatPrivKeyForBabyJub } = require("maci-crypto"); +const { Poseidon, newSalt } = require("../index.js"); const ZERO_PUBKEY = [0n, 0n]; const poseidonHash = Poseidon.poseidon4; -describe('check_utxos_owner circuit tests', () => { +describe("check_utxos_owner circuit tests", () => { let circuit; const sender = {}; let senderPrivateKey; @@ -31,7 +31,9 @@ describe('check_utxos_owner circuit tests', () => { before(async function () { this.timeout(60000); - circuit = await wasm_tester(join(__dirname, '../../circuits/check_utxos_owner.circom')); + circuit = await wasm_tester( + join(__dirname, "../../circuits/check_utxos_owner.circom"), + ); let keypair = genKeypair(); sender.privKey = keypair.privKey; @@ -39,7 +41,7 @@ describe('check_utxos_owner circuit tests', () => { senderPrivateKey = formatPrivKeyForBabyJub(sender.privKey); }); - it('should return true for valid witness', async () => { + it("should return true for valid witness", async () => { const values = [32, 40]; // create two input UTXOs, each has their own salt, but same owner @@ -56,7 +58,7 @@ describe('check_utxos_owner circuit tests', () => { salts: [salt1, salt2], ownerPrivateKey: senderPrivateKey, }, - true + true, ); // console.log(witness.slice(0, 10)); @@ -70,7 +72,7 @@ describe('check_utxos_owner circuit tests', () => { expect(witness[9]).to.equal(BigInt(sender.pubKey[1])); }); - it('should return true for valid witness using a single input value', async () => { + it("should return true for valid witness using a single input value", async () => { const values = [72, 0]; // create two input UTXOs, each has their own salt, but same owner @@ -85,7 +87,7 @@ describe('check_utxos_owner circuit tests', () => { salts: [salt1, 0], ownerPrivateKey: senderPrivateKey, }, - true + true, ); expect(witness[1]).to.equal(BigInt(commitments[0])); @@ -95,7 +97,7 @@ describe('check_utxos_owner circuit tests', () => { expect(witness[9]).to.equal(BigInt(sender.pubKey[1])); }); - it('should return true for valid witness using a single input value', async () => { + it("should return true for valid witness using a single input value", async () => { const values = [0, 72]; // create two input UTXOs, each has their own salt, but same owner @@ -110,7 +112,7 @@ describe('check_utxos_owner circuit tests', () => { salts: [0, salt1], ownerPrivateKey: senderPrivateKey, }, - true + true, ); expect(witness[1]).to.equal(BigInt(commitments[0])); @@ -120,14 +122,22 @@ describe('check_utxos_owner circuit tests', () => { expect(witness[9]).to.equal(BigInt(sender.pubKey[1])); }); - it('should fail to generate a witness because of invalid input commitments', async () => { + it("should fail to generate a witness because of invalid input commitments", async () => { const inputValues = [25, 100]; // create two input UTXOs, each has their own salt, but same owner const salt1 = newSalt(); - const input1 = poseidonHash([BigInt(inputValues[0]), salt1, ...sender.pubKey]); + const input1 = poseidonHash([ + BigInt(inputValues[0]), + salt1, + ...sender.pubKey, + ]); const salt2 = newSalt(); - const input2 = poseidonHash([BigInt(inputValues[1]), salt2, ...sender.pubKey]); + const input2 = poseidonHash([ + BigInt(inputValues[1]), + salt2, + ...sender.pubKey, + ]); const inputCommitments = [input1 + BigInt(1), input2]; let error; @@ -139,7 +149,7 @@ describe('check_utxos_owner circuit tests', () => { salts: [salt1, salt2], ownerPrivateKey: senderPrivateKey, }, - true + true, ); } catch (e) { error = e; @@ -148,14 +158,22 @@ describe('check_utxos_owner circuit tests', () => { expect(error).to.match(/Error in template CheckHashes_88 line: 47/); // hash check failed }); - it('should fail to generate a witness because of invalid owner private key', async () => { + it("should fail to generate a witness because of invalid owner private key", async () => { const inputValues = [25, 100]; // create two input UTXOs, each has their own salt, but same owner const salt1 = newSalt(); - const input1 = poseidonHash([BigInt(inputValues[0]), salt1, ...sender.pubKey]); + const input1 = poseidonHash([ + BigInt(inputValues[0]), + salt1, + ...sender.pubKey, + ]); const salt2 = newSalt(); - const input2 = poseidonHash([BigInt(inputValues[1]), salt2, ...sender.pubKey]); + const input2 = poseidonHash([ + BigInt(inputValues[1]), + salt2, + ...sender.pubKey, + ]); const inputCommitments = [input1, input2]; let error; @@ -167,7 +185,7 @@ describe('check_utxos_owner circuit tests', () => { salts: [salt1, salt2], ownerPrivateKey: senderPrivateKey + BigInt(1), }, - true + true, ); } catch (e) { error = e; diff --git a/zkp/js/test/circuits/check-hashes.circom b/zkp/js/test/circuits/check-hashes.circom index 9e29e95..f8a3a59 100644 --- a/zkp/js/test/circuits/check-hashes.circom +++ b/zkp/js/test/circuits/check-hashes.circom @@ -17,4 +17,4 @@ pragma circom 2.2.1; include "../../../circuits/lib/check-hashes.circom"; -component main {public [ commitments, ownerPublicKeys ]} = CheckHashes(2); \ No newline at end of file +component main {public [ commitmentHashes ]} = CheckHashes(2); \ No newline at end of file diff --git a/zkp/js/test/lib/check-hashes.js b/zkp/js/test/lib/check-hashes.js index cded1dc..1f7a6c7 100644 --- a/zkp/js/test/lib/check-hashes.js +++ b/zkp/js/test/lib/check-hashes.js @@ -15,7 +15,6 @@ // limitations under the License. const { expect } = require("chai"); -const { readFileSync } = require("fs"); const { join } = require("path"); const { wasm: wasm_tester } = require("circom_tester"); const { genKeypair } = require("maci-crypto"); @@ -52,25 +51,36 @@ describe("check-hashes circuit tests", () => { const input1 = poseidonHash([BigInt(values[0]), salt1, ...sender.pubKey]); const salt2 = newSalt(); const input2 = poseidonHash([BigInt(values[1]), salt2, ...sender.pubKey]); - const commitments = [input1, input2]; + const commitmentHashes = [input1, input2]; const witness = await circuit.calculateWitness( { - commitments, - values, - salts: [salt1, salt2], - ownerPublicKeys: [sender.pubKey, sender.pubKey], + commitmentHashes, + commitmentInputs: [ + BigInt(values[0]), + salt1, + ...sender.pubKey, + BigInt(values[1]), + salt2, + ...sender.pubKey, + ], }, true, ); // console.log(witness.slice(0, 10)); - // console.log('commitments', commitments); + // console.log('commitmentHashes', commitmentHashes); // console.log('sender public key', sender.pubKey); - expect(witness[1]).to.equal(BigInt(commitments[0])); - expect(witness[2]).to.equal(BigInt(commitments[1])); - expect(witness[3]).to.equal(BigInt(sender.pubKey[0])); - expect(witness[4]).to.equal(BigInt(sender.pubKey[1])); + expect(witness[1]).to.equal(BigInt(commitmentHashes[0])); + expect(witness[2]).to.equal(BigInt(commitmentHashes[1])); + expect(witness[3]).to.equal(BigInt(values[0])); + expect(witness[4]).to.equal(salt1); + expect(witness[5]).to.equal(BigInt(sender.pubKey[0])); + expect(witness[6]).to.equal(BigInt(sender.pubKey[1])); + expect(witness[7]).to.equal(BigInt(values[1])); + expect(witness[8]).to.equal(salt2); + expect(witness[9]).to.equal(BigInt(sender.pubKey[0])); + expect(witness[10]).to.equal(BigInt(sender.pubKey[1])); }); it("should return true for valid witness using a single input value", async () => { @@ -79,22 +89,28 @@ describe("check-hashes circuit tests", () => { // create two input UTXOs, each has their own salt, but same owner const salt1 = newSalt(); const input1 = poseidonHash([BigInt(values[0]), salt1, ...sender.pubKey]); - const commitments = [input1, 0]; + const commitmentHashes = [input1, 0]; const witness = await circuit.calculateWitness( { - commitments, - values, - salts: [salt1, 0], - ownerPublicKeys: [sender.pubKey, [0n, 0n]], + commitmentHashes, + commitmentInputs: [ + BigInt(values[0]), + salt1, + ...sender.pubKey, + BigInt(values[1]), + 0, + 0n, + 0n, + ], }, true, ); - expect(witness[1]).to.equal(BigInt(commitments[0])); - expect(witness[2]).to.equal(BigInt(commitments[1])); - expect(witness[3]).to.equal(BigInt(sender.pubKey[0])); - expect(witness[4]).to.equal(BigInt(sender.pubKey[1])); + expect(witness[1]).to.equal(BigInt(commitmentHashes[0])); + expect(witness[2]).to.equal(BigInt(commitmentHashes[1])); + expect(witness[5]).to.equal(BigInt(sender.pubKey[0])); + expect(witness[6]).to.equal(BigInt(sender.pubKey[1])); }); it("should return true for valid witness using a single input value", async () => { @@ -103,27 +119,35 @@ describe("check-hashes circuit tests", () => { // create two input UTXOs, each has their own salt, but same owner const salt1 = newSalt(); const input1 = poseidonHash([BigInt(values[1]), salt1, ...sender.pubKey]); - const commitments = [0n, input1]; + const commitmentHashes = [0n, input1]; const witness = await circuit.calculateWitness( { - commitments, - values, - salts: [0, salt1], - ownerPublicKeys: [[0n, 0n], sender.pubKey], + commitmentHashes, + commitmentInputs: [ + BigInt(values[0]), + 0, + 0n, + 0n, + BigInt(values[1]), + salt1, + ...sender.pubKey, + ], }, true, ); - expect(witness[1]).to.equal(BigInt(commitments[0])); - expect(witness[2]).to.equal(BigInt(commitments[1])); + expect(witness[1]).to.equal(BigInt(commitmentHashes[0])); + expect(witness[2]).to.equal(BigInt(commitmentHashes[1])); expect(witness[3]).to.equal(0n); expect(witness[4]).to.equal(0n); - expect(witness[5]).to.equal(BigInt(sender.pubKey[0])); - expect(witness[6]).to.equal(BigInt(sender.pubKey[1])); + expect(witness[5]).to.equal(0n); + expect(witness[6]).to.equal(0n); + expect(witness[9]).to.equal(BigInt(sender.pubKey[0])); + expect(witness[10]).to.equal(BigInt(sender.pubKey[1])); }); - it("should fail to generate a witness because of invalid input commitments", async () => { + it("should fail to generate a witness because of invalid input commitmentHashes", async () => { const inputValues = [25, 100]; // create two input UTXOs, each has their own salt, but same owner @@ -139,16 +163,21 @@ describe("check-hashes circuit tests", () => { salt2, ...sender.pubKey, ]); - const inputCommitments = [input1 + BigInt(1), input2]; + const commitmentHashes = [input1 + BigInt(1), input2]; let error; try { await circuit.calculateWitness( { - commitments: inputCommitments, - values: inputValues, - salts: [salt1, salt2], - ownerPublicKeys: [sender.pubKey, sender.pubKey], + commitmentHashes, + commitmentInputs: [ + BigInt(inputValues[0]), + salt1, + ...sender.pubKey, + BigInt(inputValues[1]), + salt2, + ...sender.pubKey, + ], }, true, ); @@ -156,6 +185,6 @@ describe("check-hashes circuit tests", () => { error = e; } // console.log(error); - expect(error).to.match(/Error in template CheckHashes_76 line: 47/); // hash check failed + expect(error).to.match(/Error in template CheckHashes_76 line: 62/); // hash check failed }); });