1
-
2
1
// SPDX-License-Identifier: MIT
3
2
4
3
pragma solidity 0.8.20 ;
@@ -10,7 +9,6 @@ pragma solidity 0.8.20;
10
9
/// to compress proofs.
11
10
/// @notice See <https://2π.com/23/bn254-compression> for further explanation.
12
11
contract Groth16Verifier {
13
-
14
12
/// Some of the provided public input values are larger than the field modulus.
15
13
/// @dev Public input elements are not automatically reduced, as this is can be
16
14
/// a dangerous source of bugs.
@@ -44,43 +42,67 @@ contract Groth16Verifier {
44
42
// Fp2 elements are encoded in the public interface as this became convention.
45
43
46
44
// Constants in Fp
47
- uint256 constant FRACTION_1_2_FP = 0x183227397098d014dc2822db40c0ac2ecbc0b548b438e5469e10460b6c3e7ea4 ;
48
- uint256 constant FRACTION_27_82_FP = 0x2b149d40ceb8aaae81be18991be06ac3b5b4c5e559dbefa33267e6dc24a138e5 ;
49
- uint256 constant FRACTION_3_82_FP = 0x2fcd3ac2a640a154eb23960892a85a68f031ca0c8344b23a577dcf1052b9e775 ;
45
+ uint256 constant FRACTION_1_2_FP =
46
+ 0x183227397098d014dc2822db40c0ac2ecbc0b548b438e5469e10460b6c3e7ea4 ;
47
+ uint256 constant FRACTION_27_82_FP =
48
+ 0x2b149d40ceb8aaae81be18991be06ac3b5b4c5e559dbefa33267e6dc24a138e5 ;
49
+ uint256 constant FRACTION_3_82_FP =
50
+ 0x2fcd3ac2a640a154eb23960892a85a68f031ca0c8344b23a577dcf1052b9e775 ;
50
51
51
52
// Exponents for inversions and square roots mod P
52
- uint256 constant EXP_INVERSE_FP = 0x30644E72E131A029B85045B68181585D97816A916871CA8D3C208C16D87CFD45 ; // P - 2
53
+ uint256 constant EXP_INVERSE_FP =
54
+ 0x30644E72E131A029B85045B68181585D97816A916871CA8D3C208C16D87CFD45 ; // P - 2
53
55
uint256 constant EXP_SQRT_FP = 0xC19139CB84C680A6E14116DA060561765E05AA45A1C72A34F082305B61F3F52 ; // (P + 1) / 4;
54
56
55
57
// Groth16 alpha point in G1
56
- uint256 constant ALPHA_X = 20491192805390485299153009773594534940189261866228447918068658471970481763042 ;
57
- uint256 constant ALPHA_Y = 9383485363053290200918347156157836566562967994039712273449902621266178545958 ;
58
+ uint256 constant ALPHA_X =
59
+ 20491192805390485299153009773594534940189261866228447918068658471970481763042 ;
60
+ uint256 constant ALPHA_Y =
61
+ 9383485363053290200918347156157836566562967994039712273449902621266178545958 ;
58
62
59
63
// Groth16 beta point in G2 in powers of i
60
- uint256 constant BETA_NEG_X_0 = 6375614351688725206403948262868962793625744043794305715222011528459656738731 ;
61
- uint256 constant BETA_NEG_X_1 = 4252822878758300859123897981450591353533073413197771768651442665752259397132 ;
62
- uint256 constant BETA_NEG_Y_0 = 11383000245469012944693504663162918391286475477077232690815866754273895001727 ;
63
- uint256 constant BETA_NEG_Y_1 = 41207766310529818958173054109690360505148424997958324311878202295167071904 ;
64
+ uint256 constant BETA_NEG_X_0 =
65
+ 6375614351688725206403948262868962793625744043794305715222011528459656738731 ;
66
+ uint256 constant BETA_NEG_X_1 =
67
+ 4252822878758300859123897981450591353533073413197771768651442665752259397132 ;
68
+ uint256 constant BETA_NEG_Y_0 =
69
+ 11383000245469012944693504663162918391286475477077232690815866754273895001727 ;
70
+ uint256 constant BETA_NEG_Y_1 =
71
+ 41207766310529818958173054109690360505148424997958324311878202295167071904 ;
64
72
65
73
// Groth16 gamma point in G2 in powers of i
66
- uint256 constant GAMMA_NEG_X_0 = 10857046999023057135944570762232829481370756359578518086990519993285655852781 ;
67
- uint256 constant GAMMA_NEG_X_1 = 11559732032986387107991004021392285783925812861821192530917403151452391805634 ;
68
- uint256 constant GAMMA_NEG_Y_0 = 13392588948715843804641432497768002650278120570034223513918757245338268106653 ;
69
- uint256 constant GAMMA_NEG_Y_1 = 17805874995975841540914202342111839520379459829704422454583296818431106115052 ;
74
+ uint256 constant GAMMA_NEG_X_0 =
75
+ 10857046999023057135944570762232829481370756359578518086990519993285655852781 ;
76
+ uint256 constant GAMMA_NEG_X_1 =
77
+ 11559732032986387107991004021392285783925812861821192530917403151452391805634 ;
78
+ uint256 constant GAMMA_NEG_Y_0 =
79
+ 13392588948715843804641432497768002650278120570034223513918757245338268106653 ;
80
+ uint256 constant GAMMA_NEG_Y_1 =
81
+ 17805874995975841540914202342111839520379459829704422454583296818431106115052 ;
70
82
71
83
// Groth16 delta point in G2 in powers of i
72
- uint256 constant DELTA_NEG_X_0 = 19629295988673812457237747993086053613709181874324227239033635205670891327060 ;
73
- uint256 constant DELTA_NEG_X_1 = 17270349666695681994109533429817368669497520119106681015856196115021033411091 ;
74
- uint256 constant DELTA_NEG_Y_0 = 14281790459332470419125837541415772351574094165485379719795056490664770278727 ;
75
- uint256 constant DELTA_NEG_Y_1 = 12217031863885588059779845498016696484811402332435719653934590968575679828494 ;
84
+ uint256 constant DELTA_NEG_X_0 =
85
+ 19629295988673812457237747993086053613709181874324227239033635205670891327060 ;
86
+ uint256 constant DELTA_NEG_X_1 =
87
+ 17270349666695681994109533429817368669497520119106681015856196115021033411091 ;
88
+ uint256 constant DELTA_NEG_Y_0 =
89
+ 14281790459332470419125837541415772351574094165485379719795056490664770278727 ;
90
+ uint256 constant DELTA_NEG_Y_1 =
91
+ 12217031863885588059779845498016696484811402332435719653934590968575679828494 ;
76
92
77
93
// Constant and public input points
78
- uint256 constant CONSTANT_X = 6712036353136249806951869451908368653566549662781372756321174254690599374583 ;
79
- uint256 constant CONSTANT_Y = 18149145036868871064182651529802275370638950642742152190925800889169295968585 ;
80
- uint256 constant PUB_0_X = 12384021290558951773126140100379496012525836638155233096890881157449062205923 ;
81
- uint256 constant PUB_0_Y = 16530732960917040406371332977337573092100509754908292717547628595948196259098 ;
82
- uint256 constant PUB_1_X = 18749839173537272836199384751191600551090725238737491530604969678014545165197 ;
83
- uint256 constant PUB_1_Y = 1828450848853234449784725988911172793808451038026258152543319358376349553777 ;
94
+ uint256 constant CONSTANT_X =
95
+ 6712036353136249806951869451908368653566549662781372756321174254690599374583 ;
96
+ uint256 constant CONSTANT_Y =
97
+ 18149145036868871064182651529802275370638950642742152190925800889169295968585 ;
98
+ uint256 constant PUB_0_X =
99
+ 12384021290558951773126140100379496012525836638155233096890881157449062205923 ;
100
+ uint256 constant PUB_0_Y =
101
+ 16530732960917040406371332977337573092100509754908292717547628595948196259098 ;
102
+ uint256 constant PUB_1_X =
103
+ 18749839173537272836199384751191600551090725238737491530604969678014545165197 ;
104
+ uint256 constant PUB_1_Y =
105
+ 1828450848853234449784725988911172793808451038026258152543319358376349553777 ;
84
106
85
107
/// Negation in Fp.
86
108
/// @notice Returns a number x such that a + x = 0 in Fp.
@@ -172,7 +194,11 @@ contract Groth16Verifier {
172
194
/// @param hint A hint which of two possible signs to pick in the equation.
173
195
/// @return x0 The real part of the square root.
174
196
/// @return x1 The imaginary part of the square root.
175
- function sqrt_Fp2 (uint256 a0 , uint256 a1 , bool hint ) internal view returns (uint256 x0 , uint256 x1 ) {
197
+ function sqrt_Fp2 (uint256 a0 , uint256 a1 , bool hint )
198
+ internal
199
+ view
200
+ returns (uint256 x0 , uint256 x1 )
201
+ {
176
202
// If this square root reverts there is no solution in Fp2.
177
203
uint256 d = sqrt_Fp (addmod (mulmod (a0, a0, P), mulmod (a1, a1, P), P));
178
204
if (hint) {
@@ -184,8 +210,10 @@ contract Groth16Verifier {
184
210
185
211
// Check result to make sure we found a root.
186
212
// Note: this also fails if a0 or a1 is not reduced.
187
- if (a0 != addmod (mulmod (x0, x0, P), negate (mulmod (x1, x1, P)), P)
188
- || a1 != mulmod (2 , mulmod (x0, x1, P), P)) {
213
+ if (
214
+ a0 != addmod (mulmod (x0, x0, P), negate (mulmod (x1, x1, P)), P)
215
+ || a1 != mulmod (2 , mulmod (x0, x1, P), P)
216
+ ) {
189
217
revert ProofInvalid ();
190
218
}
191
219
}
@@ -261,7 +289,10 @@ contract Groth16Verifier {
261
289
/// @return c0 The first half of the compresed point (x0 with two signal bits).
262
290
/// @return c1 The second half of the compressed point (x1 unmodified).
263
291
function compress_g2 (uint256 x0 , uint256 x1 , uint256 y0 , uint256 y1 )
264
- internal view returns (uint256 c0 , uint256 c1 ) {
292
+ internal
293
+ view
294
+ returns (uint256 c0 , uint256 c1 )
295
+ {
265
296
if (x0 >= P || x1 >= P || y0 >= P || y1 >= P) {
266
297
// G2 point not in field.
267
298
revert ProofInvalid ();
@@ -276,11 +307,11 @@ contract Groth16Verifier {
276
307
uint256 y0_pos;
277
308
uint256 y1_pos;
278
309
{
279
- uint256 n3ab = mulmod (mulmod (x0, x1, P), P- 3 , P);
310
+ uint256 n3ab = mulmod (mulmod (x0, x1, P), P - 3 , P);
280
311
uint256 a_3 = mulmod (mulmod (x0, x0, P), x0, P);
281
312
uint256 b_3 = mulmod (mulmod (x1, x1, P), x1, P);
282
313
y0_pos = addmod (FRACTION_27_82_FP, addmod (a_3, mulmod (n3ab, x1, P), P), P);
283
- y1_pos = negate (addmod (FRACTION_3_82_FP, addmod (b_3, mulmod (n3ab, x0, P), P), P));
314
+ y1_pos = negate (addmod (FRACTION_3_82_FP, addmod (b_3, mulmod (n3ab, x0, P), P), P));
284
315
}
285
316
286
317
// Determine hint bit
@@ -294,10 +325,10 @@ contract Groth16Verifier {
294
325
// Recover y
295
326
(y0_pos, y1_pos) = sqrt_Fp2 (y0_pos, y1_pos, hint);
296
327
if (y0 == y0_pos && y1 == y1_pos) {
297
- c0 = (x0 << 2 ) | (hint ? 2 : 0 ) | 0 ;
328
+ c0 = (x0 << 2 ) | (hint ? 2 : 0 ) | 0 ;
298
329
c1 = x1;
299
330
} else if (y0 == negate (y0_pos) && y1 == negate (y1_pos)) {
300
- c0 = (x0 << 2 ) | (hint ? 2 : 0 ) | 1 ;
331
+ c0 = (x0 << 2 ) | (hint ? 2 : 0 ) | 1 ;
301
332
c1 = x1;
302
333
} else {
303
334
// G1 point not on curve.
@@ -317,7 +348,10 @@ contract Groth16Verifier {
317
348
/// @return y0 The real part of the Y coordinate.
318
349
/// @return y1 The imaginary part of the Y coordinate.
319
350
function decompress_g2 (uint256 c0 , uint256 c1 )
320
- internal view returns (uint256 x0 , uint256 x1 , uint256 y0 , uint256 y1 ) {
351
+ internal
352
+ view
353
+ returns (uint256 x0 , uint256 x1 , uint256 y0 , uint256 y1 )
354
+ {
321
355
// Note that X = (0, 0) is not on the curve since 0³ + 3/(9 + i) is not a square.
322
356
// so we can use it to represent the point at infinity.
323
357
if (c0 == 0 && c1 == 0 ) {
@@ -333,12 +367,12 @@ contract Groth16Verifier {
333
367
revert ProofInvalid ();
334
368
}
335
369
336
- uint256 n3ab = mulmod (mulmod (x0, x1, P), P- 3 , P);
370
+ uint256 n3ab = mulmod (mulmod (x0, x1, P), P - 3 , P);
337
371
uint256 a_3 = mulmod (mulmod (x0, x0, P), x0, P);
338
372
uint256 b_3 = mulmod (mulmod (x1, x1, P), x1, P);
339
373
340
374
y0 = addmod (FRACTION_27_82_FP, addmod (a_3, mulmod (n3ab, x1, P), P), P);
341
- y1 = negate (addmod (FRACTION_3_82_FP, addmod (b_3, mulmod (n3ab, x0, P), P), P));
375
+ y1 = negate (addmod (FRACTION_3_82_FP, addmod (b_3, mulmod (n3ab, x0, P), P), P));
342
376
343
377
// Note: sqrt_Fp2 reverts if there is no solution, i.e. the point is not on the curve.
344
378
// Note: (X³ + 3/(9 + i)) is irreducible in Fp2, so y can not be zero.
@@ -358,7 +392,10 @@ contract Groth16Verifier {
358
392
/// @return x The X coordinate of the resulting G1 point.
359
393
/// @return y The Y coordinate of the resulting G1 point.
360
394
function publicInputMSM (uint256 [2 ] calldata input )
361
- internal view returns (uint256 x , uint256 y ) {
395
+ internal
396
+ view
397
+ returns (uint256 x , uint256 y )
398
+ {
362
399
// Note: The ECMUL precompile does not reject unreduced values, so we check this.
363
400
// Note: Unrolling this loop does not cost much extra in code-size, the bulk of the
364
401
// code-size is in the PUB_ constants.
@@ -376,14 +413,14 @@ contract Groth16Verifier {
376
413
mstore (add (f, 0x20 ), CONSTANT_Y)
377
414
mstore (g, PUB_0_X)
378
415
mstore (add (g, 0x20 ), PUB_0_Y)
379
- s := calldataload (input)
416
+ s := calldataload (input)
380
417
mstore (add (g, 0x40 ), s)
381
418
success := and (success, lt (s, R))
382
419
success := and (success, staticcall (gas (), PRECOMPILE_MUL, g, 0x60 , g, 0x40 ))
383
420
success := and (success, staticcall (gas (), PRECOMPILE_ADD, f, 0x80 , f, 0x40 ))
384
421
mstore (g, PUB_1_X)
385
422
mstore (add (g, 0x20 ), PUB_1_Y)
386
- s := calldataload (add (input, 32 ))
423
+ s := calldataload (add (input, 32 ))
387
424
mstore (add (g, 0x40 ), s)
388
425
success := and (success, lt (s, R))
389
426
success := and (success, staticcall (gas (), PRECOMPILE_MUL, g, 0x60 , g, 0x40 ))
@@ -407,7 +444,10 @@ contract Groth16Verifier {
407
444
/// @return compressed The compressed proof. Elements are in the same order as for
408
445
/// verifyCompressedProof. I.e. points (A, B, C) in compressed format.
409
446
function compressProof (uint256 [8 ] calldata proof )
410
- public view returns (uint256 [4 ] memory compressed ) {
447
+ public
448
+ view
449
+ returns (uint256 [4 ] memory compressed )
450
+ {
411
451
compressed[0 ] = compress_g1 (proof[0 ], proof[1 ]);
412
452
(compressed[2 ], compressed[1 ]) = compress_g2 (proof[3 ], proof[2 ], proof[5 ], proof[4 ]);
413
453
compressed[3 ] = compress_g1 (proof[6 ], proof[7 ]);
@@ -422,33 +462,34 @@ contract Groth16Verifier {
422
462
/// matching the output of compressProof.
423
463
/// @param input the public input field elements in the scalar field Fr.
424
464
/// Elements must be reduced.
425
- function verifyCompressedProof (
426
- uint256 [ 4 ] calldata compressedProof ,
427
- uint256 [ 2 ] calldata input
428
- ) public view {
465
+ function verifyCompressedProof (uint256 [ 4 ] calldata compressedProof , uint256 [ 2 ] calldata input )
466
+ public
467
+ view
468
+ {
429
469
uint256 [24 ] memory pairings;
430
470
431
471
{
432
472
(uint256 Ax , uint256 Ay ) = decompress_g1 (compressedProof[0 ]);
433
- (uint256 Bx0 , uint256 Bx1 , uint256 By0 , uint256 By1 ) = decompress_g2 (compressedProof[2 ], compressedProof[1 ]);
473
+ (uint256 Bx0 , uint256 Bx1 , uint256 By0 , uint256 By1 ) =
474
+ decompress_g2 (compressedProof[2 ], compressedProof[1 ]);
434
475
(uint256 Cx , uint256 Cy ) = decompress_g1 (compressedProof[3 ]);
435
476
(uint256 Lx , uint256 Ly ) = publicInputMSM (input);
436
477
437
478
// Verify the pairing
438
479
// Note: The precompile expects the F2 coefficients in big-endian order.
439
480
// Note: The pairing precompile rejects unreduced values, so we won't check that here.
440
481
// e(A, B)
441
- pairings[ 0 ] = Ax;
442
- pairings[ 1 ] = Ay;
443
- pairings[ 2 ] = Bx1;
444
- pairings[ 3 ] = Bx0;
445
- pairings[ 4 ] = By1;
446
- pairings[ 5 ] = By0;
482
+ pairings[0 ] = Ax;
483
+ pairings[1 ] = Ay;
484
+ pairings[2 ] = Bx1;
485
+ pairings[3 ] = Bx0;
486
+ pairings[4 ] = By1;
487
+ pairings[5 ] = By0;
447
488
// e(C, -δ)
448
- pairings[ 6 ] = Cx;
449
- pairings[ 7 ] = Cy;
450
- pairings[ 8 ] = DELTA_NEG_X_1;
451
- pairings[ 9 ] = DELTA_NEG_X_0;
489
+ pairings[6 ] = Cx;
490
+ pairings[7 ] = Cy;
491
+ pairings[8 ] = DELTA_NEG_X_1;
492
+ pairings[9 ] = DELTA_NEG_X_0;
452
493
pairings[10 ] = DELTA_NEG_Y_1;
453
494
pairings[11 ] = DELTA_NEG_Y_0;
454
495
// e(α, -β)
@@ -489,10 +530,7 @@ contract Groth16Verifier {
489
530
/// of compressProof.
490
531
/// @param input the public input field elements in the scalar field Fr.
491
532
/// Elements must be reduced.
492
- function Verify (
493
- uint256 [8 ] calldata proof ,
494
- uint256 [2 ] calldata input
495
- ) public view {
533
+ function Verify (uint256 [8 ] calldata proof , uint256 [2 ] calldata input ) public view {
496
534
(uint256 x , uint256 y ) = publicInputMSM (input);
497
535
498
536
// Note: The precompile expects the F2 coefficients in big-endian order.
0 commit comments