From 14daebb70df3adcdd249f70a34b4cd9e0d83b8c9 Mon Sep 17 00:00:00 2001 From: Stefanos Chaliasos Date: Thu, 26 Feb 2026 20:59:13 +0200 Subject: [PATCH 1/2] Abort extracting vk when there are no phase 2 contributions --- src/groth16_verify.js | 5 +++++ src/zkey_export_solidityverifier.js | 8 ++++++++ src/zkey_export_verificationkey.js | 4 ++++ 3 files changed, 17 insertions(+) diff --git a/src/groth16_verify.js b/src/groth16_verify.js index ed3974e3..ada7265d 100644 --- a/src/groth16_verify.js +++ b/src/groth16_verify.js @@ -69,6 +69,11 @@ export default async function groth16Verify(_vk_verifier, _publicSignals, _proof const vk_alpha_1 = curve.G1.fromObject(vk_verifier.vk_alpha_1); const vk_beta_2 = curve.G2.fromObject(vk_verifier.vk_beta_2); + if (curve.G2.eq(vk_gamma_2, vk_delta_2)) { + if (logger) logger.error("SOUNDNESS ERROR: vk_gamma_2 and vk_delta_2 are equal. This verification key is insecure, the zkey likely has no phase 2 contribution. Proofs can be forged. Aborting verification."); + return false; + } + const res = await curve.pairingEq( curve.G1.neg(pi_a) , pi_b, cpub , vk_gamma_2, diff --git a/src/zkey_export_solidityverifier.js b/src/zkey_export_solidityverifier.js index 45f62779..189b39b2 100644 --- a/src/zkey_export_solidityverifier.js +++ b/src/zkey_export_solidityverifier.js @@ -9,6 +9,14 @@ export default async function exportSolidityVerifier(zKeyName, templates, logger const verificationKey = await exportVerificationKey(zKeyName, logger); + if (verificationKey.protocol === "groth16") { + const vkGamma2 = JSON.stringify(verificationKey.vk_gamma_2); + const vkDelta2 = JSON.stringify(verificationKey.vk_delta_2); + if (vkGamma2 === vkDelta2) { + throw new Error("SOUNDNESS ERROR: vk_gamma_2 and vk_delta_2 are equal. This zkey is insecure, it likely has no phase 2 contribution. Proofs can be forged. Run 'snarkjs zkey contribute' before exporting."); + } + } + if ("fflonk" === verificationKey.protocol) { return fflonkExportSolidityVerifierCmd(verificationKey, templates, logger); } diff --git a/src/zkey_export_verificationkey.js b/src/zkey_export_verificationkey.js index bc868c10..9586ea47 100644 --- a/src/zkey_export_verificationkey.js +++ b/src/zkey_export_verificationkey.js @@ -56,6 +56,10 @@ async function groth16Vk(zkey, fd, sections) { const curve = await getCurve(zkey.q); const sG1 = curve.G1.F.n8 * 2; + if (curve.G2.eq(zkey.vk_gamma_2, zkey.vk_delta_2)) { + throw new Error("SOUNDNESS ERROR: vk_gamma_2 and vk_delta_2 are equal. This zkey is insecure, it likely has no phase 2 contribution. Proofs can be forged. Run 'snarkjs zkey contribute' before exporting."); + } + const alphaBeta = await curve.pairing(zkey.vk_alpha_1, zkey.vk_beta_2); let vKey = { From cd203128285a4ee2e3511f493e24764332a402eb Mon Sep 17 00:00:00 2001 From: Oleksandr Brezhniev Date: Mon, 23 Mar 2026 23:54:19 +0000 Subject: [PATCH 2/2] Apply suggestion from @Copilot Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/zkey_export_solidityverifier.js | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/zkey_export_solidityverifier.js b/src/zkey_export_solidityverifier.js index 189b39b2..45f62779 100644 --- a/src/zkey_export_solidityverifier.js +++ b/src/zkey_export_solidityverifier.js @@ -9,14 +9,6 @@ export default async function exportSolidityVerifier(zKeyName, templates, logger const verificationKey = await exportVerificationKey(zKeyName, logger); - if (verificationKey.protocol === "groth16") { - const vkGamma2 = JSON.stringify(verificationKey.vk_gamma_2); - const vkDelta2 = JSON.stringify(verificationKey.vk_delta_2); - if (vkGamma2 === vkDelta2) { - throw new Error("SOUNDNESS ERROR: vk_gamma_2 and vk_delta_2 are equal. This zkey is insecure, it likely has no phase 2 contribution. Proofs can be forged. Run 'snarkjs zkey contribute' before exporting."); - } - } - if ("fflonk" === verificationKey.protocol) { return fflonkExportSolidityVerifierCmd(verificationKey, templates, logger); }