From f413f1ea6492fd62edbe2ae9c507d7e29cf26500 Mon Sep 17 00:00:00 2001 From: Mark Spanbroek Date: Tue, 20 Feb 2024 17:16:49 +0100 Subject: [PATCH] Represent elements from field F_{p^2} as `real + i * imag` Reason: Circom and Ethereum EIP-197 both represent these elements as arrays of two elements, but they do it in reverse order of each other. This change makes it explicit which number is the real part, and which number is the imaginary part. --- contracts/Groth16.sol | 12 ++++++++++-- contracts/Groth16Verifier.sol | 8 ++++---- contracts/TestVerifier.sol | 8 ++++---- verifier/verifier.js | 4 ++-- 4 files changed, 20 insertions(+), 12 deletions(-) diff --git a/contracts/Groth16.sol b/contracts/Groth16.sol index 58478b0..8e92e34 100644 --- a/contracts/Groth16.sol +++ b/contracts/Groth16.sol @@ -6,9 +6,17 @@ struct G1Point { uint y; } +// A field element F_{p^2} encoded as `real + i * imag`. +// We chose to not represent this as an array of 2 numbers, because both Circom +// and Ethereum EIP-197 encode to an array, but with conflicting encodings. +struct Fp2Element { + uint real; + uint imag; +} + struct G2Point { - uint[2] x; - uint[2] y; + Fp2Element x; + Fp2Element y; } struct Groth16Proof { diff --git a/contracts/Groth16Verifier.sol b/contracts/Groth16Verifier.sol index 420dd4f..54565c3 100644 --- a/contracts/Groth16Verifier.sol +++ b/contracts/Groth16Verifier.sol @@ -92,10 +92,10 @@ library Pairing { for (uint i = 0; i < elements; i++) { input[i * 6 + 0] = p1[i].x; input[i * 6 + 1] = p1[i].y; - input[i * 6 + 2] = p2[i].x[0]; - input[i * 6 + 3] = p2[i].x[1]; - input[i * 6 + 4] = p2[i].y[0]; - input[i * 6 + 5] = p2[i].y[1]; + input[i * 6 + 2] = p2[i].x.imag; + input[i * 6 + 3] = p2[i].x.real; + input[i * 6 + 4] = p2[i].y.imag; + input[i * 6 + 5] = p2[i].y.real; } uint[1] memory out; bool success; diff --git a/contracts/TestVerifier.sol b/contracts/TestVerifier.sol index 7acef95..ec498be 100644 --- a/contracts/TestVerifier.sol +++ b/contracts/TestVerifier.sol @@ -12,10 +12,10 @@ contract TestVerifier is IGroth16Verifier { return !(proof.a.x == 0 && proof.a.y == 0 && - proof.b.x[0] == 0 && - proof.b.x[1] == 0 && - proof.b.y[0] == 0 && - proof.b.y[1] == 0 && + proof.b.x.real == 0 && + proof.b.x.imag == 0 && + proof.b.y.real == 0 && + proof.b.y.imag == 0 && proof.c.x == 0 && proof.c.y == 0); } diff --git a/verifier/verifier.js b/verifier/verifier.js index fe207b9..8faef1b 100644 --- a/verifier/verifier.js +++ b/verifier/verifier.js @@ -16,8 +16,8 @@ function G1ToStruct(point) { function G2ToStruct(point) { return { - x: [point[0][1], point[0][0]], - y: [point[1][1], point[1][0]], + x: { real: point[0][0], imag: point[0][1] }, + y: { real: point[1][0], imag: point[1][1] }, } }