diff --git a/smart_contract_tests/test/smart_contracts.test.js b/smart_contract_tests/test/smart_contracts.test.js index ec0bc7cb..54619251 100644 --- a/smart_contract_tests/test/smart_contracts.test.js +++ b/smart_contract_tests/test/smart_contracts.test.js @@ -39,6 +39,15 @@ describe("Smart contracts test suite", function () { )).to.be.equal(true); }); + it("Groth16 smart contract 1 aliased input", async () => { + expect( + await groth16VerifyAliased( + path.join("../test", "groth16", "circuit.r1cs"), + path.join("../test", "groth16", "witness.wtns") + ) + ).to.be.equal(false); + }); + it("Groth16 smart contract 3 inputs", async () => { expect(await groth16Verify( path.join("../test", "circuit2", "circuit.r1cs"), @@ -100,6 +109,35 @@ describe("Smart contracts test suite", function () { return await verifierContract.verifyProof(proofA, proofB, proofC, publicInputs); } + async function groth16VerifyAliased(r1csFilename, wtnsFilename) { + const solidityVerifierFilename = path.join("contracts", "groth16.sol"); + + const zkeyFilename = { type: "mem" }; + + await snarkjs.zKey.newZKey(r1csFilename, ptauFilename, zkeyFilename); + const { proof: proof, publicSignals: publicInputs } = await snarkjs.groth16.prove(zkeyFilename, wtnsFilename); + + const proofA = [proof.pi_a[0], proof.pi_a[1]]; + const proofB = [[proof.pi_b[0][1], proof.pi_b[0][0]], [proof.pi_b[1][1], proof.pi_b[1][0]],]; + const proofC = [proof.pi_c[0], proof.pi_c[1]]; + + // Generate groth16 verifier solidity file from groth16 template + zkey + const verifierCode = await snarkjs.zKey.exportSolidityVerifier(zkeyFilename, templates); + fs.writeFileSync(solidityVerifierFilename, verifierCode, "utf-8"); + + // Compile the groth16 verifier smart contract + await run("compile"); + + let pi_with_alias = [...publicInputs]; + pi_with_alias[1] = BigInt(publicInputs[1]) + 21888242871839275222246405745257275088548364400416034343698204186575808495617n; + + // Deploy mock groth16 verifier + const VerifierFactory = await ethers.getContractFactory("Groth16Verifier"); + verifierContract = await VerifierFactory.deploy(); + + return await verifierContract.verifyProof(proofA, proofB, proofC, pi_with_alias); + } + async function plonkVerify(r1csFilename, wtnsFilename) { const solidityVerifierFilename = path.join("contracts", "plonk.sol"); diff --git a/test/fullprocess.js b/test/fullprocess.js index 088ee92c..7ae8b199 100644 --- a/test/fullprocess.js +++ b/test/fullprocess.js @@ -25,6 +25,7 @@ describe("Full process", function () { const wtns = {type: "mem"}; let proof; let publicSignals; + let publicSignalsWithAlias; before( async () => { curve = await getCurveFromName("bn128"); @@ -70,7 +71,7 @@ describe("Full process", function () { }); it ("groth16 setup", async () => { - await snarkjs.zKey.newZKey(path.join("test", "circuit", "circuit.r1cs"), ptau_final, zkey_0); + await snarkjs.zKey.newZKey(path.join("test", "groth16", "circuit.r1cs"), ptau_final, zkey_0); }); it ("zkey contribute ", async () => { @@ -94,7 +95,7 @@ describe("Full process", function () { }); it ("zkey verify r1cs", async () => { - const res = await snarkjs.zKey.verifyFromR1cs(path.join("test", "circuit", "circuit.r1cs"), ptau_final, zkey_final); + const res = await snarkjs.zKey.verifyFromR1cs(path.join("test", "groth16", "circuit.r1cs"), ptau_final, zkey_final); assert(res); }); @@ -108,23 +109,27 @@ describe("Full process", function () { }); it ("witness calculate", async () => { - await snarkjs.wtns.calculate({a: 11, b:2}, path.join("test", "circuit", "circuit.wasm"), wtns); + await snarkjs.wtns.calculate({a: 11, b:2}, path.join("test", "groth16", "circuit.wasm"), wtns); }); it ("checks witness complies with r1cs", async () => { - await snarkjs.wtns.check(path.join("test", "circuit", "circuit.r1cs"), wtns); + await snarkjs.wtns.check(path.join("test", "groth16", "circuit.r1cs"), wtns); }); it ("groth16 proof", async () => { const res = await snarkjs.groth16.prove(zkey_final, wtns); proof = res.proof; publicSignals = res.publicSignals; + publicSignalsWithAlias = [...res.publicSignals]; + publicSignalsWithAlias[1] = BigInt(res.publicSignals[1]) + 21888242871839275222246405745257275088548364400416034343698204186575808495617n; }); - it ("groth16 verify", async () => { const res = await snarkjs.groth16.verify(vKey, publicSignals, proof); assert(res == true); + + const res2 = await snarkjs.groth16.verify(vKey, publicSignalsWithAlias, proof); + assert(res2 == false); }); it ("plonk setup", async () => { diff --git a/test/groth16/circuit.circom b/test/groth16/circuit.circom new file mode 100644 index 00000000..4e8b5332 --- /dev/null +++ b/test/groth16/circuit.circom @@ -0,0 +1,16 @@ +template Multiplier(n) { + signal input a; + signal input b; + signal output c; + + signal int[n]; + + int[0] <== a*a + b; + for (var i=1; i