I am trying to verify a zk-SNARK from a solidity contract offline, in Rust.
This is the verifying contract that checks the proof in the solidity side.
And this is the transaction that carries the proof and the public inputs.
The proof is valid and I have been able to replicate the validation offline using Solidity.
However, in Rust I don't have access to the solidity precompile that checks BN254 pairings. So I am using this implementation based in arkworks/curve crate:
pub fn check_pairings(g1s: Vec<G1Affine>, g2s: Vec<G2Affine>) -> bool {
assert_eq!(g1s.len(), g2s.len());
let mut res = Fp12::one();
for (g1, g2) in g1s.iter().zip(g2s.iter()) {
if g1.is_zero() || g2.is_zero() {
continue;
}
res = res * Bn254::pairing(*g1, *g2);
}
res.is_one()
}
The code is based in the Ethereum BN526 implementation and please note that:
The inputs (vector of G1 and G2 points) are equivalent to the solidity implementation. So I can be sure the combination of inputs, loading of proof etc. is correct.
It's basically the algorithm described in the original Groth16 paper, page 18. The A point component has been negated so that all the terms are in the same side of the equation.
It's the same curve in both implementations.
Am I missing something? Is there some additional practical step when verifying a zk-SNARK? Is a normalization of values required?