├── README.md
├── circuit
├── Nargo.toml
├── contract
│ └── circuit
│ │ └── plonk_vk.sol
├── src
│ └── main.nr
└── target
│ ├── circuit.json
│ └── debug_circuit.json
├── contracts
└── CommentVerifier.sol
├── relayer
├── .env.example
├── .gitignore
├── json_abi
│ └── CommentVerifier.json
├── package-lock.json
├── package.json
└── relayer.js
├── screenshot.png
└── webapp
├── .env.example
├── .gitignore
├── app.js
├── index.html
├── json_abi
└── CommentVerifier.json
├── package-lock.json
├── package.json
└── vite.config.js
/README.md:
--------------------------------------------------------------------------------
1 | # ⚠️Not maintained anymore, migrated [here](https://github.com/Turupawn/EcrecoverInclusionProof)⚠️
2 |
3 | # On-chain Privacy DApp Demo
4 |
5 | This demo showcases all the parts needed to create a privacy preserving DApp with good UX which are:
6 | * A circuit
7 | * A smart contract
8 | * A relayer
9 | * A webapp
10 |
11 | On this example we do a simple anonymous message board but it can be extended for other DApps in other fields such as DeFi, voting & governance, identity, etc..
12 |
13 | 
14 |
15 | ## ⭐Features
16 |
17 | | Feature | Supported |
18 | |----------|------------ |
19 | | Aztec Noir circuit | ✅ |
20 | | Solidity verifier | ✅ |
21 | | ECDSA verification circuit | ✅ |
22 | | EIP712 enabled | ✅ |
23 | | Prover on browser (WASM) | ✅ |
24 | | Ethers.js 6.9 relayer | ✅ |
25 | | MIT license | ✅ |
26 |
27 | ## 🚀How to launch
28 |
29 | ### Step 1. Generate and deploy the Solidity verifier
30 |
31 | Make sure you installed Nargo `0.19.4` as detailed below:
32 |
33 |
34 | On Linux
35 |
36 | ```bash
37 | mkdir -p $HOME/.nargo/bin && \
38 | curl -o $HOME/.nargo/bin/nargo-x86_64-unknown-linux-gnu.tar.gz -L https://github.com/noir-lang/noir/releases/download/v0.19.4/nargo-x86_64-unknown-linux-gnu.tar.gz && \
39 | tar -xvf $HOME/.nargo/bin/nargo-x86_64-unknown-linux-gnu.tar.gz -C $HOME/.nargo/bin/ && \
40 | echo 'export PATH=$PATH:$HOME/.nargo/bin' >> ~/.bashrc && \
41 | source ~/.bashrc
42 | ```
43 |
44 |
45 |
46 | On MAC
47 |
48 | ```bash
49 | mkdir -p $HOME/.nargo/bin && \
50 | curl -o $HOME/.nargo/bin/nargo-x86_64-apple-darwin.tar.gz -L https://github.com/noir-lang/noir/releases/download/v0.19.4/nargo-x86_64-apple-darwin.tar.gz && \
51 | tar -xvf $HOME/.nargo/bin/nargo-x86_64-apple-darwin.tar.gz -C $HOME/.nargo/bin/ && \
52 | echo '\nexport PATH=$PATH:$HOME/.nargo/bin' >> ~/.zshrc && \
53 | source ~/.zshrc
54 | ```
55 |
56 |
57 | Now generate the Solidity verifier.
58 |
59 | ```bash
60 | cd circuit
61 | nargo codegen-verifier
62 | ```
63 |
64 | This will generate a Solidity file located at `circuit/contract/circuit/plonk_vk.sol`. Deploy it on an EVM on-chain.
65 |
66 | ### Step 2. Deploy the verifier contract
67 |
68 | Now deploy the `CommentVerifier` contract located at `contracts/CommentVerifier.sol`. Pass the Verifier contract you just generated as constructor parameter.
69 |
70 | ### Step 3. Launch the Relayer
71 |
72 | Let's launch the relayer first. Fill the `.env` file based on `.env.example` on the `relayer/` directory and run the following.
73 |
74 | ```bash
75 | cd relayer
76 | npm install
77 | npm start
78 | ```
79 |
80 | ### Setp 4. Launch the webapp and verify a proof
81 |
82 | Open a new terminal and launch the webapp. Now fill the `.env` file based on `.env.example` on the `webapp/`, the run the following.
83 |
84 | ```bash
85 | cd webapp
86 | npm install
87 | npm start
88 | ```
89 |
90 | The webapp will automatically open on your browser. Now you will be able to generate proofs on your browser and send them to the relayer for on-chain verification.
91 |
92 | ## ⚠️Known issues (PRs welcome)
93 |
94 | * We need to compress the hashed message params to reduce L1 fees on L2s. We should use [this](https://github.com/Bank-of-JubJub/base/blob/2a0247a441463a6619cc8d5f13d81717d166b770/hardhat/contracts/UsingAccountControllers.sol#L158) and [this](https://github.com/Bank-of-JubJub/base/blob/master/circuits/change_eth_signer/src/main.nr)
95 |
--------------------------------------------------------------------------------
/circuit/Nargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "circuit"
3 | type = "bin"
4 | authors = [""]
5 | compiler_version = "0.19.4"
6 |
7 | [dependencies]
--------------------------------------------------------------------------------
/circuit/contract/circuit/plonk_vk.sol:
--------------------------------------------------------------------------------
1 | // Verification Key Hash: 457c7abc3bffd9c93470754f3ad9e49570fcd18b745ded4cc82d15acd36ba10f
2 | // SPDX-License-Identifier: Apache-2.0
3 | // Copyright 2022 Aztec
4 | pragma solidity >=0.8.4;
5 |
6 | library UltraVerificationKey {
7 | function verificationKeyHash() internal pure returns(bytes32) {
8 | return 0x457c7abc3bffd9c93470754f3ad9e49570fcd18b745ded4cc82d15acd36ba10f;
9 | }
10 |
11 | function loadVerificationKey(uint256 _vk, uint256 _omegaInverseLoc) internal pure {
12 | assembly {
13 | mstore(add(_vk, 0x00), 0x0000000000000000000000000000000000000000000000000000000000010000) // vk.circuit_size
14 | mstore(add(_vk, 0x20), 0x0000000000000000000000000000000000000000000000000000000000000020) // vk.num_inputs
15 | mstore(add(_vk, 0x40), 0x00eeb2cb5981ed45649abebde081dcff16c8601de4347e7dd1628ba2daac43b7) // vk.work_root
16 | mstore(add(_vk, 0x60), 0x30641e0e92bebef818268d663bcad6dbcfd6c0149170f6d7d350b1b1fa6c1001) // vk.domain_inverse
17 | mstore(add(_vk, 0x80), 0x108d4f3cdfafd42ec771f87cd087eee2c48cf817a945e0e97af440c4931750cf) // vk.Q1.x
18 | mstore(add(_vk, 0xa0), 0x0e20c16ebcf4d9b67fa256442cf7be89d014ec70f5987b22a9ea96253cf8a919) // vk.Q1.y
19 | mstore(add(_vk, 0xc0), 0x25d896eae69ba90acc3de581b20ca089a08f2fa0bb9a4ee2a1138e2d72534ab7) // vk.Q2.x
20 | mstore(add(_vk, 0xe0), 0x17f781d2b70ac428782716a0e1c1383bbe80cee8a89d26371d766ba7b915adb9) // vk.Q2.y
21 | mstore(add(_vk, 0x100), 0x20b7896d57e7a4ee3f34d7b435d5e2e2f710b0f8b8ebf9393ce39eded1e10c37) // vk.Q3.x
22 | mstore(add(_vk, 0x120), 0x285b48100ee0187be624e861f1ff7a2c98b649f7ad6ef9ced99192b9b6d0632e) // vk.Q3.y
23 | mstore(add(_vk, 0x140), 0x21d0968189c2449cfb641fc32810af036146156ce79674b105d399973fd3e19b) // vk.Q4.x
24 | mstore(add(_vk, 0x160), 0x24a75c0f6ed1ef3dc7e6fce31809d1c9824b515f6fb9ddcbf0a9991667d313bd) // vk.Q4.y
25 | mstore(add(_vk, 0x180), 0x23fcfe2c41069bdba6019609571bcc029261e67e2b7e7d53f4e7fd6869c3e9f1) // vk.Q_M.x
26 | mstore(add(_vk, 0x1a0), 0x1a4b515b855b38067ca2dec6528088c46ded7538d524c8fd7f2baab1cabca74a) // vk.Q_M.y
27 | mstore(add(_vk, 0x1c0), 0x205c12bdb88ed3205a0723e1adfc91ceaafac7d0d3c176dc959788fa9b6e9745) // vk.Q_C.x
28 | mstore(add(_vk, 0x1e0), 0x02dfe447d0c6653218054d0d4d0c2252fb567672975ae76a8dbc971959ef61d3) // vk.Q_C.y
29 | mstore(add(_vk, 0x200), 0x2a03ec59509fa399be2c1b9e24b56a1a3e63ae6aa66640349c4852cad93e06ee) // vk.Q_ARITHMETIC.x
30 | mstore(add(_vk, 0x220), 0x026fbbb98e200421811825cccef4b1384ad004a349035a0b1ffc088ba54f12e6) // vk.Q_ARITHMETIC.y
31 | mstore(add(_vk, 0x240), 0x060f5ed4ff5ee5d867e6a328fa5bbb97617202677923e3c93c3a1f62158495df) // vk.QSORT.x
32 | mstore(add(_vk, 0x260), 0x06908e96cb3f7e7796d970ab0f2f25234540658291cc53e16831c12cbdad5195) // vk.QSORT.y
33 | mstore(add(_vk, 0x280), 0x21245d6c0a4d2ff12b21a825f39f30e8f8cf9b259448d111183e975828539576) // vk.Q_ELLIPTIC.x
34 | mstore(add(_vk, 0x2a0), 0x16a409532c8a1693536e93b6ce9920bfc2e6796e8dfe404675a0cdf6ee77ee7a) // vk.Q_ELLIPTIC.y
35 | mstore(add(_vk, 0x2c0), 0x18e60c34b949ff280b9235cc41eaccb233ac66bdfa3a2a575788513a26d80b95) // vk.Q_AUX.x
36 | mstore(add(_vk, 0x2e0), 0x22cb3abd7f72f5e97f8234ea41dc793fa8953a104482a832725765582e6848e9) // vk.Q_AUX.y
37 | mstore(add(_vk, 0x300), 0x01788136a6ba924bbdf04ad0c1de1a0351ae089dba8035aa40e670673a84eb64) // vk.SIGMA1.x
38 | mstore(add(_vk, 0x320), 0x06573b2e8088659550771d93a366587edffc7423d4009fdaa3102204b9cb54ec) // vk.SIGMA1.y
39 | mstore(add(_vk, 0x340), 0x14260e2a7ac353f00a01de9ea6e5aa572772ff70dcf77af24afb421b2147188e) // vk.SIGMA2.x
40 | mstore(add(_vk, 0x360), 0x005b4eb7779137fa90c0a45fa14331ac71d167fa674eef01547a2939e0499c43) // vk.SIGMA2.y
41 | mstore(add(_vk, 0x380), 0x019a7ad0b7b511889f2729c51e769be7beff803a632d267403da32327508a137) // vk.SIGMA3.x
42 | mstore(add(_vk, 0x3a0), 0x04f7648d9e8ad203a38c39e268ca1a17714f2cc4d609fdaacb601a936c8a2cba) // vk.SIGMA3.y
43 | mstore(add(_vk, 0x3c0), 0x11b8da2236efce2203b3c96e6cd2436306dd8ef5e8b020ddd9472b023faadab4) // vk.SIGMA4.x
44 | mstore(add(_vk, 0x3e0), 0x2e0bb47a65bd603ba5349c19277b8fc01cd3e82677f510e5667c586ebe07541d) // vk.SIGMA4.y
45 | mstore(add(_vk, 0x400), 0x06e6d1480535f6e29a6713cd5c4e668464cbdac425322b2d3b98a34e8834c14f) // vk.TABLE1.x
46 | mstore(add(_vk, 0x420), 0x15c1b7ea4800a867676fc4c79695b5b27b0e702d7d6188d0ad0259936cb3e55f) // vk.TABLE1.y
47 | mstore(add(_vk, 0x440), 0x030b16cd4d48e7b40d2ac90b515369aabc0c273bd7c77f122e9993c2251f7f4a) // vk.TABLE2.x
48 | mstore(add(_vk, 0x460), 0x07578950db871ef62bab02e94473298e53701113cc0c09573d1ccdbb99ab49b7) // vk.TABLE2.y
49 | mstore(add(_vk, 0x480), 0x1bbfe736b28dc8ede22ad6ba3ecec3607de18a29cee6828a7303d33ceb1e2ef0) // vk.TABLE3.x
50 | mstore(add(_vk, 0x4a0), 0x2e0a348344704012f149db2aed39ea37d1fe96d4d91f803026f17ed9a0449907) // vk.TABLE3.y
51 | mstore(add(_vk, 0x4c0), 0x273714e498d7ee7471cf8859c5db4113e86f6acee195b29fd0e5953728135962) // vk.TABLE4.x
52 | mstore(add(_vk, 0x4e0), 0x2997e7f0a5012a52da8388d912ce58fffbab8f6b5d56b6c289ab367fd72f242a) // vk.TABLE4.y
53 | mstore(add(_vk, 0x500), 0x0778f9f2ccf80ad63301b1dc3c794b38b3cdbee200766df7d35b373acb6da798) // vk.TABLE_TYPE.x
54 | mstore(add(_vk, 0x520), 0x2bd1c34249d7e3745f6818cd46a2954c5df21eff4b9b9739d7c667c72314246b) // vk.TABLE_TYPE.y
55 | mstore(add(_vk, 0x540), 0x26d992dc6a0c2d3dc7577d94ddd4503a96c6abf86cb4264088e930942f1a36e4) // vk.ID1.x
56 | mstore(add(_vk, 0x560), 0x1784262c3e269323fe1a43eaf9c4afa6af67f52f1e083f2f661384d7a186d0f2) // vk.ID1.y
57 | mstore(add(_vk, 0x580), 0x20fe45d0f5ff473164023a86fb0140af519db8ebdc25703035698d9aa4cbe644) // vk.ID2.x
58 | mstore(add(_vk, 0x5a0), 0x14f5c79f909d493994b20289e31737a8ccceee60a6b45ef144ac673aca453677) // vk.ID2.y
59 | mstore(add(_vk, 0x5c0), 0x111760ed0e46b0252d0dc90fd0d24f6b018531c15ad1eb412fae73c1d842515d) // vk.ID3.x
60 | mstore(add(_vk, 0x5e0), 0x2a1f5677c6f6e18d1092ce194239a02635b9385d079dd2bc46c052bf3173651e) // vk.ID3.y
61 | mstore(add(_vk, 0x600), 0x2ba1c34652a40c5c66d8695e388f5bc265fdb89de32649931cebb2b389fc67c7) // vk.ID4.x
62 | mstore(add(_vk, 0x620), 0x1b050a94f377c90873be9448610580d634074191dc96f00d1d804c5097676239) // vk.ID4.y
63 | mstore(add(_vk, 0x640), 0x00) // vk.contains_recursive_proof
64 | mstore(add(_vk, 0x660), 0) // vk.recursive_proof_public_input_indices
65 | mstore(add(_vk, 0x680), 0x260e01b251f6f1c7e7ff4e580791dee8ea51d87a358e038b4efe30fac09383c1) // vk.g2_x.X.c1
66 | mstore(add(_vk, 0x6a0), 0x0118c4d5b837bcc2bc89b5b398b5974e9f5944073b32078b7e231fec938883b0) // vk.g2_x.X.c0
67 | mstore(add(_vk, 0x6c0), 0x04fc6369f7110fe3d25156c1bb9a72859cf2a04641f99ba4ee413c80da6a5fe4) // vk.g2_x.Y.c1
68 | mstore(add(_vk, 0x6e0), 0x22febda3c0c0632a56475b4214e5615e11e6dd3f96e6cea2854a87d4dacc5e55) // vk.g2_x.Y.c0
69 | mstore(_omegaInverseLoc, 0x0b5d56b77fe704e8e92338c0082f37e091126414c830e4c6922d5ac802d842d4) // vk.work_root_inverse
70 | }
71 | }
72 | }
73 | /**
74 | * @title Ultra Plonk proof verification contract
75 | * @dev Top level Plonk proof verification contract, which allows Plonk proof to be verified
76 | */
77 | abstract contract BaseUltraVerifier {
78 | // VERIFICATION KEY MEMORY LOCATIONS
79 | uint256 internal constant N_LOC = 0x380;
80 | uint256 internal constant NUM_INPUTS_LOC = 0x3a0;
81 | uint256 internal constant OMEGA_LOC = 0x3c0;
82 | uint256 internal constant DOMAIN_INVERSE_LOC = 0x3e0;
83 | uint256 internal constant Q1_X_LOC = 0x400;
84 | uint256 internal constant Q1_Y_LOC = 0x420;
85 | uint256 internal constant Q2_X_LOC = 0x440;
86 | uint256 internal constant Q2_Y_LOC = 0x460;
87 | uint256 internal constant Q3_X_LOC = 0x480;
88 | uint256 internal constant Q3_Y_LOC = 0x4a0;
89 | uint256 internal constant Q4_X_LOC = 0x4c0;
90 | uint256 internal constant Q4_Y_LOC = 0x4e0;
91 | uint256 internal constant QM_X_LOC = 0x500;
92 | uint256 internal constant QM_Y_LOC = 0x520;
93 | uint256 internal constant QC_X_LOC = 0x540;
94 | uint256 internal constant QC_Y_LOC = 0x560;
95 | uint256 internal constant QARITH_X_LOC = 0x580;
96 | uint256 internal constant QARITH_Y_LOC = 0x5a0;
97 | uint256 internal constant QSORT_X_LOC = 0x5c0;
98 | uint256 internal constant QSORT_Y_LOC = 0x5e0;
99 | uint256 internal constant QELLIPTIC_X_LOC = 0x600;
100 | uint256 internal constant QELLIPTIC_Y_LOC = 0x620;
101 | uint256 internal constant QAUX_X_LOC = 0x640;
102 | uint256 internal constant QAUX_Y_LOC = 0x660;
103 | uint256 internal constant SIGMA1_X_LOC = 0x680;
104 | uint256 internal constant SIGMA1_Y_LOC = 0x6a0;
105 | uint256 internal constant SIGMA2_X_LOC = 0x6c0;
106 | uint256 internal constant SIGMA2_Y_LOC = 0x6e0;
107 | uint256 internal constant SIGMA3_X_LOC = 0x700;
108 | uint256 internal constant SIGMA3_Y_LOC = 0x720;
109 | uint256 internal constant SIGMA4_X_LOC = 0x740;
110 | uint256 internal constant SIGMA4_Y_LOC = 0x760;
111 | uint256 internal constant TABLE1_X_LOC = 0x780;
112 | uint256 internal constant TABLE1_Y_LOC = 0x7a0;
113 | uint256 internal constant TABLE2_X_LOC = 0x7c0;
114 | uint256 internal constant TABLE2_Y_LOC = 0x7e0;
115 | uint256 internal constant TABLE3_X_LOC = 0x800;
116 | uint256 internal constant TABLE3_Y_LOC = 0x820;
117 | uint256 internal constant TABLE4_X_LOC = 0x840;
118 | uint256 internal constant TABLE4_Y_LOC = 0x860;
119 | uint256 internal constant TABLE_TYPE_X_LOC = 0x880;
120 | uint256 internal constant TABLE_TYPE_Y_LOC = 0x8a0;
121 | uint256 internal constant ID1_X_LOC = 0x8c0;
122 | uint256 internal constant ID1_Y_LOC = 0x8e0;
123 | uint256 internal constant ID2_X_LOC = 0x900;
124 | uint256 internal constant ID2_Y_LOC = 0x920;
125 | uint256 internal constant ID3_X_LOC = 0x940;
126 | uint256 internal constant ID3_Y_LOC = 0x960;
127 | uint256 internal constant ID4_X_LOC = 0x980;
128 | uint256 internal constant ID4_Y_LOC = 0x9a0;
129 | uint256 internal constant CONTAINS_RECURSIVE_PROOF_LOC = 0x9c0;
130 | uint256 internal constant RECURSIVE_PROOF_PUBLIC_INPUT_INDICES_LOC = 0x9e0;
131 | uint256 internal constant G2X_X0_LOC = 0xa00;
132 | uint256 internal constant G2X_X1_LOC = 0xa20;
133 | uint256 internal constant G2X_Y0_LOC = 0xa40;
134 | uint256 internal constant G2X_Y1_LOC = 0xa60;
135 |
136 | // ### PROOF DATA MEMORY LOCATIONS
137 | uint256 internal constant W1_X_LOC = 0x1200;
138 | uint256 internal constant W1_Y_LOC = 0x1220;
139 | uint256 internal constant W2_X_LOC = 0x1240;
140 | uint256 internal constant W2_Y_LOC = 0x1260;
141 | uint256 internal constant W3_X_LOC = 0x1280;
142 | uint256 internal constant W3_Y_LOC = 0x12a0;
143 | uint256 internal constant W4_X_LOC = 0x12c0;
144 | uint256 internal constant W4_Y_LOC = 0x12e0;
145 | uint256 internal constant S_X_LOC = 0x1300;
146 | uint256 internal constant S_Y_LOC = 0x1320;
147 | uint256 internal constant Z_X_LOC = 0x1340;
148 | uint256 internal constant Z_Y_LOC = 0x1360;
149 | uint256 internal constant Z_LOOKUP_X_LOC = 0x1380;
150 | uint256 internal constant Z_LOOKUP_Y_LOC = 0x13a0;
151 | uint256 internal constant T1_X_LOC = 0x13c0;
152 | uint256 internal constant T1_Y_LOC = 0x13e0;
153 | uint256 internal constant T2_X_LOC = 0x1400;
154 | uint256 internal constant T2_Y_LOC = 0x1420;
155 | uint256 internal constant T3_X_LOC = 0x1440;
156 | uint256 internal constant T3_Y_LOC = 0x1460;
157 | uint256 internal constant T4_X_LOC = 0x1480;
158 | uint256 internal constant T4_Y_LOC = 0x14a0;
159 |
160 | uint256 internal constant W1_EVAL_LOC = 0x1600;
161 | uint256 internal constant W2_EVAL_LOC = 0x1620;
162 | uint256 internal constant W3_EVAL_LOC = 0x1640;
163 | uint256 internal constant W4_EVAL_LOC = 0x1660;
164 | uint256 internal constant S_EVAL_LOC = 0x1680;
165 | uint256 internal constant Z_EVAL_LOC = 0x16a0;
166 | uint256 internal constant Z_LOOKUP_EVAL_LOC = 0x16c0;
167 | uint256 internal constant Q1_EVAL_LOC = 0x16e0;
168 | uint256 internal constant Q2_EVAL_LOC = 0x1700;
169 | uint256 internal constant Q3_EVAL_LOC = 0x1720;
170 | uint256 internal constant Q4_EVAL_LOC = 0x1740;
171 | uint256 internal constant QM_EVAL_LOC = 0x1760;
172 | uint256 internal constant QC_EVAL_LOC = 0x1780;
173 | uint256 internal constant QARITH_EVAL_LOC = 0x17a0;
174 | uint256 internal constant QSORT_EVAL_LOC = 0x17c0;
175 | uint256 internal constant QELLIPTIC_EVAL_LOC = 0x17e0;
176 | uint256 internal constant QAUX_EVAL_LOC = 0x1800;
177 | uint256 internal constant TABLE1_EVAL_LOC = 0x1840;
178 | uint256 internal constant TABLE2_EVAL_LOC = 0x1860;
179 | uint256 internal constant TABLE3_EVAL_LOC = 0x1880;
180 | uint256 internal constant TABLE4_EVAL_LOC = 0x18a0;
181 | uint256 internal constant TABLE_TYPE_EVAL_LOC = 0x18c0;
182 | uint256 internal constant ID1_EVAL_LOC = 0x18e0;
183 | uint256 internal constant ID2_EVAL_LOC = 0x1900;
184 | uint256 internal constant ID3_EVAL_LOC = 0x1920;
185 | uint256 internal constant ID4_EVAL_LOC = 0x1940;
186 | uint256 internal constant SIGMA1_EVAL_LOC = 0x1960;
187 | uint256 internal constant SIGMA2_EVAL_LOC = 0x1980;
188 | uint256 internal constant SIGMA3_EVAL_LOC = 0x19a0;
189 | uint256 internal constant SIGMA4_EVAL_LOC = 0x19c0;
190 | uint256 internal constant W1_OMEGA_EVAL_LOC = 0x19e0;
191 | uint256 internal constant W2_OMEGA_EVAL_LOC = 0x2000;
192 | uint256 internal constant W3_OMEGA_EVAL_LOC = 0x2020;
193 | uint256 internal constant W4_OMEGA_EVAL_LOC = 0x2040;
194 | uint256 internal constant S_OMEGA_EVAL_LOC = 0x2060;
195 | uint256 internal constant Z_OMEGA_EVAL_LOC = 0x2080;
196 | uint256 internal constant Z_LOOKUP_OMEGA_EVAL_LOC = 0x20a0;
197 | uint256 internal constant TABLE1_OMEGA_EVAL_LOC = 0x20c0;
198 | uint256 internal constant TABLE2_OMEGA_EVAL_LOC = 0x20e0;
199 | uint256 internal constant TABLE3_OMEGA_EVAL_LOC = 0x2100;
200 | uint256 internal constant TABLE4_OMEGA_EVAL_LOC = 0x2120;
201 |
202 | uint256 internal constant PI_Z_X_LOC = 0x2300;
203 | uint256 internal constant PI_Z_Y_LOC = 0x2320;
204 | uint256 internal constant PI_Z_OMEGA_X_LOC = 0x2340;
205 | uint256 internal constant PI_Z_OMEGA_Y_LOC = 0x2360;
206 |
207 | // Used for elliptic widget. These are alias names for wire + shifted wire evaluations
208 | uint256 internal constant X1_EVAL_LOC = W2_EVAL_LOC;
209 | uint256 internal constant X2_EVAL_LOC = W1_OMEGA_EVAL_LOC;
210 | uint256 internal constant X3_EVAL_LOC = W2_OMEGA_EVAL_LOC;
211 | uint256 internal constant Y1_EVAL_LOC = W3_EVAL_LOC;
212 | uint256 internal constant Y2_EVAL_LOC = W4_OMEGA_EVAL_LOC;
213 | uint256 internal constant Y3_EVAL_LOC = W3_OMEGA_EVAL_LOC;
214 | uint256 internal constant QBETA_LOC = Q3_EVAL_LOC;
215 | uint256 internal constant QBETA_SQR_LOC = Q4_EVAL_LOC;
216 | uint256 internal constant QSIGN_LOC = Q1_EVAL_LOC;
217 |
218 | // ### CHALLENGES MEMORY OFFSETS
219 |
220 | uint256 internal constant C_BETA_LOC = 0x2600;
221 | uint256 internal constant C_GAMMA_LOC = 0x2620;
222 | uint256 internal constant C_ALPHA_LOC = 0x2640;
223 | uint256 internal constant C_ETA_LOC = 0x2660;
224 | uint256 internal constant C_ETA_SQR_LOC = 0x2680;
225 | uint256 internal constant C_ETA_CUBE_LOC = 0x26a0;
226 |
227 | uint256 internal constant C_ZETA_LOC = 0x26c0;
228 | uint256 internal constant C_CURRENT_LOC = 0x26e0;
229 | uint256 internal constant C_V0_LOC = 0x2700;
230 | uint256 internal constant C_V1_LOC = 0x2720;
231 | uint256 internal constant C_V2_LOC = 0x2740;
232 | uint256 internal constant C_V3_LOC = 0x2760;
233 | uint256 internal constant C_V4_LOC = 0x2780;
234 | uint256 internal constant C_V5_LOC = 0x27a0;
235 | uint256 internal constant C_V6_LOC = 0x27c0;
236 | uint256 internal constant C_V7_LOC = 0x27e0;
237 | uint256 internal constant C_V8_LOC = 0x2800;
238 | uint256 internal constant C_V9_LOC = 0x2820;
239 | uint256 internal constant C_V10_LOC = 0x2840;
240 | uint256 internal constant C_V11_LOC = 0x2860;
241 | uint256 internal constant C_V12_LOC = 0x2880;
242 | uint256 internal constant C_V13_LOC = 0x28a0;
243 | uint256 internal constant C_V14_LOC = 0x28c0;
244 | uint256 internal constant C_V15_LOC = 0x28e0;
245 | uint256 internal constant C_V16_LOC = 0x2900;
246 | uint256 internal constant C_V17_LOC = 0x2920;
247 | uint256 internal constant C_V18_LOC = 0x2940;
248 | uint256 internal constant C_V19_LOC = 0x2960;
249 | uint256 internal constant C_V20_LOC = 0x2980;
250 | uint256 internal constant C_V21_LOC = 0x29a0;
251 | uint256 internal constant C_V22_LOC = 0x29c0;
252 | uint256 internal constant C_V23_LOC = 0x29e0;
253 | uint256 internal constant C_V24_LOC = 0x2a00;
254 | uint256 internal constant C_V25_LOC = 0x2a20;
255 | uint256 internal constant C_V26_LOC = 0x2a40;
256 | uint256 internal constant C_V27_LOC = 0x2a60;
257 | uint256 internal constant C_V28_LOC = 0x2a80;
258 | uint256 internal constant C_V29_LOC = 0x2aa0;
259 | uint256 internal constant C_V30_LOC = 0x2ac0;
260 |
261 | uint256 internal constant C_U_LOC = 0x2b00;
262 |
263 | // ### LOCAL VARIABLES MEMORY OFFSETS
264 | uint256 internal constant DELTA_NUMERATOR_LOC = 0x3000;
265 | uint256 internal constant DELTA_DENOMINATOR_LOC = 0x3020;
266 | uint256 internal constant ZETA_POW_N_LOC = 0x3040;
267 | uint256 internal constant PUBLIC_INPUT_DELTA_LOC = 0x3060;
268 | uint256 internal constant ZERO_POLY_LOC = 0x3080;
269 | uint256 internal constant L_START_LOC = 0x30a0;
270 | uint256 internal constant L_END_LOC = 0x30c0;
271 | uint256 internal constant R_ZERO_EVAL_LOC = 0x30e0;
272 |
273 | uint256 internal constant PLOOKUP_DELTA_NUMERATOR_LOC = 0x3100;
274 | uint256 internal constant PLOOKUP_DELTA_DENOMINATOR_LOC = 0x3120;
275 | uint256 internal constant PLOOKUP_DELTA_LOC = 0x3140;
276 |
277 | uint256 internal constant ACCUMULATOR_X_LOC = 0x3160;
278 | uint256 internal constant ACCUMULATOR_Y_LOC = 0x3180;
279 | uint256 internal constant ACCUMULATOR2_X_LOC = 0x31a0;
280 | uint256 internal constant ACCUMULATOR2_Y_LOC = 0x31c0;
281 | uint256 internal constant PAIRING_LHS_X_LOC = 0x31e0;
282 | uint256 internal constant PAIRING_LHS_Y_LOC = 0x3200;
283 | uint256 internal constant PAIRING_RHS_X_LOC = 0x3220;
284 | uint256 internal constant PAIRING_RHS_Y_LOC = 0x3240;
285 |
286 | // ### SUCCESS FLAG MEMORY LOCATIONS
287 | uint256 internal constant GRAND_PRODUCT_SUCCESS_FLAG = 0x3300;
288 | uint256 internal constant ARITHMETIC_TERM_SUCCESS_FLAG = 0x3020;
289 | uint256 internal constant BATCH_OPENING_SUCCESS_FLAG = 0x3340;
290 | uint256 internal constant OPENING_COMMITMENT_SUCCESS_FLAG = 0x3360;
291 | uint256 internal constant PAIRING_PREAMBLE_SUCCESS_FLAG = 0x3380;
292 | uint256 internal constant PAIRING_SUCCESS_FLAG = 0x33a0;
293 | uint256 internal constant RESULT_FLAG = 0x33c0;
294 |
295 | // misc stuff
296 | uint256 internal constant OMEGA_INVERSE_LOC = 0x3400;
297 | uint256 internal constant C_ALPHA_SQR_LOC = 0x3420;
298 | uint256 internal constant C_ALPHA_CUBE_LOC = 0x3440;
299 | uint256 internal constant C_ALPHA_QUAD_LOC = 0x3460;
300 | uint256 internal constant C_ALPHA_BASE_LOC = 0x3480;
301 |
302 | // ### RECURSION VARIABLE MEMORY LOCATIONS
303 | uint256 internal constant RECURSIVE_P1_X_LOC = 0x3500;
304 | uint256 internal constant RECURSIVE_P1_Y_LOC = 0x3520;
305 | uint256 internal constant RECURSIVE_P2_X_LOC = 0x3540;
306 | uint256 internal constant RECURSIVE_P2_Y_LOC = 0x3560;
307 |
308 | uint256 internal constant PUBLIC_INPUTS_HASH_LOCATION = 0x3580;
309 |
310 | // sub-identity storage
311 | uint256 internal constant PERMUTATION_IDENTITY = 0x3600;
312 | uint256 internal constant PLOOKUP_IDENTITY = 0x3620;
313 | uint256 internal constant ARITHMETIC_IDENTITY = 0x3640;
314 | uint256 internal constant SORT_IDENTITY = 0x3660;
315 | uint256 internal constant ELLIPTIC_IDENTITY = 0x3680;
316 | uint256 internal constant AUX_IDENTITY = 0x36a0;
317 | uint256 internal constant AUX_NON_NATIVE_FIELD_EVALUATION = 0x36c0;
318 | uint256 internal constant AUX_LIMB_ACCUMULATOR_EVALUATION = 0x36e0;
319 | uint256 internal constant AUX_RAM_CONSISTENCY_EVALUATION = 0x3700;
320 | uint256 internal constant AUX_ROM_CONSISTENCY_EVALUATION = 0x3720;
321 | uint256 internal constant AUX_MEMORY_EVALUATION = 0x3740;
322 |
323 | uint256 internal constant QUOTIENT_EVAL_LOC = 0x3760;
324 | uint256 internal constant ZERO_POLY_INVERSE_LOC = 0x3780;
325 |
326 | // when hashing public inputs we use memory at NU_CHALLENGE_INPUT_LOC_A, as the hash input size is unknown at compile time
327 | uint256 internal constant NU_CHALLENGE_INPUT_LOC_A = 0x37a0;
328 | uint256 internal constant NU_CHALLENGE_INPUT_LOC_B = 0x37c0;
329 | uint256 internal constant NU_CHALLENGE_INPUT_LOC_C = 0x37e0;
330 |
331 | bytes4 internal constant PUBLIC_INPUT_INVALID_BN128_G1_POINT_SELECTOR = 0xeba9f4a6;
332 | bytes4 internal constant PUBLIC_INPUT_GE_P_SELECTOR = 0x374a972f;
333 | bytes4 internal constant MOD_EXP_FAILURE_SELECTOR = 0xf894a7bc;
334 | bytes4 internal constant EC_SCALAR_MUL_FAILURE_SELECTOR = 0xf755f369;
335 | bytes4 internal constant PROOF_FAILURE_SELECTOR = 0x0711fcec;
336 |
337 | uint256 internal constant ETA_INPUT_LENGTH = 0xc0; // W1, W2, W3 = 6 * 0x20 bytes
338 |
339 | // We need to hash 41 field elements when generating the NU challenge
340 | // w1, w2, w3, w4, s, z, z_lookup, q1, q2, q3, q4, qm, qc, qarith (14)
341 | // qsort, qelliptic, qaux, sigma1, sigma2, sigma, sigma4, (7)
342 | // table1, table2, table3, table4, tabletype, id1, id2, id3, id4, (9)
343 | // w1_omega, w2_omega, w3_omega, w4_omega, s_omega, z_omega, z_lookup_omega, (7)
344 | // table1_omega, table2_omega, table3_omega, table4_omega (4)
345 | uint256 internal constant NU_INPUT_LENGTH = 0x520; // 0x520 = 41 * 0x20
346 |
347 | // There are ELEVEN G1 group elements added into the transcript in the `beta` round, that we need to skip over
348 | // W1, W2, W3, W4, S, Z, Z_LOOKUP, T1, T2, T3, T4
349 | uint256 internal constant NU_CALLDATA_SKIP_LENGTH = 0x2c0; // 11 * 0x40 = 0x2c0
350 |
351 | uint256 internal constant NEGATIVE_INVERSE_OF_2_MODULO_P =
352 | 0x183227397098d014dc2822db40c0ac2e9419f4243cdcb848a1f0fac9f8000000;
353 | uint256 internal constant LIMB_SIZE = 0x100000000000000000; // 2<<68
354 | uint256 internal constant SUBLIMB_SHIFT = 0x4000; // 2<<14
355 |
356 | // y^2 = x^3 + ax + b
357 | // for Grumpkin, a = 0 and b = -17. We use b in a custom gate relation that evaluates elliptic curve arithmetic
358 | uint256 internal constant GRUMPKIN_CURVE_B_PARAMETER_NEGATED = 17;
359 | error PUBLIC_INPUT_COUNT_INVALID(uint256 expected, uint256 actual);
360 | error PUBLIC_INPUT_INVALID_BN128_G1_POINT();
361 | error PUBLIC_INPUT_GE_P();
362 | error MOD_EXP_FAILURE();
363 | error EC_SCALAR_MUL_FAILURE();
364 | error PROOF_FAILURE();
365 |
366 | function getVerificationKeyHash() public pure virtual returns (bytes32);
367 |
368 | function loadVerificationKey(uint256 _vk, uint256 _omegaInverseLoc) internal pure virtual;
369 |
370 | /**
371 | * @notice Verify a Ultra Plonk proof
372 | * @param _proof - The serialized proof
373 | * @param _publicInputs - An array of the public inputs
374 | * @return True if proof is valid, reverts otherwise
375 | */
376 | function verify(bytes calldata _proof, bytes32[] calldata _publicInputs) external view returns (bool) {
377 | loadVerificationKey(N_LOC, OMEGA_INVERSE_LOC);
378 |
379 | uint256 requiredPublicInputCount;
380 | assembly {
381 | requiredPublicInputCount := mload(NUM_INPUTS_LOC)
382 | }
383 | if (requiredPublicInputCount != _publicInputs.length) {
384 | revert PUBLIC_INPUT_COUNT_INVALID(requiredPublicInputCount, _publicInputs.length);
385 | }
386 |
387 | assembly {
388 | let q := 21888242871839275222246405745257275088696311157297823662689037894645226208583 // EC group order
389 | let p := 21888242871839275222246405745257275088548364400416034343698204186575808495617 // Prime field order
390 |
391 | /**
392 | * LOAD PROOF FROM CALLDATA
393 | */
394 | {
395 | let data_ptr := add(calldataload(0x04), 0x24)
396 |
397 | mstore(W1_Y_LOC, mod(calldataload(data_ptr), q))
398 | mstore(W1_X_LOC, mod(calldataload(add(data_ptr, 0x20)), q))
399 |
400 | mstore(W2_Y_LOC, mod(calldataload(add(data_ptr, 0x40)), q))
401 | mstore(W2_X_LOC, mod(calldataload(add(data_ptr, 0x60)), q))
402 |
403 | mstore(W3_Y_LOC, mod(calldataload(add(data_ptr, 0x80)), q))
404 | mstore(W3_X_LOC, mod(calldataload(add(data_ptr, 0xa0)), q))
405 |
406 | mstore(W4_Y_LOC, mod(calldataload(add(data_ptr, 0xc0)), q))
407 | mstore(W4_X_LOC, mod(calldataload(add(data_ptr, 0xe0)), q))
408 |
409 | mstore(S_Y_LOC, mod(calldataload(add(data_ptr, 0x100)), q))
410 | mstore(S_X_LOC, mod(calldataload(add(data_ptr, 0x120)), q))
411 | mstore(Z_Y_LOC, mod(calldataload(add(data_ptr, 0x140)), q))
412 | mstore(Z_X_LOC, mod(calldataload(add(data_ptr, 0x160)), q))
413 | mstore(Z_LOOKUP_Y_LOC, mod(calldataload(add(data_ptr, 0x180)), q))
414 | mstore(Z_LOOKUP_X_LOC, mod(calldataload(add(data_ptr, 0x1a0)), q))
415 | mstore(T1_Y_LOC, mod(calldataload(add(data_ptr, 0x1c0)), q))
416 | mstore(T1_X_LOC, mod(calldataload(add(data_ptr, 0x1e0)), q))
417 |
418 | mstore(T2_Y_LOC, mod(calldataload(add(data_ptr, 0x200)), q))
419 | mstore(T2_X_LOC, mod(calldataload(add(data_ptr, 0x220)), q))
420 |
421 | mstore(T3_Y_LOC, mod(calldataload(add(data_ptr, 0x240)), q))
422 | mstore(T3_X_LOC, mod(calldataload(add(data_ptr, 0x260)), q))
423 |
424 | mstore(T4_Y_LOC, mod(calldataload(add(data_ptr, 0x280)), q))
425 | mstore(T4_X_LOC, mod(calldataload(add(data_ptr, 0x2a0)), q))
426 |
427 | mstore(W1_EVAL_LOC, mod(calldataload(add(data_ptr, 0x2c0)), p))
428 | mstore(W2_EVAL_LOC, mod(calldataload(add(data_ptr, 0x2e0)), p))
429 | mstore(W3_EVAL_LOC, mod(calldataload(add(data_ptr, 0x300)), p))
430 | mstore(W4_EVAL_LOC, mod(calldataload(add(data_ptr, 0x320)), p))
431 | mstore(S_EVAL_LOC, mod(calldataload(add(data_ptr, 0x340)), p))
432 | mstore(Z_EVAL_LOC, mod(calldataload(add(data_ptr, 0x360)), p))
433 | mstore(Z_LOOKUP_EVAL_LOC, mod(calldataload(add(data_ptr, 0x380)), p))
434 | mstore(Q1_EVAL_LOC, mod(calldataload(add(data_ptr, 0x3a0)), p))
435 | mstore(Q2_EVAL_LOC, mod(calldataload(add(data_ptr, 0x3c0)), p))
436 | mstore(Q3_EVAL_LOC, mod(calldataload(add(data_ptr, 0x3e0)), p))
437 | mstore(Q4_EVAL_LOC, mod(calldataload(add(data_ptr, 0x400)), p))
438 | mstore(QM_EVAL_LOC, mod(calldataload(add(data_ptr, 0x420)), p))
439 | mstore(QC_EVAL_LOC, mod(calldataload(add(data_ptr, 0x440)), p))
440 | mstore(QARITH_EVAL_LOC, mod(calldataload(add(data_ptr, 0x460)), p))
441 | mstore(QSORT_EVAL_LOC, mod(calldataload(add(data_ptr, 0x480)), p))
442 | mstore(QELLIPTIC_EVAL_LOC, mod(calldataload(add(data_ptr, 0x4a0)), p))
443 | mstore(QAUX_EVAL_LOC, mod(calldataload(add(data_ptr, 0x4c0)), p))
444 |
445 | mstore(SIGMA1_EVAL_LOC, mod(calldataload(add(data_ptr, 0x4e0)), p))
446 | mstore(SIGMA2_EVAL_LOC, mod(calldataload(add(data_ptr, 0x500)), p))
447 |
448 | mstore(SIGMA3_EVAL_LOC, mod(calldataload(add(data_ptr, 0x520)), p))
449 | mstore(SIGMA4_EVAL_LOC, mod(calldataload(add(data_ptr, 0x540)), p))
450 |
451 | mstore(TABLE1_EVAL_LOC, mod(calldataload(add(data_ptr, 0x560)), p))
452 | mstore(TABLE2_EVAL_LOC, mod(calldataload(add(data_ptr, 0x580)), p))
453 | mstore(TABLE3_EVAL_LOC, mod(calldataload(add(data_ptr, 0x5a0)), p))
454 | mstore(TABLE4_EVAL_LOC, mod(calldataload(add(data_ptr, 0x5c0)), p))
455 | mstore(TABLE_TYPE_EVAL_LOC, mod(calldataload(add(data_ptr, 0x5e0)), p))
456 |
457 | mstore(ID1_EVAL_LOC, mod(calldataload(add(data_ptr, 0x600)), p))
458 | mstore(ID2_EVAL_LOC, mod(calldataload(add(data_ptr, 0x620)), p))
459 | mstore(ID3_EVAL_LOC, mod(calldataload(add(data_ptr, 0x640)), p))
460 | mstore(ID4_EVAL_LOC, mod(calldataload(add(data_ptr, 0x660)), p))
461 |
462 | mstore(W1_OMEGA_EVAL_LOC, mod(calldataload(add(data_ptr, 0x680)), p))
463 | mstore(W2_OMEGA_EVAL_LOC, mod(calldataload(add(data_ptr, 0x6a0)), p))
464 | mstore(W3_OMEGA_EVAL_LOC, mod(calldataload(add(data_ptr, 0x6c0)), p))
465 | mstore(W4_OMEGA_EVAL_LOC, mod(calldataload(add(data_ptr, 0x6e0)), p))
466 | mstore(S_OMEGA_EVAL_LOC, mod(calldataload(add(data_ptr, 0x700)), p))
467 |
468 | mstore(Z_OMEGA_EVAL_LOC, mod(calldataload(add(data_ptr, 0x720)), p))
469 |
470 | mstore(Z_LOOKUP_OMEGA_EVAL_LOC, mod(calldataload(add(data_ptr, 0x740)), p))
471 | mstore(TABLE1_OMEGA_EVAL_LOC, mod(calldataload(add(data_ptr, 0x760)), p))
472 | mstore(TABLE2_OMEGA_EVAL_LOC, mod(calldataload(add(data_ptr, 0x780)), p))
473 | mstore(TABLE3_OMEGA_EVAL_LOC, mod(calldataload(add(data_ptr, 0x7a0)), p))
474 | mstore(TABLE4_OMEGA_EVAL_LOC, mod(calldataload(add(data_ptr, 0x7c0)), p))
475 |
476 | mstore(PI_Z_Y_LOC, mod(calldataload(add(data_ptr, 0x7e0)), q))
477 | mstore(PI_Z_X_LOC, mod(calldataload(add(data_ptr, 0x800)), q))
478 |
479 | mstore(PI_Z_OMEGA_Y_LOC, mod(calldataload(add(data_ptr, 0x820)), q))
480 | mstore(PI_Z_OMEGA_X_LOC, mod(calldataload(add(data_ptr, 0x840)), q))
481 | }
482 |
483 | /**
484 | * LOAD RECURSIVE PROOF INTO MEMORY
485 | */
486 | {
487 | if mload(CONTAINS_RECURSIVE_PROOF_LOC) {
488 | let public_inputs_ptr := add(calldataload(0x24), 0x24)
489 | let index_counter := add(shl(5, mload(RECURSIVE_PROOF_PUBLIC_INPUT_INDICES_LOC)), public_inputs_ptr)
490 |
491 | let x0 := calldataload(index_counter)
492 | x0 := add(x0, shl(68, calldataload(add(index_counter, 0x20))))
493 | x0 := add(x0, shl(136, calldataload(add(index_counter, 0x40))))
494 | x0 := add(x0, shl(204, calldataload(add(index_counter, 0x60))))
495 | let y0 := calldataload(add(index_counter, 0x80))
496 | y0 := add(y0, shl(68, calldataload(add(index_counter, 0xa0))))
497 | y0 := add(y0, shl(136, calldataload(add(index_counter, 0xc0))))
498 | y0 := add(y0, shl(204, calldataload(add(index_counter, 0xe0))))
499 | let x1 := calldataload(add(index_counter, 0x100))
500 | x1 := add(x1, shl(68, calldataload(add(index_counter, 0x120))))
501 | x1 := add(x1, shl(136, calldataload(add(index_counter, 0x140))))
502 | x1 := add(x1, shl(204, calldataload(add(index_counter, 0x160))))
503 | let y1 := calldataload(add(index_counter, 0x180))
504 | y1 := add(y1, shl(68, calldataload(add(index_counter, 0x1a0))))
505 | y1 := add(y1, shl(136, calldataload(add(index_counter, 0x1c0))))
506 | y1 := add(y1, shl(204, calldataload(add(index_counter, 0x1e0))))
507 | mstore(RECURSIVE_P1_X_LOC, x0)
508 | mstore(RECURSIVE_P1_Y_LOC, y0)
509 | mstore(RECURSIVE_P2_X_LOC, x1)
510 | mstore(RECURSIVE_P2_Y_LOC, y1)
511 |
512 | // validate these are valid bn128 G1 points
513 | if iszero(and(and(lt(x0, q), lt(x1, q)), and(lt(y0, q), lt(y1, q)))) {
514 | mstore(0x00, PUBLIC_INPUT_INVALID_BN128_G1_POINT_SELECTOR)
515 | revert(0x00, 0x04)
516 | }
517 | }
518 | }
519 |
520 | {
521 | /**
522 | * Generate initial challenge
523 | */
524 | mstore(0x00, shl(224, mload(N_LOC)))
525 | mstore(0x04, shl(224, mload(NUM_INPUTS_LOC)))
526 | let challenge := keccak256(0x00, 0x08)
527 |
528 | /**
529 | * Generate eta challenge
530 | */
531 | mstore(PUBLIC_INPUTS_HASH_LOCATION, challenge)
532 | // The public input location is stored at 0x24, we then add 0x24 to skip selector and the length of public inputs
533 | let public_inputs_start := add(calldataload(0x24), 0x24)
534 | // copy the public inputs over
535 | let public_input_size := mul(mload(NUM_INPUTS_LOC), 0x20)
536 | calldatacopy(add(PUBLIC_INPUTS_HASH_LOCATION, 0x20), public_inputs_start, public_input_size)
537 |
538 | // copy W1, W2, W3 into challenge. Each point is 0x40 bytes, so load 0xc0 = 3 * 0x40 bytes (ETA input length)
539 | let w_start := add(calldataload(0x04), 0x24)
540 | calldatacopy(add(add(PUBLIC_INPUTS_HASH_LOCATION, 0x20), public_input_size), w_start, ETA_INPUT_LENGTH)
541 |
542 | // Challenge is the old challenge + public inputs + W1, W2, W3 (0x20 + public_input_size + 0xc0)
543 | let challenge_bytes_size := add(0x20, add(public_input_size, ETA_INPUT_LENGTH))
544 |
545 | challenge := keccak256(PUBLIC_INPUTS_HASH_LOCATION, challenge_bytes_size)
546 | {
547 | let eta := mod(challenge, p)
548 | mstore(C_ETA_LOC, eta)
549 | mstore(C_ETA_SQR_LOC, mulmod(eta, eta, p))
550 | mstore(C_ETA_CUBE_LOC, mulmod(mload(C_ETA_SQR_LOC), eta, p))
551 | }
552 |
553 | /**
554 | * Generate beta challenge
555 | */
556 | mstore(0x00, challenge)
557 | mstore(0x20, mload(W4_Y_LOC))
558 | mstore(0x40, mload(W4_X_LOC))
559 | mstore(0x60, mload(S_Y_LOC))
560 | mstore(0x80, mload(S_X_LOC))
561 | challenge := keccak256(0x00, 0xa0)
562 | mstore(C_BETA_LOC, mod(challenge, p))
563 |
564 | /**
565 | * Generate gamma challenge
566 | */
567 | mstore(0x00, challenge)
568 | mstore8(0x20, 0x01)
569 | challenge := keccak256(0x00, 0x21)
570 | mstore(C_GAMMA_LOC, mod(challenge, p))
571 |
572 | /**
573 | * Generate alpha challenge
574 | */
575 | mstore(0x00, challenge)
576 | mstore(0x20, mload(Z_Y_LOC))
577 | mstore(0x40, mload(Z_X_LOC))
578 | mstore(0x60, mload(Z_LOOKUP_Y_LOC))
579 | mstore(0x80, mload(Z_LOOKUP_X_LOC))
580 | challenge := keccak256(0x00, 0xa0)
581 | mstore(C_ALPHA_LOC, mod(challenge, p))
582 |
583 | /**
584 | * Compute and store some powers of alpha for future computations
585 | */
586 | let alpha := mload(C_ALPHA_LOC)
587 | mstore(C_ALPHA_SQR_LOC, mulmod(alpha, alpha, p))
588 | mstore(C_ALPHA_CUBE_LOC, mulmod(mload(C_ALPHA_SQR_LOC), alpha, p))
589 | mstore(C_ALPHA_QUAD_LOC, mulmod(mload(C_ALPHA_CUBE_LOC), alpha, p))
590 | mstore(C_ALPHA_BASE_LOC, alpha)
591 |
592 | /**
593 | * Generate zeta challenge
594 | */
595 | mstore(0x00, challenge)
596 | mstore(0x20, mload(T1_Y_LOC))
597 | mstore(0x40, mload(T1_X_LOC))
598 | mstore(0x60, mload(T2_Y_LOC))
599 | mstore(0x80, mload(T2_X_LOC))
600 | mstore(0xa0, mload(T3_Y_LOC))
601 | mstore(0xc0, mload(T3_X_LOC))
602 | mstore(0xe0, mload(T4_Y_LOC))
603 | mstore(0x100, mload(T4_X_LOC))
604 |
605 | challenge := keccak256(0x00, 0x120)
606 |
607 | mstore(C_ZETA_LOC, mod(challenge, p))
608 | mstore(C_CURRENT_LOC, challenge)
609 | }
610 |
611 | /**
612 | * EVALUATE FIELD OPERATIONS
613 | */
614 |
615 | /**
616 | * COMPUTE PUBLIC INPUT DELTA
617 | * ΔPI = ∏ᵢ∈ℓ(wᵢ + β σ(i) + γ) / ∏ᵢ∈ℓ(wᵢ + β σ'(i) + γ)
618 | */
619 | {
620 | let beta := mload(C_BETA_LOC) // β
621 | let gamma := mload(C_GAMMA_LOC) // γ
622 | let work_root := mload(OMEGA_LOC) // ω
623 | let numerator_value := 1
624 | let denominator_value := 1
625 |
626 | let p_clone := p // move p to the front of the stack
627 | let valid_inputs := true
628 |
629 | // Load the starting point of the public inputs (jump over the selector and the length of public inputs [0x24])
630 | let public_inputs_ptr := add(calldataload(0x24), 0x24)
631 |
632 | // endpoint_ptr = public_inputs_ptr + num_inputs * 0x20. // every public input is 0x20 bytes
633 | let endpoint_ptr := add(public_inputs_ptr, mul(mload(NUM_INPUTS_LOC), 0x20))
634 |
635 | // root_1 = β * 0x05
636 | let root_1 := mulmod(beta, 0x05, p_clone) // k1.β
637 | // root_2 = β * 0x0c
638 | let root_2 := mulmod(beta, 0x0c, p_clone)
639 | // @note 0x05 + 0x07 == 0x0c == external coset generator
640 |
641 | for {} lt(public_inputs_ptr, endpoint_ptr) { public_inputs_ptr := add(public_inputs_ptr, 0x20) } {
642 | /**
643 | * input = public_input[i]
644 | * valid_inputs &= input < p
645 | * temp = input + gamma
646 | * numerator_value *= (β.σ(i) + wᵢ + γ) // σ(i) = 0x05.ωⁱ
647 | * denominator_value *= (β.σ'(i) + wᵢ + γ) // σ'(i) = 0x0c.ωⁱ
648 | * root_1 *= ω
649 | * root_2 *= ω
650 | */
651 |
652 | let input := calldataload(public_inputs_ptr)
653 | valid_inputs := and(valid_inputs, lt(input, p_clone))
654 | let temp := addmod(input, gamma, p_clone)
655 |
656 | numerator_value := mulmod(numerator_value, add(root_1, temp), p_clone)
657 | denominator_value := mulmod(denominator_value, add(root_2, temp), p_clone)
658 |
659 | root_1 := mulmod(root_1, work_root, p_clone)
660 | root_2 := mulmod(root_2, work_root, p_clone)
661 | }
662 |
663 | // Revert if not all public inputs are field elements (i.e. < p)
664 | if iszero(valid_inputs) {
665 | mstore(0x00, PUBLIC_INPUT_GE_P_SELECTOR)
666 | revert(0x00, 0x04)
667 | }
668 |
669 | mstore(DELTA_NUMERATOR_LOC, numerator_value)
670 | mstore(DELTA_DENOMINATOR_LOC, denominator_value)
671 | }
672 |
673 | /**
674 | * Compute Plookup delta factor [γ(1 + β)]^{n-k}
675 | * k = num roots cut out of Z_H = 4
676 | */
677 | {
678 | let delta_base := mulmod(mload(C_GAMMA_LOC), addmod(mload(C_BETA_LOC), 1, p), p)
679 | let delta_numerator := delta_base
680 | {
681 | let exponent := mload(N_LOC)
682 | let count := 1
683 | for {} lt(count, exponent) { count := add(count, count) } {
684 | delta_numerator := mulmod(delta_numerator, delta_numerator, p)
685 | }
686 | }
687 | mstore(PLOOKUP_DELTA_NUMERATOR_LOC, delta_numerator)
688 |
689 | let delta_denominator := mulmod(delta_base, delta_base, p)
690 | delta_denominator := mulmod(delta_denominator, delta_denominator, p)
691 | mstore(PLOOKUP_DELTA_DENOMINATOR_LOC, delta_denominator)
692 | }
693 | /**
694 | * Compute lagrange poly and vanishing poly fractions
695 | */
696 | {
697 | /**
698 | * vanishing_numerator = zeta
699 | * ZETA_POW_N = zeta^n
700 | * vanishing_numerator -= 1
701 | * accumulating_root = omega_inverse
702 | * work_root = p - accumulating_root
703 | * domain_inverse = domain_inverse
704 | * vanishing_denominator = zeta + work_root
705 | * work_root *= accumulating_root
706 | * vanishing_denominator *= (zeta + work_root)
707 | * work_root *= accumulating_root
708 | * vanishing_denominator *= (zeta + work_root)
709 | * vanishing_denominator *= (zeta + (zeta + accumulating_root))
710 | * work_root = omega
711 | * lagrange_numerator = vanishing_numerator * domain_inverse
712 | * l_start_denominator = zeta - 1
713 | * accumulating_root = work_root^2
714 | * l_end_denominator = accumulating_root^2 * work_root * zeta - 1
715 | * Note: l_end_denominator term contains a term \omega^5 to cut out 5 roots of unity from vanishing poly
716 | */
717 |
718 | let zeta := mload(C_ZETA_LOC)
719 |
720 | // compute zeta^n, where n is a power of 2
721 | let vanishing_numerator := zeta
722 | {
723 | // pow_small
724 | let exponent := mload(N_LOC)
725 | let count := 1
726 | for {} lt(count, exponent) { count := add(count, count) } {
727 | vanishing_numerator := mulmod(vanishing_numerator, vanishing_numerator, p)
728 | }
729 | }
730 | mstore(ZETA_POW_N_LOC, vanishing_numerator)
731 | vanishing_numerator := addmod(vanishing_numerator, sub(p, 1), p)
732 |
733 | let accumulating_root := mload(OMEGA_INVERSE_LOC)
734 | let work_root := sub(p, accumulating_root)
735 | let domain_inverse := mload(DOMAIN_INVERSE_LOC)
736 |
737 | let vanishing_denominator := addmod(zeta, work_root, p)
738 | work_root := mulmod(work_root, accumulating_root, p)
739 | vanishing_denominator := mulmod(vanishing_denominator, addmod(zeta, work_root, p), p)
740 | work_root := mulmod(work_root, accumulating_root, p)
741 | vanishing_denominator := mulmod(vanishing_denominator, addmod(zeta, work_root, p), p)
742 | vanishing_denominator :=
743 | mulmod(vanishing_denominator, addmod(zeta, mulmod(work_root, accumulating_root, p), p), p)
744 |
745 | work_root := mload(OMEGA_LOC)
746 |
747 | let lagrange_numerator := mulmod(vanishing_numerator, domain_inverse, p)
748 | let l_start_denominator := addmod(zeta, sub(p, 1), p)
749 |
750 | accumulating_root := mulmod(work_root, work_root, p)
751 |
752 | let l_end_denominator :=
753 | addmod(
754 | mulmod(mulmod(mulmod(accumulating_root, accumulating_root, p), work_root, p), zeta, p), sub(p, 1), p
755 | )
756 |
757 | /**
758 | * Compute inversions using Montgomery's batch inversion trick
759 | */
760 | let accumulator := mload(DELTA_DENOMINATOR_LOC)
761 | let t0 := accumulator
762 | accumulator := mulmod(accumulator, vanishing_denominator, p)
763 | let t1 := accumulator
764 | accumulator := mulmod(accumulator, vanishing_numerator, p)
765 | let t2 := accumulator
766 | accumulator := mulmod(accumulator, l_start_denominator, p)
767 | let t3 := accumulator
768 | accumulator := mulmod(accumulator, mload(PLOOKUP_DELTA_DENOMINATOR_LOC), p)
769 | let t4 := accumulator
770 | {
771 | mstore(0, 0x20)
772 | mstore(0x20, 0x20)
773 | mstore(0x40, 0x20)
774 | mstore(0x60, mulmod(accumulator, l_end_denominator, p))
775 | mstore(0x80, sub(p, 2))
776 | mstore(0xa0, p)
777 | if iszero(staticcall(gas(), 0x05, 0x00, 0xc0, 0x00, 0x20)) {
778 | mstore(0x0, MOD_EXP_FAILURE_SELECTOR)
779 | revert(0x00, 0x04)
780 | }
781 | accumulator := mload(0x00)
782 | }
783 |
784 | t4 := mulmod(accumulator, t4, p)
785 | accumulator := mulmod(accumulator, l_end_denominator, p)
786 |
787 | t3 := mulmod(accumulator, t3, p)
788 | accumulator := mulmod(accumulator, mload(PLOOKUP_DELTA_DENOMINATOR_LOC), p)
789 |
790 | t2 := mulmod(accumulator, t2, p)
791 | accumulator := mulmod(accumulator, l_start_denominator, p)
792 |
793 | t1 := mulmod(accumulator, t1, p)
794 | accumulator := mulmod(accumulator, vanishing_numerator, p)
795 |
796 | t0 := mulmod(accumulator, t0, p)
797 | accumulator := mulmod(accumulator, vanishing_denominator, p)
798 |
799 | accumulator := mulmod(mulmod(accumulator, accumulator, p), mload(DELTA_DENOMINATOR_LOC), p)
800 |
801 | mstore(PUBLIC_INPUT_DELTA_LOC, mulmod(mload(DELTA_NUMERATOR_LOC), accumulator, p))
802 | mstore(ZERO_POLY_LOC, mulmod(vanishing_numerator, t0, p))
803 | mstore(ZERO_POLY_INVERSE_LOC, mulmod(vanishing_denominator, t1, p))
804 | mstore(L_START_LOC, mulmod(lagrange_numerator, t2, p))
805 | mstore(PLOOKUP_DELTA_LOC, mulmod(mload(PLOOKUP_DELTA_NUMERATOR_LOC), t3, p))
806 | mstore(L_END_LOC, mulmod(lagrange_numerator, t4, p))
807 | }
808 |
809 | /**
810 | * UltraPlonk Widget Ordering:
811 | *
812 | * 1. Permutation widget
813 | * 2. Plookup widget
814 | * 3. Arithmetic widget
815 | * 4. Fixed base widget (?)
816 | * 5. GenPermSort widget
817 | * 6. Elliptic widget
818 | * 7. Auxiliary widget
819 | */
820 |
821 | /**
822 | * COMPUTE PERMUTATION WIDGET EVALUATION
823 | */
824 | {
825 | let alpha := mload(C_ALPHA_LOC)
826 | let beta := mload(C_BETA_LOC)
827 | let gamma := mload(C_GAMMA_LOC)
828 |
829 | /**
830 | * t1 = (W1 + gamma + beta * ID1) * (W2 + gamma + beta * ID2)
831 | * t2 = (W3 + gamma + beta * ID3) * (W4 + gamma + beta * ID4)
832 | * result = alpha_base * z_eval * t1 * t2
833 | * t1 = (W1 + gamma + beta * sigma_1_eval) * (W2 + gamma + beta * sigma_2_eval)
834 | * t2 = (W2 + gamma + beta * sigma_3_eval) * (W3 + gamma + beta * sigma_4_eval)
835 | * result -= (alpha_base * z_omega_eval * t1 * t2)
836 | */
837 | let t1 :=
838 | mulmod(
839 | add(add(mload(W1_EVAL_LOC), gamma), mulmod(beta, mload(ID1_EVAL_LOC), p)),
840 | add(add(mload(W2_EVAL_LOC), gamma), mulmod(beta, mload(ID2_EVAL_LOC), p)),
841 | p
842 | )
843 | let t2 :=
844 | mulmod(
845 | add(add(mload(W3_EVAL_LOC), gamma), mulmod(beta, mload(ID3_EVAL_LOC), p)),
846 | add(add(mload(W4_EVAL_LOC), gamma), mulmod(beta, mload(ID4_EVAL_LOC), p)),
847 | p
848 | )
849 | let result := mulmod(mload(C_ALPHA_BASE_LOC), mulmod(mload(Z_EVAL_LOC), mulmod(t1, t2, p), p), p)
850 | t1 :=
851 | mulmod(
852 | add(add(mload(W1_EVAL_LOC), gamma), mulmod(beta, mload(SIGMA1_EVAL_LOC), p)),
853 | add(add(mload(W2_EVAL_LOC), gamma), mulmod(beta, mload(SIGMA2_EVAL_LOC), p)),
854 | p
855 | )
856 | t2 :=
857 | mulmod(
858 | add(add(mload(W3_EVAL_LOC), gamma), mulmod(beta, mload(SIGMA3_EVAL_LOC), p)),
859 | add(add(mload(W4_EVAL_LOC), gamma), mulmod(beta, mload(SIGMA4_EVAL_LOC), p)),
860 | p
861 | )
862 | result :=
863 | addmod(
864 | result,
865 | sub(p, mulmod(mload(C_ALPHA_BASE_LOC), mulmod(mload(Z_OMEGA_EVAL_LOC), mulmod(t1, t2, p), p), p)),
866 | p
867 | )
868 |
869 | /**
870 | * alpha_base *= alpha
871 | * result += alpha_base . (L_{n-k}(ʓ) . (z(ʓ.ω) - ∆_{PI}))
872 | * alpha_base *= alpha
873 | * result += alpha_base . (L_1(ʓ)(Z(ʓ) - 1))
874 | * alpha_Base *= alpha
875 | */
876 | mstore(C_ALPHA_BASE_LOC, mulmod(mload(C_ALPHA_BASE_LOC), mload(C_ALPHA_LOC), p))
877 | result :=
878 | addmod(
879 | result,
880 | mulmod(
881 | mload(C_ALPHA_BASE_LOC),
882 | mulmod(
883 | mload(L_END_LOC),
884 | addmod(mload(Z_OMEGA_EVAL_LOC), sub(p, mload(PUBLIC_INPUT_DELTA_LOC)), p),
885 | p
886 | ),
887 | p
888 | ),
889 | p
890 | )
891 | mstore(C_ALPHA_BASE_LOC, mulmod(mload(C_ALPHA_BASE_LOC), mload(C_ALPHA_LOC), p))
892 | mstore(
893 | PERMUTATION_IDENTITY,
894 | addmod(
895 | result,
896 | mulmod(
897 | mload(C_ALPHA_BASE_LOC),
898 | mulmod(mload(L_START_LOC), addmod(mload(Z_EVAL_LOC), sub(p, 1), p), p),
899 | p
900 | ),
901 | p
902 | )
903 | )
904 | mstore(C_ALPHA_BASE_LOC, mulmod(mload(C_ALPHA_BASE_LOC), mload(C_ALPHA_LOC), p))
905 | }
906 |
907 | /**
908 | * COMPUTE PLOOKUP WIDGET EVALUATION
909 | */
910 | {
911 | /**
912 | * Goal: f = (w1(z) + q2.w1(zω)) + η(w2(z) + qm.w2(zω)) + η²(w3(z) + qc.w_3(zω)) + q3(z).η³
913 | * f = η.q3(z)
914 | * f += (w3(z) + qc.w_3(zω))
915 | * f *= η
916 | * f += (w2(z) + qm.w2(zω))
917 | * f *= η
918 | * f += (w1(z) + q2.w1(zω))
919 | */
920 | let f := mulmod(mload(C_ETA_LOC), mload(Q3_EVAL_LOC), p)
921 | f :=
922 | addmod(f, addmod(mload(W3_EVAL_LOC), mulmod(mload(QC_EVAL_LOC), mload(W3_OMEGA_EVAL_LOC), p), p), p)
923 | f := mulmod(f, mload(C_ETA_LOC), p)
924 | f :=
925 | addmod(f, addmod(mload(W2_EVAL_LOC), mulmod(mload(QM_EVAL_LOC), mload(W2_OMEGA_EVAL_LOC), p), p), p)
926 | f := mulmod(f, mload(C_ETA_LOC), p)
927 | f :=
928 | addmod(f, addmod(mload(W1_EVAL_LOC), mulmod(mload(Q2_EVAL_LOC), mload(W1_OMEGA_EVAL_LOC), p), p), p)
929 |
930 | // t(z) = table4(z).η³ + table3(z).η² + table2(z).η + table1(z)
931 | let t :=
932 | addmod(
933 | addmod(
934 | addmod(
935 | mulmod(mload(TABLE4_EVAL_LOC), mload(C_ETA_CUBE_LOC), p),
936 | mulmod(mload(TABLE3_EVAL_LOC), mload(C_ETA_SQR_LOC), p),
937 | p
938 | ),
939 | mulmod(mload(TABLE2_EVAL_LOC), mload(C_ETA_LOC), p),
940 | p
941 | ),
942 | mload(TABLE1_EVAL_LOC),
943 | p
944 | )
945 |
946 | // t(zw) = table4(zw).η³ + table3(zw).η² + table2(zw).η + table1(zw)
947 | let t_omega :=
948 | addmod(
949 | addmod(
950 | addmod(
951 | mulmod(mload(TABLE4_OMEGA_EVAL_LOC), mload(C_ETA_CUBE_LOC), p),
952 | mulmod(mload(TABLE3_OMEGA_EVAL_LOC), mload(C_ETA_SQR_LOC), p),
953 | p
954 | ),
955 | mulmod(mload(TABLE2_OMEGA_EVAL_LOC), mload(C_ETA_LOC), p),
956 | p
957 | ),
958 | mload(TABLE1_OMEGA_EVAL_LOC),
959 | p
960 | )
961 |
962 | /**
963 | * Goal: numerator = (TABLE_TYPE_EVAL * f(z) + γ) * (t(z) + βt(zω) + γ(β + 1)) * (β + 1)
964 | * gamma_beta_constant = γ(β + 1)
965 | * numerator = f * TABLE_TYPE_EVAL + gamma
966 | * temp0 = t(z) + t(zω) * β + gamma_beta_constant
967 | * numerator *= temp0
968 | * numerator *= (β + 1)
969 | * temp0 = alpha * l_1
970 | * numerator += temp0
971 | * numerator *= z_lookup(z)
972 | * numerator -= temp0
973 | */
974 | let gamma_beta_constant := mulmod(mload(C_GAMMA_LOC), addmod(mload(C_BETA_LOC), 1, p), p)
975 | let numerator := addmod(mulmod(f, mload(TABLE_TYPE_EVAL_LOC), p), mload(C_GAMMA_LOC), p)
976 | let temp0 := addmod(addmod(t, mulmod(t_omega, mload(C_BETA_LOC), p), p), gamma_beta_constant, p)
977 | numerator := mulmod(numerator, temp0, p)
978 | numerator := mulmod(numerator, addmod(mload(C_BETA_LOC), 1, p), p)
979 | temp0 := mulmod(mload(C_ALPHA_LOC), mload(L_START_LOC), p)
980 | numerator := addmod(numerator, temp0, p)
981 | numerator := mulmod(numerator, mload(Z_LOOKUP_EVAL_LOC), p)
982 | numerator := addmod(numerator, sub(p, temp0), p)
983 |
984 | /**
985 | * Goal: denominator = z_lookup(zω)*[s(z) + βs(zω) + γ(1 + β)] - [z_lookup(zω) - [γ(1 + β)]^{n-k}]*α²L_end(z)
986 | * note: delta_factor = [γ(1 + β)]^{n-k}
987 | * denominator = s(z) + βs(zω) + γ(β + 1)
988 | * temp1 = α²L_end(z)
989 | * denominator -= temp1
990 | * denominator *= z_lookup(zω)
991 | * denominator += temp1 * delta_factor
992 | * PLOOKUP_IDENTITY = (numerator - denominator).alpha_base
993 | * alpha_base *= alpha^3
994 | */
995 | let denominator :=
996 | addmod(
997 | addmod(mload(S_EVAL_LOC), mulmod(mload(S_OMEGA_EVAL_LOC), mload(C_BETA_LOC), p), p),
998 | gamma_beta_constant,
999 | p
1000 | )
1001 | let temp1 := mulmod(mload(C_ALPHA_SQR_LOC), mload(L_END_LOC), p)
1002 | denominator := addmod(denominator, sub(p, temp1), p)
1003 | denominator := mulmod(denominator, mload(Z_LOOKUP_OMEGA_EVAL_LOC), p)
1004 | denominator := addmod(denominator, mulmod(temp1, mload(PLOOKUP_DELTA_LOC), p), p)
1005 |
1006 | mstore(PLOOKUP_IDENTITY, mulmod(addmod(numerator, sub(p, denominator), p), mload(C_ALPHA_BASE_LOC), p))
1007 |
1008 | // update alpha
1009 | mstore(C_ALPHA_BASE_LOC, mulmod(mload(C_ALPHA_BASE_LOC), mload(C_ALPHA_CUBE_LOC), p))
1010 | }
1011 |
1012 | /**
1013 | * COMPUTE ARITHMETIC WIDGET EVALUATION
1014 | */
1015 | {
1016 | /**
1017 | * The basic arithmetic gate identity in standard plonk is as follows.
1018 | * (w_1 . w_2 . q_m) + (w_1 . q_1) + (w_2 . q_2) + (w_3 . q_3) + (w_4 . q_4) + q_c = 0
1019 | * However, for Ultraplonk, we extend this to support "passing" wires between rows (shown without alpha scaling below):
1020 | * q_arith * ( ( (-1/2) * (q_arith - 3) * q_m * w_1 * w_2 + q_1 * w_1 + q_2 * w_2 + q_3 * w_3 + q_4 * w_4 + q_c ) +
1021 | * (q_arith - 1)*( α * (q_arith - 2) * (w_1 + w_4 - w_1_omega + q_m) + w_4_omega) ) = 0
1022 | *
1023 | * This formula results in several cases depending on q_arith:
1024 | * 1. q_arith == 0: Arithmetic gate is completely disabled
1025 | *
1026 | * 2. q_arith == 1: Everything in the minigate on the right is disabled. The equation is just a standard plonk equation
1027 | * with extra wires: q_m * w_1 * w_2 + q_1 * w_1 + q_2 * w_2 + q_3 * w_3 + q_4 * w_4 + q_c = 0
1028 | *
1029 | * 3. q_arith == 2: The (w_1 + w_4 - ...) term is disabled. THe equation is:
1030 | * (1/2) * q_m * w_1 * w_2 + q_1 * w_1 + q_2 * w_2 + q_3 * w_3 + q_4 * w_4 + q_c + w_4_omega = 0
1031 | * It allows defining w_4 at next index (w_4_omega) in terms of current wire values
1032 | *
1033 | * 4. q_arith == 3: The product of w_1 and w_2 is disabled, but a mini addition gate is enabled. α allows us to split
1034 | * the equation into two:
1035 | *
1036 | * q_1 * w_1 + q_2 * w_2 + q_3 * w_3 + q_4 * w_4 + q_c + 2 * w_4_omega = 0
1037 | * and
1038 | * w_1 + w_4 - w_1_omega + q_m = 0 (we are reusing q_m here)
1039 | *
1040 | * 5. q_arith > 3: The product of w_1 and w_2 is scaled by (q_arith - 3), while the w_4_omega term is scaled by (q_arith - 1).
1041 | * The equation can be split into two:
1042 | *
1043 | * (q_arith - 3)* q_m * w_1 * w_ 2 + q_1 * w_1 + q_2 * w_2 + q_3 * w_3 + q_4 * w_4 + q_c + (q_arith - 1) * w_4_omega = 0
1044 | * and
1045 | * w_1 + w_4 - w_1_omega + q_m = 0
1046 | *
1047 | * The problem that q_m is used both in both equations can be dealt with by appropriately changing selector values at
1048 | * the next gate. Then we can treat (q_arith - 1) as a simulated q_6 selector and scale q_m to handle (q_arith - 3) at
1049 | * product.
1050 | */
1051 |
1052 | let w1q1 := mulmod(mload(W1_EVAL_LOC), mload(Q1_EVAL_LOC), p)
1053 | let w2q2 := mulmod(mload(W2_EVAL_LOC), mload(Q2_EVAL_LOC), p)
1054 | let w3q3 := mulmod(mload(W3_EVAL_LOC), mload(Q3_EVAL_LOC), p)
1055 | let w4q3 := mulmod(mload(W4_EVAL_LOC), mload(Q4_EVAL_LOC), p)
1056 |
1057 | // @todo - Add a explicit test that hits QARITH == 3
1058 | // w1w2qm := (w_1 . w_2 . q_m . (QARITH_EVAL_LOC - 3)) / 2
1059 | let w1w2qm :=
1060 | mulmod(
1061 | mulmod(
1062 | mulmod(mulmod(mload(W1_EVAL_LOC), mload(W2_EVAL_LOC), p), mload(QM_EVAL_LOC), p),
1063 | addmod(mload(QARITH_EVAL_LOC), sub(p, 3), p),
1064 | p
1065 | ),
1066 | NEGATIVE_INVERSE_OF_2_MODULO_P,
1067 | p
1068 | )
1069 |
1070 | // (w_1 . w_2 . q_m . (q_arith - 3)) / -2) + (w_1 . q_1) + (w_2 . q_2) + (w_3 . q_3) + (w_4 . q_4) + q_c
1071 | let identity :=
1072 | addmod(
1073 | mload(QC_EVAL_LOC), addmod(w4q3, addmod(w3q3, addmod(w2q2, addmod(w1q1, w1w2qm, p), p), p), p), p
1074 | )
1075 |
1076 | // if q_arith == 3 we evaluate an additional mini addition gate (on top of the regular one), where:
1077 | // w_1 + w_4 - w_1_omega + q_m = 0
1078 | // we use this gate to save an addition gate when adding or subtracting non-native field elements
1079 | // α * (q_arith - 2) * (w_1 + w_4 - w_1_omega + q_m)
1080 | let extra_small_addition_gate_identity :=
1081 | mulmod(
1082 | mload(C_ALPHA_LOC),
1083 | mulmod(
1084 | addmod(mload(QARITH_EVAL_LOC), sub(p, 2), p),
1085 | addmod(
1086 | mload(QM_EVAL_LOC),
1087 | addmod(
1088 | sub(p, mload(W1_OMEGA_EVAL_LOC)), addmod(mload(W1_EVAL_LOC), mload(W4_EVAL_LOC), p), p
1089 | ),
1090 | p
1091 | ),
1092 | p
1093 | ),
1094 | p
1095 | )
1096 |
1097 | // if q_arith == 2 OR q_arith == 3 we add the 4th wire of the NEXT gate into the arithmetic identity
1098 | // N.B. if q_arith > 2, this wire value will be scaled by (q_arith - 1) relative to the other gate wires!
1099 | // alpha_base * q_arith * (identity + (q_arith - 1) * (w_4_omega + extra_small_addition_gate_identity))
1100 | mstore(
1101 | ARITHMETIC_IDENTITY,
1102 | mulmod(
1103 | mload(C_ALPHA_BASE_LOC),
1104 | mulmod(
1105 | mload(QARITH_EVAL_LOC),
1106 | addmod(
1107 | identity,
1108 | mulmod(
1109 | addmod(mload(QARITH_EVAL_LOC), sub(p, 1), p),
1110 | addmod(mload(W4_OMEGA_EVAL_LOC), extra_small_addition_gate_identity, p),
1111 | p
1112 | ),
1113 | p
1114 | ),
1115 | p
1116 | ),
1117 | p
1118 | )
1119 | )
1120 |
1121 | // update alpha
1122 | mstore(C_ALPHA_BASE_LOC, mulmod(mload(C_ALPHA_BASE_LOC), mload(C_ALPHA_SQR_LOC), p))
1123 | }
1124 |
1125 | /**
1126 | * COMPUTE GENPERMSORT WIDGET EVALUATION
1127 | */
1128 | {
1129 | /**
1130 | * D1 = (w2 - w1)
1131 | * D2 = (w3 - w2)
1132 | * D3 = (w4 - w3)
1133 | * D4 = (w1_omega - w4)
1134 | *
1135 | * α_a = alpha_base
1136 | * α_b = alpha_base * α
1137 | * α_c = alpha_base * α^2
1138 | * α_d = alpha_base * α^3
1139 | *
1140 | * range_accumulator = (
1141 | * D1(D1 - 1)(D1 - 2)(D1 - 3).α_a +
1142 | * D2(D2 - 1)(D2 - 2)(D2 - 3).α_b +
1143 | * D3(D3 - 1)(D3 - 2)(D3 - 3).α_c +
1144 | * D4(D4 - 1)(D4 - 2)(D4 - 3).α_d +
1145 | * ) . q_sort
1146 | */
1147 | let minus_two := sub(p, 2)
1148 | let minus_three := sub(p, 3)
1149 | let d1 := addmod(mload(W2_EVAL_LOC), sub(p, mload(W1_EVAL_LOC)), p)
1150 | let d2 := addmod(mload(W3_EVAL_LOC), sub(p, mload(W2_EVAL_LOC)), p)
1151 | let d3 := addmod(mload(W4_EVAL_LOC), sub(p, mload(W3_EVAL_LOC)), p)
1152 | let d4 := addmod(mload(W1_OMEGA_EVAL_LOC), sub(p, mload(W4_EVAL_LOC)), p)
1153 |
1154 | let range_accumulator :=
1155 | mulmod(
1156 | mulmod(
1157 | mulmod(addmod(mulmod(d1, d1, p), sub(p, d1), p), addmod(d1, minus_two, p), p),
1158 | addmod(d1, minus_three, p),
1159 | p
1160 | ),
1161 | mload(C_ALPHA_BASE_LOC),
1162 | p
1163 | )
1164 | range_accumulator :=
1165 | addmod(
1166 | range_accumulator,
1167 | mulmod(
1168 | mulmod(
1169 | mulmod(addmod(mulmod(d2, d2, p), sub(p, d2), p), addmod(d2, minus_two, p), p),
1170 | addmod(d2, minus_three, p),
1171 | p
1172 | ),
1173 | mulmod(mload(C_ALPHA_BASE_LOC), mload(C_ALPHA_LOC), p),
1174 | p
1175 | ),
1176 | p
1177 | )
1178 | range_accumulator :=
1179 | addmod(
1180 | range_accumulator,
1181 | mulmod(
1182 | mulmod(
1183 | mulmod(addmod(mulmod(d3, d3, p), sub(p, d3), p), addmod(d3, minus_two, p), p),
1184 | addmod(d3, minus_three, p),
1185 | p
1186 | ),
1187 | mulmod(mload(C_ALPHA_BASE_LOC), mload(C_ALPHA_SQR_LOC), p),
1188 | p
1189 | ),
1190 | p
1191 | )
1192 | range_accumulator :=
1193 | addmod(
1194 | range_accumulator,
1195 | mulmod(
1196 | mulmod(
1197 | mulmod(addmod(mulmod(d4, d4, p), sub(p, d4), p), addmod(d4, minus_two, p), p),
1198 | addmod(d4, minus_three, p),
1199 | p
1200 | ),
1201 | mulmod(mload(C_ALPHA_BASE_LOC), mload(C_ALPHA_CUBE_LOC), p),
1202 | p
1203 | ),
1204 | p
1205 | )
1206 | range_accumulator := mulmod(range_accumulator, mload(QSORT_EVAL_LOC), p)
1207 |
1208 | mstore(SORT_IDENTITY, range_accumulator)
1209 |
1210 | // update alpha
1211 | mstore(C_ALPHA_BASE_LOC, mulmod(mload(C_ALPHA_BASE_LOC), mload(C_ALPHA_QUAD_LOC), p))
1212 | }
1213 |
1214 | /**
1215 | * COMPUTE ELLIPTIC WIDGET EVALUATION
1216 | */
1217 | {
1218 | /**
1219 | * endo_term = (-x_2) * x_1 * (x_3 * 2 + x_1) * q_beta
1220 | * endo_sqr_term = x_2^2
1221 | * endo_sqr_term *= (x_3 - x_1)
1222 | * endo_sqr_term *= q_beta^2
1223 | * leftovers = x_2^2
1224 | * leftovers *= x_2
1225 | * leftovers += x_1^2 * (x_3 + x_1) @follow-up Invalid comment in BB widget
1226 | * leftovers -= (y_2^2 + y_1^2)
1227 | * sign_term = y_2 * y_1
1228 | * sign_term += sign_term
1229 | * sign_term *= q_sign
1230 | */
1231 | // q_elliptic * (x3 + x2 + x1)(x2 - x1)(x2 - x1) - y2^2 - y1^2 + 2(y2y1)*q_sign = 0
1232 | let x_diff := addmod(mload(X2_EVAL_LOC), sub(p, mload(X1_EVAL_LOC)), p)
1233 | let y2_sqr := mulmod(mload(Y2_EVAL_LOC), mload(Y2_EVAL_LOC), p)
1234 | let y1_sqr := mulmod(mload(Y1_EVAL_LOC), mload(Y1_EVAL_LOC), p)
1235 | let y1y2 := mulmod(mulmod(mload(Y1_EVAL_LOC), mload(Y2_EVAL_LOC), p), mload(QSIGN_LOC), p)
1236 |
1237 | let x_add_identity :=
1238 | addmod(
1239 | mulmod(
1240 | addmod(mload(X3_EVAL_LOC), addmod(mload(X2_EVAL_LOC), mload(X1_EVAL_LOC), p), p),
1241 | mulmod(x_diff, x_diff, p),
1242 | p
1243 | ),
1244 | addmod(
1245 | sub(
1246 | p,
1247 | addmod(y2_sqr, y1_sqr, p)
1248 | ),
1249 | addmod(y1y2, y1y2, p),
1250 | p
1251 | ),
1252 | p
1253 | )
1254 | x_add_identity :=
1255 | mulmod(
1256 | mulmod(
1257 | x_add_identity,
1258 | addmod(
1259 | 1,
1260 | sub(p, mload(QM_EVAL_LOC)),
1261 | p
1262 | ),
1263 | p
1264 | ),
1265 | mload(C_ALPHA_BASE_LOC),
1266 | p
1267 | )
1268 |
1269 | // q_elliptic * (x3 + x2 + x1)(x2 - x1)(x2 - x1) - y2^2 - y1^2 + 2(y2y1)*q_sign = 0
1270 | let y1_plus_y3 := addmod(
1271 | mload(Y1_EVAL_LOC),
1272 | mload(Y3_EVAL_LOC),
1273 | p
1274 | )
1275 | let y_diff := addmod(mulmod(mload(Y2_EVAL_LOC), mload(QSIGN_LOC), p), sub(p, mload(Y1_EVAL_LOC)), p)
1276 | let y_add_identity :=
1277 | addmod(
1278 | mulmod(y1_plus_y3, x_diff, p),
1279 | mulmod(addmod(mload(X3_EVAL_LOC), sub(p, mload(X1_EVAL_LOC)), p), y_diff, p),
1280 | p
1281 | )
1282 | y_add_identity :=
1283 | mulmod(
1284 | mulmod(y_add_identity, addmod(1, sub(p, mload(QM_EVAL_LOC)), p), p),
1285 | mulmod(mload(C_ALPHA_BASE_LOC), mload(C_ALPHA_LOC), p),
1286 | p
1287 | )
1288 |
1289 | // ELLIPTIC_IDENTITY = (x_identity + y_identity) * Q_ELLIPTIC_EVAL
1290 | mstore(
1291 | ELLIPTIC_IDENTITY, mulmod(addmod(x_add_identity, y_add_identity, p), mload(QELLIPTIC_EVAL_LOC), p)
1292 | )
1293 | }
1294 | {
1295 | /**
1296 | * x_pow_4 = (y_1_sqr - curve_b) * x_1;
1297 | * y_1_sqr_mul_4 = y_1_sqr + y_1_sqr;
1298 | * y_1_sqr_mul_4 += y_1_sqr_mul_4;
1299 | * x_1_pow_4_mul_9 = x_pow_4;
1300 | * x_1_pow_4_mul_9 += x_1_pow_4_mul_9;
1301 | * x_1_pow_4_mul_9 += x_1_pow_4_mul_9;
1302 | * x_1_pow_4_mul_9 += x_1_pow_4_mul_9;
1303 | * x_1_pow_4_mul_9 += x_pow_4;
1304 | * x_1_sqr_mul_3 = x_1_sqr + x_1_sqr + x_1_sqr;
1305 | * x_double_identity = (x_3 + x_1 + x_1) * y_1_sqr_mul_4 - x_1_pow_4_mul_9;
1306 | * y_double_identity = x_1_sqr_mul_3 * (x_1 - x_3) - (y_1 + y_1) * (y_1 + y_3);
1307 | */
1308 | // (x3 + x1 + x1) (4y1*y1) - 9 * x1 * x1 * x1 * x1 = 0
1309 | let x1_sqr := mulmod(mload(X1_EVAL_LOC), mload(X1_EVAL_LOC), p)
1310 | let y1_sqr := mulmod(mload(Y1_EVAL_LOC), mload(Y1_EVAL_LOC), p)
1311 | let x_pow_4 := mulmod(addmod(y1_sqr, GRUMPKIN_CURVE_B_PARAMETER_NEGATED, p), mload(X1_EVAL_LOC), p)
1312 | let y1_sqr_mul_4 := mulmod(y1_sqr, 4, p)
1313 | let x1_pow_4_mul_9 := mulmod(x_pow_4, 9, p)
1314 | let x1_sqr_mul_3 := mulmod(x1_sqr, 3, p)
1315 | let x_double_identity :=
1316 | addmod(
1317 | mulmod(
1318 | addmod(mload(X3_EVAL_LOC), addmod(mload(X1_EVAL_LOC), mload(X1_EVAL_LOC), p), p),
1319 | y1_sqr_mul_4,
1320 | p
1321 | ),
1322 | sub(p, x1_pow_4_mul_9),
1323 | p
1324 | )
1325 | // (y1 + y1) (2y1) - (3 * x1 * x1)(x1 - x3) = 0
1326 | let y_double_identity :=
1327 | addmod(
1328 | mulmod(x1_sqr_mul_3, addmod(mload(X1_EVAL_LOC), sub(p, mload(X3_EVAL_LOC)), p), p),
1329 | sub(
1330 | p,
1331 | mulmod(
1332 | addmod(mload(Y1_EVAL_LOC), mload(Y1_EVAL_LOC), p),
1333 | addmod(mload(Y1_EVAL_LOC), mload(Y3_EVAL_LOC), p),
1334 | p
1335 | )
1336 | ),
1337 | p
1338 | )
1339 | x_double_identity := mulmod(x_double_identity, mload(C_ALPHA_BASE_LOC), p)
1340 | y_double_identity :=
1341 | mulmod(y_double_identity, mulmod(mload(C_ALPHA_BASE_LOC), mload(C_ALPHA_LOC), p), p)
1342 | x_double_identity := mulmod(x_double_identity, mload(QM_EVAL_LOC), p)
1343 | y_double_identity := mulmod(y_double_identity, mload(QM_EVAL_LOC), p)
1344 | // ELLIPTIC_IDENTITY += (x_double_identity + y_double_identity) * Q_DOUBLE_EVAL
1345 | mstore(
1346 | ELLIPTIC_IDENTITY,
1347 | addmod(
1348 | mload(ELLIPTIC_IDENTITY),
1349 | mulmod(addmod(x_double_identity, y_double_identity, p), mload(QELLIPTIC_EVAL_LOC), p),
1350 | p
1351 | )
1352 | )
1353 |
1354 | // update alpha
1355 | mstore(C_ALPHA_BASE_LOC, mulmod(mload(C_ALPHA_BASE_LOC), mload(C_ALPHA_QUAD_LOC), p))
1356 | }
1357 |
1358 | /**
1359 | * COMPUTE AUXILIARY WIDGET EVALUATION
1360 | */
1361 | {
1362 | {
1363 | /**
1364 | * Non native field arithmetic gate 2
1365 | * _ _
1366 | * / _ _ _ 14 \
1367 | * q_2 . q_4 | (w_1 . w_2) + (w_1 . w_2) + (w_1 . w_4 + w_2 . w_3 - w_3) . 2 - w_3 - w_4 |
1368 | * \_ _/
1369 | *
1370 | * limb_subproduct = w_1 . w_2_omega + w_1_omega . w_2
1371 | * non_native_field_gate_2 = w_1 * w_4 + w_4 * w_3 - w_3_omega
1372 | * non_native_field_gate_2 = non_native_field_gate_2 * limb_size
1373 | * non_native_field_gate_2 -= w_4_omega
1374 | * non_native_field_gate_2 += limb_subproduct
1375 | * non_native_field_gate_2 *= q_4
1376 | * limb_subproduct *= limb_size
1377 | * limb_subproduct += w_1_omega * w_2_omega
1378 | * non_native_field_gate_1 = (limb_subproduct + w_3 + w_4) * q_3
1379 | * non_native_field_gate_3 = (limb_subproduct + w_4 - (w_3_omega + w_4_omega)) * q_m
1380 | * non_native_field_identity = (non_native_field_gate_1 + non_native_field_gate_2 + non_native_field_gate_3) * q_2
1381 | */
1382 |
1383 | let limb_subproduct :=
1384 | addmod(
1385 | mulmod(mload(W1_EVAL_LOC), mload(W2_OMEGA_EVAL_LOC), p),
1386 | mulmod(mload(W1_OMEGA_EVAL_LOC), mload(W2_EVAL_LOC), p),
1387 | p
1388 | )
1389 |
1390 | let non_native_field_gate_2 :=
1391 | addmod(
1392 | addmod(
1393 | mulmod(mload(W1_EVAL_LOC), mload(W4_EVAL_LOC), p),
1394 | mulmod(mload(W2_EVAL_LOC), mload(W3_EVAL_LOC), p),
1395 | p
1396 | ),
1397 | sub(p, mload(W3_OMEGA_EVAL_LOC)),
1398 | p
1399 | )
1400 | non_native_field_gate_2 := mulmod(non_native_field_gate_2, LIMB_SIZE, p)
1401 | non_native_field_gate_2 := addmod(non_native_field_gate_2, sub(p, mload(W4_OMEGA_EVAL_LOC)), p)
1402 | non_native_field_gate_2 := addmod(non_native_field_gate_2, limb_subproduct, p)
1403 | non_native_field_gate_2 := mulmod(non_native_field_gate_2, mload(Q4_EVAL_LOC), p)
1404 | limb_subproduct := mulmod(limb_subproduct, LIMB_SIZE, p)
1405 | limb_subproduct :=
1406 | addmod(limb_subproduct, mulmod(mload(W1_OMEGA_EVAL_LOC), mload(W2_OMEGA_EVAL_LOC), p), p)
1407 | let non_native_field_gate_1 :=
1408 | mulmod(
1409 | addmod(limb_subproduct, sub(p, addmod(mload(W3_EVAL_LOC), mload(W4_EVAL_LOC), p)), p),
1410 | mload(Q3_EVAL_LOC),
1411 | p
1412 | )
1413 | let non_native_field_gate_3 :=
1414 | mulmod(
1415 | addmod(
1416 | addmod(limb_subproduct, mload(W4_EVAL_LOC), p),
1417 | sub(p, addmod(mload(W3_OMEGA_EVAL_LOC), mload(W4_OMEGA_EVAL_LOC), p)),
1418 | p
1419 | ),
1420 | mload(QM_EVAL_LOC),
1421 | p
1422 | )
1423 | let non_native_field_identity :=
1424 | mulmod(
1425 | addmod(addmod(non_native_field_gate_1, non_native_field_gate_2, p), non_native_field_gate_3, p),
1426 | mload(Q2_EVAL_LOC),
1427 | p
1428 | )
1429 |
1430 | mstore(AUX_NON_NATIVE_FIELD_EVALUATION, non_native_field_identity)
1431 | }
1432 |
1433 | {
1434 | /**
1435 | * limb_accumulator_1 = w_2_omega;
1436 | * limb_accumulator_1 *= SUBLIMB_SHIFT;
1437 | * limb_accumulator_1 += w_1_omega;
1438 | * limb_accumulator_1 *= SUBLIMB_SHIFT;
1439 | * limb_accumulator_1 += w_3;
1440 | * limb_accumulator_1 *= SUBLIMB_SHIFT;
1441 | * limb_accumulator_1 += w_2;
1442 | * limb_accumulator_1 *= SUBLIMB_SHIFT;
1443 | * limb_accumulator_1 += w_1;
1444 | * limb_accumulator_1 -= w_4;
1445 | * limb_accumulator_1 *= q_4;
1446 | */
1447 | let limb_accumulator_1 := mulmod(mload(W2_OMEGA_EVAL_LOC), SUBLIMB_SHIFT, p)
1448 | limb_accumulator_1 := addmod(limb_accumulator_1, mload(W1_OMEGA_EVAL_LOC), p)
1449 | limb_accumulator_1 := mulmod(limb_accumulator_1, SUBLIMB_SHIFT, p)
1450 | limb_accumulator_1 := addmod(limb_accumulator_1, mload(W3_EVAL_LOC), p)
1451 | limb_accumulator_1 := mulmod(limb_accumulator_1, SUBLIMB_SHIFT, p)
1452 | limb_accumulator_1 := addmod(limb_accumulator_1, mload(W2_EVAL_LOC), p)
1453 | limb_accumulator_1 := mulmod(limb_accumulator_1, SUBLIMB_SHIFT, p)
1454 | limb_accumulator_1 := addmod(limb_accumulator_1, mload(W1_EVAL_LOC), p)
1455 | limb_accumulator_1 := addmod(limb_accumulator_1, sub(p, mload(W4_EVAL_LOC)), p)
1456 | limb_accumulator_1 := mulmod(limb_accumulator_1, mload(Q4_EVAL_LOC), p)
1457 |
1458 | /**
1459 | * limb_accumulator_2 = w_3_omega;
1460 | * limb_accumulator_2 *= SUBLIMB_SHIFT;
1461 | * limb_accumulator_2 += w_2_omega;
1462 | * limb_accumulator_2 *= SUBLIMB_SHIFT;
1463 | * limb_accumulator_2 += w_1_omega;
1464 | * limb_accumulator_2 *= SUBLIMB_SHIFT;
1465 | * limb_accumulator_2 += w_4;
1466 | * limb_accumulator_2 *= SUBLIMB_SHIFT;
1467 | * limb_accumulator_2 += w_3;
1468 | * limb_accumulator_2 -= w_4_omega;
1469 | * limb_accumulator_2 *= q_m;
1470 | */
1471 | let limb_accumulator_2 := mulmod(mload(W3_OMEGA_EVAL_LOC), SUBLIMB_SHIFT, p)
1472 | limb_accumulator_2 := addmod(limb_accumulator_2, mload(W2_OMEGA_EVAL_LOC), p)
1473 | limb_accumulator_2 := mulmod(limb_accumulator_2, SUBLIMB_SHIFT, p)
1474 | limb_accumulator_2 := addmod(limb_accumulator_2, mload(W1_OMEGA_EVAL_LOC), p)
1475 | limb_accumulator_2 := mulmod(limb_accumulator_2, SUBLIMB_SHIFT, p)
1476 | limb_accumulator_2 := addmod(limb_accumulator_2, mload(W4_EVAL_LOC), p)
1477 | limb_accumulator_2 := mulmod(limb_accumulator_2, SUBLIMB_SHIFT, p)
1478 | limb_accumulator_2 := addmod(limb_accumulator_2, mload(W3_EVAL_LOC), p)
1479 | limb_accumulator_2 := addmod(limb_accumulator_2, sub(p, mload(W4_OMEGA_EVAL_LOC)), p)
1480 | limb_accumulator_2 := mulmod(limb_accumulator_2, mload(QM_EVAL_LOC), p)
1481 |
1482 | mstore(
1483 | AUX_LIMB_ACCUMULATOR_EVALUATION,
1484 | mulmod(addmod(limb_accumulator_1, limb_accumulator_2, p), mload(Q3_EVAL_LOC), p)
1485 | )
1486 | }
1487 |
1488 | {
1489 | /**
1490 | * memory_record_check = w_3;
1491 | * memory_record_check *= eta;
1492 | * memory_record_check += w_2;
1493 | * memory_record_check *= eta;
1494 | * memory_record_check += w_1;
1495 | * memory_record_check *= eta;
1496 | * memory_record_check += q_c;
1497 | *
1498 | * partial_record_check = memory_record_check;
1499 | *
1500 | * memory_record_check -= w_4;
1501 | */
1502 |
1503 | let memory_record_check := mulmod(mload(W3_EVAL_LOC), mload(C_ETA_LOC), p)
1504 | memory_record_check := addmod(memory_record_check, mload(W2_EVAL_LOC), p)
1505 | memory_record_check := mulmod(memory_record_check, mload(C_ETA_LOC), p)
1506 | memory_record_check := addmod(memory_record_check, mload(W1_EVAL_LOC), p)
1507 | memory_record_check := mulmod(memory_record_check, mload(C_ETA_LOC), p)
1508 | memory_record_check := addmod(memory_record_check, mload(QC_EVAL_LOC), p)
1509 |
1510 | let partial_record_check := memory_record_check
1511 | memory_record_check := addmod(memory_record_check, sub(p, mload(W4_EVAL_LOC)), p)
1512 |
1513 | mstore(AUX_MEMORY_EVALUATION, memory_record_check)
1514 |
1515 | // index_delta = w_1_omega - w_1
1516 | let index_delta := addmod(mload(W1_OMEGA_EVAL_LOC), sub(p, mload(W1_EVAL_LOC)), p)
1517 | // record_delta = w_4_omega - w_4
1518 | let record_delta := addmod(mload(W4_OMEGA_EVAL_LOC), sub(p, mload(W4_EVAL_LOC)), p)
1519 | // index_is_monotonically_increasing = index_delta * (index_delta - 1)
1520 | let index_is_monotonically_increasing := mulmod(index_delta, addmod(index_delta, sub(p, 1), p), p)
1521 |
1522 | // adjacent_values_match_if_adjacent_indices_match = record_delta * (1 - index_delta)
1523 | let adjacent_values_match_if_adjacent_indices_match :=
1524 | mulmod(record_delta, addmod(1, sub(p, index_delta), p), p)
1525 |
1526 | // AUX_ROM_CONSISTENCY_EVALUATION = ((adjacent_values_match_if_adjacent_indices_match * alpha) + index_is_monotonically_increasing) * alpha + partial_record_check
1527 | mstore(
1528 | AUX_ROM_CONSISTENCY_EVALUATION,
1529 | addmod(
1530 | mulmod(
1531 | addmod(
1532 | mulmod(adjacent_values_match_if_adjacent_indices_match, mload(C_ALPHA_LOC), p),
1533 | index_is_monotonically_increasing,
1534 | p
1535 | ),
1536 | mload(C_ALPHA_LOC),
1537 | p
1538 | ),
1539 | memory_record_check,
1540 | p
1541 | )
1542 | )
1543 |
1544 | {
1545 | /**
1546 | * next_gate_access_type = w_3_omega;
1547 | * next_gate_access_type *= eta;
1548 | * next_gate_access_type += w_2_omega;
1549 | * next_gate_access_type *= eta;
1550 | * next_gate_access_type += w_1_omega;
1551 | * next_gate_access_type *= eta;
1552 | * next_gate_access_type = w_4_omega - next_gate_access_type;
1553 | */
1554 | let next_gate_access_type := mulmod(mload(W3_OMEGA_EVAL_LOC), mload(C_ETA_LOC), p)
1555 | next_gate_access_type := addmod(next_gate_access_type, mload(W2_OMEGA_EVAL_LOC), p)
1556 | next_gate_access_type := mulmod(next_gate_access_type, mload(C_ETA_LOC), p)
1557 | next_gate_access_type := addmod(next_gate_access_type, mload(W1_OMEGA_EVAL_LOC), p)
1558 | next_gate_access_type := mulmod(next_gate_access_type, mload(C_ETA_LOC), p)
1559 | next_gate_access_type := addmod(mload(W4_OMEGA_EVAL_LOC), sub(p, next_gate_access_type), p)
1560 |
1561 | // value_delta = w_3_omega - w_3
1562 | let value_delta := addmod(mload(W3_OMEGA_EVAL_LOC), sub(p, mload(W3_EVAL_LOC)), p)
1563 | // adjacent_values_match_if_adjacent_indices_match_and_next_access_is_a_read_operation = (1 - index_delta) * value_delta * (1 - next_gate_access_type);
1564 |
1565 | let adjacent_values_match_if_adjacent_indices_match_and_next_access_is_a_read_operation :=
1566 | mulmod(
1567 | addmod(1, sub(p, index_delta), p),
1568 | mulmod(value_delta, addmod(1, sub(p, next_gate_access_type), p), p),
1569 | p
1570 | )
1571 |
1572 | // AUX_RAM_CONSISTENCY_EVALUATION
1573 |
1574 | /**
1575 | * access_type = w_4 - partial_record_check
1576 | * access_check = access_type^2 - access_type
1577 | * next_gate_access_type_is_boolean = next_gate_access_type^2 - next_gate_access_type
1578 | * RAM_consistency_check_identity = adjacent_values_match_if_adjacent_indices_match_and_next_access_is_a_read_operation;
1579 | * RAM_consistency_check_identity *= alpha;
1580 | * RAM_consistency_check_identity += index_is_monotonically_increasing;
1581 | * RAM_consistency_check_identity *= alpha;
1582 | * RAM_consistency_check_identity += next_gate_access_type_is_boolean;
1583 | * RAM_consistency_check_identity *= alpha;
1584 | * RAM_consistency_check_identity += access_check;
1585 | */
1586 |
1587 | let access_type := addmod(mload(W4_EVAL_LOC), sub(p, partial_record_check), p)
1588 | let access_check := mulmod(access_type, addmod(access_type, sub(p, 1), p), p)
1589 | let next_gate_access_type_is_boolean :=
1590 | mulmod(next_gate_access_type, addmod(next_gate_access_type, sub(p, 1), p), p)
1591 | let RAM_cci :=
1592 | mulmod(
1593 | adjacent_values_match_if_adjacent_indices_match_and_next_access_is_a_read_operation,
1594 | mload(C_ALPHA_LOC),
1595 | p
1596 | )
1597 | RAM_cci := addmod(RAM_cci, index_is_monotonically_increasing, p)
1598 | RAM_cci := mulmod(RAM_cci, mload(C_ALPHA_LOC), p)
1599 | RAM_cci := addmod(RAM_cci, next_gate_access_type_is_boolean, p)
1600 | RAM_cci := mulmod(RAM_cci, mload(C_ALPHA_LOC), p)
1601 | RAM_cci := addmod(RAM_cci, access_check, p)
1602 |
1603 | mstore(AUX_RAM_CONSISTENCY_EVALUATION, RAM_cci)
1604 | }
1605 |
1606 | {
1607 | // timestamp_delta = w_2_omega - w_2
1608 | let timestamp_delta := addmod(mload(W2_OMEGA_EVAL_LOC), sub(p, mload(W2_EVAL_LOC)), p)
1609 |
1610 | // RAM_timestamp_check_identity = (1 - index_delta) * timestamp_delta - w_3
1611 | let RAM_timestamp_check_identity :=
1612 | addmod(
1613 | mulmod(timestamp_delta, addmod(1, sub(p, index_delta), p), p), sub(p, mload(W3_EVAL_LOC)), p
1614 | )
1615 |
1616 | /**
1617 | * memory_identity = ROM_consistency_check_identity * q_2;
1618 | * memory_identity += RAM_timestamp_check_identity * q_4;
1619 | * memory_identity += memory_record_check * q_m;
1620 | * memory_identity *= q_1;
1621 | * memory_identity += (RAM_consistency_check_identity * q_arith);
1622 | *
1623 | * auxiliary_identity = memory_identity + non_native_field_identity + limb_accumulator_identity;
1624 | * auxiliary_identity *= q_aux;
1625 | * auxiliary_identity *= alpha_base;
1626 | */
1627 | let memory_identity := mulmod(mload(AUX_ROM_CONSISTENCY_EVALUATION), mload(Q2_EVAL_LOC), p)
1628 | memory_identity :=
1629 | addmod(memory_identity, mulmod(RAM_timestamp_check_identity, mload(Q4_EVAL_LOC), p), p)
1630 | memory_identity :=
1631 | addmod(memory_identity, mulmod(mload(AUX_MEMORY_EVALUATION), mload(QM_EVAL_LOC), p), p)
1632 | memory_identity := mulmod(memory_identity, mload(Q1_EVAL_LOC), p)
1633 | memory_identity :=
1634 | addmod(
1635 | memory_identity, mulmod(mload(AUX_RAM_CONSISTENCY_EVALUATION), mload(QARITH_EVAL_LOC), p), p
1636 | )
1637 |
1638 | let auxiliary_identity := addmod(memory_identity, mload(AUX_NON_NATIVE_FIELD_EVALUATION), p)
1639 | auxiliary_identity := addmod(auxiliary_identity, mload(AUX_LIMB_ACCUMULATOR_EVALUATION), p)
1640 | auxiliary_identity := mulmod(auxiliary_identity, mload(QAUX_EVAL_LOC), p)
1641 | auxiliary_identity := mulmod(auxiliary_identity, mload(C_ALPHA_BASE_LOC), p)
1642 |
1643 | mstore(AUX_IDENTITY, auxiliary_identity)
1644 |
1645 | // update alpha
1646 | mstore(C_ALPHA_BASE_LOC, mulmod(mload(C_ALPHA_BASE_LOC), mload(C_ALPHA_CUBE_LOC), p))
1647 | }
1648 | }
1649 | }
1650 |
1651 | {
1652 | /**
1653 | * quotient = ARITHMETIC_IDENTITY
1654 | * quotient += PERMUTATION_IDENTITY
1655 | * quotient += PLOOKUP_IDENTITY
1656 | * quotient += SORT_IDENTITY
1657 | * quotient += ELLIPTIC_IDENTITY
1658 | * quotient += AUX_IDENTITY
1659 | * quotient *= ZERO_POLY_INVERSE
1660 | */
1661 | mstore(
1662 | QUOTIENT_EVAL_LOC,
1663 | mulmod(
1664 | addmod(
1665 | addmod(
1666 | addmod(
1667 | addmod(
1668 | addmod(mload(PERMUTATION_IDENTITY), mload(PLOOKUP_IDENTITY), p),
1669 | mload(ARITHMETIC_IDENTITY),
1670 | p
1671 | ),
1672 | mload(SORT_IDENTITY),
1673 | p
1674 | ),
1675 | mload(ELLIPTIC_IDENTITY),
1676 | p
1677 | ),
1678 | mload(AUX_IDENTITY),
1679 | p
1680 | ),
1681 | mload(ZERO_POLY_INVERSE_LOC),
1682 | p
1683 | )
1684 | )
1685 | }
1686 |
1687 | /**
1688 | * GENERATE NU AND SEPARATOR CHALLENGES
1689 | */
1690 | {
1691 | let current_challenge := mload(C_CURRENT_LOC)
1692 | // get a calldata pointer that points to the start of the data we want to copy
1693 | let calldata_ptr := add(calldataload(0x04), 0x24)
1694 |
1695 | calldata_ptr := add(calldata_ptr, NU_CALLDATA_SKIP_LENGTH)
1696 |
1697 | mstore(NU_CHALLENGE_INPUT_LOC_A, current_challenge)
1698 | mstore(NU_CHALLENGE_INPUT_LOC_B, mload(QUOTIENT_EVAL_LOC))
1699 | calldatacopy(NU_CHALLENGE_INPUT_LOC_C, calldata_ptr, NU_INPUT_LENGTH)
1700 |
1701 | // hash length = (0x20 + num field elements), we include the previous challenge in the hash
1702 | let challenge := keccak256(NU_CHALLENGE_INPUT_LOC_A, add(NU_INPUT_LENGTH, 0x40))
1703 |
1704 | mstore(C_V0_LOC, mod(challenge, p))
1705 | // We need THIRTY-ONE independent nu challenges!
1706 | mstore(0x00, challenge)
1707 | mstore8(0x20, 0x01)
1708 | mstore(C_V1_LOC, mod(keccak256(0x00, 0x21), p))
1709 | mstore8(0x20, 0x02)
1710 | mstore(C_V2_LOC, mod(keccak256(0x00, 0x21), p))
1711 | mstore8(0x20, 0x03)
1712 | mstore(C_V3_LOC, mod(keccak256(0x00, 0x21), p))
1713 | mstore8(0x20, 0x04)
1714 | mstore(C_V4_LOC, mod(keccak256(0x00, 0x21), p))
1715 | mstore8(0x20, 0x05)
1716 | mstore(C_V5_LOC, mod(keccak256(0x00, 0x21), p))
1717 | mstore8(0x20, 0x06)
1718 | mstore(C_V6_LOC, mod(keccak256(0x00, 0x21), p))
1719 | mstore8(0x20, 0x07)
1720 | mstore(C_V7_LOC, mod(keccak256(0x00, 0x21), p))
1721 | mstore8(0x20, 0x08)
1722 | mstore(C_V8_LOC, mod(keccak256(0x00, 0x21), p))
1723 | mstore8(0x20, 0x09)
1724 | mstore(C_V9_LOC, mod(keccak256(0x00, 0x21), p))
1725 | mstore8(0x20, 0x0a)
1726 | mstore(C_V10_LOC, mod(keccak256(0x00, 0x21), p))
1727 | mstore8(0x20, 0x0b)
1728 | mstore(C_V11_LOC, mod(keccak256(0x00, 0x21), p))
1729 | mstore8(0x20, 0x0c)
1730 | mstore(C_V12_LOC, mod(keccak256(0x00, 0x21), p))
1731 | mstore8(0x20, 0x0d)
1732 | mstore(C_V13_LOC, mod(keccak256(0x00, 0x21), p))
1733 | mstore8(0x20, 0x0e)
1734 | mstore(C_V14_LOC, mod(keccak256(0x00, 0x21), p))
1735 | mstore8(0x20, 0x0f)
1736 | mstore(C_V15_LOC, mod(keccak256(0x00, 0x21), p))
1737 | mstore8(0x20, 0x10)
1738 | mstore(C_V16_LOC, mod(keccak256(0x00, 0x21), p))
1739 | mstore8(0x20, 0x11)
1740 | mstore(C_V17_LOC, mod(keccak256(0x00, 0x21), p))
1741 | mstore8(0x20, 0x12)
1742 | mstore(C_V18_LOC, mod(keccak256(0x00, 0x21), p))
1743 | mstore8(0x20, 0x13)
1744 | mstore(C_V19_LOC, mod(keccak256(0x00, 0x21), p))
1745 | mstore8(0x20, 0x14)
1746 | mstore(C_V20_LOC, mod(keccak256(0x00, 0x21), p))
1747 | mstore8(0x20, 0x15)
1748 | mstore(C_V21_LOC, mod(keccak256(0x00, 0x21), p))
1749 | mstore8(0x20, 0x16)
1750 | mstore(C_V22_LOC, mod(keccak256(0x00, 0x21), p))
1751 | mstore8(0x20, 0x17)
1752 | mstore(C_V23_LOC, mod(keccak256(0x00, 0x21), p))
1753 | mstore8(0x20, 0x18)
1754 | mstore(C_V24_LOC, mod(keccak256(0x00, 0x21), p))
1755 | mstore8(0x20, 0x19)
1756 | mstore(C_V25_LOC, mod(keccak256(0x00, 0x21), p))
1757 | mstore8(0x20, 0x1a)
1758 | mstore(C_V26_LOC, mod(keccak256(0x00, 0x21), p))
1759 | mstore8(0x20, 0x1b)
1760 | mstore(C_V27_LOC, mod(keccak256(0x00, 0x21), p))
1761 | mstore8(0x20, 0x1c)
1762 | mstore(C_V28_LOC, mod(keccak256(0x00, 0x21), p))
1763 | mstore8(0x20, 0x1d)
1764 | mstore(C_V29_LOC, mod(keccak256(0x00, 0x21), p))
1765 |
1766 | // @follow-up - Why are both v29 and v30 using appending 0x1d to the prior challenge and hashing, should it not change?
1767 | mstore8(0x20, 0x1d)
1768 | challenge := keccak256(0x00, 0x21)
1769 | mstore(C_V30_LOC, mod(challenge, p))
1770 |
1771 | // separator
1772 | mstore(0x00, challenge)
1773 | mstore(0x20, mload(PI_Z_Y_LOC))
1774 | mstore(0x40, mload(PI_Z_X_LOC))
1775 | mstore(0x60, mload(PI_Z_OMEGA_Y_LOC))
1776 | mstore(0x80, mload(PI_Z_OMEGA_X_LOC))
1777 |
1778 | mstore(C_U_LOC, mod(keccak256(0x00, 0xa0), p))
1779 | }
1780 |
1781 | let success := 0
1782 | // VALIDATE T1
1783 | {
1784 | let x := mload(T1_X_LOC)
1785 | let y := mload(T1_Y_LOC)
1786 | let xx := mulmod(x, x, q)
1787 | // validate on curve
1788 | success := eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))
1789 | mstore(ACCUMULATOR_X_LOC, x)
1790 | mstore(add(ACCUMULATOR_X_LOC, 0x20), y)
1791 | }
1792 | // VALIDATE T2
1793 | {
1794 | let x := mload(T2_X_LOC) // 0x1400
1795 | let y := mload(T2_Y_LOC) // 0x1420
1796 | let xx := mulmod(x, x, q)
1797 | // validate on curve
1798 | success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))
1799 | mstore(0x00, x)
1800 | mstore(0x20, y)
1801 | }
1802 | mstore(0x40, mload(ZETA_POW_N_LOC))
1803 | // accumulator_2 = [T2].zeta^n
1804 | success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))
1805 | // accumulator = [T1] + accumulator_2
1806 | success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))
1807 |
1808 | // VALIDATE T3
1809 | {
1810 | let x := mload(T3_X_LOC)
1811 | let y := mload(T3_Y_LOC)
1812 | let xx := mulmod(x, x, q)
1813 | // validate on curve
1814 | success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))
1815 | mstore(0x00, x)
1816 | mstore(0x20, y)
1817 | }
1818 | mstore(0x40, mulmod(mload(ZETA_POW_N_LOC), mload(ZETA_POW_N_LOC), p))
1819 | // accumulator_2 = [T3].zeta^{2n}
1820 | success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))
1821 | // accumulator = accumulator + accumulator_2
1822 | success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))
1823 |
1824 | // VALIDATE T4
1825 | {
1826 | let x := mload(T4_X_LOC)
1827 | let y := mload(T4_Y_LOC)
1828 | let xx := mulmod(x, x, q)
1829 | // validate on curve
1830 | success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))
1831 | mstore(0x00, x)
1832 | mstore(0x20, y)
1833 | }
1834 | mstore(0x40, mulmod(mulmod(mload(ZETA_POW_N_LOC), mload(ZETA_POW_N_LOC), p), mload(ZETA_POW_N_LOC), p))
1835 | // accumulator_2 = [T4].zeta^{3n}
1836 | success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))
1837 | // accumulator = accumulator + accumulator_2
1838 | success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))
1839 |
1840 | // VALIDATE W1
1841 | {
1842 | let x := mload(W1_X_LOC)
1843 | let y := mload(W1_Y_LOC)
1844 | let xx := mulmod(x, x, q)
1845 | // validate on curve
1846 | success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))
1847 | mstore(0x00, x)
1848 | mstore(0x20, y)
1849 | }
1850 | mstore(0x40, mulmod(addmod(mload(C_U_LOC), 0x1, p), mload(C_V0_LOC), p))
1851 | // accumulator_2 = v0.(u + 1).[W1]
1852 | success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))
1853 | // accumulator = accumulator + accumulator_2
1854 | success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))
1855 |
1856 | // VALIDATE W2
1857 | {
1858 | let x := mload(W2_X_LOC)
1859 | let y := mload(W2_Y_LOC)
1860 | let xx := mulmod(x, x, q)
1861 | // validate on curve
1862 | success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))
1863 | mstore(0x00, x)
1864 | mstore(0x20, y)
1865 | }
1866 | mstore(0x40, mulmod(addmod(mload(C_U_LOC), 0x1, p), mload(C_V1_LOC), p))
1867 | // accumulator_2 = v1.(u + 1).[W2]
1868 | success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))
1869 | // accumulator = accumulator + accumulator_2
1870 | success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))
1871 |
1872 | // VALIDATE W3
1873 | {
1874 | let x := mload(W3_X_LOC)
1875 | let y := mload(W3_Y_LOC)
1876 | let xx := mulmod(x, x, q)
1877 | // validate on curve
1878 | success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))
1879 | mstore(0x00, x)
1880 | mstore(0x20, y)
1881 | }
1882 | mstore(0x40, mulmod(addmod(mload(C_U_LOC), 0x1, p), mload(C_V2_LOC), p))
1883 | // accumulator_2 = v2.(u + 1).[W3]
1884 | success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))
1885 | // accumulator = accumulator + accumulator_2
1886 | success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))
1887 |
1888 | // VALIDATE W4
1889 | {
1890 | let x := mload(W4_X_LOC)
1891 | let y := mload(W4_Y_LOC)
1892 | let xx := mulmod(x, x, q)
1893 | // validate on curve
1894 | success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))
1895 | mstore(0x00, x)
1896 | mstore(0x20, y)
1897 | }
1898 | mstore(0x40, mulmod(addmod(mload(C_U_LOC), 0x1, p), mload(C_V3_LOC), p))
1899 | // accumulator_2 = v3.(u + 1).[W4]
1900 | success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))
1901 | // accumulator = accumulator + accumulator_2
1902 | success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))
1903 |
1904 | // VALIDATE S
1905 | {
1906 | let x := mload(S_X_LOC)
1907 | let y := mload(S_Y_LOC)
1908 | let xx := mulmod(x, x, q)
1909 | // validate on curve
1910 | success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))
1911 | mstore(0x00, x)
1912 | mstore(0x20, y)
1913 | }
1914 | mstore(0x40, mulmod(addmod(mload(C_U_LOC), 0x1, p), mload(C_V4_LOC), p))
1915 | // accumulator_2 = v4.(u + 1).[S]
1916 | success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))
1917 | // accumulator = accumulator + accumulator_2
1918 | success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))
1919 |
1920 | // VALIDATE Z
1921 | {
1922 | let x := mload(Z_X_LOC)
1923 | let y := mload(Z_Y_LOC)
1924 | let xx := mulmod(x, x, q)
1925 | // validate on curve
1926 | success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))
1927 | mstore(0x00, x)
1928 | mstore(0x20, y)
1929 | }
1930 | mstore(0x40, mulmod(addmod(mload(C_U_LOC), 0x1, p), mload(C_V5_LOC), p))
1931 | // accumulator_2 = v5.(u + 1).[Z]
1932 | success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))
1933 | // accumulator = accumulator + accumulator_2
1934 | success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))
1935 |
1936 | // VALIDATE Z_LOOKUP
1937 | {
1938 | let x := mload(Z_LOOKUP_X_LOC)
1939 | let y := mload(Z_LOOKUP_Y_LOC)
1940 | let xx := mulmod(x, x, q)
1941 | // validate on curve
1942 | success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))
1943 | mstore(0x00, x)
1944 | mstore(0x20, y)
1945 | }
1946 | mstore(0x40, mulmod(addmod(mload(C_U_LOC), 0x1, p), mload(C_V6_LOC), p))
1947 | // accumulator_2 = v6.(u + 1).[Z_LOOKUP]
1948 | success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))
1949 | // accumulator = accumulator + accumulator_2
1950 | success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))
1951 |
1952 | // VALIDATE Q1
1953 | {
1954 | let x := mload(Q1_X_LOC)
1955 | let y := mload(Q1_Y_LOC)
1956 | let xx := mulmod(x, x, q)
1957 | // validate on curve
1958 | success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))
1959 | mstore(0x00, x)
1960 | mstore(0x20, y)
1961 | }
1962 | mstore(0x40, mload(C_V7_LOC))
1963 | // accumulator_2 = v7.[Q1]
1964 | success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))
1965 | // accumulator = accumulator + accumulator_2
1966 | success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))
1967 |
1968 | // VALIDATE Q2
1969 | {
1970 | let x := mload(Q2_X_LOC)
1971 | let y := mload(Q2_Y_LOC)
1972 | let xx := mulmod(x, x, q)
1973 | // validate on curve
1974 | success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))
1975 | mstore(0x00, x)
1976 | mstore(0x20, y)
1977 | }
1978 | mstore(0x40, mload(C_V8_LOC))
1979 | // accumulator_2 = v8.[Q2]
1980 | success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))
1981 | // accumulator = accumulator + accumulator_2
1982 | success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))
1983 |
1984 | // VALIDATE Q3
1985 | {
1986 | let x := mload(Q3_X_LOC)
1987 | let y := mload(Q3_Y_LOC)
1988 | let xx := mulmod(x, x, q)
1989 | // validate on curve
1990 | success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))
1991 | mstore(0x00, x)
1992 | mstore(0x20, y)
1993 | }
1994 | mstore(0x40, mload(C_V9_LOC))
1995 | // accumulator_2 = v9.[Q3]
1996 | success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))
1997 | // accumulator = accumulator + accumulator_2
1998 | success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))
1999 |
2000 | // VALIDATE Q4
2001 | {
2002 | let x := mload(Q4_X_LOC)
2003 | let y := mload(Q4_Y_LOC)
2004 | let xx := mulmod(x, x, q)
2005 | // validate on curve
2006 | success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))
2007 | mstore(0x00, x)
2008 | mstore(0x20, y)
2009 | }
2010 | mstore(0x40, mload(C_V10_LOC))
2011 | // accumulator_2 = v10.[Q4]
2012 | success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))
2013 | // accumulator = accumulator + accumulator_2
2014 | success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))
2015 |
2016 | // VALIDATE QM
2017 | {
2018 | let x := mload(QM_X_LOC)
2019 | let y := mload(QM_Y_LOC)
2020 | let xx := mulmod(x, x, q)
2021 | // validate on curve
2022 | success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))
2023 | mstore(0x00, x)
2024 | mstore(0x20, y)
2025 | }
2026 | mstore(0x40, mload(C_V11_LOC))
2027 | // accumulator_2 = v11.[Q;]
2028 | success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))
2029 | // accumulator = accumulator + accumulator_2
2030 | success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))
2031 |
2032 | // VALIDATE QC
2033 | {
2034 | let x := mload(QC_X_LOC)
2035 | let y := mload(QC_Y_LOC)
2036 | let xx := mulmod(x, x, q)
2037 | // validate on curve
2038 | success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))
2039 | mstore(0x00, x)
2040 | mstore(0x20, y)
2041 | }
2042 | mstore(0x40, mload(C_V12_LOC))
2043 | // accumulator_2 = v12.[QC]
2044 | success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))
2045 | // accumulator = accumulator + accumulator_2
2046 | success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))
2047 |
2048 | // VALIDATE QARITH
2049 | {
2050 | let x := mload(QARITH_X_LOC)
2051 | let y := mload(QARITH_Y_LOC)
2052 | let xx := mulmod(x, x, q)
2053 | // validate on curve
2054 | success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))
2055 | mstore(0x00, x)
2056 | mstore(0x20, y)
2057 | }
2058 | mstore(0x40, mload(C_V13_LOC))
2059 | // accumulator_2 = v13.[QARITH]
2060 | success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))
2061 | // accumulator = accumulator + accumulator_2
2062 | success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))
2063 |
2064 | // VALIDATE QSORT
2065 | {
2066 | let x := mload(QSORT_X_LOC)
2067 | let y := mload(QSORT_Y_LOC)
2068 | let xx := mulmod(x, x, q)
2069 | // validate on curve
2070 | success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))
2071 | mstore(0x00, x)
2072 | mstore(0x20, y)
2073 | }
2074 | mstore(0x40, mload(C_V14_LOC))
2075 | // accumulator_2 = v14.[QSORT]
2076 | success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))
2077 | // accumulator = accumulator + accumulator_2
2078 | success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))
2079 |
2080 | // VALIDATE QELLIPTIC
2081 | {
2082 | let x := mload(QELLIPTIC_X_LOC)
2083 | let y := mload(QELLIPTIC_Y_LOC)
2084 | let xx := mulmod(x, x, q)
2085 | // validate on curve
2086 | success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))
2087 | mstore(0x00, x)
2088 | mstore(0x20, y)
2089 | }
2090 | mstore(0x40, mload(C_V15_LOC))
2091 | // accumulator_2 = v15.[QELLIPTIC]
2092 | success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))
2093 | // accumulator = accumulator + accumulator_2
2094 | success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))
2095 |
2096 | // VALIDATE QAUX
2097 | {
2098 | let x := mload(QAUX_X_LOC)
2099 | let y := mload(QAUX_Y_LOC)
2100 | let xx := mulmod(x, x, q)
2101 | // validate on curve
2102 | success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))
2103 | mstore(0x00, x)
2104 | mstore(0x20, y)
2105 | }
2106 | mstore(0x40, mload(C_V16_LOC))
2107 | // accumulator_2 = v15.[Q_AUX]
2108 | success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))
2109 | // accumulator = accumulator + accumulator_2
2110 | success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))
2111 |
2112 | // VALIDATE SIGMA1
2113 | {
2114 | let x := mload(SIGMA1_X_LOC)
2115 | let y := mload(SIGMA1_Y_LOC)
2116 | let xx := mulmod(x, x, q)
2117 | // validate on curve
2118 | success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))
2119 | mstore(0x00, x)
2120 | mstore(0x20, y)
2121 | }
2122 | mstore(0x40, mload(C_V17_LOC))
2123 | // accumulator_2 = v17.[sigma1]
2124 | success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))
2125 | // accumulator = accumulator + accumulator_2
2126 | success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))
2127 |
2128 | // VALIDATE SIGMA2
2129 | {
2130 | let x := mload(SIGMA2_X_LOC)
2131 | let y := mload(SIGMA2_Y_LOC)
2132 | let xx := mulmod(x, x, q)
2133 | // validate on curve
2134 | success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))
2135 | mstore(0x00, x)
2136 | mstore(0x20, y)
2137 | }
2138 | mstore(0x40, mload(C_V18_LOC))
2139 | // accumulator_2 = v18.[sigma2]
2140 | success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))
2141 | // accumulator = accumulator + accumulator_2
2142 | success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))
2143 |
2144 | // VALIDATE SIGMA3
2145 | {
2146 | let x := mload(SIGMA3_X_LOC)
2147 | let y := mload(SIGMA3_Y_LOC)
2148 | let xx := mulmod(x, x, q)
2149 | // validate on curve
2150 | success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))
2151 | mstore(0x00, x)
2152 | mstore(0x20, y)
2153 | }
2154 | mstore(0x40, mload(C_V19_LOC))
2155 | // accumulator_2 = v19.[sigma3]
2156 | success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))
2157 | // accumulator = accumulator + accumulator_2
2158 | success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))
2159 |
2160 | // VALIDATE SIGMA4
2161 | {
2162 | let x := mload(SIGMA4_X_LOC)
2163 | let y := mload(SIGMA4_Y_LOC)
2164 | let xx := mulmod(x, x, q)
2165 | // validate on curve
2166 | success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))
2167 | mstore(0x00, x)
2168 | mstore(0x20, y)
2169 | }
2170 | mstore(0x40, mload(C_V20_LOC))
2171 | // accumulator_2 = v20.[sigma4]
2172 | success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))
2173 | // accumulator = accumulator + accumulator_2
2174 | success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))
2175 |
2176 | // VALIDATE TABLE1
2177 | {
2178 | let x := mload(TABLE1_X_LOC)
2179 | let y := mload(TABLE1_Y_LOC)
2180 | let xx := mulmod(x, x, q)
2181 | // validate on curve
2182 | success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))
2183 | mstore(0x00, x)
2184 | mstore(0x20, y)
2185 | }
2186 | mstore(0x40, mulmod(addmod(mload(C_U_LOC), 0x1, p), mload(C_V21_LOC), p))
2187 | // accumulator_2 = u.[table1]
2188 | success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))
2189 | // accumulator = accumulator + accumulator_2
2190 | success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))
2191 |
2192 | // VALIDATE TABLE2
2193 | {
2194 | let x := mload(TABLE2_X_LOC)
2195 | let y := mload(TABLE2_Y_LOC)
2196 | let xx := mulmod(x, x, q)
2197 | // validate on curve
2198 | success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))
2199 | mstore(0x00, x)
2200 | mstore(0x20, y)
2201 | }
2202 | mstore(0x40, mulmod(addmod(mload(C_U_LOC), 0x1, p), mload(C_V22_LOC), p))
2203 | // accumulator_2 = u.[table2]
2204 | success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))
2205 | // accumulator = accumulator + accumulator_2
2206 | success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))
2207 |
2208 | // VALIDATE TABLE3
2209 | {
2210 | let x := mload(TABLE3_X_LOC)
2211 | let y := mload(TABLE3_Y_LOC)
2212 | let xx := mulmod(x, x, q)
2213 | // validate on curve
2214 | success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))
2215 | mstore(0x00, x)
2216 | mstore(0x20, y)
2217 | }
2218 | mstore(0x40, mulmod(addmod(mload(C_U_LOC), 0x1, p), mload(C_V23_LOC), p))
2219 | // accumulator_2 = u.[table3]
2220 | success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))
2221 | // accumulator = accumulator + accumulator_2
2222 | success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))
2223 |
2224 | // VALIDATE TABLE4
2225 | {
2226 | let x := mload(TABLE4_X_LOC)
2227 | let y := mload(TABLE4_Y_LOC)
2228 | let xx := mulmod(x, x, q)
2229 | // validate on curve
2230 | success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))
2231 | mstore(0x00, x)
2232 | mstore(0x20, y)
2233 | }
2234 | mstore(0x40, mulmod(addmod(mload(C_U_LOC), 0x1, p), mload(C_V24_LOC), p))
2235 | // accumulator_2 = u.[table4]
2236 | success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))
2237 | // accumulator = accumulator + accumulator_2
2238 | success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))
2239 |
2240 | // VALIDATE TABLE_TYPE
2241 | {
2242 | let x := mload(TABLE_TYPE_X_LOC)
2243 | let y := mload(TABLE_TYPE_Y_LOC)
2244 | let xx := mulmod(x, x, q)
2245 | // validate on curve
2246 | success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))
2247 | mstore(0x00, x)
2248 | mstore(0x20, y)
2249 | }
2250 | mstore(0x40, mload(C_V25_LOC))
2251 | // accumulator_2 = v25.[TableType]
2252 | success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))
2253 | // accumulator = accumulator + accumulator_2
2254 | success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))
2255 |
2256 | // VALIDATE ID1
2257 | {
2258 | let x := mload(ID1_X_LOC)
2259 | let y := mload(ID1_Y_LOC)
2260 | let xx := mulmod(x, x, q)
2261 | // validate on curve
2262 | success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))
2263 | mstore(0x00, x)
2264 | mstore(0x20, y)
2265 | }
2266 | mstore(0x40, mload(C_V26_LOC))
2267 | // accumulator_2 = v26.[ID1]
2268 | success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))
2269 | // accumulator = accumulator + accumulator_2
2270 | success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))
2271 |
2272 | // VALIDATE ID2
2273 | {
2274 | let x := mload(ID2_X_LOC)
2275 | let y := mload(ID2_Y_LOC)
2276 | let xx := mulmod(x, x, q)
2277 | // validate on curve
2278 | success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))
2279 | mstore(0x00, x)
2280 | mstore(0x20, y)
2281 | }
2282 | mstore(0x40, mload(C_V27_LOC))
2283 | // accumulator_2 = v27.[ID2]
2284 | success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))
2285 | // accumulator = accumulator + accumulator_2
2286 | success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))
2287 |
2288 | // VALIDATE ID3
2289 | {
2290 | let x := mload(ID3_X_LOC)
2291 | let y := mload(ID3_Y_LOC)
2292 | let xx := mulmod(x, x, q)
2293 | // validate on curve
2294 | success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))
2295 | mstore(0x00, x)
2296 | mstore(0x20, y)
2297 | }
2298 | mstore(0x40, mload(C_V28_LOC))
2299 | // accumulator_2 = v28.[ID3]
2300 | success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))
2301 | // accumulator = accumulator + accumulator_2
2302 | success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))
2303 |
2304 | // VALIDATE ID4
2305 | {
2306 | let x := mload(ID4_X_LOC)
2307 | let y := mload(ID4_Y_LOC)
2308 | let xx := mulmod(x, x, q)
2309 | // validate on curve
2310 | success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))
2311 | mstore(0x00, x)
2312 | mstore(0x20, y)
2313 | }
2314 | mstore(0x40, mload(C_V29_LOC))
2315 | // accumulator_2 = v29.[ID4]
2316 | success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))
2317 | // accumulator = accumulator + accumulator_2
2318 | success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))
2319 |
2320 | /**
2321 | * COMPUTE BATCH EVALUATION SCALAR MULTIPLIER
2322 | */
2323 | {
2324 | /**
2325 | * batch_evaluation = v0 * (w_1_omega * u + w_1_eval)
2326 | * batch_evaluation += v1 * (w_2_omega * u + w_2_eval)
2327 | * batch_evaluation += v2 * (w_3_omega * u + w_3_eval)
2328 | * batch_evaluation += v3 * (w_4_omega * u + w_4_eval)
2329 | * batch_evaluation += v4 * (s_omega_eval * u + s_eval)
2330 | * batch_evaluation += v5 * (z_omega_eval * u + z_eval)
2331 | * batch_evaluation += v6 * (z_lookup_omega_eval * u + z_lookup_eval)
2332 | */
2333 | let batch_evaluation :=
2334 | mulmod(
2335 | mload(C_V0_LOC),
2336 | addmod(mulmod(mload(W1_OMEGA_EVAL_LOC), mload(C_U_LOC), p), mload(W1_EVAL_LOC), p),
2337 | p
2338 | )
2339 | batch_evaluation :=
2340 | addmod(
2341 | batch_evaluation,
2342 | mulmod(
2343 | mload(C_V1_LOC),
2344 | addmod(mulmod(mload(W2_OMEGA_EVAL_LOC), mload(C_U_LOC), p), mload(W2_EVAL_LOC), p),
2345 | p
2346 | ),
2347 | p
2348 | )
2349 | batch_evaluation :=
2350 | addmod(
2351 | batch_evaluation,
2352 | mulmod(
2353 | mload(C_V2_LOC),
2354 | addmod(mulmod(mload(W3_OMEGA_EVAL_LOC), mload(C_U_LOC), p), mload(W3_EVAL_LOC), p),
2355 | p
2356 | ),
2357 | p
2358 | )
2359 | batch_evaluation :=
2360 | addmod(
2361 | batch_evaluation,
2362 | mulmod(
2363 | mload(C_V3_LOC),
2364 | addmod(mulmod(mload(W4_OMEGA_EVAL_LOC), mload(C_U_LOC), p), mload(W4_EVAL_LOC), p),
2365 | p
2366 | ),
2367 | p
2368 | )
2369 | batch_evaluation :=
2370 | addmod(
2371 | batch_evaluation,
2372 | mulmod(
2373 | mload(C_V4_LOC),
2374 | addmod(mulmod(mload(S_OMEGA_EVAL_LOC), mload(C_U_LOC), p), mload(S_EVAL_LOC), p),
2375 | p
2376 | ),
2377 | p
2378 | )
2379 | batch_evaluation :=
2380 | addmod(
2381 | batch_evaluation,
2382 | mulmod(
2383 | mload(C_V5_LOC),
2384 | addmod(mulmod(mload(Z_OMEGA_EVAL_LOC), mload(C_U_LOC), p), mload(Z_EVAL_LOC), p),
2385 | p
2386 | ),
2387 | p
2388 | )
2389 | batch_evaluation :=
2390 | addmod(
2391 | batch_evaluation,
2392 | mulmod(
2393 | mload(C_V6_LOC),
2394 | addmod(mulmod(mload(Z_LOOKUP_OMEGA_EVAL_LOC), mload(C_U_LOC), p), mload(Z_LOOKUP_EVAL_LOC), p),
2395 | p
2396 | ),
2397 | p
2398 | )
2399 |
2400 | /**
2401 | * batch_evaluation += v7 * Q1_EVAL
2402 | * batch_evaluation += v8 * Q2_EVAL
2403 | * batch_evaluation += v9 * Q3_EVAL
2404 | * batch_evaluation += v10 * Q4_EVAL
2405 | * batch_evaluation += v11 * QM_EVAL
2406 | * batch_evaluation += v12 * QC_EVAL
2407 | * batch_evaluation += v13 * QARITH_EVAL
2408 | * batch_evaluation += v14 * QSORT_EVAL_LOC
2409 | * batch_evaluation += v15 * QELLIPTIC_EVAL_LOC
2410 | * batch_evaluation += v16 * QAUX_EVAL_LOC
2411 | * batch_evaluation += v17 * SIGMA1_EVAL_LOC
2412 | * batch_evaluation += v18 * SIGMA2_EVAL_LOC
2413 | * batch_evaluation += v19 * SIGMA3_EVAL_LOC
2414 | * batch_evaluation += v20 * SIGMA4_EVAL_LOC
2415 | */
2416 | batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V7_LOC), mload(Q1_EVAL_LOC), p), p)
2417 | batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V8_LOC), mload(Q2_EVAL_LOC), p), p)
2418 | batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V9_LOC), mload(Q3_EVAL_LOC), p), p)
2419 | batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V10_LOC), mload(Q4_EVAL_LOC), p), p)
2420 | batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V11_LOC), mload(QM_EVAL_LOC), p), p)
2421 | batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V12_LOC), mload(QC_EVAL_LOC), p), p)
2422 | batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V13_LOC), mload(QARITH_EVAL_LOC), p), p)
2423 | batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V14_LOC), mload(QSORT_EVAL_LOC), p), p)
2424 | batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V15_LOC), mload(QELLIPTIC_EVAL_LOC), p), p)
2425 | batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V16_LOC), mload(QAUX_EVAL_LOC), p), p)
2426 | batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V17_LOC), mload(SIGMA1_EVAL_LOC), p), p)
2427 | batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V18_LOC), mload(SIGMA2_EVAL_LOC), p), p)
2428 | batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V19_LOC), mload(SIGMA3_EVAL_LOC), p), p)
2429 | batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V20_LOC), mload(SIGMA4_EVAL_LOC), p), p)
2430 |
2431 | /**
2432 | * batch_evaluation += v21 * (table1(zw) * u + table1(z))
2433 | * batch_evaluation += v22 * (table2(zw) * u + table2(z))
2434 | * batch_evaluation += v23 * (table3(zw) * u + table3(z))
2435 | * batch_evaluation += v24 * (table4(zw) * u + table4(z))
2436 | * batch_evaluation += v25 * table_type_eval
2437 | * batch_evaluation += v26 * id1_eval
2438 | * batch_evaluation += v27 * id2_eval
2439 | * batch_evaluation += v28 * id3_eval
2440 | * batch_evaluation += v29 * id4_eval
2441 | * batch_evaluation += quotient_eval
2442 | */
2443 | batch_evaluation :=
2444 | addmod(
2445 | batch_evaluation,
2446 | mulmod(
2447 | mload(C_V21_LOC),
2448 | addmod(mulmod(mload(TABLE1_OMEGA_EVAL_LOC), mload(C_U_LOC), p), mload(TABLE1_EVAL_LOC), p),
2449 | p
2450 | ),
2451 | p
2452 | )
2453 | batch_evaluation :=
2454 | addmod(
2455 | batch_evaluation,
2456 | mulmod(
2457 | mload(C_V22_LOC),
2458 | addmod(mulmod(mload(TABLE2_OMEGA_EVAL_LOC), mload(C_U_LOC), p), mload(TABLE2_EVAL_LOC), p),
2459 | p
2460 | ),
2461 | p
2462 | )
2463 | batch_evaluation :=
2464 | addmod(
2465 | batch_evaluation,
2466 | mulmod(
2467 | mload(C_V23_LOC),
2468 | addmod(mulmod(mload(TABLE3_OMEGA_EVAL_LOC), mload(C_U_LOC), p), mload(TABLE3_EVAL_LOC), p),
2469 | p
2470 | ),
2471 | p
2472 | )
2473 | batch_evaluation :=
2474 | addmod(
2475 | batch_evaluation,
2476 | mulmod(
2477 | mload(C_V24_LOC),
2478 | addmod(mulmod(mload(TABLE4_OMEGA_EVAL_LOC), mload(C_U_LOC), p), mload(TABLE4_EVAL_LOC), p),
2479 | p
2480 | ),
2481 | p
2482 | )
2483 | batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V25_LOC), mload(TABLE_TYPE_EVAL_LOC), p), p)
2484 | batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V26_LOC), mload(ID1_EVAL_LOC), p), p)
2485 | batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V27_LOC), mload(ID2_EVAL_LOC), p), p)
2486 | batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V28_LOC), mload(ID3_EVAL_LOC), p), p)
2487 | batch_evaluation := addmod(batch_evaluation, mulmod(mload(C_V29_LOC), mload(ID4_EVAL_LOC), p), p)
2488 | batch_evaluation := addmod(batch_evaluation, mload(QUOTIENT_EVAL_LOC), p)
2489 |
2490 | mstore(0x00, 0x01) // [1].x
2491 | mstore(0x20, 0x02) // [1].y
2492 | mstore(0x40, sub(p, batch_evaluation))
2493 | // accumulator_2 = -[1].(batch_evaluation)
2494 | success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))
2495 | // accumulator = accumulator + accumulator_2
2496 | success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))
2497 |
2498 | mstore(OPENING_COMMITMENT_SUCCESS_FLAG, success)
2499 | }
2500 |
2501 | /**
2502 | * PERFORM PAIRING PREAMBLE
2503 | */
2504 | {
2505 | let u := mload(C_U_LOC)
2506 | let zeta := mload(C_ZETA_LOC)
2507 | // VALIDATE PI_Z
2508 | {
2509 | let x := mload(PI_Z_X_LOC)
2510 | let y := mload(PI_Z_Y_LOC)
2511 | let xx := mulmod(x, x, q)
2512 | // validate on curve
2513 | success := eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))
2514 | mstore(0x00, x)
2515 | mstore(0x20, y)
2516 | }
2517 | // compute zeta.[PI_Z] and add into accumulator
2518 | mstore(0x40, zeta)
2519 | success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))
2520 | // accumulator = accumulator + accumulator_2
2521 | success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40))
2522 |
2523 | // VALIDATE PI_Z_OMEGA
2524 | {
2525 | let x := mload(PI_Z_OMEGA_X_LOC)
2526 | let y := mload(PI_Z_OMEGA_Y_LOC)
2527 | let xx := mulmod(x, x, q)
2528 | // validate on curve
2529 | success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))
2530 | mstore(0x00, x)
2531 | mstore(0x20, y)
2532 | }
2533 | mstore(0x40, mulmod(mulmod(u, zeta, p), mload(OMEGA_LOC), p))
2534 | // accumulator_2 = u.zeta.omega.[PI_Z_OMEGA]
2535 | success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40))
2536 | // PAIRING_RHS = accumulator + accumulator_2
2537 | success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, PAIRING_RHS_X_LOC, 0x40))
2538 |
2539 | mstore(0x00, mload(PI_Z_X_LOC))
2540 | mstore(0x20, mload(PI_Z_Y_LOC))
2541 | mstore(0x40, mload(PI_Z_OMEGA_X_LOC))
2542 | mstore(0x60, mload(PI_Z_OMEGA_Y_LOC))
2543 | mstore(0x80, u)
2544 | success := and(success, staticcall(gas(), 7, 0x40, 0x60, 0x40, 0x40))
2545 | // PAIRING_LHS = [PI_Z] + [PI_Z_OMEGA] * u
2546 | success := and(success, staticcall(gas(), 6, 0x00, 0x80, PAIRING_LHS_X_LOC, 0x40))
2547 | // negate lhs y-coordinate
2548 | mstore(PAIRING_LHS_Y_LOC, sub(q, mload(PAIRING_LHS_Y_LOC)))
2549 |
2550 | if mload(CONTAINS_RECURSIVE_PROOF_LOC) {
2551 | // VALIDATE RECURSIVE P1
2552 | {
2553 | let x := mload(RECURSIVE_P1_X_LOC)
2554 | let y := mload(RECURSIVE_P1_Y_LOC)
2555 | let xx := mulmod(x, x, q)
2556 | // validate on curve
2557 | success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))
2558 | mstore(0x00, x)
2559 | mstore(0x20, y)
2560 | }
2561 |
2562 | // compute u.u.[recursive_p1] and write into 0x60
2563 | mstore(0x40, mulmod(u, u, p))
2564 | success := and(success, staticcall(gas(), 7, 0x00, 0x60, 0x60, 0x40))
2565 | // VALIDATE RECURSIVE P2
2566 | {
2567 | let x := mload(RECURSIVE_P2_X_LOC)
2568 | let y := mload(RECURSIVE_P2_Y_LOC)
2569 | let xx := mulmod(x, x, q)
2570 | // validate on curve
2571 | success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)))
2572 | mstore(0x00, x)
2573 | mstore(0x20, y)
2574 | }
2575 | // compute u.u.[recursive_p2] and write into 0x00
2576 | // 0x40 still contains u*u
2577 | success := and(success, staticcall(gas(), 7, 0x00, 0x60, 0x00, 0x40))
2578 |
2579 | // compute u.u.[recursiveP1] + rhs and write into rhs
2580 | mstore(0xa0, mload(PAIRING_RHS_X_LOC))
2581 | mstore(0xc0, mload(PAIRING_RHS_Y_LOC))
2582 | success := and(success, staticcall(gas(), 6, 0x60, 0x80, PAIRING_RHS_X_LOC, 0x40))
2583 |
2584 | // compute u.u.[recursiveP2] + lhs and write into lhs
2585 | mstore(0x40, mload(PAIRING_LHS_X_LOC))
2586 | mstore(0x60, mload(PAIRING_LHS_Y_LOC))
2587 | success := and(success, staticcall(gas(), 6, 0x00, 0x80, PAIRING_LHS_X_LOC, 0x40))
2588 | }
2589 |
2590 | if iszero(success) {
2591 | mstore(0x0, EC_SCALAR_MUL_FAILURE_SELECTOR)
2592 | revert(0x00, 0x04)
2593 | }
2594 | mstore(PAIRING_PREAMBLE_SUCCESS_FLAG, success)
2595 | }
2596 |
2597 | /**
2598 | * PERFORM PAIRING
2599 | */
2600 | {
2601 | // rhs paired with [1]_2
2602 | // lhs paired with [x]_2
2603 |
2604 | mstore(0x00, mload(PAIRING_RHS_X_LOC))
2605 | mstore(0x20, mload(PAIRING_RHS_Y_LOC))
2606 | mstore(0x40, 0x198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c2) // this is [1]_2
2607 | mstore(0x60, 0x1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed)
2608 | mstore(0x80, 0x090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b)
2609 | mstore(0xa0, 0x12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa)
2610 |
2611 | mstore(0xc0, mload(PAIRING_LHS_X_LOC))
2612 | mstore(0xe0, mload(PAIRING_LHS_Y_LOC))
2613 | mstore(0x100, mload(G2X_X0_LOC))
2614 | mstore(0x120, mload(G2X_X1_LOC))
2615 | mstore(0x140, mload(G2X_Y0_LOC))
2616 | mstore(0x160, mload(G2X_Y1_LOC))
2617 |
2618 | success := staticcall(gas(), 8, 0x00, 0x180, 0x00, 0x20)
2619 | mstore(PAIRING_SUCCESS_FLAG, success)
2620 | mstore(RESULT_FLAG, mload(0x00))
2621 | }
2622 | if iszero(
2623 | and(
2624 | and(and(mload(PAIRING_SUCCESS_FLAG), mload(RESULT_FLAG)), mload(PAIRING_PREAMBLE_SUCCESS_FLAG)),
2625 | mload(OPENING_COMMITMENT_SUCCESS_FLAG)
2626 | )
2627 | ) {
2628 | mstore(0x0, PROOF_FAILURE_SELECTOR)
2629 | revert(0x00, 0x04)
2630 | }
2631 | {
2632 | mstore(0x00, 0x01)
2633 | return(0x00, 0x20) // Proof succeeded!
2634 | }
2635 | }
2636 | }
2637 | }
2638 |
2639 | contract UltraVerifier is BaseUltraVerifier {
2640 | function getVerificationKeyHash() public pure override(BaseUltraVerifier) returns (bytes32) {
2641 | return UltraVerificationKey.verificationKeyHash();
2642 | }
2643 |
2644 | function loadVerificationKey(uint256 vk, uint256 _omegaInverseLoc) internal pure virtual override(BaseUltraVerifier) {
2645 | UltraVerificationKey.loadVerificationKey(vk, _omegaInverseLoc);
2646 | }
2647 | }
2648 |
--------------------------------------------------------------------------------
/circuit/src/main.nr:
--------------------------------------------------------------------------------
1 | use dep::std::ecdsa_secp256k1::verify_signature;
2 |
3 | fn main(
4 | pub_key_x: [u8; 32],
5 | pub_key_y: [u8; 32],
6 | signature: [u8; 64],
7 | hashed_message: pub [u8; 32],
8 | ) {
9 | let valid_signature = verify_signature(pub_key_x, pub_key_y, signature, hashed_message);
10 | assert(valid_signature);
11 | }
--------------------------------------------------------------------------------
/circuit/target/circuit.json:
--------------------------------------------------------------------------------
1 | {"noir_version":"0.19.4+4d133c50a50f21ca23861a9d1987207bd8783d36","hash":14454786671665241064,"backend":"acvm-backend-barretenberg","abi":{"parameters":[{"name":"pub_key_x","type":{"kind":"array","length":32,"type":{"kind":"integer","sign":"unsigned","width":8}},"visibility":"private"},{"name":"pub_key_y","type":{"kind":"array","length":32,"type":{"kind":"integer","sign":"unsigned","width":8}},"visibility":"private"},{"name":"signature","type":{"kind":"array","length":64,"type":{"kind":"integer","sign":"unsigned","width":8}},"visibility":"private"},{"name":"hashed_message","type":{"kind":"array","length":32,"type":{"kind":"integer","sign":"unsigned","width":8}},"visibility":"public"}],"param_witnesses":{"hashed_message":[{"start":129,"end":161}],"pub_key_x":[{"start":1,"end":33}],"pub_key_y":[{"start":33,"end":65}],"signature":[{"start":65,"end":129}]},"return_type":null,"return_witnesses":[]},"bytecode":"H4sIAAAAAAAA/6WWZW/bZxxF/8moY2ZKO8rYju3EHjXtKGNmSrw6y5iZMigzc5v0k7ZHfq7knL7sI1k/nbywIkv33LtYVdWJqv+GTn2Gy102wMPis8Rni88Rnys+T7xMfL74AvGF4ovEF4svEV8qvkx8ufgK8ZXiq8RXi68RXyu+Tny9+AbxjeKbxDeLbxHfKh4RLxevEN8mvl18h/hO8V3iUfHd4nvE94rvE98vfkD8oLgmrovHxA1xU9wSj4snxG1xR/yQ+GHxI+JHxY+JV4onxavEq8WPi58QPyl+Svy0eEr8jPhZ8XPi58UviF8UvyR+WfyK+FXxa+LXxW+I3xS/JX5b/I74XfF74vfFH4g/FH8knhbPiLvij8VrxD3xrPgT8Zz4U/Fn4s/FX4i/FH8l/lr8jfhb8Xfi78U/iH8U/yT+WfyL+Ffxb+LfxX+I/xT/Jf5bPC/+R/yv+D/x/+K14nXi9eIN4o3iTeLN4i3ireJt4u3iHeKd4l3i3eI94r3ifeL94gPig+JD4sPiI+Kj4mPi4+KFAWZ7jVT9N1T+Plxudl/2XnZe9l12XT7Zcdlv2W3Za9lp2WfZZdlj2WHZX9ld2VvZWdlX2VXZU9lR2U/ZTdlL2UnZR9lFIwOXt7zwinKzf7J7sneyc7JvRsvNnsmOyX7JbsleyU7JPskuyR7JDsn+yO7I3sjOyL7IrsieyI7IfshuyF7ITsg+mBy4vFWFV5ebHZD+T++n79PzU+Wm19Pn6fH0d3o7fZ2eTj+nl9PH6eH0b3o3fZueTb+mV9On6dH0Z3ozfZmenC53ptxuuenB9F96L32XnpsrN72WPkuPpb/SW+mr9FT6Kb2UPkoPpX/SO+mb9Ez6Jb2SPkmPpD/SG+mL9MR8tTQP6Yf0QvogPRD/x/vx/YZy4/d4PT6Px+PveDu+jqfj53g5Po6H4994N76NZ+PXeDU+jUfjz3gzvlwod7Fa+obKnSy3dmavvjjwXY3aeLPZmxjr1Rv1mdpYp9tu1Zqt7ni73q632q01Y+1Go9dutic63c5ErVNvNnr12VanMVu+bH7gf8TjOBx/4268HWfjajyNo/EzbsbLOBkf42I8jIPxL+7FuzgX3+JaPItj8Stuxas4daTqOxR/4k68iTPxJa4crfqOxI+4ES/iRHyIC/EgDsR/uA/v4Tx8h+vwHI7Db7gNr+E0fLay/Ja4C2/hLHyFq/AUjpqq+m7CSzgJH+EiPISD8A/uwTs4B9/gGjyDY/ALbsErOAWf4BI8gkOmq7478AbOwBe4Ak/giLmq7wa8gBPwAS7AAziA/JN9ck/myTtZJ+dknHyTbXJNpskzWSbHZHi+WppdcktmyStZJadklHySTXJJJskjWSSHZJD8kT1yR+bIG1kjZ2SMfJEtckWmyBNZIkdkaKE6/Z0Etse+D4ASAAA="}
--------------------------------------------------------------------------------
/circuit/target/debug_circuit.json:
--------------------------------------------------------------------------------
1 | {"debug_symbols":[{"locations":{"160":[{"span":{"start":190,"end":255},"file":1}],"161":[{"span":{"start":268,"end":283},"file":1}]}}],"file_map":{"1":{"source":"use dep::std::ecdsa_secp256k1::verify_signature;\n\nfn main(\n pub_key_x: [u8; 32],\n pub_key_y: [u8; 32],\n signature: [u8; 64],\n hashed_message: pub [u8; 32],\n) {\n let valid_signature = verify_signature(pub_key_x, pub_key_y, signature, hashed_message);\n assert(valid_signature);\n}","path":"/home/turupawn/Projects/NEGRO/test01/circuit/src/main.nr"}},"warnings":[]}
--------------------------------------------------------------------------------
/contracts/CommentVerifier.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: MIT
2 | pragma solidity 0.8.23;
3 |
4 | interface IUltraVerifier {
5 | function verify(bytes calldata _proof, bytes32[] calldata _publicInputs) external view returns (bool);
6 | }
7 |
8 | abstract contract Utils {
9 | // ADDRESS TO STRING
10 | // From 0age on Stackoverflow
11 | //https://ethereum.stackexchange.com/questions/63908/address-checksum-solidity-implementation
12 | function toChecksumString( address account) internal pure returns (string memory asciiString) {
13 | // convert the account argument from address to bytes.
14 | bytes20 data = bytes20(account);
15 |
16 | // create an in-memory fixed-size bytes array.
17 | bytes memory asciiBytes = new bytes(40);
18 |
19 | // declare variable types.
20 | uint8 b;
21 | uint8 leftNibble;
22 | uint8 rightNibble;
23 | bool leftCaps;
24 | bool rightCaps;
25 | uint8 asciiOffset;
26 |
27 | // get the capitalized characters in the actual checksum.
28 | bool[40] memory caps = _toChecksumCapsFlags(account);
29 |
30 | // iterate over bytes, processing left and right nibble in each iteration.
31 | for (uint256 i = 0; i < data.length; i++) {
32 | // locate the byte and extract each nibble.
33 | b = uint8(uint160(data) / (2**(8*(19 - i))));
34 | leftNibble = b / 16;
35 | rightNibble = b - 16 * leftNibble;
36 |
37 | // locate and extract each capitalization status.
38 | leftCaps = caps[2*i];
39 | rightCaps = caps[2*i + 1];
40 |
41 | // get the offset from nibble value to ascii character for left nibble.
42 | asciiOffset = _getAsciiOffset(leftNibble, leftCaps);
43 |
44 | // add the converted character to the byte array.
45 | asciiBytes[2 * i] = bytes1(leftNibble + asciiOffset);
46 |
47 | // get the offset from nibble value to ascii character for right nibble.
48 | asciiOffset = _getAsciiOffset(rightNibble, rightCaps);
49 |
50 | // add the converted character to the byte array.
51 | asciiBytes[2 * i + 1] = bytes1(rightNibble + asciiOffset);
52 | }
53 |
54 | return string(asciiBytes);
55 | }
56 |
57 | function _toChecksumCapsFlags(address account) internal pure returns (bool[40] memory characterCapitalized) {
58 | // convert the address to bytes.
59 | bytes20 a = bytes20(account);
60 |
61 | // hash the address (used to calculate checksum).
62 | bytes32 b = keccak256(abi.encodePacked(_toAsciiString(a)));
63 |
64 | // declare variable types.
65 | uint8 leftNibbleAddress;
66 | uint8 rightNibbleAddress;
67 | uint8 leftNibbleHash;
68 | uint8 rightNibbleHash;
69 |
70 | // iterate over bytes, processing left and right nibble in each iteration.
71 | for (uint256 i; i < a.length; i++) {
72 | // locate the byte and extract each nibble for the address and the hash.
73 | rightNibbleAddress = uint8(a[i]) % 16;
74 | leftNibbleAddress = (uint8(a[i]) - rightNibbleAddress) / 16;
75 | rightNibbleHash = uint8(b[i]) % 16;
76 | leftNibbleHash = (uint8(b[i]) - rightNibbleHash) / 16;
77 |
78 | characterCapitalized[2 * i] = (
79 | leftNibbleAddress > 9 &&
80 | leftNibbleHash > 7
81 | );
82 | characterCapitalized[2 * i + 1] = (
83 | rightNibbleAddress > 9 &&
84 | rightNibbleHash > 7
85 | );
86 | }
87 | }
88 |
89 | function _getAsciiOffset(uint8 nibble, bool caps) internal pure returns (uint8 offset) {
90 | // to convert to ascii characters, add 48 to 0-9, 55 to A-F, & 87 to a-f.
91 | if (nibble < 10) {
92 | offset = 48;
93 | } else if (caps) {
94 | offset = 55;
95 | } else {
96 | offset = 87;
97 | }
98 | }
99 |
100 |
101 | // based on https://ethereum.stackexchange.com/a/56499/48410
102 | function _toAsciiString(bytes20 data) internal pure returns (string memory asciiString) {
103 | // create an in-memory fixed-size bytes array.
104 | bytes memory asciiBytes = new bytes(40);
105 |
106 | // declare variable types.
107 | uint8 b;
108 | uint8 leftNibble;
109 | uint8 rightNibble;
110 |
111 | // iterate over bytes, processing left and right nibble in each iteration.
112 | for (uint256 i = 0; i < data.length; i++) {
113 | // locate the byte and extract each nibble.
114 | b = uint8(uint160(data) / (2 ** (8 * (19 - i))));
115 | leftNibble = b / 16;
116 | rightNibble = b - 16 * leftNibble;
117 |
118 | // to convert to ascii characters, add 48 to 0-9 and 87 to a-f.
119 | asciiBytes[2 * i] = bytes1(leftNibble + (leftNibble < 10 ? 48 : 87));
120 | asciiBytes[2 * i + 1] = bytes1(rightNibble + (rightNibble < 10 ? 48 : 87));
121 | }
122 |
123 | return string(asciiBytes);
124 | }
125 |
126 | // UINT TO STRING
127 | // From OpenZeppelin
128 | // https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/Strings.sol
129 | function log10(uint256 value) internal pure returns (uint256) {
130 | uint256 result = 0;
131 | unchecked {
132 | if (value >= 10 ** 64) {
133 | value /= 10 ** 64;
134 | result += 64;
135 | }
136 | if (value >= 10 ** 32) {
137 | value /= 10 ** 32;
138 | result += 32;
139 | }
140 | if (value >= 10 ** 16) {
141 | value /= 10 ** 16;
142 | result += 16;
143 | }
144 | if (value >= 10 ** 8) {
145 | value /= 10 ** 8;
146 | result += 8;
147 | }
148 | if (value >= 10 ** 4) {
149 | value /= 10 ** 4;
150 | result += 4;
151 | }
152 | if (value >= 10 ** 2) {
153 | value /= 10 ** 2;
154 | result += 2;
155 | }
156 | if (value >= 10 ** 1) {
157 | result += 1;
158 | }
159 | }
160 | return result;
161 | }
162 |
163 | bytes16 private constant HEX_DIGITS = "0123456789abcdef";
164 |
165 | function toString(uint256 value) internal pure returns (string memory) {
166 | unchecked {
167 | uint256 length = log10(value) + 1;
168 | string memory buffer = new string(length);
169 | uint256 ptr;
170 | /// @solidity memory-safe-assembly
171 | assembly {
172 | ptr := add(buffer, add(32, length))
173 | }
174 | while (true) {
175 | ptr--;
176 | /// @solidity memory-safe-assembly
177 | assembly {
178 | mstore8(ptr, byte(mod(value, 10), HEX_DIGITS))
179 | }
180 | value /= 10;
181 | if (value == 0) break;
182 | }
183 | return buffer;
184 | }
185 | }
186 |
187 | // CONCATENATE HEX ARRAY
188 | // From ChatGPT
189 | function concatenateHexArray(bytes32[] memory hexArray) internal pure returns (bytes32) {
190 | bytes32 result;
191 | for (uint256 i = 0; i < hexArray.length; i++) {
192 | result = result << 8 | hexArray[i];
193 | }
194 | return result;
195 | }
196 | }
197 |
198 | contract CommentVerifier is Utils {
199 | uint public commentAmount;
200 | mapping(uint commentId => string title) public titles;
201 | mapping(uint commentId => string text) public texts;
202 | IUltraVerifier ultraVerifier;
203 |
204 | string public myAddress;
205 | string public messageHeader;
206 | string public messagePrefix;
207 | string public messageMiddlefix;
208 | string public messageSuffix;
209 |
210 | constructor(address verifierAddress) {
211 | ultraVerifier = IUltraVerifier(verifierAddress);
212 |
213 | myAddress = toChecksumString(address(this));
214 | messageHeader = "\x19Ethereum Signed Message:\n";
215 | messagePrefix = string(abi.encodePacked(
216 | "{\"types\":{\"EIP712Domain\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"version\",\"type\":\"string\"},{\"name\":\"chainId\",\"type\":\"uint256\"},{\"name\":\"verifyingContract\",\"type\":\"address\"}],\"Comment\":[{\"name\":\"title\",\"type\":\"string\"},{\"name\":\"text\",\"type\":\"string\"}]},\"primaryType\":\"Comment\",\"domain\":{\"name\":\"Anon Message Board\",\"version\":\"1\",\"chainId\":534351,\"verifyingContract\":\"0x",
217 | myAddress,
218 | "\"},\"message\":{\"title\":\""));
219 | messageMiddlefix = "\",\"text\":\"";
220 | messageSuffix = "\"}}";
221 | }
222 |
223 | function isValidHash(bytes32 hash, string memory title, string memory text) public view returns(bool) {
224 | string memory jsonMessage = string(abi.encodePacked(messagePrefix, title, messageMiddlefix, text, messageSuffix));
225 | return hash == keccak256(abi.encodePacked(
226 | messageHeader,
227 | toString(bytes(jsonMessage).length),
228 | jsonMessage));
229 | }
230 |
231 | function sendProof(bytes calldata _proof, bytes32[] calldata _publicInputs, string memory title, string memory text) public
232 | {
233 | require(isValidHash(concatenateHexArray(_publicInputs), title, text), "Invalid message hash");
234 | ultraVerifier.verify(_proof, _publicInputs);
235 | titles[commentAmount] = title;
236 | texts[commentAmount] = text;
237 | commentAmount+=1;
238 | }
239 | }
240 |
--------------------------------------------------------------------------------
/relayer/.env.example:
--------------------------------------------------------------------------------
1 | RPC_URL="https://sepolia-rpc.scroll.io"
2 | COMMENT_VERIFIER_ADDRESS = "0x123abc"
3 | RELAYER_PRIVATE_KEY ="123abc"
4 | RELAYER_ADDRESS = "0x123abv"
--------------------------------------------------------------------------------
/relayer/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | .env
--------------------------------------------------------------------------------
/relayer/json_abi/CommentVerifier.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "inputs": [
4 | {
5 | "internalType": "bytes",
6 | "name": "_proof",
7 | "type": "bytes"
8 | },
9 | {
10 | "internalType": "bytes32[]",
11 | "name": "_publicInputs",
12 | "type": "bytes32[]"
13 | },
14 | {
15 | "internalType": "string",
16 | "name": "title",
17 | "type": "string"
18 | },
19 | {
20 | "internalType": "string",
21 | "name": "text",
22 | "type": "string"
23 | }
24 | ],
25 | "name": "sendProof",
26 | "outputs": [],
27 | "stateMutability": "nonpayable",
28 | "type": "function"
29 | },
30 | {
31 | "inputs": [],
32 | "stateMutability": "nonpayable",
33 | "type": "constructor"
34 | },
35 | {
36 | "inputs": [],
37 | "name": "commentAmount",
38 | "outputs": [
39 | {
40 | "internalType": "uint256",
41 | "name": "",
42 | "type": "uint256"
43 | }
44 | ],
45 | "stateMutability": "view",
46 | "type": "function"
47 | },
48 | {
49 | "inputs": [
50 | {
51 | "internalType": "bytes32",
52 | "name": "hash",
53 | "type": "bytes32"
54 | },
55 | {
56 | "internalType": "string",
57 | "name": "title",
58 | "type": "string"
59 | },
60 | {
61 | "internalType": "string",
62 | "name": "text",
63 | "type": "string"
64 | }
65 | ],
66 | "name": "isValidHash",
67 | "outputs": [
68 | {
69 | "internalType": "bool",
70 | "name": "",
71 | "type": "bool"
72 | }
73 | ],
74 | "stateMutability": "view",
75 | "type": "function"
76 | },
77 | {
78 | "inputs": [],
79 | "name": "messageHeader",
80 | "outputs": [
81 | {
82 | "internalType": "string",
83 | "name": "",
84 | "type": "string"
85 | }
86 | ],
87 | "stateMutability": "view",
88 | "type": "function"
89 | },
90 | {
91 | "inputs": [],
92 | "name": "messageMiddlefix",
93 | "outputs": [
94 | {
95 | "internalType": "string",
96 | "name": "",
97 | "type": "string"
98 | }
99 | ],
100 | "stateMutability": "view",
101 | "type": "function"
102 | },
103 | {
104 | "inputs": [],
105 | "name": "messagePrefix",
106 | "outputs": [
107 | {
108 | "internalType": "string",
109 | "name": "",
110 | "type": "string"
111 | }
112 | ],
113 | "stateMutability": "view",
114 | "type": "function"
115 | },
116 | {
117 | "inputs": [],
118 | "name": "messageSuffix",
119 | "outputs": [
120 | {
121 | "internalType": "string",
122 | "name": "",
123 | "type": "string"
124 | }
125 | ],
126 | "stateMutability": "view",
127 | "type": "function"
128 | },
129 | {
130 | "inputs": [],
131 | "name": "myAddress",
132 | "outputs": [
133 | {
134 | "internalType": "string",
135 | "name": "",
136 | "type": "string"
137 | }
138 | ],
139 | "stateMutability": "view",
140 | "type": "function"
141 | },
142 | {
143 | "inputs": [
144 | {
145 | "internalType": "uint256",
146 | "name": "commentId",
147 | "type": "uint256"
148 | }
149 | ],
150 | "name": "texts",
151 | "outputs": [
152 | {
153 | "internalType": "string",
154 | "name": "text",
155 | "type": "string"
156 | }
157 | ],
158 | "stateMutability": "view",
159 | "type": "function"
160 | },
161 | {
162 | "inputs": [
163 | {
164 | "internalType": "uint256",
165 | "name": "commentId",
166 | "type": "uint256"
167 | }
168 | ],
169 | "name": "titles",
170 | "outputs": [
171 | {
172 | "internalType": "string",
173 | "name": "title",
174 | "type": "string"
175 | }
176 | ],
177 | "stateMutability": "view",
178 | "type": "function"
179 | }
180 | ]
--------------------------------------------------------------------------------
/relayer/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "relayer",
3 | "version": "1.0.0",
4 | "lockfileVersion": 3,
5 | "requires": true,
6 | "packages": {
7 | "": {
8 | "name": "relayer",
9 | "version": "1.0.0",
10 | "license": "ISC",
11 | "dependencies": {
12 | "cors": "^2.8.5",
13 | "dotenv": "^10.0.0",
14 | "ethers": "^6.9.0",
15 | "node-fetch": "^3.1.0"
16 | }
17 | },
18 | "node_modules/@adraffy/ens-normalize": {
19 | "version": "1.10.0",
20 | "resolved": "https://registry.npmjs.org/@adraffy/ens-normalize/-/ens-normalize-1.10.0.tgz",
21 | "integrity": "sha512-nA9XHtlAkYfJxY7bce8DcN7eKxWWCWkU+1GR9d+U6MbNpfwQp8TI7vqOsBsMcHoT4mBu2kypKoSKnghEzOOq5Q=="
22 | },
23 | "node_modules/aes-js": {
24 | "version": "4.0.0-beta.5",
25 | "resolved": "https://registry.npmjs.org/aes-js/-/aes-js-4.0.0-beta.5.tgz",
26 | "integrity": "sha512-G965FqalsNyrPqgEGON7nIx1e/OVENSgiEIzyC63haUMuvNnwIgIjMs52hlTCKhkBny7A2ORNlfY9Zu+jmGk1Q=="
27 | },
28 | "node_modules/bufferutil": {
29 | "version": "4.0.8",
30 | "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.8.tgz",
31 | "integrity": "sha512-4T53u4PdgsXqKaIctwF8ifXlRTTmEPJ8iEPWFdGZvcf7sbwYo6FKFEX9eNNAnzFZ7EzJAQ3CJeOtCRA4rDp7Pw==",
32 | "hasInstallScript": true,
33 | "optional": true,
34 | "peer": true,
35 | "dependencies": {
36 | "node-gyp-build": "^4.3.0"
37 | },
38 | "engines": {
39 | "node": ">=6.14.2"
40 | }
41 | },
42 | "node_modules/cors": {
43 | "version": "2.8.5",
44 | "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz",
45 | "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==",
46 | "dependencies": {
47 | "object-assign": "^4",
48 | "vary": "^1"
49 | },
50 | "engines": {
51 | "node": ">= 0.10"
52 | }
53 | },
54 | "node_modules/data-uri-to-buffer": {
55 | "version": "4.0.1",
56 | "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz",
57 | "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==",
58 | "engines": {
59 | "node": ">= 12"
60 | }
61 | },
62 | "node_modules/dotenv": {
63 | "version": "10.0.0",
64 | "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz",
65 | "integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==",
66 | "engines": {
67 | "node": ">=10"
68 | }
69 | },
70 | "node_modules/ethers": {
71 | "version": "6.9.0",
72 | "resolved": "https://registry.npmjs.org/ethers/-/ethers-6.9.0.tgz",
73 | "integrity": "sha512-pmfNyQzc2mseLe91FnT2vmNaTt8dDzhxZ/xItAV7uGsF4dI4ek2ufMu3rAkgQETL/TIs0GS5A+U05g9QyWnv3Q==",
74 | "funding": [
75 | {
76 | "type": "individual",
77 | "url": "https://github.com/sponsors/ethers-io/"
78 | },
79 | {
80 | "type": "individual",
81 | "url": "https://www.buymeacoffee.com/ricmoo"
82 | }
83 | ],
84 | "dependencies": {
85 | "@adraffy/ens-normalize": "1.10.0",
86 | "@noble/curves": "1.2.0",
87 | "@noble/hashes": "1.3.2",
88 | "@types/node": "18.15.13",
89 | "aes-js": "4.0.0-beta.5",
90 | "tslib": "2.4.0",
91 | "ws": "8.5.0"
92 | },
93 | "engines": {
94 | "node": ">=14.0.0"
95 | }
96 | },
97 | "node_modules/ethers/node_modules/@noble/curves": {
98 | "version": "1.2.0",
99 | "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.2.0.tgz",
100 | "integrity": "sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw==",
101 | "dependencies": {
102 | "@noble/hashes": "1.3.2"
103 | },
104 | "funding": {
105 | "url": "https://paulmillr.com/funding/"
106 | }
107 | },
108 | "node_modules/ethers/node_modules/@noble/hashes": {
109 | "version": "1.3.2",
110 | "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.2.tgz",
111 | "integrity": "sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ==",
112 | "engines": {
113 | "node": ">= 16"
114 | },
115 | "funding": {
116 | "url": "https://paulmillr.com/funding/"
117 | }
118 | },
119 | "node_modules/ethers/node_modules/@types/node": {
120 | "version": "18.15.13",
121 | "resolved": "https://registry.npmjs.org/@types/node/-/node-18.15.13.tgz",
122 | "integrity": "sha512-N+0kuo9KgrUQ1Sn/ifDXsvg0TTleP7rIy4zOBGECxAljqvqfqpTfzx0Q1NUedOixRMBfe2Whhb056a42cWs26Q=="
123 | },
124 | "node_modules/ethers/node_modules/tslib": {
125 | "version": "2.4.0",
126 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz",
127 | "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ=="
128 | },
129 | "node_modules/ethers/node_modules/ws": {
130 | "version": "8.5.0",
131 | "resolved": "https://registry.npmjs.org/ws/-/ws-8.5.0.tgz",
132 | "integrity": "sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg==",
133 | "engines": {
134 | "node": ">=10.0.0"
135 | },
136 | "peerDependencies": {
137 | "bufferutil": "^4.0.1",
138 | "utf-8-validate": "^5.0.2"
139 | },
140 | "peerDependenciesMeta": {
141 | "bufferutil": {
142 | "optional": true
143 | },
144 | "utf-8-validate": {
145 | "optional": true
146 | }
147 | }
148 | },
149 | "node_modules/fetch-blob": {
150 | "version": "3.2.0",
151 | "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz",
152 | "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==",
153 | "funding": [
154 | {
155 | "type": "github",
156 | "url": "https://github.com/sponsors/jimmywarting"
157 | },
158 | {
159 | "type": "paypal",
160 | "url": "https://paypal.me/jimmywarting"
161 | }
162 | ],
163 | "dependencies": {
164 | "node-domexception": "^1.0.0",
165 | "web-streams-polyfill": "^3.0.3"
166 | },
167 | "engines": {
168 | "node": "^12.20 || >= 14.13"
169 | }
170 | },
171 | "node_modules/formdata-polyfill": {
172 | "version": "4.0.10",
173 | "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz",
174 | "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==",
175 | "dependencies": {
176 | "fetch-blob": "^3.1.2"
177 | },
178 | "engines": {
179 | "node": ">=12.20.0"
180 | }
181 | },
182 | "node_modules/node-domexception": {
183 | "version": "1.0.0",
184 | "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz",
185 | "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==",
186 | "funding": [
187 | {
188 | "type": "github",
189 | "url": "https://github.com/sponsors/jimmywarting"
190 | },
191 | {
192 | "type": "github",
193 | "url": "https://paypal.me/jimmywarting"
194 | }
195 | ],
196 | "engines": {
197 | "node": ">=10.5.0"
198 | }
199 | },
200 | "node_modules/node-fetch": {
201 | "version": "3.3.2",
202 | "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz",
203 | "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==",
204 | "dependencies": {
205 | "data-uri-to-buffer": "^4.0.0",
206 | "fetch-blob": "^3.1.4",
207 | "formdata-polyfill": "^4.0.10"
208 | },
209 | "engines": {
210 | "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
211 | },
212 | "funding": {
213 | "type": "opencollective",
214 | "url": "https://opencollective.com/node-fetch"
215 | }
216 | },
217 | "node_modules/node-gyp-build": {
218 | "version": "4.7.1",
219 | "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.7.1.tgz",
220 | "integrity": "sha512-wTSrZ+8lsRRa3I3H8Xr65dLWSgCvY2l4AOnaeKdPA9TB/WYMPaTcrzf3rXvFoVvjKNVnu0CcWSx54qq9GKRUYg==",
221 | "optional": true,
222 | "peer": true,
223 | "bin": {
224 | "node-gyp-build": "bin.js",
225 | "node-gyp-build-optional": "optional.js",
226 | "node-gyp-build-test": "build-test.js"
227 | }
228 | },
229 | "node_modules/object-assign": {
230 | "version": "4.1.1",
231 | "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
232 | "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
233 | "engines": {
234 | "node": ">=0.10.0"
235 | }
236 | },
237 | "node_modules/utf-8-validate": {
238 | "version": "5.0.10",
239 | "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.10.tgz",
240 | "integrity": "sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==",
241 | "hasInstallScript": true,
242 | "optional": true,
243 | "peer": true,
244 | "dependencies": {
245 | "node-gyp-build": "^4.3.0"
246 | },
247 | "engines": {
248 | "node": ">=6.14.2"
249 | }
250 | },
251 | "node_modules/vary": {
252 | "version": "1.1.2",
253 | "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
254 | "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==",
255 | "engines": {
256 | "node": ">= 0.8"
257 | }
258 | },
259 | "node_modules/web-streams-polyfill": {
260 | "version": "3.2.1",
261 | "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz",
262 | "integrity": "sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==",
263 | "engines": {
264 | "node": ">= 8"
265 | }
266 | }
267 | }
268 | }
269 |
--------------------------------------------------------------------------------
/relayer/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "relayer",
3 | "version": "1.0.0",
4 | "description": "huh",
5 | "main": "index.js",
6 | "type": "module",
7 | "scripts": {
8 | "test": "echo \"Error: no test specified\" && exit 1",
9 | "start": "node relayer.js"
10 | },
11 | "author": "",
12 | "license": "ISC",
13 | "dependencies": {
14 | "cors": "^2.8.5",
15 | "dotenv": "^10.0.0",
16 | "ethers": "^6.9.0",
17 | "node-fetch": "^3.1.0"
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/relayer/relayer.js:
--------------------------------------------------------------------------------
1 | import dotenv from "dotenv"
2 | import fs from "fs"
3 | import cors from "cors"
4 | import express from "express"
5 | import { ethers } from 'ethers';
6 |
7 | const app = express()
8 | dotenv.config();
9 | app.use(cors())
10 |
11 | const JSON_CONTRACT_PATH = "./json_abi/CommentVerifier.json"
12 | const PORT = 8080
13 | var contract
14 | var provider
15 | var signer
16 |
17 | const { RPC_URL, COMMENT_VERIFIER_ADDRESS, RELAYER_PRIVATE_KEY, RELAYER_ADDRESS } = process.env;
18 |
19 | const loadContract = async (data) => {
20 | data = JSON.parse(data);
21 | contract = new ethers.Contract(COMMENT_VERIFIER_ADDRESS, data, signer);
22 | }
23 |
24 | async function initAPI() {
25 | provider = new ethers.JsonRpcProvider(RPC_URL);
26 | signer = new ethers.Wallet(RELAYER_PRIVATE_KEY, provider);
27 |
28 | fs.readFile(JSON_CONTRACT_PATH, 'utf8', function (err,data) {
29 | if (err) {
30 | return console.log(err);
31 | }
32 | loadContract(data)
33 | });
34 |
35 | app.listen(PORT, () => {
36 | console.log(`Listening to port ${PORT}`)
37 | })
38 | }
39 |
40 | async function relayMessage(proof, hashedMessage, title, text)
41 | {
42 | const transaction = {
43 | from: RELAYER_ADDRESS,
44 | to: COMMENT_VERIFIER_ADDRESS,
45 | value: '0',
46 | gasPrice: "700000000", // 0.7 gwei
47 | nonce: await provider.getTransactionCount(RELAYER_ADDRESS),
48 | chainId: "534351",
49 | data: contract.interface.encodeFunctionData(
50 | "sendProof",[proof, hashedMessage, title, text]
51 | )
52 | };
53 | const signedTransaction = await signer.populateTransaction(transaction);
54 | const transactionResponse = await signer.sendTransaction(signedTransaction);
55 | console.log('🎉 The hash of your transaction is:', transactionResponse.hash);
56 | }
57 |
58 | app.get('/relay', (req, res) => {
59 | var proof = req.query["proof"]
60 | var hashedMessage = req.query["hashedMessage"].split(',')
61 | var title = req.query["title"]
62 | var text = req.query["text"]
63 |
64 | relayMessage(proof, hashedMessage, title, text)
65 |
66 | res.setHeader('Content-Type', 'application/json');
67 | res.send({
68 | "message": "the proof was relayed"
69 | })
70 | })
71 | initAPI()
--------------------------------------------------------------------------------
/screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Turupawn/PrivacyDAppDemo/548fe899c86cc2a6ec96c7c300a33d8814036752/screenshot.png
--------------------------------------------------------------------------------
/webapp/.env.example:
--------------------------------------------------------------------------------
1 | CHAIN_ID = "534351"
2 | COMMENT_VERIFIER_ADDRESS = "0x123abc"
--------------------------------------------------------------------------------
/webapp/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | .env
--------------------------------------------------------------------------------
/webapp/app.js:
--------------------------------------------------------------------------------
1 | import { BarretenbergBackend } from '@noir-lang/backend_barretenberg';
2 | import { Noir } from '@noir-lang/noir_js';
3 | import circuit from '../circuit/target/circuit.json';
4 |
5 | const NETWORK_ID = process.env.CHAIN_ID
6 |
7 | const METADA_API_URL = "http://localhost:8080"
8 |
9 | const COMMENT_VERIFIER_ADDRESS = process.env.COMMENT_VERIFIER_ADDRESS;
10 |
11 | const MY_CONTRACT_ABI_PATH = "../json_abi/CommentVerifier.json"
12 | var my_contract
13 |
14 | var accounts
15 | var web3
16 |
17 | function metamaskReloadCallback() {
18 | window.ethereum.on('accountsChanged', (accounts) => {
19 | document.getElementById("web3_message").textContent="Se cambió el account, refrescando...";
20 | window.location.reload()
21 | })
22 | window.ethereum.on('networkChanged', (accounts) => {
23 | document.getElementById("web3_message").textContent="Se el network, refrescando...";
24 | window.location.reload()
25 | })
26 | }
27 |
28 | const getWeb3 = async () => {
29 | return new Promise((resolve, reject) => {
30 | if(document.readyState=="complete")
31 | {
32 | if (window.ethereum) {
33 | const web3 = new Web3(window.ethereum)
34 | window.location.reload()
35 | resolve(web3)
36 | } else {
37 | reject("must install MetaMask")
38 | document.getElementById("web3_message").textContent="Error: Please connect to Metamask";
39 | }
40 | }else
41 | {
42 | window.addEventListener("load", async () => {
43 | if (window.ethereum) {
44 | const web3 = new Web3(window.ethereum)
45 | resolve(web3)
46 | } else {
47 | reject("must install MetaMask")
48 | document.getElementById("web3_message").textContent="Error: Please install Metamask";
49 | }
50 | });
51 | }
52 | });
53 | };
54 |
55 | const getContract = async (web3, address, abi_path) => {
56 | const response = await fetch(abi_path);
57 | const data = await response.json();
58 |
59 | const netId = await web3.eth.net.getId();
60 | var contract = new web3.eth.Contract(
61 | data,
62 | address
63 | );
64 | return contract
65 | }
66 |
67 | async function loadDapp() {
68 | metamaskReloadCallback()
69 | document.getElementById("web3_message").textContent="Please connect to Metamask"
70 | var awaitWeb3 = async function () {
71 | web3 = await getWeb3()
72 | web3.eth.net.getId((err, netId) => {
73 | if (netId == NETWORK_ID) {
74 | var awaitContract = async function () {
75 | my_contract = await getContract(web3, COMMENT_VERIFIER_ADDRESS, MY_CONTRACT_ABI_PATH)
76 | document.getElementById("web3_message").textContent="You are connected to Metamask"
77 | onContractInitCallback()
78 | web3.eth.getAccounts(function(err, _accounts){
79 | accounts = _accounts
80 | if (err != null)
81 | {
82 | console.error("An error occurred: "+err)
83 | } else if (accounts.length > 0)
84 | {
85 | onWalletConnectedCallback()
86 | document.getElementById("account_address").style.display = "block"
87 | } else
88 | {
89 | document.getElementById("connect_button").style.display = "block"
90 | }
91 | });
92 | };
93 | awaitContract();
94 | } else {
95 | document.getElementById("web3_message").textContent="Please connect to Scroll Sepolia";
96 | }
97 | });
98 | };
99 | awaitWeb3();
100 | }
101 |
102 | async function connectWallet() {
103 | await window.ethereum.request({ method: "eth_requestAccounts" })
104 | accounts = await web3.eth.getAccounts()
105 | onWalletConnectedCallback()
106 | }
107 | window.connectWallet=connectWallet;
108 |
109 | const onContractInitCallback = async () => {
110 | var commentAmount = await my_contract.methods.commentAmount().call()
111 | var contract_state = "commentAmount: " + commentAmount
112 |
113 | var maxMsgPerPage = 5;
114 | var pageIterator = 0;
115 | var commentsElement = document.getElementById("comments");
116 |
117 | for(var i=parseInt(commentAmount);i>0;i--)
118 | {
119 | var title = await my_contract.methods.titles(i-1).call()
120 | var text = await my_contract.methods.texts(i-1).call()
121 | var paragraph = document.createElement("p");
122 | var boldElement = document.createElement("b");
123 | var textElement = document.createElement("span");
124 | var brElement = document.createElement("br");
125 | var titleElement = document.createElement("span");
126 | titleElement.textContent = title;
127 | textElement.textContent = text;
128 | boldElement.appendChild(titleElement);
129 | paragraph.appendChild(boldElement);
130 | paragraph.appendChild(brElement);
131 | paragraph.appendChild(textElement);
132 | commentsElement.appendChild(paragraph);
133 | pageIterator++
134 | if(pageIterator >= maxMsgPerPage)
135 | {
136 | break
137 | }
138 | }
139 | document.getElementById("contract_state").textContent = contract_state;
140 | }
141 |
142 | const onWalletConnectedCallback = async () => {
143 | }
144 |
145 | document.addEventListener('DOMContentLoaded', async () => {
146 | loadDapp()
147 | });
148 |
149 | function splitIntoPairs(str) {
150 | return str.match(/.{1,2}/g) || [];
151 | }
152 |
153 | const sendProof = async (title, text) => {
154 | document.getElementById("web3_message").textContent="Please sign the message ✍️";
155 | var msgParams = JSON.stringify({
156 | types: {
157 | EIP712Domain: [
158 | { name: 'name', type: 'string' },
159 | { name: 'version', type: 'string' },
160 | { name: 'chainId', type: 'uint256' },
161 | { name: 'verifyingContract', type: 'address' },
162 | ],
163 | Comment: [
164 | { name: 'title', type: 'string' },
165 | { name: 'text', type: 'string' }
166 | ],
167 | },
168 | primaryType: 'Comment',
169 | domain: {
170 | name: 'Anon Message Board',
171 | version: '1',
172 | chainId: parseInt(NETWORK_ID),
173 | verifyingContract: COMMENT_VERIFIER_ADDRESS,
174 | },
175 | message: {
176 | title: title,
177 | text: text,
178 | },
179 | });
180 |
181 | var signature = await ethereum.request({
182 | method: "eth_signTypedData_v4",
183 | params: [accounts[0], msgParams],
184 | });
185 |
186 | var hashedMessage = ethers.utils.hashMessage(msgParams)
187 | const hashedMessageArray = ethers.utils.arrayify(hashedMessage)
188 |
189 | var publicKey = ethers.utils.recoverPublicKey(hashedMessage, signature)
190 | publicKey = publicKey.substring(4)
191 |
192 | let pub_key_x = publicKey.substring(0, 64);
193 | let pub_key_y = publicKey.substring(64);
194 |
195 | const backend = new BarretenbergBackend(circuit);
196 | const noir = new Noir(circuit, backend);
197 |
198 | var sSignature = Array.from(ethers.utils.arrayify(signature))
199 | sSignature.pop()
200 |
201 | const input = {
202 | pub_key_x: Array.from(ethers.utils.arrayify("0x"+pub_key_x)),
203 | pub_key_y: Array.from(ethers.utils.arrayify("0x"+pub_key_y)),
204 | signature: sSignature,
205 | hashed_message: Array.from(hashedMessageArray)
206 | };
207 |
208 | document.getElementById("web3_message").textContent="Generating proof... ⌛";
209 | var proof = await noir.generateFinalProof(input);
210 | document.getElementById("web3_message").textContent="Generating proof... ✅";
211 |
212 | proof = "0x" + ethereumjs.Buffer.Buffer.from(proof.proof).toString('hex')
213 |
214 | var tHashedMessage = splitIntoPairs(hashedMessage.substring(2))
215 | for(var i=0; i {
234 | console.log("ERROR! Transaction reverted: " + revertReason.receipt.transactionHash)
235 | });
236 | */
237 |
238 |
239 | }
240 |
241 | const updateMetadata = async (proof, hashedMessage, title, text) => {
242 | fetch(METADA_API_URL + "/relay?proof=" + proof + "&hashedMessage=" + hashedMessage + "&title=" + title + "&text=" + text)
243 | .then(res => res.json())
244 | .then(out =>
245 | console.log(out))
246 | .catch();
247 | }
248 |
249 |
250 | window.sendProof=sendProof;
--------------------------------------------------------------------------------
/webapp/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Aztec Noir - Scroll Demo
4 | Anon Message Board
5 |
6 |
7 |
8 |
9 |
10 | Send a comment
11 | title:
12 | text:
13 |
14 |
15 | Comments
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
35 |
36 |