forked from Consensys/gnark
-
Notifications
You must be signed in to change notification settings - Fork 0
/
solidity.go
1432 lines (1222 loc) · 59.4 KB
/
solidity.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
package plonk
const tmplSolidityVerifier = `// SPDX-License-Identifier: Apache-2.0
// Copyright 2023 Consensys Software Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Code generated by gnark DO NOT EDIT
pragma solidity ^0.8.19;
contract PlonkVerifier {
uint256 private constant R_MOD = 21888242871839275222246405745257275088548364400416034343698204186575808495617;
uint256 private constant R_MOD_MINUS_ONE = 21888242871839275222246405745257275088548364400416034343698204186575808495616;
uint256 private constant P_MOD = 21888242871839275222246405745257275088696311157297823662689037894645226208583;
{{ range $index, $element := .Kzg.G2 }}
uint256 private constant G2_SRS_{{ $index }}_X_0 = {{ (fpstr $element.X.A1) }};
uint256 private constant G2_SRS_{{ $index }}_X_1 = {{ (fpstr $element.X.A0) }};
uint256 private constant G2_SRS_{{ $index }}_Y_0 = {{ (fpstr $element.Y.A1) }};
uint256 private constant G2_SRS_{{ $index }}_Y_1 = {{ (fpstr $element.Y.A0) }};
{{ end }}
uint256 private constant G1_SRS_X = {{ fpstr .Kzg.G1.X }};
uint256 private constant G1_SRS_Y = {{ fpstr .Kzg.G1.Y }};
// ----------------------- vk ---------------------
uint256 private constant VK_NB_PUBLIC_INPUTS = {{ .NbPublicVariables }};
uint256 private constant VK_DOMAIN_SIZE = {{ .Size }};
uint256 private constant VK_INV_DOMAIN_SIZE = {{ (frstr .SizeInv) }};
uint256 private constant VK_OMEGA = {{ (frstr .Generator) }};
uint256 private constant VK_QL_COM_X = {{ (fpstr .Ql.X) }};
uint256 private constant VK_QL_COM_Y = {{ (fpstr .Ql.Y) }};
uint256 private constant VK_QR_COM_X = {{ (fpstr .Qr.X) }};
uint256 private constant VK_QR_COM_Y = {{ (fpstr .Qr.Y) }};
uint256 private constant VK_QM_COM_X = {{ (fpstr .Qm.X) }};
uint256 private constant VK_QM_COM_Y = {{ (fpstr .Qm.Y) }};
uint256 private constant VK_QO_COM_X = {{ (fpstr .Qo.X) }};
uint256 private constant VK_QO_COM_Y = {{ (fpstr .Qo.Y) }};
uint256 private constant VK_QK_COM_X = {{ (fpstr .Qk.X) }};
uint256 private constant VK_QK_COM_Y = {{ (fpstr .Qk.Y) }};
{{ range $index, $element := .S }}
uint256 private constant VK_S{{ inc $index }}_COM_X = {{ (fpstr $element.X) }};
uint256 private constant VK_S{{ inc $index }}_COM_Y = {{ (fpstr $element.Y) }};
{{ end }}
uint256 private constant VK_COSET_SHIFT = 5;
{{ range $index, $element := .Qcp}}
uint256 private constant VK_QCP_{{ $index }}_X = {{ (fpstr $element.X) }};
uint256 private constant VK_QCP_{{ $index }}_Y = {{ (fpstr $element.Y) }};
{{ end }}
{{ range $index, $element := .CommitmentConstraintIndexes -}}
uint256 private constant VK_INDEX_COMMIT_API{{ $index }} = {{ $element }};
{{ end -}}
uint256 private constant VK_NB_CUSTOM_GATES = {{ len .CommitmentConstraintIndexes }};
// ------------------------------------------------
// offset proof
uint256 private constant PROOF_L_COM_X = 0x00;
uint256 private constant PROOF_L_COM_Y = 0x20;
uint256 private constant PROOF_R_COM_X = 0x40;
uint256 private constant PROOF_R_COM_Y = 0x60;
uint256 private constant PROOF_O_COM_X = 0x80;
uint256 private constant PROOF_O_COM_Y = 0xa0;
// h = h_0 + x^{n+2}h_1 + x^{2(n+2)}h_2
uint256 private constant PROOF_H_0_X = 0xc0;
uint256 private constant PROOF_H_0_Y = 0xe0;
uint256 private constant PROOF_H_1_X = 0x100;
uint256 private constant PROOF_H_1_Y = 0x120;
uint256 private constant PROOF_H_2_X = 0x140;
uint256 private constant PROOF_H_2_Y = 0x160;
// wire values at zeta
uint256 private constant PROOF_L_AT_ZETA = 0x180;
uint256 private constant PROOF_R_AT_ZETA = 0x1a0;
uint256 private constant PROOF_O_AT_ZETA = 0x1c0;
//uint256[STATE_WIDTH-1] permutation_polynomials_at_zeta; // Sσ1(zeta),Sσ2(zeta)
uint256 private constant PROOF_S1_AT_ZETA = 0x1e0; // Sσ1(zeta)
uint256 private constant PROOF_S2_AT_ZETA = 0x200; // Sσ2(zeta)
//Bn254.G1Point grand_product_commitment; // [z(x)]
uint256 private constant PROOF_GRAND_PRODUCT_COMMITMENT_X = 0x220;
uint256 private constant PROOF_GRAND_PRODUCT_COMMITMENT_Y = 0x240;
uint256 private constant PROOF_GRAND_PRODUCT_AT_ZETA_OMEGA = 0x260; // z(w*zeta)
uint256 private constant PROOF_QUOTIENT_POLYNOMIAL_AT_ZETA = 0x280; // t(zeta)
uint256 private constant PROOF_LINEARISED_POLYNOMIAL_AT_ZETA = 0x2a0; // r(zeta)
// Folded proof for the opening of H, linearised poly, l, r, o, s_1, s_2, qcp
uint256 private constant PROOF_BATCH_OPENING_AT_ZETA_X = 0x2c0; // [Wzeta]
uint256 private constant PROOF_BATCH_OPENING_AT_ZETA_Y = 0x2e0;
uint256 private constant PROOF_OPENING_AT_ZETA_OMEGA_X = 0x300;
uint256 private constant PROOF_OPENING_AT_ZETA_OMEGA_Y = 0x320;
uint256 private constant PROOF_OPENING_QCP_AT_ZETA = 0x340;
uint256 private constant PROOF_COMMITMENTS_WIRES_CUSTOM_GATES = {{ hex (add 832 (mul (len .CommitmentConstraintIndexes) 32 ) )}};
// -> next part of proof is
// [ openings_selector_commits || commitments_wires_commit_api]
// -------- offset state
// challenges to check the claimed quotient
uint256 private constant STATE_ALPHA = 0x00;
uint256 private constant STATE_BETA = 0x20;
uint256 private constant STATE_GAMMA = 0x40;
uint256 private constant STATE_ZETA = 0x60;
// reusable value
uint256 private constant STATE_ALPHA_SQUARE_LAGRANGE_0 = 0x80;
// commitment to H
uint256 private constant STATE_FOLDED_H_X = 0xa0;
uint256 private constant STATE_FOLDED_H_Y = 0xc0;
// commitment to the linearised polynomial
uint256 private constant STATE_LINEARISED_POLYNOMIAL_X = 0xe0;
uint256 private constant STATE_LINEARISED_POLYNOMIAL_Y = 0x100;
// Folded proof for the opening of H, linearised poly, l, r, o, s_1, s_2, qcp
uint256 private constant STATE_FOLDED_CLAIMED_VALUES = 0x120;
// folded digests of H, linearised poly, l, r, o, s_1, s_2, qcp
uint256 private constant STATE_FOLDED_DIGESTS_X = 0x140;
uint256 private constant STATE_FOLDED_DIGESTS_Y = 0x160;
uint256 private constant STATE_PI = 0x180;
uint256 private constant STATE_ZETA_POWER_N_MINUS_ONE = 0x1a0;
uint256 private constant STATE_GAMMA_KZG = 0x1c0;
uint256 private constant STATE_SUCCESS = 0x1e0;
uint256 private constant STATE_CHECK_VAR = 0x200; // /!\ this slot is used for debugging only
uint256 private constant STATE_LAST_MEM = 0x220;
// -------- errors
uint256 private constant ERROR_STRING_ID = 0x08c379a000000000000000000000000000000000000000000000000000000000; // selector for function Error(string)
{{ if (gt (len .CommitmentConstraintIndexes) 0 )}}
// -------- utils (for hash_fr)
uint256 private constant HASH_FR_BB = 340282366920938463463374607431768211456; // 2**128
uint256 private constant HASH_FR_ZERO_UINT256 = 0;
uint8 private constant HASH_FR_LEN_IN_BYTES = 48;
uint8 private constant HASH_FR_SIZE_DOMAIN = 11;
uint8 private constant HASH_FR_ONE = 1;
uint8 private constant HASH_FR_TWO = 2;
{{ end }}
/// Verify a Plonk proof.
/// Reverts if the proof or the public inputs are malformed.
/// @param proof serialised plonk proof (using gnark's MarshalSolidity)
/// @param public_inputs (must be reduced)
/// @return success true if the proof passes false otherwise
function Verify(bytes calldata proof, uint256[] calldata public_inputs)
public view returns(bool success) {
assembly {
let mem := mload(0x40)
let freeMem := add(mem, STATE_LAST_MEM)
// sanity checks
check_number_of_public_inputs(public_inputs.length)
check_inputs_size(public_inputs.length, public_inputs.offset)
check_proof_size(proof.length)
check_proof_openings_size(proof.offset)
// compute the challenges
let prev_challenge_non_reduced
prev_challenge_non_reduced := derive_gamma(proof.offset, public_inputs.length, public_inputs.offset)
prev_challenge_non_reduced := derive_beta(prev_challenge_non_reduced)
prev_challenge_non_reduced := derive_alpha(proof.offset, prev_challenge_non_reduced)
derive_zeta(proof.offset, prev_challenge_non_reduced)
// evaluation of Z=Xⁿ-1 at ζ, we save this value
let zeta := mload(add(mem, STATE_ZETA))
let zeta_power_n_minus_one := addmod(pow(zeta, VK_DOMAIN_SIZE, freeMem), sub(R_MOD, 1), R_MOD)
mstore(add(mem, STATE_ZETA_POWER_N_MINUS_ONE), zeta_power_n_minus_one)
// public inputs contribution
let l_pi := sum_pi_wo_api_commit(public_inputs.offset, public_inputs.length, freeMem)
{{ if (gt (len .CommitmentConstraintIndexes) 0 ) -}}
let l_wocommit := sum_pi_commit(proof.offset, public_inputs.length, freeMem)
l_pi := addmod(l_wocommit, l_pi, R_MOD)
{{ end -}}
mstore(add(mem, STATE_PI), l_pi)
compute_alpha_square_lagrange_0()
verify_quotient_poly_eval_at_zeta(proof.offset)
fold_h(proof.offset)
compute_commitment_linearised_polynomial(proof.offset)
compute_gamma_kzg(proof.offset)
fold_state(proof.offset)
batch_verify_multi_points(proof.offset)
success := mload(add(mem, STATE_SUCCESS))
// Beginning errors -------------------------------------------------
function error_nb_public_inputs() {
let ptError := mload(0x40)
mstore(ptError, ERROR_STRING_ID) // selector for function Error(string)
mstore(add(ptError, 0x4), 0x20)
mstore(add(ptError, 0x24), 0x1d)
mstore(add(ptError, 0x44), "wrong number of public inputs")
revert(ptError, 0x64)
}
/// Called when an operation on Bn254 fails
/// @dev for instance when calling EcMul on a point not on Bn254.
function error_ec_op() {
let ptError := mload(0x40)
mstore(ptError, ERROR_STRING_ID) // selector for function Error(string)
mstore(add(ptError, 0x4), 0x20)
mstore(add(ptError, 0x24), 0x12)
mstore(add(ptError, 0x44), "error ec operation")
revert(ptError, 0x64)
}
/// Called when one of the public inputs is not reduced.
function error_inputs_size() {
let ptError := mload(0x40)
mstore(ptError, ERROR_STRING_ID) // selector for function Error(string)
mstore(add(ptError, 0x4), 0x20)
mstore(add(ptError, 0x24), 0x18)
mstore(add(ptError, 0x44), "inputs are bigger than r")
revert(ptError, 0x64)
}
/// Called when the size proof is not as expected
/// @dev to avoid overflow attack for instance
function error_proof_size() {
let ptError := mload(0x40)
mstore(ptError, ERROR_STRING_ID) // selector for function Error(string)
mstore(add(ptError, 0x4), 0x20)
mstore(add(ptError, 0x24), 0x10)
mstore(add(ptError, 0x44), "wrong proof size")
revert(ptError, 0x64)
}
/// Called when one the openings is bigger than r
/// The openings are the claimed evalutions of a polynomial
/// in a Kzg proof.
function error_proof_openings_size() {
let ptError := mload(0x40)
mstore(ptError, ERROR_STRING_ID) // selector for function Error(string)
mstore(add(ptError, 0x4), 0x20)
mstore(add(ptError, 0x24), 0x16)
mstore(add(ptError, 0x44), "openings bigger than r")
revert(ptError, 0x64)
}
function error_verify() {
let ptError := mload(0x40)
mstore(ptError, ERROR_STRING_ID) // selector for function Error(string)
mstore(add(ptError, 0x4), 0x20)
mstore(add(ptError, 0x24), 0xc)
mstore(add(ptError, 0x44), "error verify")
revert(ptError, 0x64)
}
function error_random_generation() {
let ptError := mload(0x40)
mstore(ptError, ERROR_STRING_ID) // selector for function Error(string)
mstore(add(ptError, 0x4), 0x20)
mstore(add(ptError, 0x24), 0x14)
mstore(add(ptError, 0x44), "error random gen kzg")
revert(ptError, 0x64)
}
// end errors -------------------------------------------------
// Beginning checks -------------------------------------------------
/// @param s actual number of public inputs
function check_number_of_public_inputs(s) {
if iszero(eq(s, VK_NB_PUBLIC_INPUTS)) {
error_nb_public_inputs()
}
}
/// Checks that the public inputs are < R_MOD.
/// @param s number of public inputs
/// @param p pointer to the public inputs array
function check_inputs_size(s, p) {
for {let i} lt(i, s) {i:=add(i,1)}
{
if gt(calldataload(p), R_MOD_MINUS_ONE) {
error_inputs_size()
}
p := add(p, 0x20)
}
}
/// Checks if the proof is of the correct size
/// @param actual_proof_size size of the proof (not the expected size)
function check_proof_size(actual_proof_size) {
let expected_proof_size := add(0x340, mul(VK_NB_CUSTOM_GATES,0x60))
if iszero(eq(actual_proof_size, expected_proof_size)) {
error_proof_size()
}
}
/// Checks if the multiple openings of the polynomials are < R_MOD.
/// @param aproof pointer to the beginning of the proof
/// @dev the 'a' prepending proof is to have a local name
function check_proof_openings_size(aproof) {
// linearised polynomial at zeta
let p := add(aproof, PROOF_LINEARISED_POLYNOMIAL_AT_ZETA)
if gt(calldataload(p), R_MOD_MINUS_ONE) {
error_proof_openings_size()
}
// quotient polynomial at zeta
p := add(aproof, PROOF_QUOTIENT_POLYNOMIAL_AT_ZETA)
if gt(calldataload(p), R_MOD_MINUS_ONE) {
error_proof_openings_size()
}
// PROOF_L_AT_ZETA
p := add(aproof, PROOF_L_AT_ZETA)
if gt(calldataload(p), R_MOD_MINUS_ONE) {
error_proof_openings_size()
}
// PROOF_R_AT_ZETA
p := add(aproof, PROOF_R_AT_ZETA)
if gt(calldataload(p), R_MOD_MINUS_ONE) {
error_proof_openings_size()
}
// PROOF_O_AT_ZETA
p := add(aproof, PROOF_O_AT_ZETA)
if gt(calldataload(p), R_MOD_MINUS_ONE) {
error_proof_openings_size()
}
// PROOF_S1_AT_ZETA
p := add(aproof, PROOF_S1_AT_ZETA)
if gt(calldataload(p), R_MOD_MINUS_ONE) {
error_proof_openings_size()
}
// PROOF_S2_AT_ZETA
p := add(aproof, PROOF_S2_AT_ZETA)
if gt(calldataload(p), R_MOD_MINUS_ONE) {
error_proof_openings_size()
}
// PROOF_GRAND_PRODUCT_AT_ZETA_OMEGA
p := add(aproof, PROOF_GRAND_PRODUCT_AT_ZETA_OMEGA)
if gt(calldataload(p), R_MOD_MINUS_ONE) {
error_proof_openings_size()
}
// PROOF_OPENING_QCP_AT_ZETA
p := add(aproof, PROOF_OPENING_QCP_AT_ZETA)
for {let i:=0} lt(i, VK_NB_CUSTOM_GATES) {i:=add(i,1)}
{
if gt(calldataload(p), R_MOD_MINUS_ONE) {
error_proof_openings_size()
}
p := add(p, 0x20)
}
}
// end checks -------------------------------------------------
// Beginning challenges -------------------------------------------------
/// Derive gamma as Sha256(<transcript>)
/// @param aproof pointer to the proof
/// @param nb_pi number of public inputs
/// @param pi pointer to the array of public inputs
/// @return the challenge gamma, not reduced
/// @notice The transcript is the concatenation (in this order) of:
/// * the word "gamma" in ascii, equal to [0x67,0x61,0x6d, 0x6d, 0x61] and encoded as a uint256.
/// * the commitments to the permutation polynomials S1, S2, S3, where we concatenate the coordinates of those points
/// * the commitments of Ql, Qr, Qm, Qo, Qk
/// * the public inputs
/// * the commitments of the wires related to the custom gates (commitments_wires_commit_api)
/// * commitments to L, R, O (proof_<l,r,o>_com_<x,y>)
/// The data described above is written starting at mPtr. "gamma" lies on 5 bytes,
/// and is encoded as a uint256 number n. In basis b = 256, the number looks like this
/// [0 0 0 .. 0x67 0x61 0x6d, 0x6d, 0x61]. The first non zero entry is at position 27=0x1b
/// Gamma reduced (the actual challenge) is stored at add(state, state_gamma)
function derive_gamma(aproof, nb_pi, pi)->gamma_not_reduced {
let state := mload(0x40)
let mPtr := add(state, STATE_LAST_MEM)
// gamma
// gamma in ascii is [0x67,0x61,0x6d, 0x6d, 0x61]
// (same for alpha, beta, zeta)
mstore(mPtr, 0x67616d6d61) // "gamma"
mstore(add(mPtr, 0x20), VK_S1_COM_X)
mstore(add(mPtr, 0x40), VK_S1_COM_Y)
mstore(add(mPtr, 0x60), VK_S2_COM_X)
mstore(add(mPtr, 0x80), VK_S2_COM_Y)
mstore(add(mPtr, 0xa0), VK_S3_COM_X)
mstore(add(mPtr, 0xc0), VK_S3_COM_Y)
mstore(add(mPtr, 0xe0), VK_QL_COM_X)
mstore(add(mPtr, 0x100), VK_QL_COM_Y)
mstore(add(mPtr, 0x120), VK_QR_COM_X)
mstore(add(mPtr, 0x140), VK_QR_COM_Y)
mstore(add(mPtr, 0x160), VK_QM_COM_X)
mstore(add(mPtr, 0x180), VK_QM_COM_Y)
mstore(add(mPtr, 0x1a0), VK_QO_COM_X)
mstore(add(mPtr, 0x1c0), VK_QO_COM_Y)
mstore(add(mPtr, 0x1e0), VK_QK_COM_X)
mstore(add(mPtr, 0x200), VK_QK_COM_Y)
{{ range $index, $element := .CommitmentConstraintIndexes}}
mstore(add(mPtr, {{ hex (add 544 (mul $index 64)) }}), VK_QCP_{{ $index }}_X)
mstore(add(mPtr, {{ hex (add 576 (mul $index 64)) }}), VK_QCP_{{ $index }}_Y)
{{ end }}
// public inputs
let _mPtr := add(mPtr, {{ hex (add (mul (len .CommitmentConstraintIndexes) 64) 544) }})
let size_pi_in_bytes := mul(nb_pi, 0x20)
calldatacopy(_mPtr, pi, size_pi_in_bytes)
_mPtr := add(_mPtr, size_pi_in_bytes)
// commitments to l, r, o
let size_commitments_lro_in_bytes := 0xc0
calldatacopy(_mPtr, aproof, size_commitments_lro_in_bytes)
_mPtr := add(_mPtr, size_commitments_lro_in_bytes)
// total size is :
// sizegamma(=0x5) + 11*64(=0x2c0)
// + nb_public_inputs*0x20
// + nb_custom gates*0x40
let size := add(0x2c5, size_pi_in_bytes)
{{ if (gt (len .CommitmentConstraintIndexes) 0 )}}
size := add(size, mul(VK_NB_CUSTOM_GATES, 0x40))
{{ end -}}
let l_success := staticcall(gas(), 0x2, add(mPtr, 0x1b), size, mPtr, 0x20) //0x1b -> 000.."gamma"
if iszero(l_success) {
error_verify()
}
gamma_not_reduced := mload(mPtr)
mstore(add(state, STATE_GAMMA), mod(gamma_not_reduced, R_MOD))
}
/// derive beta as Sha256<transcript>
/// @param gamma_not_reduced the previous challenge (gamma) not reduced
/// @return beta_not_reduced the next challenge, beta, not reduced
/// @notice the transcript consists of the previous challenge only.
/// The reduced version of beta is stored at add(state, state_beta)
function derive_beta(gamma_not_reduced)->beta_not_reduced{
let state := mload(0x40)
let mPtr := add(mload(0x40), STATE_LAST_MEM)
// beta
mstore(mPtr, 0x62657461) // "beta"
mstore(add(mPtr, 0x20), gamma_not_reduced)
let l_success := staticcall(gas(), 0x2, add(mPtr, 0x1c), 0x24, mPtr, 0x20) //0x1b -> 000.."gamma"
if iszero(l_success) {
error_verify()
}
beta_not_reduced := mload(mPtr)
mstore(add(state, STATE_BETA), mod(beta_not_reduced, R_MOD))
}
/// derive alpha as sha256<transcript>
/// @param aproof pointer to the proof object
/// @param beta_not_reduced the previous challenge (beta) not reduced
/// @return alpha_not_reduced the next challenge, alpha, not reduced
/// @notice the transcript consists of the previous challenge (beta)
/// not reduced, the commitments to the wires associated to the QCP_i,
/// and the commitment to the grand product polynomial
function derive_alpha(aproof, beta_not_reduced)->alpha_not_reduced {
let state := mload(0x40)
let mPtr := add(mload(0x40), STATE_LAST_MEM)
let full_size := 0x65 // size("alpha") + 0x20 (previous challenge)
// alpha
mstore(mPtr, 0x616C706861) // "alpha"
let _mPtr := add(mPtr, 0x20)
mstore(_mPtr, beta_not_reduced)
_mPtr := add(_mPtr, 0x20)
{{ if (gt (len .CommitmentConstraintIndexes) 0 )}}
// Bsb22Commitments
let proof_bsb_commitments := add(aproof, PROOF_COMMITMENTS_WIRES_CUSTOM_GATES)
let size_bsb_commitments := mul(0x40, VK_NB_CUSTOM_GATES)
calldatacopy(_mPtr, proof_bsb_commitments, size_bsb_commitments)
_mPtr := add(_mPtr, size_bsb_commitments)
full_size := add(full_size, size_bsb_commitments)
{{ end }}
// [Z], the commitment to the grand product polynomial
calldatacopy(_mPtr, add(aproof, PROOF_GRAND_PRODUCT_COMMITMENT_X), 0x40)
let l_success := staticcall(gas(), 0x2, add(mPtr, 0x1b), full_size, mPtr, 0x20)
if iszero(l_success) {
error_verify()
}
alpha_not_reduced := mload(mPtr)
mstore(add(state, STATE_ALPHA), mod(alpha_not_reduced, R_MOD))
}
/// derive zeta as sha256<transcript>
/// @param aproof pointer to the proof object
/// @param alpha_not_reduced the previous challenge (alpha) not reduced
/// The transcript consists of the previous challenge and the commitment to
/// the quotient polynomial h.
function derive_zeta(aproof, alpha_not_reduced) {
let state := mload(0x40)
let mPtr := add(mload(0x40), STATE_LAST_MEM)
// zeta
mstore(mPtr, 0x7a657461) // "zeta"
mstore(add(mPtr, 0x20), alpha_not_reduced)
calldatacopy(add(mPtr, 0x40), add(aproof, PROOF_H_0_X), 0xc0)
let l_success := staticcall(gas(), 0x2, add(mPtr, 0x1c), 0xe4, mPtr, 0x20)
if iszero(l_success) {
error_verify()
}
let zeta_not_reduced := mload(mPtr)
mstore(add(state, STATE_ZETA), mod(zeta_not_reduced, R_MOD))
}
// END challenges -------------------------------------------------
// BEGINNING compute_pi -------------------------------------------------
/// sum_pi_wo_api_commit computes the public inputs contributions,
/// except for the public inputs coming from the custom gate
/// @param ins pointer to the public inputs
/// @param n number of public inputs
/// @param mPtr free memory
/// @return pi_wo_commit public inputs contribution (except the public inputs coming from the custom gate)
function sum_pi_wo_api_commit(ins, n, mPtr)->pi_wo_commit {
let state := mload(0x40)
let z := mload(add(state, STATE_ZETA))
let zpnmo := mload(add(state, STATE_ZETA_POWER_N_MINUS_ONE))
let li := mPtr
batch_compute_lagranges_at_z(z, zpnmo, n, li)
let tmp := 0
for {let i:=0} lt(i,n) {i:=add(i,1)}
{
tmp := mulmod(mload(li), calldataload(ins), R_MOD)
pi_wo_commit := addmod(pi_wo_commit, tmp, R_MOD)
li := add(li, 0x20)
ins := add(ins, 0x20)
}
}
/// batch_compute_lagranges_at_z computes [L_0(z), .., L_{n-1}(z)]
/// @param z point at which the Lagranges are evaluated
/// @param zpnmo ζⁿ-1
/// @param n number of public inputs (number of Lagranges to compute)
/// @param mPtr pointer to which the results are stored
function batch_compute_lagranges_at_z(z, zpnmo, n, mPtr) {
let zn := mulmod(zpnmo, VK_INV_DOMAIN_SIZE, R_MOD) // 1/n * (ζⁿ - 1)
let _w := 1
let _mPtr := mPtr
for {let i:=0} lt(i,n) {i:=add(i,1)}
{
mstore(_mPtr, addmod(z,sub(R_MOD, _w), R_MOD))
_w := mulmod(_w, VK_OMEGA, R_MOD)
_mPtr := add(_mPtr, 0x20)
}
batch_invert(mPtr, n, _mPtr)
_mPtr := mPtr
_w := 1
for {let i:=0} lt(i,n) {i:=add(i,1)}
{
mstore(_mPtr, mulmod(mulmod(mload(_mPtr), zn , R_MOD), _w, R_MOD))
_mPtr := add(_mPtr, 0x20)
_w := mulmod(_w, VK_OMEGA, R_MOD)
}
}
/// @notice Montgomery trick for batch inversion mod R_MOD
/// @param ins pointer to the data to batch invert
/// @param number of elements to batch invert
/// @param mPtr free memory
function batch_invert(ins, nb_ins, mPtr) {
mstore(mPtr, 1)
let offset := 0
for {let i:=0} lt(i, nb_ins) {i:=add(i,1)}
{
let prev := mload(add(mPtr, offset))
let cur := mload(add(ins, offset))
cur := mulmod(prev, cur, R_MOD)
offset := add(offset, 0x20)
mstore(add(mPtr, offset), cur)
}
ins := add(ins, sub(offset, 0x20))
mPtr := add(mPtr, offset)
let inv := pow(mload(mPtr), sub(R_MOD,2), add(mPtr, 0x20))
for {let i:=0} lt(i, nb_ins) {i:=add(i,1)}
{
mPtr := sub(mPtr, 0x20)
let tmp := mload(ins)
let cur := mulmod(inv, mload(mPtr), R_MOD)
mstore(ins, cur)
inv := mulmod(inv, tmp, R_MOD)
ins := sub(ins, 0x20)
}
}
{{ if (gt (len .CommitmentConstraintIndexes) 0 )}}
/// Public inputs (the ones coming from the custom gate) contribution
/// @param aproof pointer to the proof
/// @param nb_public_inputs number of public inputs
/// @param mPtr pointer to free memory
/// @return pi_commit custom gate public inputs contribution
function sum_pi_commit(aproof, nb_public_inputs, mPtr)->pi_commit {
let state := mload(0x40)
let z := mload(add(state, STATE_ZETA))
let zpnmo := mload(add(state, STATE_ZETA_POWER_N_MINUS_ONE))
let p := add(aproof, PROOF_COMMITMENTS_WIRES_CUSTOM_GATES)
let h_fr, ith_lagrange
{{ range $index, $element := .CommitmentConstraintIndexes}}
h_fr := hash_fr(calldataload(p), calldataload(add(p, 0x20)), mPtr)
ith_lagrange := compute_ith_lagrange_at_z(z, zpnmo, add(nb_public_inputs, VK_INDEX_COMMIT_API{{ $index }}), mPtr)
pi_commit := addmod(pi_commit, mulmod(h_fr, ith_lagrange, R_MOD), R_MOD)
p := add(p, 0x40)
{{ end }}
}
/// Computes L_i(zeta) = ωⁱ/n * (ζⁿ-1)/(ζ-ωⁱ) where:
/// @param z zeta
/// @param zpmno ζⁿ-1
/// @param i i-th lagrange
/// @param mPtr free memory
/// @return res = ωⁱ/n * (ζⁿ-1)/(ζ-ωⁱ)
function compute_ith_lagrange_at_z(z, zpnmo, i, mPtr)->res {
let w := pow(VK_OMEGA, i, mPtr) // w**i
i := addmod(z, sub(R_MOD, w), R_MOD) // z-w**i
w := mulmod(w, VK_INV_DOMAIN_SIZE, R_MOD) // w**i/n
i := pow(i, sub(R_MOD,2), mPtr) // (z-w**i)**-1
w := mulmod(w, i, R_MOD) // w**i/n*(z-w)**-1
res := mulmod(w, zpnmo, R_MOD)
}
/// @dev https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-06#section-5.2
/// @param x x coordinate of a point on Bn254(𝔽_p)
/// @param y y coordinate of a point on Bn254(𝔽_p)
/// @param mPtr free memory
/// @return res an element mod R_MOD
function hash_fr(x, y, mPtr)->res {
// [0x00, .. , 0x00 || x, y, || 0, 48, 0, dst, HASH_FR_SIZE_DOMAIN]
// <- 64 bytes -> <-64b -> <- 1 bytes each ->
// [0x00, .., 0x00] 64 bytes of zero
mstore(mPtr, HASH_FR_ZERO_UINT256)
mstore(add(mPtr, 0x20), HASH_FR_ZERO_UINT256)
// msg = x || y , both on 32 bytes
mstore(add(mPtr, 0x40), x)
mstore(add(mPtr, 0x60), y)
// 0 || 48 || 0 all on 1 byte
mstore8(add(mPtr, 0x80), 0)
mstore8(add(mPtr, 0x81), HASH_FR_LEN_IN_BYTES)
mstore8(add(mPtr, 0x82), 0)
// "BSB22-Plonk" = [42, 53, 42, 32, 32, 2d, 50, 6c, 6f, 6e, 6b,]
mstore8(add(mPtr, 0x83), 0x42)
mstore8(add(mPtr, 0x84), 0x53)
mstore8(add(mPtr, 0x85), 0x42)
mstore8(add(mPtr, 0x86), 0x32)
mstore8(add(mPtr, 0x87), 0x32)
mstore8(add(mPtr, 0x88), 0x2d)
mstore8(add(mPtr, 0x89), 0x50)
mstore8(add(mPtr, 0x8a), 0x6c)
mstore8(add(mPtr, 0x8b), 0x6f)
mstore8(add(mPtr, 0x8c), 0x6e)
mstore8(add(mPtr, 0x8d), 0x6b)
// size domain
mstore8(add(mPtr, 0x8e), HASH_FR_SIZE_DOMAIN)
let l_success := staticcall(gas(), 0x2, mPtr, 0x8f, mPtr, 0x20)
if iszero(l_success) {
error_verify()
}
let b0 := mload(mPtr)
// [b0 || one || dst || HASH_FR_SIZE_DOMAIN]
// <-64bytes -> <- 1 byte each ->
mstore8(add(mPtr, 0x20), HASH_FR_ONE) // 1
mstore8(add(mPtr, 0x21), 0x42) // dst
mstore8(add(mPtr, 0x22), 0x53)
mstore8(add(mPtr, 0x23), 0x42)
mstore8(add(mPtr, 0x24), 0x32)
mstore8(add(mPtr, 0x25), 0x32)
mstore8(add(mPtr, 0x26), 0x2d)
mstore8(add(mPtr, 0x27), 0x50)
mstore8(add(mPtr, 0x28), 0x6c)
mstore8(add(mPtr, 0x29), 0x6f)
mstore8(add(mPtr, 0x2a), 0x6e)
mstore8(add(mPtr, 0x2b), 0x6b)
mstore8(add(mPtr, 0x2c), HASH_FR_SIZE_DOMAIN) // size domain
l_success := staticcall(gas(), 0x2, mPtr, 0x2d, mPtr, 0x20)
if iszero(l_success) {
error_verify()
}
// b1 is located at mPtr. We store b2 at add(mPtr, 0x20)
// [b0^b1 || two || dst || HASH_FR_SIZE_DOMAIN]
// <-64bytes -> <- 1 byte each ->
mstore(add(mPtr, 0x20), xor(mload(mPtr), b0))
mstore8(add(mPtr, 0x40), HASH_FR_TWO)
mstore8(add(mPtr, 0x41), 0x42) // dst
mstore8(add(mPtr, 0x42), 0x53)
mstore8(add(mPtr, 0x43), 0x42)
mstore8(add(mPtr, 0x44), 0x32)
mstore8(add(mPtr, 0x45), 0x32)
mstore8(add(mPtr, 0x46), 0x2d)
mstore8(add(mPtr, 0x47), 0x50)
mstore8(add(mPtr, 0x48), 0x6c)
mstore8(add(mPtr, 0x49), 0x6f)
mstore8(add(mPtr, 0x4a), 0x6e)
mstore8(add(mPtr, 0x4b), 0x6b)
mstore8(add(mPtr, 0x4c), HASH_FR_SIZE_DOMAIN) // size domain
let offset := add(mPtr, 0x20)
l_success := staticcall(gas(), 0x2, offset, 0x2d, offset, 0x20)
if iszero(l_success) {
error_verify()
}
// at this point we have mPtr = [ b1 || b2] where b1 is on 32byes and b2 in 16bytes.
// we interpret it as a big integer mod r in big endian (similar to regular decimal notation)
// the result is then 2**(8*16)*mPtr[32:] + mPtr[32:48]
res := mulmod(mload(mPtr), HASH_FR_BB, R_MOD) // <- res = 2**128 * mPtr[:32]
let b1 := shr(128, mload(add(mPtr, 0x20))) // b1 <- [0, 0, .., 0 || b2[:16] ]
res := addmod(res, b1, R_MOD)
}
{{ end }}
// END compute_pi -------------------------------------------------
/// @notice compute α² * 1/n * (ζ{n}-1)/(ζ - 1) where
/// * α = challenge derived in derive_gamma_beta_alpha_zeta
/// * n = vk_domain_size
/// * ω = vk_omega (generator of the multiplicative cyclic group of order n in (ℤ/rℤ)*)
/// * ζ = zeta (challenge derived with Fiat Shamir)
function compute_alpha_square_lagrange_0() {
let state := mload(0x40)
let mPtr := add(mload(0x40), STATE_LAST_MEM)
let res := mload(add(state, STATE_ZETA_POWER_N_MINUS_ONE))
let den := addmod(mload(add(state, STATE_ZETA)), sub(R_MOD, 1), R_MOD)
den := pow(den, sub(R_MOD, 2), mPtr)
den := mulmod(den, VK_INV_DOMAIN_SIZE, R_MOD)
res := mulmod(den, res, R_MOD)
let l_alpha := mload(add(state, STATE_ALPHA))
res := mulmod(res, l_alpha, R_MOD)
res := mulmod(res, l_alpha, R_MOD)
mstore(add(state, STATE_ALPHA_SQUARE_LAGRANGE_0), res)
}
/// @notice follows alg. p.13 of https://eprint.iacr.org/2019/953.pdf
/// with t₁ = t₂ = 1, and the proofs are ([digest] + [quotient] +purported evaluation):
/// * [state_folded_state_digests], [proof_batch_opening_at_zeta_x], state_folded_evals
/// * [proof_grand_product_commitment], [proof_opening_at_zeta_omega_x], [proof_grand_product_at_zeta_omega]
/// @param aproof pointer to the proof
function batch_verify_multi_points(aproof) {
let state := mload(0x40)
let mPtr := add(state, STATE_LAST_MEM)
// derive a random number. As there is no random generator, we
// do an FS like challenge derivation, depending on both digests and
// ζ to ensure that the prover cannot control the random numger.
// Note: adding the other point ζω is not needed, as ω is known beforehand.
mstore(mPtr, mload(add(state, STATE_FOLDED_DIGESTS_X)))
mstore(add(mPtr, 0x20), mload(add(state, STATE_FOLDED_DIGESTS_Y)))
mstore(add(mPtr, 0x40), calldataload(add(aproof, PROOF_BATCH_OPENING_AT_ZETA_X)))
mstore(add(mPtr, 0x60), calldataload(add(aproof, PROOF_BATCH_OPENING_AT_ZETA_Y)))
mstore(add(mPtr, 0x80), calldataload(add(aproof, PROOF_GRAND_PRODUCT_COMMITMENT_X)))
mstore(add(mPtr, 0xa0), calldataload(add(aproof, PROOF_GRAND_PRODUCT_COMMITMENT_Y)))
mstore(add(mPtr, 0xc0), calldataload(add(aproof, PROOF_OPENING_AT_ZETA_OMEGA_X)))
mstore(add(mPtr, 0xe0), calldataload(add(aproof, PROOF_OPENING_AT_ZETA_OMEGA_Y)))
mstore(add(mPtr, 0x100), mload(add(state, STATE_ZETA)))
mstore(add(mPtr, 0x120), mload(add(state, STATE_GAMMA_KZG)))
let random := staticcall(gas(), 0x2, mPtr, 0x140, mPtr, 0x20)
if iszero(random){
error_random_generation()
}
random := mod(mload(mPtr), R_MOD) // use the same variable as we are one variable away from getting stack-too-deep error...
let folded_quotients := mPtr
mPtr := add(folded_quotients, 0x40)
mstore(folded_quotients, calldataload(add(aproof, PROOF_BATCH_OPENING_AT_ZETA_X)))
mstore(add(folded_quotients, 0x20), calldataload(add(aproof, PROOF_BATCH_OPENING_AT_ZETA_Y)))
point_acc_mul_calldata(folded_quotients, add(aproof, PROOF_OPENING_AT_ZETA_OMEGA_X), random, mPtr)
let folded_digests := add(state, STATE_FOLDED_DIGESTS_X)
point_acc_mul_calldata(folded_digests, add(aproof, PROOF_GRAND_PRODUCT_COMMITMENT_X), random, mPtr)
let folded_evals := add(state, STATE_FOLDED_CLAIMED_VALUES)
fr_acc_mul_calldata(folded_evals, add(aproof, PROOF_GRAND_PRODUCT_AT_ZETA_OMEGA), random)
let folded_evals_commit := mPtr
mPtr := add(folded_evals_commit, 0x40)
mstore(folded_evals_commit, G1_SRS_X)
mstore(add(folded_evals_commit, 0x20), G1_SRS_Y)
mstore(add(folded_evals_commit, 0x40), mload(folded_evals))
let check_staticcall := staticcall(gas(), 7, folded_evals_commit, 0x60, folded_evals_commit, 0x40)
if iszero(check_staticcall) {
error_verify()
}
let folded_evals_commit_y := add(folded_evals_commit, 0x20)
mstore(folded_evals_commit_y, sub(P_MOD, mload(folded_evals_commit_y)))
point_add(folded_digests, folded_digests, folded_evals_commit, mPtr)
let folded_points_quotients := mPtr
mPtr := add(mPtr, 0x40)
point_mul_calldata(
folded_points_quotients,
add(aproof, PROOF_BATCH_OPENING_AT_ZETA_X),
mload(add(state, STATE_ZETA)),
mPtr
)
let zeta_omega := mulmod(mload(add(state, STATE_ZETA)), VK_OMEGA, R_MOD)
random := mulmod(random, zeta_omega, R_MOD)
point_acc_mul_calldata(folded_points_quotients, add(aproof, PROOF_OPENING_AT_ZETA_OMEGA_X), random, mPtr)
point_add(folded_digests, folded_digests, folded_points_quotients, mPtr)
let folded_quotients_y := add(folded_quotients, 0x20)
mstore(folded_quotients_y, sub(P_MOD, mload(folded_quotients_y)))
mstore(mPtr, mload(folded_digests))
mstore(add(mPtr, 0x20), mload(add(folded_digests, 0x20)))
mstore(add(mPtr, 0x40), G2_SRS_0_X_0) // the 4 lines are the canonical G2 point on BN254
mstore(add(mPtr, 0x60), G2_SRS_0_X_1)
mstore(add(mPtr, 0x80), G2_SRS_0_Y_0)
mstore(add(mPtr, 0xa0), G2_SRS_0_Y_1)
mstore(add(mPtr, 0xc0), mload(folded_quotients))
mstore(add(mPtr, 0xe0), mload(add(folded_quotients, 0x20)))
mstore(add(mPtr, 0x100), G2_SRS_1_X_0)
mstore(add(mPtr, 0x120), G2_SRS_1_X_1)
mstore(add(mPtr, 0x140), G2_SRS_1_Y_0)
mstore(add(mPtr, 0x160), G2_SRS_1_Y_1)
check_pairing_kzg(mPtr)
}
/// @notice check_pairing_kzg checks the result of the final pairing product of the batched
/// kzg verification. The purpose of this function is to avoid exhausting the stack
/// in the function batch_verify_multi_points.
/// @param mPtr pointer storing the tuple of pairs
function check_pairing_kzg(mPtr) {
let state := mload(0x40)
// TODO test the staticcall using the method from audit_4-5
let l_success := staticcall(gas(), 8, mPtr, 0x180, 0x00, 0x20)
let res_pairing := mload(0x00)
let s_success := mload(add(state, STATE_SUCCESS))
res_pairing := and(and(res_pairing, l_success), s_success)
mstore(add(state, STATE_SUCCESS), res_pairing)
}
/// @notice Fold the opening proofs at ζ:
/// * at state+state_folded_digest we store: [H] + γ[Linearised_polynomial]+γ²[L] + γ³[R] + γ⁴[O] + γ⁵[S₁] +γ⁶[S₂] + ∑ᵢγ⁶⁺ⁱ[Pi_{i}]
/// * at state+state_folded_claimed_values we store: H(ζ) + γLinearised_polynomial(ζ)+γ²L(ζ) + γ³R(ζ)+ γ⁴O(ζ) + γ⁵S₁(ζ) +γ⁶S₂(ζ) + ∑ᵢγ⁶⁺ⁱPi_{i}(ζ)
/// @param aproof pointer to the proof
/// acc_gamma stores the γⁱ
function fold_state(aproof) {
let state := mload(0x40)
let mPtr := add(mload(0x40), STATE_LAST_MEM)
let mPtr20 := add(mPtr, 0x20)
let mPtr40 := add(mPtr, 0x40)
let l_gamma_kzg := mload(add(state, STATE_GAMMA_KZG))
let acc_gamma := l_gamma_kzg
let state_folded_digests := add(state, STATE_FOLDED_DIGESTS_X)
mstore(add(state, STATE_FOLDED_DIGESTS_X), mload(add(state, STATE_FOLDED_H_X)))
mstore(add(state, STATE_FOLDED_DIGESTS_Y), mload(add(state, STATE_FOLDED_H_Y)))
mstore(add(state, STATE_FOLDED_CLAIMED_VALUES), calldataload(add(aproof, PROOF_QUOTIENT_POLYNOMIAL_AT_ZETA)))
point_acc_mul(state_folded_digests, add(state, STATE_LINEARISED_POLYNOMIAL_X), acc_gamma, mPtr)
fr_acc_mul_calldata(add(state, STATE_FOLDED_CLAIMED_VALUES), add(aproof, PROOF_LINEARISED_POLYNOMIAL_AT_ZETA), acc_gamma)
acc_gamma := mulmod(acc_gamma, l_gamma_kzg, R_MOD)
point_acc_mul_calldata(add(state, STATE_FOLDED_DIGESTS_X), add(aproof, PROOF_L_COM_X), acc_gamma, mPtr)
fr_acc_mul_calldata(add(state, STATE_FOLDED_CLAIMED_VALUES), add(aproof, PROOF_L_AT_ZETA), acc_gamma)
acc_gamma := mulmod(acc_gamma, l_gamma_kzg, R_MOD)
point_acc_mul_calldata(state_folded_digests, add(aproof, PROOF_R_COM_X), acc_gamma, mPtr)
fr_acc_mul_calldata(add(state, STATE_FOLDED_CLAIMED_VALUES), add(aproof, PROOF_R_AT_ZETA), acc_gamma)
acc_gamma := mulmod(acc_gamma, l_gamma_kzg, R_MOD)
point_acc_mul_calldata(state_folded_digests, add(aproof, PROOF_O_COM_X), acc_gamma, mPtr)
fr_acc_mul_calldata(add(state, STATE_FOLDED_CLAIMED_VALUES), add(aproof, PROOF_O_AT_ZETA), acc_gamma)
acc_gamma := mulmod(acc_gamma, l_gamma_kzg, R_MOD)
mstore(mPtr, VK_S1_COM_X)
mstore(mPtr20, VK_S1_COM_Y)
point_acc_mul(state_folded_digests, mPtr, acc_gamma, mPtr40)
fr_acc_mul_calldata(add(state, STATE_FOLDED_CLAIMED_VALUES), add(aproof, PROOF_S1_AT_ZETA), acc_gamma)
acc_gamma := mulmod(acc_gamma, l_gamma_kzg, R_MOD)
mstore(mPtr, VK_S2_COM_X)
mstore(mPtr20, VK_S2_COM_Y)
point_acc_mul(state_folded_digests, mPtr, acc_gamma, mPtr40)
fr_acc_mul_calldata(add(state, STATE_FOLDED_CLAIMED_VALUES), add(aproof, PROOF_S2_AT_ZETA), acc_gamma)
{{- if (gt (len .CommitmentConstraintIndexes) 0 ) }}
let poscaz := add(aproof, PROOF_OPENING_QCP_AT_ZETA)
{{ end -}}
{{ range $index, $element := .CommitmentConstraintIndexes }}
acc_gamma := mulmod(acc_gamma, l_gamma_kzg, R_MOD)
mstore(mPtr, VK_QCP_{{ $index }}_X)
mstore(mPtr20, VK_QCP_{{ $index }}_Y)
point_acc_mul(state_folded_digests, mPtr, acc_gamma, mPtr40)
fr_acc_mul_calldata(add(state, STATE_FOLDED_CLAIMED_VALUES), poscaz, acc_gamma)
poscaz := add(poscaz, 0x20)
{{ end }}
}
/// @notice generate the challenge (using Fiat Shamir) to fold the opening proofs
/// at ζ.
/// The process for deriving γ is the same as in derive_gamma but this time the inputs are
/// in this order (the [] means it's a commitment):
/// * ζ
/// * [H] ( = H₁ + ζᵐ⁺²*H₂ + ζ²⁽ᵐ⁺²⁾*H₃ )
/// * [Linearised polynomial]
/// * [L], [R], [O]
/// * [S₁] [S₂]
/// * [Pi_{i}] (wires associated to custom gates)
/// Then there are the purported evaluations of the previous committed polynomials:
/// * H(ζ)
/// * Linearised_polynomial(ζ)
/// * L(ζ), R(ζ), O(ζ), S₁(ζ), S₂(ζ)
/// * Pi_{i}(ζ)
/// * Z(ζω)
/// @param aproof pointer to the proof
function compute_gamma_kzg(aproof) {
let state := mload(0x40)
let mPtr := add(mload(0x40), STATE_LAST_MEM)
mstore(mPtr, 0x67616d6d61) // "gamma"
mstore(add(mPtr, 0x20), mload(add(state, STATE_ZETA)))
mstore(add(mPtr,0x40), mload(add(state, STATE_FOLDED_H_X)))
mstore(add(mPtr,0x60), mload(add(state, STATE_FOLDED_H_Y)))
mstore(add(mPtr,0x80), mload(add(state, STATE_LINEARISED_POLYNOMIAL_X)))
mstore(add(mPtr,0xa0), mload(add(state, STATE_LINEARISED_POLYNOMIAL_Y)))
calldatacopy(add(mPtr, 0xc0), add(aproof, PROOF_L_COM_X), 0xc0)
mstore(add(mPtr,0x180), VK_S1_COM_X)
mstore(add(mPtr,0x1a0), VK_S1_COM_Y)
mstore(add(mPtr,0x1c0), VK_S2_COM_X)
mstore(add(mPtr,0x1e0), VK_S2_COM_Y)
let offset := 0x200
{{ range $index, $element := .CommitmentConstraintIndexes }}
mstore(add(mPtr,offset), VK_QCP_{{ $index }}_X)
mstore(add(mPtr,add(offset, 0x20)), VK_QCP_{{ $index }}_Y)
offset := add(offset, 0x40)