├── .gitattributes ├── .gitignore ├── README.md ├── Scheme.png ├── backend_fluence ├── Cargo.lock ├── Cargo.toml ├── README.md ├── rust-toolchain └── src │ ├── error_type.rs │ ├── lib.rs │ ├── proof_manager.rs │ └── request_response.rs ├── backend_zk ├── README.md ├── generated │ ├── out │ ├── out.code │ ├── proof.json │ ├── proving.key │ ├── verification.key │ ├── verifier.sol │ └── witness └── root.code ├── frontend ├── README.md ├── index.html ├── index.js ├── package-lock.json ├── package.json └── webpack.config.js └── truffle ├── README.md ├── contracts ├── IVerifier.sol ├── Lazy.sol ├── Migrations.sol ├── Structs.sol ├── Verifier.sol └── VerifierProxy.sol ├── migrations ├── 1_initial_migration.js └── 2_deploy_lazy.js ├── package.json ├── test └── test.js └── truffle.js /.gitattributes: -------------------------------------------------------------------------------- 1 | *.sol linguist-language=Solidity -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | node_modules/ 3 | bundle/ 4 | target/ 5 | .idea/ -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # LAZY SNARK: trustless off-chain zk-proof verification 2 | ## Abstract 3 | In Ethereum, it is expensive to check zero-knowledge proofs on-chain. So, we propose to use Fluence to do heavy-lifting off-chain and only go on-chain to challenge incorrect proofs. Our project should help exisiting Ethereum projects that rely on zk-proofs to achieve privacy, scalability, and trustlessness. 4 | ## Why 5 | Let us say, there is a project that needs to verify zk-proofs in Ethereum smart contract. The problem is that zk-proof verification is a heavy computational task and thus costs a lot of gas. As a result, checking proofs on-chain is expensive, and is susceptible to network congestion. 6 | ## What 7 | We suggest checking proofs on Fluence instead. This option does not has gas problem. Thus, it is much cheaper. Also, it won't consume all the gas in the block. Besides, it is trustless and the results of the checks are public. 8 | ## How it works 9 | The process includes the following entities: 10 | - Ethereum smart contract that stores (data, proof) pairs and implements on-chain proof verification. In case the proof is not correct, the smart contract rewards the user who challenges the invalid proof with ether. 11 | - The user aka proof consumer who wants to chalenge invalid proofs in the smart contract to get a reward. 12 | - Proof supplier who uploads (data, proof) pairs to the smart contract. The proof supplier stakes ether to the smart contract. In case the proof supplier provides an invalid proof, the proof supplier is punished: a part of the stake is given to the user who chellenged the proof as a reward. 13 | - Fluence back end that implements off-chain proof verification. It also stores proof verification results. 14 | - Ethereum project user aka proof consumer. The user checks whether the proof supplier has provided valid proofs and challenges invalid ones using smart contract to get a reward. 15 | - Arweave front end. The user performs all the actions via the front end. Also, proof results from the Fluence back end are displayed in the front end. 16 | 17 | Here is the workflow: 18 | 1. The proof supplier uploads (data, proof) to the smart contract. 19 | 2. The user takes (data, proof) from the smart contract and sends it to the back end. 20 | 3. The back end checkes the proof. 21 | 4. The following actions depend on the result of the check: 22 | - a. If the proof is valid, it is stored by the back end with TRUE flag. Other users can see it in the front end and will not check this proof again. 23 | - b. If the proof is invalid, it is stored by the back end with FALSE flag. The user challenges this proof in the smart contract. In that case the user is sure that the proof is FALSE and thus the user will get the reward. 24 | 25 | To better understand the workflow, please review the scheme. 26 | 27 | ![Image](Scheme.png "Scheme") 28 | 29 | ## Benefits 30 | LAZY SNARK (not to be confused with Lady Stark) provides the following benefits compared to checking zk-proofs on-chain: 31 | - It doesn't require much gas. In case of e.g. mass exit the zk-proofs verifications will take all the gas in the block. LAZY SNARK won't. 32 | - It is ~10 times cheaper than verifying zk-proofs in Ethereum smart contract. Checking zk-proof on-chain costs ~$1 (gasprice and ETH price on June 23, 2019). Checking them in Fluence costs ~$0.01. Since we still need to put data and proofs on-chain, the whole system operation will cost 10 times less than checking the proofs on-chain. 33 | 34 | LAZY SNARK provides the following benefits compared to checking zk-proofs locally: 35 | - It is trustless unlike checking zk-proofs locally. All the proof check results are available on Fluence via Arweave front end. 36 | - The results are public, so everyone will be able to see which proofs are valid and which proof suppliers are honest. 37 | - The results are public, so the users who seek for invalid proofs won't check the proofs that has already been checked. 38 | 39 | ## Use cases 40 | LAZY SNARK can be used in the following cases (and not only in these): 41 | - Plasma implementations that require zk-proofs. The proof supplier in that case will also act as a user (proof supplier). The proof supplier will send the proofs to the Fluence back end to prove to the community that the proof supplier is honest. 42 | - Mixers. People deposit ether to the smart contract from one address and withdraw it using another address. They provide zk-proof that it is their ether without revealing their identity. Other users check that all the money have been withdrawn by their owners. 43 | - Private money like ZkDai. They utilize zk-proofs to provide privacy. 44 | - Games. 45 | - Many other systems that use zk-proofs. For now, they are mostly limited to money-like systems, hence the examples above. However, it is only the matter of imagination what other use cases need zk-proofs, scalability, and trustlessness. 46 | 47 | ## Build instructions 48 | To be provided :) -------------------------------------------------------------------------------- /Scheme.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/smartkek/lazy-snark/158e2e9e17c08f2d5d297ff54824516eca44dfe8/Scheme.png -------------------------------------------------------------------------------- /backend_fluence/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | [[package]] 4 | name = "arrayvec" 5 | version = "0.4.10" 6 | source = "registry+https://github.com/rust-lang/crates.io-index" 7 | dependencies = [ 8 | "nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", 9 | ] 10 | 11 | [[package]] 12 | name = "autocfg" 13 | version = "0.1.4" 14 | source = "registry+https://github.com/rust-lang/crates.io-index" 15 | 16 | [[package]] 17 | name = "bellman" 18 | version = "0.2.0" 19 | source = "git+https://github.com/matterinc/bellman?tag=0.2.0#6e45a4b233e97a71f4a8a0565c8f8d753c04c08f" 20 | dependencies = [ 21 | "bit-vec 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", 22 | "blake2-rfc 0.2.18 (git+https://github.com/gtank/blake2-rfc?rev=7a5b5fc99ae483a0043db7547fb79a6fa44b88a9)", 23 | "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", 24 | "crossbeam 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", 25 | "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", 26 | "futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", 27 | "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", 28 | "pairing 0.16.2 (git+https://github.com/matterinc/pairing?tag=0.16.2)", 29 | "rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", 30 | ] 31 | 32 | [[package]] 33 | name = "bit-vec" 34 | version = "0.4.4" 35 | source = "registry+https://github.com/rust-lang/crates.io-index" 36 | 37 | [[package]] 38 | name = "blake2-rfc" 39 | version = "0.2.18" 40 | source = "git+https://github.com/gtank/blake2-rfc?rev=7a5b5fc99ae483a0043db7547fb79a6fa44b88a9#7a5b5fc99ae483a0043db7547fb79a6fa44b88a9" 41 | dependencies = [ 42 | "arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", 43 | "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", 44 | "constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", 45 | ] 46 | 47 | [[package]] 48 | name = "byteorder" 49 | version = "1.3.2" 50 | source = "registry+https://github.com/rust-lang/crates.io-index" 51 | 52 | [[package]] 53 | name = "cfg-if" 54 | version = "0.1.9" 55 | source = "registry+https://github.com/rust-lang/crates.io-index" 56 | 57 | [[package]] 58 | name = "constant_time_eq" 59 | version = "0.1.3" 60 | source = "registry+https://github.com/rust-lang/crates.io-index" 61 | 62 | [[package]] 63 | name = "crossbeam" 64 | version = "0.7.1" 65 | source = "registry+https://github.com/rust-lang/crates.io-index" 66 | dependencies = [ 67 | "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", 68 | "crossbeam-channel 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", 69 | "crossbeam-deque 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", 70 | "crossbeam-epoch 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", 71 | "crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", 72 | "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", 73 | ] 74 | 75 | [[package]] 76 | name = "crossbeam-channel" 77 | version = "0.3.8" 78 | source = "registry+https://github.com/rust-lang/crates.io-index" 79 | dependencies = [ 80 | "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", 81 | "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", 82 | ] 83 | 84 | [[package]] 85 | name = "crossbeam-deque" 86 | version = "0.7.1" 87 | source = "registry+https://github.com/rust-lang/crates.io-index" 88 | dependencies = [ 89 | "crossbeam-epoch 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", 90 | "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", 91 | ] 92 | 93 | [[package]] 94 | name = "crossbeam-epoch" 95 | version = "0.7.1" 96 | source = "registry+https://github.com/rust-lang/crates.io-index" 97 | dependencies = [ 98 | "arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", 99 | "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", 100 | "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", 101 | "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", 102 | "memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", 103 | "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", 104 | ] 105 | 106 | [[package]] 107 | name = "crossbeam-queue" 108 | version = "0.1.2" 109 | source = "registry+https://github.com/rust-lang/crates.io-index" 110 | dependencies = [ 111 | "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", 112 | ] 113 | 114 | [[package]] 115 | name = "crossbeam-utils" 116 | version = "0.6.5" 117 | source = "registry+https://github.com/rust-lang/crates.io-index" 118 | dependencies = [ 119 | "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", 120 | "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", 121 | ] 122 | 123 | [[package]] 124 | name = "ff" 125 | version = "0.5.0" 126 | source = "git+https://github.com/matterinc/ff?tag=0.5#056a13b95f4b971a9ae2c6fbb5fbc9f1e4f4828e" 127 | dependencies = [ 128 | "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", 129 | "ff_derive 0.4.0 (git+https://github.com/matterinc/ff?tag=0.5)", 130 | "rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", 131 | ] 132 | 133 | [[package]] 134 | name = "ff_derive" 135 | version = "0.4.0" 136 | source = "git+https://github.com/matterinc/ff?tag=0.5#056a13b95f4b971a9ae2c6fbb5fbc9f1e4f4828e" 137 | dependencies = [ 138 | "num-bigint 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", 139 | "num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", 140 | "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", 141 | "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", 142 | "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", 143 | "serde_derive 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)", 144 | "syn 0.14.9 (registry+https://github.com/rust-lang/crates.io-index)", 145 | ] 146 | 147 | [[package]] 148 | name = "fluence" 149 | version = "0.1.5" 150 | source = "registry+https://github.com/rust-lang/crates.io-index" 151 | dependencies = [ 152 | "fluence-sdk-macro 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", 153 | "fluence-sdk-main 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", 154 | ] 155 | 156 | [[package]] 157 | name = "fluence-sdk-macro" 158 | version = "0.1.5" 159 | source = "registry+https://github.com/rust-lang/crates.io-index" 160 | dependencies = [ 161 | "fluence-sdk-main 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", 162 | "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", 163 | "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", 164 | "syn 0.15.39 (registry+https://github.com/rust-lang/crates.io-index)", 165 | ] 166 | 167 | [[package]] 168 | name = "fluence-sdk-main" 169 | version = "0.1.5" 170 | source = "registry+https://github.com/rust-lang/crates.io-index" 171 | dependencies = [ 172 | "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", 173 | "syn 0.15.39 (registry+https://github.com/rust-lang/crates.io-index)", 174 | ] 175 | 176 | [[package]] 177 | name = "fuchsia-cprng" 178 | version = "0.1.1" 179 | source = "registry+https://github.com/rust-lang/crates.io-index" 180 | 181 | [[package]] 182 | name = "futures" 183 | version = "0.1.28" 184 | source = "registry+https://github.com/rust-lang/crates.io-index" 185 | 186 | [[package]] 187 | name = "futures-cpupool" 188 | version = "0.1.8" 189 | source = "registry+https://github.com/rust-lang/crates.io-index" 190 | dependencies = [ 191 | "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", 192 | "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", 193 | ] 194 | 195 | [[package]] 196 | name = "hex" 197 | version = "0.3.2" 198 | source = "registry+https://github.com/rust-lang/crates.io-index" 199 | 200 | [[package]] 201 | name = "itoa" 202 | version = "0.4.4" 203 | source = "registry+https://github.com/rust-lang/crates.io-index" 204 | 205 | [[package]] 206 | name = "lazy_static" 207 | version = "1.3.0" 208 | source = "registry+https://github.com/rust-lang/crates.io-index" 209 | 210 | [[package]] 211 | name = "libc" 212 | version = "0.2.58" 213 | source = "registry+https://github.com/rust-lang/crates.io-index" 214 | 215 | [[package]] 216 | name = "linked-hash-map" 217 | version = "0.5.2" 218 | source = "registry+https://github.com/rust-lang/crates.io-index" 219 | 220 | [[package]] 221 | name = "log" 222 | version = "0.4.6" 223 | source = "registry+https://github.com/rust-lang/crates.io-index" 224 | dependencies = [ 225 | "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", 226 | ] 227 | 228 | [[package]] 229 | name = "memoffset" 230 | version = "0.2.1" 231 | source = "registry+https://github.com/rust-lang/crates.io-index" 232 | 233 | [[package]] 234 | name = "nodrop" 235 | version = "0.1.13" 236 | source = "registry+https://github.com/rust-lang/crates.io-index" 237 | 238 | [[package]] 239 | name = "num-bigint" 240 | version = "0.2.2" 241 | source = "registry+https://github.com/rust-lang/crates.io-index" 242 | dependencies = [ 243 | "num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", 244 | "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", 245 | ] 246 | 247 | [[package]] 248 | name = "num-integer" 249 | version = "0.1.41" 250 | source = "registry+https://github.com/rust-lang/crates.io-index" 251 | dependencies = [ 252 | "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", 253 | "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", 254 | ] 255 | 256 | [[package]] 257 | name = "num-traits" 258 | version = "0.2.8" 259 | source = "registry+https://github.com/rust-lang/crates.io-index" 260 | dependencies = [ 261 | "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", 262 | ] 263 | 264 | [[package]] 265 | name = "num_cpus" 266 | version = "1.10.1" 267 | source = "registry+https://github.com/rust-lang/crates.io-index" 268 | dependencies = [ 269 | "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", 270 | ] 271 | 272 | [[package]] 273 | name = "pairing" 274 | version = "0.16.2" 275 | source = "git+https://github.com/matterinc/pairing?tag=0.16.2#c2af46cac3e6ebc8e1e1f37bb993e5e6c7f689d1" 276 | dependencies = [ 277 | "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", 278 | "ff 0.5.0 (git+https://github.com/matterinc/ff?tag=0.5)", 279 | "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", 280 | "rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", 281 | "serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)", 282 | "serde_derive 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)", 283 | "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", 284 | ] 285 | 286 | [[package]] 287 | name = "proc-macro2" 288 | version = "0.4.30" 289 | source = "registry+https://github.com/rust-lang/crates.io-index" 290 | dependencies = [ 291 | "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 292 | ] 293 | 294 | [[package]] 295 | name = "quote" 296 | version = "0.6.12" 297 | source = "registry+https://github.com/rust-lang/crates.io-index" 298 | dependencies = [ 299 | "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", 300 | ] 301 | 302 | [[package]] 303 | name = "rand" 304 | version = "0.4.6" 305 | source = "registry+https://github.com/rust-lang/crates.io-index" 306 | dependencies = [ 307 | "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", 308 | "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", 309 | "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 310 | "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 311 | "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", 312 | ] 313 | 314 | [[package]] 315 | name = "rand_core" 316 | version = "0.3.1" 317 | source = "registry+https://github.com/rust-lang/crates.io-index" 318 | dependencies = [ 319 | "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 320 | ] 321 | 322 | [[package]] 323 | name = "rand_core" 324 | version = "0.4.0" 325 | source = "registry+https://github.com/rust-lang/crates.io-index" 326 | 327 | [[package]] 328 | name = "rdrand" 329 | version = "0.4.0" 330 | source = "registry+https://github.com/rust-lang/crates.io-index" 331 | dependencies = [ 332 | "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 333 | ] 334 | 335 | [[package]] 336 | name = "ryu" 337 | version = "1.0.0" 338 | source = "registry+https://github.com/rust-lang/crates.io-index" 339 | 340 | [[package]] 341 | name = "scopeguard" 342 | version = "0.3.3" 343 | source = "registry+https://github.com/rust-lang/crates.io-index" 344 | 345 | [[package]] 346 | name = "serde" 347 | version = "1.0.94" 348 | source = "registry+https://github.com/rust-lang/crates.io-index" 349 | dependencies = [ 350 | "serde_derive 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)", 351 | ] 352 | 353 | [[package]] 354 | name = "serde_derive" 355 | version = "1.0.94" 356 | source = "registry+https://github.com/rust-lang/crates.io-index" 357 | dependencies = [ 358 | "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", 359 | "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", 360 | "syn 0.15.39 (registry+https://github.com/rust-lang/crates.io-index)", 361 | ] 362 | 363 | [[package]] 364 | name = "serde_json" 365 | version = "1.0.40" 366 | source = "registry+https://github.com/rust-lang/crates.io-index" 367 | dependencies = [ 368 | "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", 369 | "ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", 370 | "serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)", 371 | ] 372 | 373 | [[package]] 374 | name = "smallvec" 375 | version = "0.6.10" 376 | source = "registry+https://github.com/rust-lang/crates.io-index" 377 | 378 | [[package]] 379 | name = "syn" 380 | version = "0.14.9" 381 | source = "registry+https://github.com/rust-lang/crates.io-index" 382 | dependencies = [ 383 | "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", 384 | "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", 385 | "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 386 | ] 387 | 388 | [[package]] 389 | name = "syn" 390 | version = "0.15.39" 391 | source = "registry+https://github.com/rust-lang/crates.io-index" 392 | dependencies = [ 393 | "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", 394 | "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", 395 | "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 396 | ] 397 | 398 | [[package]] 399 | name = "unicode-xid" 400 | version = "0.1.0" 401 | source = "registry+https://github.com/rust-lang/crates.io-index" 402 | 403 | [[package]] 404 | name = "verifier" 405 | version = "0.0.1" 406 | dependencies = [ 407 | "bellman 0.2.0 (git+https://github.com/matterinc/bellman?tag=0.2.0)", 408 | "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", 409 | "fluence 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", 410 | "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", 411 | "linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", 412 | "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", 413 | "serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)", 414 | "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", 415 | ] 416 | 417 | [[package]] 418 | name = "winapi" 419 | version = "0.3.7" 420 | source = "registry+https://github.com/rust-lang/crates.io-index" 421 | dependencies = [ 422 | "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 423 | "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 424 | ] 425 | 426 | [[package]] 427 | name = "winapi-i686-pc-windows-gnu" 428 | version = "0.4.0" 429 | source = "registry+https://github.com/rust-lang/crates.io-index" 430 | 431 | [[package]] 432 | name = "winapi-x86_64-pc-windows-gnu" 433 | version = "0.4.0" 434 | source = "registry+https://github.com/rust-lang/crates.io-index" 435 | 436 | [metadata] 437 | "checksum arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "92c7fb76bc8826a8b33b4ee5bb07a247a81e76764ab4d55e8f73e3a4d8808c71" 438 | "checksum autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "0e49efa51329a5fd37e7c79db4621af617cd4e3e5bc224939808d076077077bf" 439 | "checksum bellman 0.2.0 (git+https://github.com/matterinc/bellman?tag=0.2.0)" = "" 440 | "checksum bit-vec 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "02b4ff8b16e6076c3e14220b39fbc1fabb6737522281a388998046859400895f" 441 | "checksum blake2-rfc 0.2.18 (git+https://github.com/gtank/blake2-rfc?rev=7a5b5fc99ae483a0043db7547fb79a6fa44b88a9)" = "" 442 | "checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5" 443 | "checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33" 444 | "checksum constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8ff012e225ce166d4422e0e78419d901719760f62ae2b7969ca6b564d1b54a9e" 445 | "checksum crossbeam 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b14492071ca110999a20bf90e3833406d5d66bfd93b4e52ec9539025ff43fe0d" 446 | "checksum crossbeam-channel 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "0f0ed1a4de2235cabda8558ff5840bffb97fcb64c97827f354a451307df5f72b" 447 | "checksum crossbeam-deque 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b18cd2e169ad86297e6bc0ad9aa679aee9daa4f19e8163860faf7c164e4f5a71" 448 | "checksum crossbeam-epoch 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "04c9e3102cc2d69cd681412141b390abd55a362afc1540965dad0ad4d34280b4" 449 | "checksum crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7c979cd6cfe72335896575c6b5688da489e420d36a27a0b9eb0c73db574b4a4b" 450 | "checksum crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "f8306fcef4a7b563b76b7dd949ca48f52bc1141aa067d2ea09565f3e2652aa5c" 451 | "checksum ff 0.5.0 (git+https://github.com/matterinc/ff?tag=0.5)" = "" 452 | "checksum ff_derive 0.4.0 (git+https://github.com/matterinc/ff?tag=0.5)" = "" 453 | "checksum fluence 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "60cb68f8345b46e3bab0f9cb5a041dad4e0ad944a27d4a89b312db8d5f01cadd" 454 | "checksum fluence-sdk-macro 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d25c41f9afe101ca24ebc41a58ca9e1c7a9627cf5249211776881fdf954b14ed" 455 | "checksum fluence-sdk-main 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "a2e09744c4895d07bafdc275d2da9c3a61edae9790f00283aa1fd48661d12506" 456 | "checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" 457 | "checksum futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)" = "45dc39533a6cae6da2b56da48edae506bb767ec07370f86f70fc062e9d435869" 458 | "checksum futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "ab90cde24b3319636588d0c35fe03b1333857621051837ed769faefb4c2162e4" 459 | "checksum hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77" 460 | "checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f" 461 | "checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14" 462 | "checksum libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)" = "6281b86796ba5e4366000be6e9e18bf35580adf9e63fbe2294aadb587613a319" 463 | "checksum linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ae91b68aebc4ddb91978b11a1b02ddd8602a05ec19002801c5666000e05e0f83" 464 | "checksum log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c84ec4b527950aa83a329754b01dbe3f58361d1c5efacd1f6d68c494d08a17c6" 465 | "checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3" 466 | "checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945" 467 | "checksum num-bigint 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "57450397855d951f1a41305e54851b1a7b8f5d2e349543a02a2effe25459f718" 468 | "checksum num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "b85e541ef8255f6cf42bbfe4ef361305c6c135d10919ecc26126c4e5ae94bc09" 469 | "checksum num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "6ba9a427cfca2be13aa6f6403b0b7e7368fe982bfa16fccc450ce74c46cd9b32" 470 | "checksum num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bcef43580c035376c0705c42792c294b66974abbfd2789b511784023f71f3273" 471 | "checksum pairing 0.16.2 (git+https://github.com/matterinc/pairing?tag=0.16.2)" = "" 472 | "checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" 473 | "checksum quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "faf4799c5d274f3868a4aae320a0a182cbd2baee377b378f080e16a23e9d80db" 474 | "checksum rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" 475 | "checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" 476 | "checksum rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0e7a549d590831370895ab7ba4ea0c1b6b011d106b5ff2da6eee112615e6dc0" 477 | "checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" 478 | "checksum ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c92464b447c0ee8c4fb3824ecc8383b81717b9f1e74ba2e72540aef7b9f82997" 479 | "checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" 480 | "checksum serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)" = "076a696fdea89c19d3baed462576b8f6d663064414b5c793642da8dfeb99475b" 481 | "checksum serde_derive 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)" = "ef45eb79d6463b22f5f9e16d283798b7c0175ba6050bc25c1a946c122727fe7b" 482 | "checksum serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)" = "051c49229f282f7c6f3813f8286cc1e3323e8051823fce42c7ea80fe13521704" 483 | "checksum smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ab606a9c5e214920bb66c458cd7be8ef094f813f20fe77a54cc7dbfff220d4b7" 484 | "checksum syn 0.14.9 (registry+https://github.com/rust-lang/crates.io-index)" = "261ae9ecaa397c42b960649561949d69311f08eeaea86a65696e6e46517cf741" 485 | "checksum syn 0.15.39 (registry+https://github.com/rust-lang/crates.io-index)" = "b4d960b829a55e56db167e861ddb43602c003c7be0bee1d345021703fac2fb7c" 486 | "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" 487 | "checksum winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f10e386af2b13e47c89e7236a7a14a086791a2b88ebad6df9bf42040195cf770" 488 | "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 489 | "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 490 | -------------------------------------------------------------------------------- /backend_fluence/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = ["Alexander Drygin "] 3 | name = "verifier" 4 | version = "0.0.1" 5 | publish = false 6 | edition = "2018" 7 | 8 | [lib] 9 | name = "proof" 10 | path = "src/lib.rs" 11 | crate-type = ["cdylib"] 12 | 13 | [profile.release] 14 | debug = false 15 | lto = true 16 | opt-level = "z" 17 | panic = "abort" 18 | 19 | [dependencies] 20 | serde = { version = "1.0", features = ["derive"] } 21 | serde_json = "1.0.38" 22 | linked-hash-map = "0.5.1" 23 | log = "0.4" 24 | fluence = { version = "0.1.5", features = ["wasm_logger"] } 25 | 26 | hex = "0.3.2" 27 | byteorder = "1.3.2" 28 | bellman = { git = 'https://github.com/matterinc/bellman', tag = "0.2.0" } 29 | -------------------------------------------------------------------------------- /backend_fluence/README.md: -------------------------------------------------------------------------------- 1 | # Usage 2 | 0. [install](https://github.com/fluencelabs/tutorials/tree/master/dice-game#developing-the-backend-app) needed dependencies for Fluence 3 | 4 | 1. compiling Rust to WebAssembly, in directory backend_fluence/src 5 | ```cargo +nightly build --target wasm32-unknown-unknown --release``` 6 | 7 | 2. [publishing](https://fluence.network/docs/book/quickstart/publish.html) to Fluence network 8 | 9 | * current Fluence appId is 299 -------------------------------------------------------------------------------- /backend_fluence/rust-toolchain: -------------------------------------------------------------------------------- 1 | nightly 2 | -------------------------------------------------------------------------------- /backend_fluence/src/error_type.rs: -------------------------------------------------------------------------------- 1 | use std::error::Error; 2 | 3 | pub type AppResult = ::std::result::Result>; 4 | -------------------------------------------------------------------------------- /backend_fluence/src/lib.rs: -------------------------------------------------------------------------------- 1 | mod error_type; 2 | mod proof_manager; 3 | mod request_response; 4 | 5 | use crate::error_type::AppResult; 6 | use crate::proof_manager::ProofManager; 7 | use crate::request_response::{Request, Response}; 8 | 9 | use fluence::sdk::*; 10 | use log::info; 11 | use serde_json::Value; 12 | use std::cell::RefCell; 13 | 14 | fn init() { 15 | logger::WasmLogger::init_with_level(log::Level::Info).unwrap(); 16 | } 17 | 18 | thread_local! { 19 | static PROOF_MANAGER: RefCell = RefCell::new(ProofManager::new()); 20 | } 21 | 22 | fn do_request(req: String) -> AppResult { 23 | let request: Request = serde_json::from_str(req.as_str())?; 24 | 25 | match request { 26 | Request::Verify { 27 | proof_id, 28 | public_par, 29 | proof, 30 | } => PROOF_MANAGER.with(|gm| gm.borrow_mut().verify(proof_id, public_par, proof)), 31 | 32 | Request::Check { proof_id } => PROOF_MANAGER.with(|gm| gm.borrow_mut().check(proof_id)), 33 | } 34 | } 35 | 36 | #[invocation_handler(init_fn = init)] 37 | fn main(req: String) -> String { 38 | info!("req string: {}", req); 39 | match do_request(req) { 40 | Ok(res) => res.to_string(), 41 | Err(err) => { 42 | let response = Response::Error { 43 | message: err.to_string(), 44 | }; 45 | serde_json::to_string(&response).unwrap() 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /backend_fluence/src/proof_manager.rs: -------------------------------------------------------------------------------- 1 | use crate::error_type::AppResult; 2 | use crate::request_response::Response; 3 | 4 | use linked_hash_map::LinkedHashMap; 5 | use serde_json::Value; 6 | 7 | use bellman::groth16::{ 8 | prepare_verifying_key, verify_proof, PreparedVerifyingKey, Proof, VerifyingKey, 9 | }; 10 | use bellman::pairing::bn256::*; 11 | use bellman::pairing::ff::{Field, PrimeField, PrimeFieldRepr}; 12 | use bellman::pairing::{CurveAffine, EncodedPoint}; 13 | 14 | use byteorder::{BigEndian, WriteBytesExt}; 15 | use std::io::{self, Cursor, Read, Seek, SeekFrom, Write}; 16 | 17 | pub struct ProofManager { 18 | // map from proof id to verify status 19 | proofs: LinkedHashMap, 20 | 21 | // prepared verifying key for proof 22 | prepared_vk: PreparedVerifyingKey, 23 | } 24 | 25 | impl ProofManager { 26 | pub fn new() -> Self { 27 | let vk_alpha_g1 = hex::decode( 28 | "2e0a814dd75e4118233ddf6a916a813c40bae07d976fdcd01dbfa22bea641a96\ 29 | 1779e77cff5e54cf2cdc237e51cd6d95ef2c37ab6a7d5f9ce0a242188e1a1fe3", 30 | ) 31 | .unwrap(); 32 | 33 | //some g1 point, because ZoKrates does not return that and it is not needed for verification 34 | let vk_beta_g1 = hex::decode( 35 | "1fea09defec64586a976a33dbfb70961fc7e03fb6f4d5a1e074f97312ce789cd\ 36 | 006653d8d2e65ab55fa795c44971eabcc6dbb1dd383c7a8a20de68486eb28154", 37 | ) 38 | .unwrap(); 39 | 40 | let vk_beta_g2 = hex::decode( 41 | "021548b93199574bdef2be8cb1908a1079b1664d8a041d2e297c3aa6c554855c\ 42 | 190b2d5d03854400e2c2a702f502813677a1d4be920d79648f810e320a30f2c5\ 43 | 0bc956fa715451d64e20b260759c2ae74a82b68f1eef86504051cd3ae547f282\ 44 | 011192ee83c0347e363b7c5fffe156fbadd91591b35dc8fe912d2b498c3a9301", 45 | ) 46 | .unwrap(); 47 | 48 | let vk_gamma_g2 = hex::decode( 49 | "1c4c46720835faf06e35cd85f05c589a1a98f58112ecf7aacf0deac60681f5a4\ 50 | 1b438f01daf6402ff298981b74f80a5e79c39cce21c67770f74b89e65eb3b9ca\ 51 | 101b8c9c29aa1ac1a709878f6eb4d4a74f4ed1368a18f29c2762b76b8c389f4d\ 52 | 009538b3640e10082d0bf4b18b997fef6af2e7cceb942ebb26bd263e8805fedd", 53 | ) 54 | .unwrap(); 55 | 56 | //some g1 point, because ZoKrates does not return that and it is not needed for verification 57 | let vk_delta_g1 = hex::decode( 58 | "1fea09defec64586a976a33dbfb70961fc7e03fb6f4d5a1e074f97312ce789cd\ 59 | 006653d8d2e65ab55fa795c44971eabcc6dbb1dd383c7a8a20de68486eb28154", 60 | ) 61 | .unwrap(); 62 | 63 | let vk_delta_g2 = hex::decode( 64 | "25161a4cc549ffabd2c4508038c12d49447c15e9c565b025183ff6114ffcc58b\ 65 | 110f2b773f6d9632162bc2c629467a58e7539ed0f0dc64ff4fd8f63baf4b5a32\ 66 | 0eb80be9e5a3f3f4cb0e39edc1db88dbf8de59b0c800b72dcc34d9c0fae14d55\ 67 | 0839d69bfc27640a59af741138d4f34500d925eb1a4e9fd57fcda269a7411c33", 68 | ) 69 | .unwrap(); 70 | 71 | let vk_ic_len = 6; 72 | 73 | let vk_ic = hex::decode( 74 | "2bb604557c5f1096973ab8afe980ea3ae23bd7457f3f11f67fb395f2d1f3b568\ 75 | 0f12fdb646ea572637ea6e1bbf04158bcabe6947cf614c67efb3f0278279f866\ 76 | 228bbefb9d7457c97766bcae9412c6ddd1de8e3dbcf1606ca6b8f027836affee\ 77 | 01bf2712a663f5a72a469ea83a4c3d453c6023a0cd5d5f86330157f1505d62b3\ 78 | 23af3409b4b3fb3f194dc683be70c5e442de55544edeace8f891a891a4701ca3\ 79 | 1d13edb38da07247e70158557cfa93097d90d92b9a2c99f190c1413f3fdf8828\ 80 | 00572fbfedfe16fd1dcae266bf009907451cd8db485325ad322fb658cb0c30ff\ 81 | 25415b150b181b2cbecc6f84382b0bd8fd49f2cf498da1c775ad624e5e7b7eaf\ 82 | 1a294f13fbf284a6e11c2f54ed2946fc5fd732dafbf49ac01ce741f224b57c29\ 83 | 182d4a788849c87d27548cbe3a511a0237cb0d4595425eee878d78c4eb4e5529\ 84 | 10ec12d1090de44b1aecb41030d123df2d61318c1928d6de10f916c9bfc2f681\ 85 | 0621a1ea9bbbfa893358dfaa206ba1cb8af2ecca483c3c36f2a0c302da401c8f", 86 | ) 87 | .unwrap(); 88 | 89 | let mut c = Cursor::new(Vec::new()); 90 | 91 | c.write_all(vk_alpha_g1.as_slice()).unwrap(); 92 | c.write_all(vk_beta_g1.as_slice()).unwrap(); 93 | c.write_all(vk_beta_g2.as_slice()).unwrap(); 94 | c.write_all(vk_gamma_g2.as_slice()).unwrap(); 95 | c.write_all(vk_delta_g1.as_slice()).unwrap(); 96 | c.write_all(vk_delta_g2.as_slice()).unwrap(); 97 | c.write_i32::(vk_ic_len).unwrap(); 98 | c.write_all(vk_ic.as_slice()).unwrap(); 99 | 100 | c.seek(SeekFrom::Start(0)).unwrap(); 101 | 102 | let vk: VerifyingKey = VerifyingKey::read(c).unwrap(); 103 | let prepared_vk: PreparedVerifyingKey = prepare_verifying_key(&vk); 104 | 105 | ProofManager { 106 | proofs: LinkedHashMap::new(), 107 | prepared_vk, 108 | } 109 | } 110 | 111 | pub fn verify( 112 | &mut self, 113 | proof_id: u64, 114 | public_par: [String; 5], 115 | proof: [String; 8], 116 | ) -> AppResult { 117 | let mut c = Cursor::new(Vec::new()); 118 | 119 | // write a, b, c 120 | for proof_part in &proof { 121 | c.write_all(hex::decode(proof_part)?.as_slice())?; 122 | } 123 | c.seek(SeekFrom::Start(0)).unwrap(); 124 | 125 | let mut g1_repr = ::Uncompressed::empty(); 126 | let mut g2_repr = ::Uncompressed::empty(); 127 | 128 | c.read_exact(g1_repr.as_mut())?; 129 | let a = g1_repr 130 | .into_affine() 131 | .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e)) 132 | .and_then(|e| { 133 | if e.is_zero() { 134 | Err(io::Error::new( 135 | io::ErrorKind::InvalidData, 136 | "point at infinity", 137 | )) 138 | } else { 139 | Ok(e) 140 | } 141 | })?; 142 | 143 | c.read_exact(g2_repr.as_mut())?; 144 | let b = g2_repr 145 | .into_affine() 146 | .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e)) 147 | .and_then(|e| { 148 | if e.is_zero() { 149 | Err(io::Error::new( 150 | io::ErrorKind::InvalidData, 151 | "point at infinity", 152 | )) 153 | } else { 154 | Ok(e) 155 | } 156 | })?; 157 | 158 | c.read_exact(g1_repr.as_mut())?; 159 | let c = g1_repr 160 | .into_affine() 161 | .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e)) 162 | .and_then(|e| { 163 | if e.is_zero() { 164 | Err(io::Error::new( 165 | io::ErrorKind::InvalidData, 166 | "point at infinity", 167 | )) 168 | } else { 169 | Ok(e) 170 | } 171 | })?; 172 | 173 | let proof: Proof = Proof { a, b, c }; 174 | 175 | // import public inputs ----------------------------------------------- 176 | 177 | let mut public_inputs = Vec::new(); 178 | 179 | for public_part in &public_par { 180 | let inp = hex::decode(public_part)?; 181 | 182 | let mut repr_inp = Fr::zero().into_repr(); 183 | repr_inp.read_be(&inp[..])?; 184 | let inp_fr = Fr::from_repr(repr_inp)?; 185 | 186 | public_inputs.push(inp_fr); 187 | } 188 | 189 | let is_valid = verify_proof(&self.prepared_vk, &proof, &public_inputs)?; 190 | 191 | // update proof status ------------------------------------------------ 192 | 193 | let result: u8 = is_valid.into(); 194 | 195 | // TODO: check that such proof is already in the map (?) 196 | self.proofs.insert(proof_id, result); 197 | 198 | let response = Response::Verify { result }; 199 | serde_json::to_value(response).map_err(Into::into) 200 | } 201 | 202 | pub fn check(&self, proof_id: u64) -> AppResult { 203 | let status = self.proof_status(proof_id)?; 204 | let response = Response::Check { verified: status }; 205 | 206 | serde_json::to_value(response).map_err(Into::into) 207 | } 208 | 209 | fn proof_status(&self, proof_id: u64) -> AppResult { 210 | let status = self 211 | .proofs 212 | .get(&proof_id) 213 | .ok_or_else(|| format!("Proof with id {} wasn't found", proof_id))?; 214 | 215 | Ok(*status) 216 | } 217 | } 218 | -------------------------------------------------------------------------------- /backend_fluence/src/request_response.rs: -------------------------------------------------------------------------------- 1 | use serde::{Deserialize, Serialize}; 2 | 3 | #[derive(Serialize, Deserialize)] 4 | #[serde(tag = "action")] 5 | pub enum Request { 6 | Verify { 7 | proof_id: u64, 8 | public_par: [String; 5], 9 | proof: [String; 8], 10 | }, 11 | Check { 12 | proof_id: u64, 13 | }, 14 | } 15 | 16 | #[derive(Serialize, Deserialize)] 17 | #[serde(untagged)] 18 | pub enum Response { 19 | Verify { result: u8 }, 20 | Check { verified: u8 }, 21 | Error { message: String }, 22 | } 23 | -------------------------------------------------------------------------------- /backend_zk/README.md: -------------------------------------------------------------------------------- 1 | # Usage 2 | 0. [install](https://zokrates.github.io/gettingstarted.html) ZoKrates 3 | 4 | 1. compile ```zokrates compile -i root.code``` 5 | 6 | 2. perform the setup phase ```zokrates setup``` 7 | 8 | 3. execute the program ```zokrates compute-witness -a 0 0 0 5 5 0 0 0 263561599766550617289250058199814760685 65303172752238645975888084098459749904 121528245299328017710050549170605934178 329200266467600403224363203181133000487``` 9 | 10 | 4. generate a proof of computation ```zokrates generate-proof``` 11 | 12 | 5. export a solidity verifier ```zokrates export-verifier``` 13 | 14 | * Generated folder contains already generated files. -------------------------------------------------------------------------------- /backend_zk/generated/out: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/smartkek/lazy-snark/158e2e9e17c08f2d5d297ff54824516eca44dfe8/backend_zk/generated/out -------------------------------------------------------------------------------- /backend_zk/generated/proof.json: -------------------------------------------------------------------------------- 1 | { 2 | "proof": { 3 | "a": ["0x24d858a8ffc1766e7cccf95643f1339cb10978a5b06a6f8abad82782a3ab3efd", "0x2d0b5206a856f75a93284728f7cfa61e998868b632b11886a439add8e6150f3e"], 4 | "b": [["0x13e6a883986efe7bb0c6e99b00c157d31ea8479283ac6c4934e42368da31e6d8", "0x0718d8dfecf7726df8a27092bac85d58767230b33a66dd8c69ca54f576361fc1"], ["0x160f03315ee7766d576122244d12bcabd24ee3c7d33e1cb05d838337a0fd0dfb", "0x2ea4c7c18ed1b8f3544a4fb3c4d95efa5543182406fef71bfda8760e407a05c7"]], 5 | "c": ["0x1111708b97dac3f087a3d8e13cfd513d7a82c619d39e9148080b600b7dae210e", "0x2a6e76f3003e65afefae71d3fe18ba26a3940e81463bf94615478cdf5daa2249"] 6 | }, 7 | "inputs": ["0x00000000000000000000000000000000c6481e22c5ff4164af680b8cfaa5e8ed", "0x000000000000000000000000000000003120eeff89c4f307c4a6faaae059ce10", "0x000000000000000000000000000000005b6d7d198c48c17c9540d29275a04662", "0x00000000000000000000000000000000f7a9aa434629a33c84eec3e16e196f27", "0x0000000000000000000000000000000000000000000000000000000000000001"] 8 | } -------------------------------------------------------------------------------- /backend_zk/generated/proving.key: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/smartkek/lazy-snark/158e2e9e17c08f2d5d297ff54824516eca44dfe8/backend_zk/generated/proving.key -------------------------------------------------------------------------------- /backend_zk/generated/verification.key: -------------------------------------------------------------------------------- 1 | vk.alpha = 0x2e0a814dd75e4118233ddf6a916a813c40bae07d976fdcd01dbfa22bea641a96, 0x1779e77cff5e54cf2cdc237e51cd6d95ef2c37ab6a7d5f9ce0a242188e1a1fe3 2 | vk.beta = [0x021548b93199574bdef2be8cb1908a1079b1664d8a041d2e297c3aa6c554855c, 0x190b2d5d03854400e2c2a702f502813677a1d4be920d79648f810e320a30f2c5], [0x0bc956fa715451d64e20b260759c2ae74a82b68f1eef86504051cd3ae547f282, 0x011192ee83c0347e363b7c5fffe156fbadd91591b35dc8fe912d2b498c3a9301] 3 | vk.gamma = [0x1c4c46720835faf06e35cd85f05c589a1a98f58112ecf7aacf0deac60681f5a4, 0x1b438f01daf6402ff298981b74f80a5e79c39cce21c67770f74b89e65eb3b9ca], [0x101b8c9c29aa1ac1a709878f6eb4d4a74f4ed1368a18f29c2762b76b8c389f4d, 0x009538b3640e10082d0bf4b18b997fef6af2e7cceb942ebb26bd263e8805fedd] 4 | vk.delta = [0x25161a4cc549ffabd2c4508038c12d49447c15e9c565b025183ff6114ffcc58b, 0x110f2b773f6d9632162bc2c629467a58e7539ed0f0dc64ff4fd8f63baf4b5a32], [0x0eb80be9e5a3f3f4cb0e39edc1db88dbf8de59b0c800b72dcc34d9c0fae14d55, 0x0839d69bfc27640a59af741138d4f34500d925eb1a4e9fd57fcda269a7411c33] 5 | vk.gammaABC.len() = 6 6 | vk.gammaABC[0] = 0x2bb604557c5f1096973ab8afe980ea3ae23bd7457f3f11f67fb395f2d1f3b568, 0x0f12fdb646ea572637ea6e1bbf04158bcabe6947cf614c67efb3f0278279f866 7 | vk.gammaABC[1] = 0x228bbefb9d7457c97766bcae9412c6ddd1de8e3dbcf1606ca6b8f027836affee, 0x01bf2712a663f5a72a469ea83a4c3d453c6023a0cd5d5f86330157f1505d62b3 8 | vk.gammaABC[2] = 0x23af3409b4b3fb3f194dc683be70c5e442de55544edeace8f891a891a4701ca3, 0x1d13edb38da07247e70158557cfa93097d90d92b9a2c99f190c1413f3fdf8828 9 | vk.gammaABC[3] = 0x00572fbfedfe16fd1dcae266bf009907451cd8db485325ad322fb658cb0c30ff, 0x25415b150b181b2cbecc6f84382b0bd8fd49f2cf498da1c775ad624e5e7b7eaf 10 | vk.gammaABC[4] = 0x1a294f13fbf284a6e11c2f54ed2946fc5fd732dafbf49ac01ce741f224b57c29, 0x182d4a788849c87d27548cbe3a511a0237cb0d4595425eee878d78c4eb4e5529 11 | vk.gammaABC[5] = 0x10ec12d1090de44b1aecb41030d123df2d61318c1928d6de10f916c9bfc2f681, 0x0621a1ea9bbbfa893358dfaa206ba1cb8af2ecca483c3c36f2a0c302da401c8f -------------------------------------------------------------------------------- /backend_zk/generated/verifier.sol: -------------------------------------------------------------------------------- 1 | // This file is LGPL3 Licensed 2 | 3 | /** 4 | * @title Elliptic curve operations on twist points for alt_bn128 5 | * @author Mustafa Al-Bassam (mus@musalbas.com) 6 | */ 7 | library BN256G2 { 8 | uint256 internal constant FIELD_MODULUS = 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47; 9 | uint256 internal constant TWISTBX = 0x2b149d40ceb8aaae81be18991be06ac3b5b4c5e559dbefa33267e6dc24a138e5; 10 | uint256 internal constant TWISTBY = 0x9713b03af0fed4cd2cafadeed8fdf4a74fa084e52d1852e4a2bd0685c315d2; 11 | uint internal constant PTXX = 0; 12 | uint internal constant PTXY = 1; 13 | uint internal constant PTYX = 2; 14 | uint internal constant PTYY = 3; 15 | uint internal constant PTZX = 4; 16 | uint internal constant PTZY = 5; 17 | 18 | /** 19 | * @notice Add two twist points 20 | * @param pt1xx Coefficient 1 of x on point 1 21 | * @param pt1xy Coefficient 2 of x on point 1 22 | * @param pt1yx Coefficient 1 of y on point 1 23 | * @param pt1yy Coefficient 2 of y on point 1 24 | * @param pt2xx Coefficient 1 of x on point 2 25 | * @param pt2xy Coefficient 2 of x on point 2 26 | * @param pt2yx Coefficient 1 of y on point 2 27 | * @param pt2yy Coefficient 2 of y on point 2 28 | * @return (pt3xx, pt3xy, pt3yx, pt3yy) 29 | */ 30 | function ECTwistAdd( 31 | uint256 pt1xx, uint256 pt1xy, 32 | uint256 pt1yx, uint256 pt1yy, 33 | uint256 pt2xx, uint256 pt2xy, 34 | uint256 pt2yx, uint256 pt2yy 35 | ) public pure returns ( 36 | uint256, uint256, 37 | uint256, uint256 38 | ) { 39 | if ( 40 | pt1xx == 0 && pt1xy == 0 && 41 | pt1yx == 0 && pt1yy == 0 42 | ) { 43 | if (!( 44 | pt2xx == 0 && pt2xy == 0 && 45 | pt2yx == 0 && pt2yy == 0 46 | )) { 47 | assert(_isOnCurve( 48 | pt2xx, pt2xy, 49 | pt2yx, pt2yy 50 | )); 51 | } 52 | return ( 53 | pt2xx, pt2xy, 54 | pt2yx, pt2yy 55 | ); 56 | } else if ( 57 | pt2xx == 0 && pt2xy == 0 && 58 | pt2yx == 0 && pt2yy == 0 59 | ) { 60 | assert(_isOnCurve( 61 | pt1xx, pt1xy, 62 | pt1yx, pt1yy 63 | )); 64 | return ( 65 | pt1xx, pt1xy, 66 | pt1yx, pt1yy 67 | ); 68 | } 69 | 70 | assert(_isOnCurve( 71 | pt1xx, pt1xy, 72 | pt1yx, pt1yy 73 | )); 74 | assert(_isOnCurve( 75 | pt2xx, pt2xy, 76 | pt2yx, pt2yy 77 | )); 78 | 79 | uint256[6] memory pt3 = _ECTwistAddJacobian( 80 | pt1xx, pt1xy, 81 | pt1yx, pt1yy, 82 | 1, 0, 83 | pt2xx, pt2xy, 84 | pt2yx, pt2yy, 85 | 1, 0 86 | ); 87 | 88 | return _fromJacobian( 89 | pt3[PTXX], pt3[PTXY], 90 | pt3[PTYX], pt3[PTYY], 91 | pt3[PTZX], pt3[PTZY] 92 | ); 93 | } 94 | 95 | /** 96 | * @notice Multiply a twist point by a scalar 97 | * @param s Scalar to multiply by 98 | * @param pt1xx Coefficient 1 of x 99 | * @param pt1xy Coefficient 2 of x 100 | * @param pt1yx Coefficient 1 of y 101 | * @param pt1yy Coefficient 2 of y 102 | * @return (pt2xx, pt2xy, pt2yx, pt2yy) 103 | */ 104 | function ECTwistMul( 105 | uint256 s, 106 | uint256 pt1xx, uint256 pt1xy, 107 | uint256 pt1yx, uint256 pt1yy 108 | ) public pure returns ( 109 | uint256, uint256, 110 | uint256, uint256 111 | ) { 112 | uint256 pt1zx = 1; 113 | if ( 114 | pt1xx == 0 && pt1xy == 0 && 115 | pt1yx == 0 && pt1yy == 0 116 | ) { 117 | pt1xx = 1; 118 | pt1yx = 1; 119 | pt1zx = 0; 120 | } else { 121 | assert(_isOnCurve( 122 | pt1xx, pt1xy, 123 | pt1yx, pt1yy 124 | )); 125 | } 126 | 127 | uint256[6] memory pt2 = _ECTwistMulJacobian( 128 | s, 129 | pt1xx, pt1xy, 130 | pt1yx, pt1yy, 131 | pt1zx, 0 132 | ); 133 | 134 | return _fromJacobian( 135 | pt2[PTXX], pt2[PTXY], 136 | pt2[PTYX], pt2[PTYY], 137 | pt2[PTZX], pt2[PTZY] 138 | ); 139 | } 140 | 141 | /** 142 | * @notice Get the field modulus 143 | * @return The field modulus 144 | */ 145 | function GetFieldModulus() public pure returns (uint256) { 146 | return FIELD_MODULUS; 147 | } 148 | 149 | function submod(uint256 a, uint256 b, uint256 n) internal pure returns (uint256) { 150 | return addmod(a, n - b, n); 151 | } 152 | 153 | function _FQ2Mul( 154 | uint256 xx, uint256 xy, 155 | uint256 yx, uint256 yy 156 | ) internal pure returns(uint256, uint256) { 157 | return ( 158 | submod(mulmod(xx, yx, FIELD_MODULUS), mulmod(xy, yy, FIELD_MODULUS), FIELD_MODULUS), 159 | addmod(mulmod(xx, yy, FIELD_MODULUS), mulmod(xy, yx, FIELD_MODULUS), FIELD_MODULUS) 160 | ); 161 | } 162 | 163 | function _FQ2Muc( 164 | uint256 xx, uint256 xy, 165 | uint256 c 166 | ) internal pure returns(uint256, uint256) { 167 | return ( 168 | mulmod(xx, c, FIELD_MODULUS), 169 | mulmod(xy, c, FIELD_MODULUS) 170 | ); 171 | } 172 | 173 | function _FQ2Add( 174 | uint256 xx, uint256 xy, 175 | uint256 yx, uint256 yy 176 | ) internal pure returns(uint256, uint256) { 177 | return ( 178 | addmod(xx, yx, FIELD_MODULUS), 179 | addmod(xy, yy, FIELD_MODULUS) 180 | ); 181 | } 182 | 183 | function _FQ2Sub( 184 | uint256 xx, uint256 xy, 185 | uint256 yx, uint256 yy 186 | ) internal pure returns(uint256 rx, uint256 ry) { 187 | return ( 188 | submod(xx, yx, FIELD_MODULUS), 189 | submod(xy, yy, FIELD_MODULUS) 190 | ); 191 | } 192 | 193 | function _FQ2Div( 194 | uint256 xx, uint256 xy, 195 | uint256 yx, uint256 yy 196 | ) internal pure returns(uint256, uint256) { 197 | (yx, yy) = _FQ2Inv(yx, yy); 198 | return _FQ2Mul(xx, xy, yx, yy); 199 | } 200 | 201 | function _FQ2Inv(uint256 x, uint256 y) internal pure returns(uint256, uint256) { 202 | uint256 inv = _modInv(addmod(mulmod(y, y, FIELD_MODULUS), mulmod(x, x, FIELD_MODULUS), FIELD_MODULUS), FIELD_MODULUS); 203 | return ( 204 | mulmod(x, inv, FIELD_MODULUS), 205 | FIELD_MODULUS - mulmod(y, inv, FIELD_MODULUS) 206 | ); 207 | } 208 | 209 | function _isOnCurve( 210 | uint256 xx, uint256 xy, 211 | uint256 yx, uint256 yy 212 | ) internal pure returns (bool) { 213 | uint256 yyx; 214 | uint256 yyy; 215 | uint256 xxxx; 216 | uint256 xxxy; 217 | (yyx, yyy) = _FQ2Mul(yx, yy, yx, yy); 218 | (xxxx, xxxy) = _FQ2Mul(xx, xy, xx, xy); 219 | (xxxx, xxxy) = _FQ2Mul(xxxx, xxxy, xx, xy); 220 | (yyx, yyy) = _FQ2Sub(yyx, yyy, xxxx, xxxy); 221 | (yyx, yyy) = _FQ2Sub(yyx, yyy, TWISTBX, TWISTBY); 222 | return yyx == 0 && yyy == 0; 223 | } 224 | 225 | function _modInv(uint256 a, uint256 n) internal pure returns(uint256 t) { 226 | t = 0; 227 | uint256 newT = 1; 228 | uint256 r = n; 229 | uint256 newR = a; 230 | uint256 q; 231 | while (newR != 0) { 232 | q = r / newR; 233 | (t, newT) = (newT, submod(t, mulmod(q, newT, n), n)); 234 | (r, newR) = (newR, r - q * newR); 235 | } 236 | } 237 | 238 | function _fromJacobian( 239 | uint256 pt1xx, uint256 pt1xy, 240 | uint256 pt1yx, uint256 pt1yy, 241 | uint256 pt1zx, uint256 pt1zy 242 | ) internal pure returns ( 243 | uint256 pt2xx, uint256 pt2xy, 244 | uint256 pt2yx, uint256 pt2yy 245 | ) { 246 | uint256 invzx; 247 | uint256 invzy; 248 | (invzx, invzy) = _FQ2Inv(pt1zx, pt1zy); 249 | (pt2xx, pt2xy) = _FQ2Mul(pt1xx, pt1xy, invzx, invzy); 250 | (pt2yx, pt2yy) = _FQ2Mul(pt1yx, pt1yy, invzx, invzy); 251 | } 252 | 253 | function _ECTwistAddJacobian( 254 | uint256 pt1xx, uint256 pt1xy, 255 | uint256 pt1yx, uint256 pt1yy, 256 | uint256 pt1zx, uint256 pt1zy, 257 | uint256 pt2xx, uint256 pt2xy, 258 | uint256 pt2yx, uint256 pt2yy, 259 | uint256 pt2zx, uint256 pt2zy) internal pure returns (uint256[6] memory pt3) { 260 | if (pt1zx == 0 && pt1zy == 0) { 261 | ( 262 | pt3[PTXX], pt3[PTXY], 263 | pt3[PTYX], pt3[PTYY], 264 | pt3[PTZX], pt3[PTZY] 265 | ) = ( 266 | pt2xx, pt2xy, 267 | pt2yx, pt2yy, 268 | pt2zx, pt2zy 269 | ); 270 | return pt3; 271 | } else if (pt2zx == 0 && pt2zy == 0) { 272 | ( 273 | pt3[PTXX], pt3[PTXY], 274 | pt3[PTYX], pt3[PTYY], 275 | pt3[PTZX], pt3[PTZY] 276 | ) = ( 277 | pt1xx, pt1xy, 278 | pt1yx, pt1yy, 279 | pt1zx, pt1zy 280 | ); 281 | return pt3; 282 | } 283 | 284 | (pt2yx, pt2yy) = _FQ2Mul(pt2yx, pt2yy, pt1zx, pt1zy); // U1 = y2 * z1 285 | (pt3[PTYX], pt3[PTYY]) = _FQ2Mul(pt1yx, pt1yy, pt2zx, pt2zy); // U2 = y1 * z2 286 | (pt2xx, pt2xy) = _FQ2Mul(pt2xx, pt2xy, pt1zx, pt1zy); // V1 = x2 * z1 287 | (pt3[PTZX], pt3[PTZY]) = _FQ2Mul(pt1xx, pt1xy, pt2zx, pt2zy); // V2 = x1 * z2 288 | 289 | if (pt2xx == pt3[PTZX] && pt2xy == pt3[PTZY]) { 290 | if (pt2yx == pt3[PTYX] && pt2yy == pt3[PTYY]) { 291 | ( 292 | pt3[PTXX], pt3[PTXY], 293 | pt3[PTYX], pt3[PTYY], 294 | pt3[PTZX], pt3[PTZY] 295 | ) = _ECTwistDoubleJacobian(pt1xx, pt1xy, pt1yx, pt1yy, pt1zx, pt1zy); 296 | return pt3; 297 | } 298 | ( 299 | pt3[PTXX], pt3[PTXY], 300 | pt3[PTYX], pt3[PTYY], 301 | pt3[PTZX], pt3[PTZY] 302 | ) = ( 303 | 1, 0, 304 | 1, 0, 305 | 0, 0 306 | ); 307 | return pt3; 308 | } 309 | 310 | (pt2zx, pt2zy) = _FQ2Mul(pt1zx, pt1zy, pt2zx, pt2zy); // W = z1 * z2 311 | (pt1xx, pt1xy) = _FQ2Sub(pt2yx, pt2yy, pt3[PTYX], pt3[PTYY]); // U = U1 - U2 312 | (pt1yx, pt1yy) = _FQ2Sub(pt2xx, pt2xy, pt3[PTZX], pt3[PTZY]); // V = V1 - V2 313 | (pt1zx, pt1zy) = _FQ2Mul(pt1yx, pt1yy, pt1yx, pt1yy); // V_squared = V * V 314 | (pt2yx, pt2yy) = _FQ2Mul(pt1zx, pt1zy, pt3[PTZX], pt3[PTZY]); // V_squared_times_V2 = V_squared * V2 315 | (pt1zx, pt1zy) = _FQ2Mul(pt1zx, pt1zy, pt1yx, pt1yy); // V_cubed = V * V_squared 316 | (pt3[PTZX], pt3[PTZY]) = _FQ2Mul(pt1zx, pt1zy, pt2zx, pt2zy); // newz = V_cubed * W 317 | (pt2xx, pt2xy) = _FQ2Mul(pt1xx, pt1xy, pt1xx, pt1xy); // U * U 318 | (pt2xx, pt2xy) = _FQ2Mul(pt2xx, pt2xy, pt2zx, pt2zy); // U * U * W 319 | (pt2xx, pt2xy) = _FQ2Sub(pt2xx, pt2xy, pt1zx, pt1zy); // U * U * W - V_cubed 320 | (pt2zx, pt2zy) = _FQ2Muc(pt2yx, pt2yy, 2); // 2 * V_squared_times_V2 321 | (pt2xx, pt2xy) = _FQ2Sub(pt2xx, pt2xy, pt2zx, pt2zy); // A = U * U * W - V_cubed - 2 * V_squared_times_V2 322 | (pt3[PTXX], pt3[PTXY]) = _FQ2Mul(pt1yx, pt1yy, pt2xx, pt2xy); // newx = V * A 323 | (pt1yx, pt1yy) = _FQ2Sub(pt2yx, pt2yy, pt2xx, pt2xy); // V_squared_times_V2 - A 324 | (pt1yx, pt1yy) = _FQ2Mul(pt1xx, pt1xy, pt1yx, pt1yy); // U * (V_squared_times_V2 - A) 325 | (pt1xx, pt1xy) = _FQ2Mul(pt1zx, pt1zy, pt3[PTYX], pt3[PTYY]); // V_cubed * U2 326 | (pt3[PTYX], pt3[PTYY]) = _FQ2Sub(pt1yx, pt1yy, pt1xx, pt1xy); // newy = U * (V_squared_times_V2 - A) - V_cubed * U2 327 | } 328 | 329 | function _ECTwistDoubleJacobian( 330 | uint256 pt1xx, uint256 pt1xy, 331 | uint256 pt1yx, uint256 pt1yy, 332 | uint256 pt1zx, uint256 pt1zy 333 | ) internal pure returns( 334 | uint256 pt2xx, uint256 pt2xy, 335 | uint256 pt2yx, uint256 pt2yy, 336 | uint256 pt2zx, uint256 pt2zy 337 | ) { 338 | (pt2xx, pt2xy) = _FQ2Muc(pt1xx, pt1xy, 3); // 3 * x 339 | (pt2xx, pt2xy) = _FQ2Mul(pt2xx, pt2xy, pt1xx, pt1xy); // W = 3 * x * x 340 | (pt1zx, pt1zy) = _FQ2Mul(pt1yx, pt1yy, pt1zx, pt1zy); // S = y * z 341 | (pt2yx, pt2yy) = _FQ2Mul(pt1xx, pt1xy, pt1yx, pt1yy); // x * y 342 | (pt2yx, pt2yy) = _FQ2Mul(pt2yx, pt2yy, pt1zx, pt1zy); // B = x * y * S 343 | (pt1xx, pt1xy) = _FQ2Mul(pt2xx, pt2xy, pt2xx, pt2xy); // W * W 344 | (pt2zx, pt2zy) = _FQ2Muc(pt2yx, pt2yy, 8); // 8 * B 345 | (pt1xx, pt1xy) = _FQ2Sub(pt1xx, pt1xy, pt2zx, pt2zy); // H = W * W - 8 * B 346 | (pt2zx, pt2zy) = _FQ2Mul(pt1zx, pt1zy, pt1zx, pt1zy); // S_squared = S * S 347 | (pt2yx, pt2yy) = _FQ2Muc(pt2yx, pt2yy, 4); // 4 * B 348 | (pt2yx, pt2yy) = _FQ2Sub(pt2yx, pt2yy, pt1xx, pt1xy); // 4 * B - H 349 | (pt2yx, pt2yy) = _FQ2Mul(pt2yx, pt2yy, pt2xx, pt2xy); // W * (4 * B - H) 350 | (pt2xx, pt2xy) = _FQ2Muc(pt1yx, pt1yy, 8); // 8 * y 351 | (pt2xx, pt2xy) = _FQ2Mul(pt2xx, pt2xy, pt1yx, pt1yy); // 8 * y * y 352 | (pt2xx, pt2xy) = _FQ2Mul(pt2xx, pt2xy, pt2zx, pt2zy); // 8 * y * y * S_squared 353 | (pt2yx, pt2yy) = _FQ2Sub(pt2yx, pt2yy, pt2xx, pt2xy); // newy = W * (4 * B - H) - 8 * y * y * S_squared 354 | (pt2xx, pt2xy) = _FQ2Muc(pt1xx, pt1xy, 2); // 2 * H 355 | (pt2xx, pt2xy) = _FQ2Mul(pt2xx, pt2xy, pt1zx, pt1zy); // newx = 2 * H * S 356 | (pt2zx, pt2zy) = _FQ2Mul(pt1zx, pt1zy, pt2zx, pt2zy); // S * S_squared 357 | (pt2zx, pt2zy) = _FQ2Muc(pt2zx, pt2zy, 8); // newz = 8 * S * S_squared 358 | } 359 | 360 | function _ECTwistMulJacobian( 361 | uint256 d, 362 | uint256 pt1xx, uint256 pt1xy, 363 | uint256 pt1yx, uint256 pt1yy, 364 | uint256 pt1zx, uint256 pt1zy 365 | ) internal pure returns(uint256[6] memory pt2) { 366 | while (d != 0) { 367 | if ((d & 1) != 0) { 368 | pt2 = _ECTwistAddJacobian( 369 | pt2[PTXX], pt2[PTXY], 370 | pt2[PTYX], pt2[PTYY], 371 | pt2[PTZX], pt2[PTZY], 372 | pt1xx, pt1xy, 373 | pt1yx, pt1yy, 374 | pt1zx, pt1zy); 375 | } 376 | ( 377 | pt1xx, pt1xy, 378 | pt1yx, pt1yy, 379 | pt1zx, pt1zy 380 | ) = _ECTwistDoubleJacobian( 381 | pt1xx, pt1xy, 382 | pt1yx, pt1yy, 383 | pt1zx, pt1zy 384 | ); 385 | 386 | d = d / 2; 387 | } 388 | } 389 | } 390 | 391 | 392 | // This file is MIT Licensed. 393 | // 394 | // Copyright 2017 Christian Reitwiessner 395 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 396 | // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 397 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 398 | 399 | pragma solidity ^0.5.0; 400 | library Pairing { 401 | struct G1Point { 402 | uint X; 403 | uint Y; 404 | } 405 | // Encoding of field elements is: X[0] * z + X[1] 406 | struct G2Point { 407 | uint[2] X; 408 | uint[2] Y; 409 | } 410 | /// @return the generator of G1 411 | function P1() pure internal returns (G1Point memory) { 412 | return G1Point(1, 2); 413 | } 414 | /// @return the generator of G2 415 | function P2() pure internal returns (G2Point memory) { 416 | return G2Point( 417 | [11559732032986387107991004021392285783925812861821192530917403151452391805634, 418 | 10857046999023057135944570762232829481370756359578518086990519993285655852781], 419 | [4082367875863433681332203403145435568316851327593401208105741076214120093531, 420 | 8495653923123431417604973247489272438418190587263600148770280649306958101930] 421 | ); 422 | } 423 | /// @return the negation of p, i.e. p.addition(p.negate()) should be zero. 424 | function negate(G1Point memory p) pure internal returns (G1Point memory) { 425 | // The prime q in the base field F_q for G1 426 | uint q = 21888242871839275222246405745257275088696311157297823662689037894645226208583; 427 | if (p.X == 0 && p.Y == 0) 428 | return G1Point(0, 0); 429 | return G1Point(p.X, q - (p.Y % q)); 430 | } 431 | /// @return the sum of two points of G1 432 | function addition(G1Point memory p1, G1Point memory p2) internal returns (G1Point memory r) { 433 | uint[4] memory input; 434 | input[0] = p1.X; 435 | input[1] = p1.Y; 436 | input[2] = p2.X; 437 | input[3] = p2.Y; 438 | bool success; 439 | assembly { 440 | success := call(sub(gas, 2000), 6, 0, input, 0xc0, r, 0x60) 441 | // Use "invalid" to make gas estimation work 442 | switch success case 0 { invalid() } 443 | } 444 | require(success); 445 | } 446 | /// @return the sum of two points of G2 447 | function addition(G2Point memory p1, G2Point memory p2) internal pure returns (G2Point memory r) { 448 | (r.X[1], r.X[0], r.Y[1], r.Y[0]) = BN256G2.ECTwistAdd(p1.X[1],p1.X[0],p1.Y[1],p1.Y[0],p2.X[1],p2.X[0],p2.Y[1],p2.Y[0]); 449 | } 450 | /// @return the product of a point on G1 and a scalar, i.e. 451 | /// p == p.scalar_mul(1) and p.addition(p) == p.scalar_mul(2) for all points p. 452 | function scalar_mul(G1Point memory p, uint s) internal returns (G1Point memory r) { 453 | uint[3] memory input; 454 | input[0] = p.X; 455 | input[1] = p.Y; 456 | input[2] = s; 457 | bool success; 458 | assembly { 459 | success := call(sub(gas, 2000), 7, 0, input, 0x80, r, 0x60) 460 | // Use "invalid" to make gas estimation work 461 | switch success case 0 { invalid() } 462 | } 463 | require (success); 464 | } 465 | /// @return the result of computing the pairing check 466 | /// e(p1[0], p2[0]) * .... * e(p1[n], p2[n]) == 1 467 | /// For example pairing([P1(), P1().negate()], [P2(), P2()]) should 468 | /// return true. 469 | function pairing(G1Point[] memory p1, G2Point[] memory p2) internal returns (bool) { 470 | require(p1.length == p2.length); 471 | uint elements = p1.length; 472 | uint inputSize = elements * 6; 473 | uint[] memory input = new uint[](inputSize); 474 | for (uint i = 0; i < elements; i++) 475 | { 476 | input[i * 6 + 0] = p1[i].X; 477 | input[i * 6 + 1] = p1[i].Y; 478 | input[i * 6 + 2] = p2[i].X[0]; 479 | input[i * 6 + 3] = p2[i].X[1]; 480 | input[i * 6 + 4] = p2[i].Y[0]; 481 | input[i * 6 + 5] = p2[i].Y[1]; 482 | } 483 | uint[1] memory out; 484 | bool success; 485 | assembly { 486 | success := call(sub(gas, 2000), 8, 0, add(input, 0x20), mul(inputSize, 0x20), out, 0x20) 487 | // Use "invalid" to make gas estimation work 488 | switch success case 0 { invalid() } 489 | } 490 | require(success); 491 | return out[0] != 0; 492 | } 493 | /// Convenience method for a pairing check for two pairs. 494 | function pairingProd2(G1Point memory a1, G2Point memory a2, G1Point memory b1, G2Point memory b2) internal returns (bool) { 495 | G1Point[] memory p1 = new G1Point[](2); 496 | G2Point[] memory p2 = new G2Point[](2); 497 | p1[0] = a1; 498 | p1[1] = b1; 499 | p2[0] = a2; 500 | p2[1] = b2; 501 | return pairing(p1, p2); 502 | } 503 | /// Convenience method for a pairing check for three pairs. 504 | function pairingProd3( 505 | G1Point memory a1, G2Point memory a2, 506 | G1Point memory b1, G2Point memory b2, 507 | G1Point memory c1, G2Point memory c2 508 | ) internal returns (bool) { 509 | G1Point[] memory p1 = new G1Point[](3); 510 | G2Point[] memory p2 = new G2Point[](3); 511 | p1[0] = a1; 512 | p1[1] = b1; 513 | p1[2] = c1; 514 | p2[0] = a2; 515 | p2[1] = b2; 516 | p2[2] = c2; 517 | return pairing(p1, p2); 518 | } 519 | /// Convenience method for a pairing check for four pairs. 520 | function pairingProd4( 521 | G1Point memory a1, G2Point memory a2, 522 | G1Point memory b1, G2Point memory b2, 523 | G1Point memory c1, G2Point memory c2, 524 | G1Point memory d1, G2Point memory d2 525 | ) internal returns (bool) { 526 | G1Point[] memory p1 = new G1Point[](4); 527 | G2Point[] memory p2 = new G2Point[](4); 528 | p1[0] = a1; 529 | p1[1] = b1; 530 | p1[2] = c1; 531 | p1[3] = d1; 532 | p2[0] = a2; 533 | p2[1] = b2; 534 | p2[2] = c2; 535 | p2[3] = d2; 536 | return pairing(p1, p2); 537 | } 538 | } 539 | 540 | contract Verifier { 541 | using Pairing for *; 542 | struct VerifyingKey { 543 | Pairing.G1Point a; 544 | Pairing.G2Point b; 545 | Pairing.G2Point gamma; 546 | Pairing.G2Point delta; 547 | Pairing.G1Point[] gammaABC; 548 | } 549 | struct Proof { 550 | Pairing.G1Point A; 551 | Pairing.G2Point B; 552 | Pairing.G1Point C; 553 | } 554 | function verifyingKey() pure internal returns (VerifyingKey memory vk) { 555 | vk.a = Pairing.G1Point(uint256(0x2e0a814dd75e4118233ddf6a916a813c40bae07d976fdcd01dbfa22bea641a96), uint256(0x1779e77cff5e54cf2cdc237e51cd6d95ef2c37ab6a7d5f9ce0a242188e1a1fe3)); 556 | vk.b = Pairing.G2Point([uint256(0x021548b93199574bdef2be8cb1908a1079b1664d8a041d2e297c3aa6c554855c), uint256(0x190b2d5d03854400e2c2a702f502813677a1d4be920d79648f810e320a30f2c5)], [uint256(0x0bc956fa715451d64e20b260759c2ae74a82b68f1eef86504051cd3ae547f282), uint256(0x011192ee83c0347e363b7c5fffe156fbadd91591b35dc8fe912d2b498c3a9301)]); 557 | vk.gamma = Pairing.G2Point([uint256(0x1c4c46720835faf06e35cd85f05c589a1a98f58112ecf7aacf0deac60681f5a4), uint256(0x1b438f01daf6402ff298981b74f80a5e79c39cce21c67770f74b89e65eb3b9ca)], [uint256(0x101b8c9c29aa1ac1a709878f6eb4d4a74f4ed1368a18f29c2762b76b8c389f4d), uint256(0x009538b3640e10082d0bf4b18b997fef6af2e7cceb942ebb26bd263e8805fedd)]); 558 | vk.delta = Pairing.G2Point([uint256(0x25161a4cc549ffabd2c4508038c12d49447c15e9c565b025183ff6114ffcc58b), uint256(0x110f2b773f6d9632162bc2c629467a58e7539ed0f0dc64ff4fd8f63baf4b5a32)], [uint256(0x0eb80be9e5a3f3f4cb0e39edc1db88dbf8de59b0c800b72dcc34d9c0fae14d55), uint256(0x0839d69bfc27640a59af741138d4f34500d925eb1a4e9fd57fcda269a7411c33)]); 559 | vk.gammaABC = new Pairing.G1Point[](6); 560 | vk.gammaABC[0] = Pairing.G1Point(uint256(0x2bb604557c5f1096973ab8afe980ea3ae23bd7457f3f11f67fb395f2d1f3b568), uint256(0x0f12fdb646ea572637ea6e1bbf04158bcabe6947cf614c67efb3f0278279f866)); 561 | vk.gammaABC[1] = Pairing.G1Point(uint256(0x228bbefb9d7457c97766bcae9412c6ddd1de8e3dbcf1606ca6b8f027836affee), uint256(0x01bf2712a663f5a72a469ea83a4c3d453c6023a0cd5d5f86330157f1505d62b3)); 562 | vk.gammaABC[2] = Pairing.G1Point(uint256(0x23af3409b4b3fb3f194dc683be70c5e442de55544edeace8f891a891a4701ca3), uint256(0x1d13edb38da07247e70158557cfa93097d90d92b9a2c99f190c1413f3fdf8828)); 563 | vk.gammaABC[3] = Pairing.G1Point(uint256(0x00572fbfedfe16fd1dcae266bf009907451cd8db485325ad322fb658cb0c30ff), uint256(0x25415b150b181b2cbecc6f84382b0bd8fd49f2cf498da1c775ad624e5e7b7eaf)); 564 | vk.gammaABC[4] = Pairing.G1Point(uint256(0x1a294f13fbf284a6e11c2f54ed2946fc5fd732dafbf49ac01ce741f224b57c29), uint256(0x182d4a788849c87d27548cbe3a511a0237cb0d4595425eee878d78c4eb4e5529)); 565 | vk.gammaABC[5] = Pairing.G1Point(uint256(0x10ec12d1090de44b1aecb41030d123df2d61318c1928d6de10f916c9bfc2f681), uint256(0x0621a1ea9bbbfa893358dfaa206ba1cb8af2ecca483c3c36f2a0c302da401c8f)); 566 | } 567 | function verify(uint[] memory input, Proof memory proof) internal returns (uint) { 568 | VerifyingKey memory vk = verifyingKey(); 569 | require(input.length + 1 == vk.gammaABC.length); 570 | // Compute the linear combination vk_x 571 | Pairing.G1Point memory vk_x = Pairing.G1Point(0, 0); 572 | for (uint i = 0; i < input.length; i++) 573 | vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.gammaABC[i + 1], input[i])); 574 | vk_x = Pairing.addition(vk_x, vk.gammaABC[0]); 575 | if(!Pairing.pairingProd4( 576 | proof.A, proof.B, 577 | Pairing.negate(vk_x), vk.gamma, 578 | Pairing.negate(proof.C), vk.delta, 579 | Pairing.negate(vk.a), vk.b)) return 1; 580 | return 0; 581 | } 582 | event Verified(string s); 583 | function verifyTx( 584 | uint[2] memory a, 585 | uint[2][2] memory b, 586 | uint[2] memory c, 587 | uint[5] memory input 588 | ) public returns (bool r) { 589 | Proof memory proof; 590 | proof.A = Pairing.G1Point(a[0], a[1]); 591 | proof.B = Pairing.G2Point([b[0][0], b[0][1]], [b[1][0], b[1][1]]); 592 | proof.C = Pairing.G1Point(c[0], c[1]); 593 | uint[] memory inputValues = new uint[](input.length); 594 | for(uint i = 0; i < input.length; i++){ 595 | inputValues[i] = input[i]; 596 | } 597 | if (verify(inputValues, proof) == 0) { 598 | emit Verified("Transaction successfully verified."); 599 | return true; 600 | } else { 601 | return false; 602 | } 603 | } 604 | } 605 | -------------------------------------------------------------------------------- /backend_zk/root.code: -------------------------------------------------------------------------------- 1 | import "hashes/sha256/512bitPacked.code" as sha256packed 2 | 3 | def main(private field[4] n_old, private field[4] n_new, field[2] hash_old, field[2] hash_new) -> (field): 4 | 5 | //check sum 6 | n_old[0] + n_old[1] + n_old[2] + n_old[3] == n_new[0] + n_new[1] + n_new[2] + n_new[3] 7 | 8 | // check old hash 9 | h_old = sha256packed([n_old[0], n_old[1], n_old[2], n_old[3]]) 10 | h_old[0] == hash_old[0] 11 | h_old[1] == hash_old[1] 12 | 13 | // check new hash 14 | h_new = sha256packed([n_new[0], n_new[1], n_new[2], n_new[3]]) 15 | h_new[0] == hash_new[0] 16 | h_new[1] == hash_new[1] 17 | 18 | return 1 19 | -------------------------------------------------------------------------------- /frontend/README.md: -------------------------------------------------------------------------------- 1 | # Usage 2 | 3 | 0. set the `appId` (Fluence) and `lazyAddress` (Eth contract) in `index.js` 4 | 1. run `npm i` 5 | 2. run `npm run build` 6 | 3. run `npm run start` 7 | 8 | * now deployed on http://arweave.net/IhkHrfWKa4RtbuO01kFa-bfzpzH0513bcdDYxv_gpHU -------------------------------------------------------------------------------- /frontend/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Lazy snark dashboard 7 | 8 | 9 | 10 | 11 | 12 |
13 |
14 |

15 |

16 | Lazy snark dashboard 17 |

18 |

19 |
20 |
21 |
22 | 23 |
24 |
25 | 26 |
27 |
28 | 29 |
30 |
31 |

32 |
33 |
34 | 35 |
36 |
37 | 38 |
39 |
40 | 41 |
42 |
43 |

44 |
45 |
46 | 47 |
48 |
49 | 50 |
51 |
52 | 53 |
54 |
55 |

56 |
57 |
58 | 59 |
60 |
61 | 62 |
63 |
64 | 65 |
66 |
67 |

68 |
69 |
70 | 71 |
72 |
73 | 74 |
75 |
76 | 77 |
78 |
79 |

80 |
81 |
82 | 83 |
84 |
85 | 86 |
87 |
88 | 89 |
90 |
91 |
92 | 93 | 94 | -------------------------------------------------------------------------------- /frontend/index.js: -------------------------------------------------------------------------------- 1 | //CONNECT FLUENCE 2 | import * as fluence from "fluence"; 3 | 4 | 5 | window.getResultAsString = function (result) { 6 | return result.result().then((r) => r.asString()) 7 | }; 8 | 9 | var contractInstance; 10 | 11 | $(document).ready(async function() { 12 | let contractAddress = "0xeFF91455de6D4CF57C141bD8bF819E5f873c1A01"; 13 | 14 | // set ethUrl to `undefined` to use MetaMask instead of Ethereum node 15 | let ethUrl = "http://geth.fluence.one:8545/"; 16 | 17 | // application to interact with that stored in Fluence contract 18 | let appId = "299"; 19 | 20 | // create a session between client and backend application, and then join the game 21 | await fluence.connect(contractAddress, appId, ethUrl).then((s) => { 22 | console.log("Session created"); 23 | window.session = s; 24 | }); 25 | 26 | var lazyAddress = '0x834B5BBFd4482E3301b9C10a34f73A94590129A7'; 27 | let ControllerAbi = [ 28 | { 29 | "constant": true, 30 | "inputs": [], 31 | "name": "verifier", 32 | "outputs": [ 33 | { 34 | "name": "", 35 | "type": "address" 36 | } 37 | ], 38 | "payable": false, 39 | "stateMutability": "view", 40 | "type": "function" 41 | }, 42 | { 43 | "constant": true, 44 | "inputs": [], 45 | "name": "stake", 46 | "outputs": [ 47 | { 48 | "name": "", 49 | "type": "uint256" 50 | } 51 | ], 52 | "payable": false, 53 | "stateMutability": "view", 54 | "type": "function" 55 | }, 56 | { 57 | "constant": true, 58 | "inputs": [ 59 | { 60 | "name": "", 61 | "type": "uint256" 62 | } 63 | ], 64 | "name": "tasks", 65 | "outputs": [ 66 | { 67 | "components": [ 68 | { 69 | "name": "input", 70 | "type": "uint256[5]" 71 | } 72 | ], 73 | "name": "data", 74 | "type": "tuple" 75 | }, 76 | { 77 | "components": [ 78 | { 79 | "name": "a", 80 | "type": "uint256[2]" 81 | }, 82 | { 83 | "name": "b", 84 | "type": "uint256[2][2]" 85 | }, 86 | { 87 | "name": "c", 88 | "type": "uint256[2]" 89 | } 90 | ], 91 | "name": "proof", 92 | "type": "tuple" 93 | }, 94 | { 95 | "name": "submitter", 96 | "type": "address" 97 | }, 98 | { 99 | "name": "timestamp", 100 | "type": "uint256" 101 | }, 102 | { 103 | "name": "status", 104 | "type": "uint8" 105 | } 106 | ], 107 | "payable": false, 108 | "stateMutability": "view", 109 | "type": "function" 110 | }, 111 | { 112 | "anonymous": false, 113 | "inputs": [ 114 | { 115 | "indexed": true, 116 | "name": "sender", 117 | "type": "address" 118 | }, 119 | { 120 | "indexed": false, 121 | "name": "index", 122 | "type": "uint256" 123 | }, 124 | { 125 | "components": [ 126 | { 127 | "components": [ 128 | { 129 | "name": "input", 130 | "type": "uint256[5]" 131 | } 132 | ], 133 | "name": "data", 134 | "type": "tuple" 135 | }, 136 | { 137 | "components": [ 138 | { 139 | "name": "a", 140 | "type": "uint256[2]" 141 | }, 142 | { 143 | "name": "b", 144 | "type": "uint256[2][2]" 145 | }, 146 | { 147 | "name": "c", 148 | "type": "uint256[2]" 149 | } 150 | ], 151 | "name": "proof", 152 | "type": "tuple" 153 | }, 154 | { 155 | "name": "submitter", 156 | "type": "address" 157 | }, 158 | { 159 | "name": "timestamp", 160 | "type": "uint256" 161 | }, 162 | { 163 | "name": "status", 164 | "type": "uint8" 165 | } 166 | ], 167 | "indexed": false, 168 | "name": "task", 169 | "type": "tuple" 170 | } 171 | ], 172 | "name": "Submitted", 173 | "type": "event" 174 | }, 175 | { 176 | "anonymous": false, 177 | "inputs": [ 178 | { 179 | "indexed": true, 180 | "name": "challenger", 181 | "type": "address" 182 | }, 183 | { 184 | "indexed": false, 185 | "name": "index", 186 | "type": "uint256" 187 | } 188 | ], 189 | "name": "Challenged", 190 | "type": "event" 191 | }, 192 | { 193 | "constant": true, 194 | "inputs": [], 195 | "name": "tasksNum", 196 | "outputs": [ 197 | { 198 | "name": "", 199 | "type": "uint256" 200 | } 201 | ], 202 | "payable": false, 203 | "stateMutability": "view", 204 | "type": "function" 205 | }, 206 | { 207 | "constant": false, 208 | "inputs": [ 209 | { 210 | "components": [ 211 | { 212 | "name": "input", 213 | "type": "uint256[5]" 214 | } 215 | ], 216 | "name": "data", 217 | "type": "tuple" 218 | }, 219 | { 220 | "components": [ 221 | { 222 | "name": "a", 223 | "type": "uint256[2]" 224 | }, 225 | { 226 | "name": "b", 227 | "type": "uint256[2][2]" 228 | }, 229 | { 230 | "name": "c", 231 | "type": "uint256[2]" 232 | } 233 | ], 234 | "name": "proof", 235 | "type": "tuple" 236 | } 237 | ], 238 | "name": "submit", 239 | "outputs": [], 240 | "payable": true, 241 | "stateMutability": "payable", 242 | "type": "function" 243 | }, 244 | { 245 | "constant": false, 246 | "inputs": [ 247 | { 248 | "name": "id", 249 | "type": "uint256" 250 | } 251 | ], 252 | "name": "challenge", 253 | "outputs": [], 254 | "payable": false, 255 | "stateMutability": "nonpayable", 256 | "type": "function" 257 | }, 258 | { 259 | "constant": false, 260 | "inputs": [ 261 | { 262 | "name": "id", 263 | "type": "uint256" 264 | } 265 | ], 266 | "name": "finzalize", 267 | "outputs": [], 268 | "payable": false, 269 | "stateMutability": "nonpayable", 270 | "type": "function" 271 | }, 272 | { 273 | "constant": true, 274 | "inputs": [ 275 | { 276 | "name": "id", 277 | "type": "uint256" 278 | } 279 | ], 280 | "name": "taskDataById", 281 | "outputs": [ 282 | { 283 | "name": "data", 284 | "type": "uint256[13]" 285 | } 286 | ], 287 | "payable": false, 288 | "stateMutability": "view", 289 | "type": "function" 290 | }, 291 | { 292 | "constant": true, 293 | "inputs": [], 294 | "name": "last5Timestamps", 295 | "outputs": [ 296 | { 297 | "name": "result", 298 | "type": "uint256[5]" 299 | } 300 | ], 301 | "payable": false, 302 | "stateMutability": "view", 303 | "type": "function" 304 | }, 305 | { 306 | "constant": true, 307 | "inputs": [ 308 | { 309 | "name": "id", 310 | "type": "uint256" 311 | } 312 | ], 313 | "name": "getDataById", 314 | "outputs": [ 315 | { 316 | "components": [ 317 | { 318 | "components": [ 319 | { 320 | "name": "input", 321 | "type": "uint256[5]" 322 | } 323 | ], 324 | "name": "data", 325 | "type": "tuple" 326 | }, 327 | { 328 | "components": [ 329 | { 330 | "name": "a", 331 | "type": "uint256[2]" 332 | }, 333 | { 334 | "name": "b", 335 | "type": "uint256[2][2]" 336 | }, 337 | { 338 | "name": "c", 339 | "type": "uint256[2]" 340 | } 341 | ], 342 | "name": "proof", 343 | "type": "tuple" 344 | }, 345 | { 346 | "name": "submitter", 347 | "type": "address" 348 | }, 349 | { 350 | "name": "timestamp", 351 | "type": "uint256" 352 | }, 353 | { 354 | "name": "status", 355 | "type": "uint8" 356 | } 357 | ], 358 | "name": "task", 359 | "type": "tuple" 360 | } 361 | ], 362 | "payable": false, 363 | "stateMutability": "view", 364 | "type": "function" 365 | } 366 | ]; 367 | let ControllerContract = web3.eth.contract(ControllerAbi); 368 | contractInstance = ControllerContract.at(lazyAddress); 369 | window.ethereum.enable(); 370 | 371 | contractInstance.tasksNum(function (err, result) { 372 | let maxLen = Math.min(result, 5); 373 | for (let i = 0; i < maxLen; i++) { 374 | let data = result - 1 - i; 375 | $('#state-id-' + i).text(data); 376 | let fluenceResponse_check = session.request(`{"action": "Check", "proof_id": ${data}}`); 377 | getResultAsString(fluenceResponse_check).then(function (str) { 378 | let fluenceResponse = JSON.parse(str); 379 | console.log(fluenceResponse); 380 | if (fluenceResponse.hasOwnProperty('verifed')) { 381 | if (fluenceResponse.verifed) { 382 | // все хорошо - мы проверили в флюенсе 383 | $('#state-status-fluence-' + i).text('TRUE by Fluence.'); 384 | $('#challenge-' + i).prop('disabled', true); 385 | } else { 386 | // мы проверили, пруф неправильный 387 | $('#state-status-fluence-' + i).text('FALSE by Fluence.'); 388 | $('#challenge-' + i).text('Challenge on Ethereum!') 389 | } 390 | } else { 391 | console.log('Task N ' + data + ' is not checked on Fluence!') 392 | } 393 | }); 394 | } 395 | }); 396 | }); 397 | 398 | $('button').click(function () { 399 | let id = $(this)[0].id.slice(-1); 400 | let data = $('#state-id-' + id)[0].textContent; 401 | 402 | if ($(this)[0].textContent === 'Challenge on Fluence!') { 403 | contractInstance.taskDataById(data, function (err, result) { 404 | let public_par = result.slice(0, 5); 405 | let proof = result.slice(5, 13); 406 | 407 | public_par.forEach(function(element) { 408 | let i = public_par.indexOf(element) 409 | public_par[i] = element.toString(16); 410 | if (public_par[i].length < 64) { 411 | public_par[i] = "0".repeat(64-public_par[i].length) + public_par[i] 412 | } 413 | }); 414 | proof.forEach(function(element) { 415 | let i = proof.indexOf(element) 416 | proof[i] = element.toString(16); 417 | if (proof[i].length < 64) { 418 | proof[i] = "0".repeat(64-proof[i].length) + proof[i] 419 | } 420 | }); 421 | 422 | let fluenceResponse_ver = session.request( 423 | `{"action": "Verify", "proof_id": ${data}, "public_par": ${JSON.stringify(public_par)}, "proof": ${JSON.stringify(proof)}}`); 424 | 425 | getResultAsString(fluenceResponse_ver).then(function (str) { 426 | let fluenceResponse = JSON.parse(str); 427 | let success = fluenceResponse.result === 1; 428 | console.log(fluenceResponse); 429 | if (success) { 430 | // все хорошо - мы проверили в флюенсе 431 | $('#state-status-fluence-' + id).text('TRUE by Fluence.'); 432 | $('#challenge-' + id).prop('disabled', true); 433 | } else { 434 | // мы проверили, пруф неправильный 435 | $('#state-status-fluence-' + id).text('FALSE by Fluence.'); 436 | $('#challenge-' + id).text('Challenge on Ethereum!') 437 | } 438 | }); 439 | }); 440 | } else if ($(this)[0].textContent === 'Challenge on Ethereum!') { 441 | challengeEthereum(id, data); 442 | } else { 443 | 444 | } 445 | }); 446 | 447 | function challengeEthereum(id, data) { 448 | console.log('Challenging task N ' + data + ' on Ethereum!'); 449 | contractInstance.challenge.sendTransaction(data, function (err, txHash) { 450 | if (!err) { 451 | $('#challenge-' + id).text('See tx on Etherscan!').attr("onclick", "window.open('https://rinkeby.etherscan.io/tx/" + txHash + "')"); 452 | } 453 | }); 454 | } 455 | -------------------------------------------------------------------------------- /frontend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "lazy-snark-frontend", 3 | "version": "1.0.0", 4 | "description": "", 5 | "private": true, 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "start": "webpack-dev-server", 9 | "build": "webpack" 10 | }, 11 | "files": [ 12 | "index.html" 13 | ], 14 | "keywords": [], 15 | "author": "", 16 | "devDependencies": { 17 | "copy-webpack-plugin": "^5.0.2", 18 | "css-loader": "^2.1.1", 19 | "html-webpack-plugin": "^3.2.0", 20 | "style-loader": "0.23.1", 21 | "webpack": "^4.29.6", 22 | "webpack-cli": "^3.3.0", 23 | "webpack-dev-server": "^3.2.1", 24 | "web3": "1.0.0-beta.55" 25 | }, 26 | "dependencies": { 27 | "Package": "0.0.1", 28 | "fluence": "0.1.26" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /frontend/webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const webpack = require('webpack'); 3 | const CopyWebpackPlugin = require('copy-webpack-plugin'); 4 | 5 | module.exports = { 6 | // use index.js as entrypoint 7 | entry: { 8 | app: ['./index.js'] 9 | }, 10 | devServer: { 11 | contentBase: './bundle', 12 | hot: true 13 | }, 14 | mode: "production", 15 | module: { 16 | rules: [ 17 | { 18 | test: /\.css$/, 19 | use: ['style-loader', 'css-loader'] 20 | } 21 | ] 22 | }, 23 | // build all code in `bundle.js` in `bundle` directory 24 | output: { 25 | filename: 'bundle.js', 26 | path: path.resolve(__dirname, 'bundle') 27 | }, 28 | plugins: [ 29 | // create `index.html` with imported `bundle.js` 30 | new CopyWebpackPlugin([{ 31 | from: './*.html' 32 | }]), 33 | new webpack.HotModuleReplacementPlugin() 34 | ] 35 | }; 36 | -------------------------------------------------------------------------------- /truffle/README.md: -------------------------------------------------------------------------------- 1 | * now deployed on Rinkeby: 0x834B5BBFd4482E3301b9C10a34f73A94590129A7 -------------------------------------------------------------------------------- /truffle/contracts/IVerifier.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.5.10; 2 | pragma experimental ABIEncoderV2; 3 | 4 | import "./Structs.sol"; 5 | 6 | contract IVerifier is Structs { 7 | function isValid(Data calldata data, Proof calldata proof) external returns (bool); 8 | } 9 | -------------------------------------------------------------------------------- /truffle/contracts/Lazy.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.5.10; 2 | pragma experimental ABIEncoderV2; 3 | 4 | import "./IVerifier.sol"; 5 | import "./Structs.sol"; 6 | 7 | contract Lazy is Structs { 8 | event Submitted(address indexed sender, uint256 index, Task task); 9 | event Challenged(address indexed challenger, uint256 index); 10 | 11 | 12 | enum Status {UNCHECKED, VALID, INVALID, FINALIZED} 13 | struct Task { 14 | Data data; 15 | Proof proof; 16 | address payable submitter; 17 | uint timestamp; 18 | Status status; 19 | } 20 | 21 | Task[] public tasks; 22 | function tasksNum() external view returns(uint) { 23 | return tasks.length; 24 | } 25 | 26 | uint256 public stake; 27 | IVerifier public verifier; 28 | 29 | constructor(IVerifier _verifier) public { 30 | verifier = _verifier; 31 | } 32 | 33 | /// @dev This function submits data. 34 | /// @param data - public inptut for zkp 35 | /// @param proof - proof that verifies input 36 | function submit(Data calldata data, Proof calldata proof) external payable { 37 | require(msg.value == stake); 38 | 39 | Task memory task = Task(data, proof, msg.sender, now, Status.UNCHECKED); 40 | uint index = tasks.push(task); 41 | 42 | emit Submitted(msg.sender, index, task); 43 | } 44 | 45 | /// @dev This function challenges a submission by calling the validation function. 46 | /// @param id The id of the submission to challenge. 47 | function challenge(uint id) external { 48 | Task storage task = tasks[id]; 49 | require(now < task.timestamp + 1 weeks); 50 | require(task.status == Status.UNCHECKED); 51 | 52 | if (verifier.isValid(task.data, task.proof)) { 53 | task.status = Status.VALID; 54 | task.submitter.transfer(stake); 55 | } else { 56 | task.status = Status.INVALID; 57 | msg.sender.transfer(stake); 58 | } 59 | 60 | 61 | // пруф не подходит, на это надо реагировать 62 | 63 | emit Challenged(msg.sender, id); 64 | } 65 | 66 | function finzalize(uint id) external { 67 | Task storage task = tasks[id]; 68 | require(now > task.timestamp + 1 weeks); 69 | require(task.status == Status.UNCHECKED); 70 | 71 | task.status = Status.FINALIZED; 72 | msg.sender.transfer(stake); 73 | } 74 | 75 | function taskDataById(uint id) external view returns(uint[13] memory data) { 76 | Task memory task = tasks[id]; 77 | 78 | data[0] = task.data.input[0]; 79 | data[1] = task.data.input[1]; 80 | data[2] = task.data.input[2]; 81 | data[3] = task.data.input[3]; 82 | data[4] = task.data.input[4]; 83 | 84 | data[5] = task.proof.a[0]; 85 | data[6] = task.proof.a[1]; 86 | 87 | data[7] = task.proof.b[0][0]; 88 | data[8] = task.proof.b[0][1]; 89 | data[9] = task.proof.b[1][0]; 90 | data[10] = task.proof.b[1][1]; 91 | 92 | data[11] = task.proof.c[0]; 93 | data[12] = task.proof.c[1]; 94 | } 95 | } 96 | 97 | -------------------------------------------------------------------------------- /truffle/contracts/Migrations.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >=0.4.21 <0.6.0; 2 | 3 | contract Migrations { 4 | address public owner; 5 | uint public last_completed_migration; 6 | 7 | constructor() public { 8 | owner = msg.sender; 9 | } 10 | 11 | modifier restricted() { 12 | if (msg.sender == owner) _; 13 | } 14 | 15 | function setCompleted(uint completed) public restricted { 16 | last_completed_migration = completed; 17 | } 18 | 19 | function upgrade(address new_address) public restricted { 20 | Migrations upgraded = Migrations(new_address); 21 | upgraded.setCompleted(last_completed_migration); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /truffle/contracts/Structs.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.5.10; 2 | 3 | interface Structs { 4 | struct Data { 5 | uint[5] input; 6 | } 7 | 8 | struct Proof { 9 | uint[2] a; 10 | uint[2][2] b; 11 | uint[2] c; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /truffle/contracts/Verifier.sol: -------------------------------------------------------------------------------- 1 | // This file is LGPL3 Licensed 2 | 3 | /** 4 | * @title Elliptic curve operations on twist points for alt_bn128 5 | * @author Mustafa Al-Bassam (mus@musalbas.com) 6 | */ 7 | library BN256G2 { 8 | uint256 internal constant FIELD_MODULUS = 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47; 9 | uint256 internal constant TWISTBX = 0x2b149d40ceb8aaae81be18991be06ac3b5b4c5e559dbefa33267e6dc24a138e5; 10 | uint256 internal constant TWISTBY = 0x9713b03af0fed4cd2cafadeed8fdf4a74fa084e52d1852e4a2bd0685c315d2; 11 | uint internal constant PTXX = 0; 12 | uint internal constant PTXY = 1; 13 | uint internal constant PTYX = 2; 14 | uint internal constant PTYY = 3; 15 | uint internal constant PTZX = 4; 16 | uint internal constant PTZY = 5; 17 | 18 | /** 19 | * @notice Add two twist points 20 | * @param pt1xx Coefficient 1 of x on point 1 21 | * @param pt1xy Coefficient 2 of x on point 1 22 | * @param pt1yx Coefficient 1 of y on point 1 23 | * @param pt1yy Coefficient 2 of y on point 1 24 | * @param pt2xx Coefficient 1 of x on point 2 25 | * @param pt2xy Coefficient 2 of x on point 2 26 | * @param pt2yx Coefficient 1 of y on point 2 27 | * @param pt2yy Coefficient 2 of y on point 2 28 | * @return (pt3xx, pt3xy, pt3yx, pt3yy) 29 | */ 30 | function ECTwistAdd( 31 | uint256 pt1xx, uint256 pt1xy, 32 | uint256 pt1yx, uint256 pt1yy, 33 | uint256 pt2xx, uint256 pt2xy, 34 | uint256 pt2yx, uint256 pt2yy 35 | ) public pure returns ( 36 | uint256, uint256, 37 | uint256, uint256 38 | ) { 39 | if ( 40 | pt1xx == 0 && pt1xy == 0 && 41 | pt1yx == 0 && pt1yy == 0 42 | ) { 43 | if (!( 44 | pt2xx == 0 && pt2xy == 0 && 45 | pt2yx == 0 && pt2yy == 0 46 | )) { 47 | require(_isOnCurve( 48 | pt2xx, pt2xy, 49 | pt2yx, pt2yy 50 | )); 51 | } 52 | return ( 53 | pt2xx, pt2xy, 54 | pt2yx, pt2yy 55 | ); 56 | } else if ( 57 | pt2xx == 0 && pt2xy == 0 && 58 | pt2yx == 0 && pt2yy == 0 59 | ) { 60 | require(_isOnCurve( 61 | pt1xx, pt1xy, 62 | pt1yx, pt1yy 63 | )); 64 | return ( 65 | pt1xx, pt1xy, 66 | pt1yx, pt1yy 67 | ); 68 | } 69 | 70 | require(_isOnCurve( 71 | pt1xx, pt1xy, 72 | pt1yx, pt1yy 73 | )); 74 | require(_isOnCurve( 75 | pt2xx, pt2xy, 76 | pt2yx, pt2yy 77 | )); 78 | 79 | uint256[6] memory pt3 = _ECTwistAddJacobian( 80 | pt1xx, pt1xy, 81 | pt1yx, pt1yy, 82 | 1, 0, 83 | pt2xx, pt2xy, 84 | pt2yx, pt2yy, 85 | 1, 0 86 | ); 87 | 88 | return _fromJacobian( 89 | pt3[PTXX], pt3[PTXY], 90 | pt3[PTYX], pt3[PTYY], 91 | pt3[PTZX], pt3[PTZY] 92 | ); 93 | } 94 | 95 | /** 96 | * @notice Multiply a twist point by a scalar 97 | * @param s Scalar to multiply by 98 | * @param pt1xx Coefficient 1 of x 99 | * @param pt1xy Coefficient 2 of x 100 | * @param pt1yx Coefficient 1 of y 101 | * @param pt1yy Coefficient 2 of y 102 | * @return (pt2xx, pt2xy, pt2yx, pt2yy) 103 | */ 104 | function ECTwistMul( 105 | uint256 s, 106 | uint256 pt1xx, uint256 pt1xy, 107 | uint256 pt1yx, uint256 pt1yy 108 | ) public pure returns ( 109 | uint256, uint256, 110 | uint256, uint256 111 | ) { 112 | uint256 pt1zx = 1; 113 | if ( 114 | pt1xx == 0 && pt1xy == 0 && 115 | pt1yx == 0 && pt1yy == 0 116 | ) { 117 | pt1xx = 1; 118 | pt1yx = 1; 119 | pt1zx = 0; 120 | } else { 121 | require(_isOnCurve( 122 | pt1xx, pt1xy, 123 | pt1yx, pt1yy 124 | )); 125 | } 126 | 127 | uint256[6] memory pt2 = _ECTwistMulJacobian( 128 | s, 129 | pt1xx, pt1xy, 130 | pt1yx, pt1yy, 131 | pt1zx, 0 132 | ); 133 | 134 | return _fromJacobian( 135 | pt2[PTXX], pt2[PTXY], 136 | pt2[PTYX], pt2[PTYY], 137 | pt2[PTZX], pt2[PTZY] 138 | ); 139 | } 140 | 141 | /** 142 | * @notice Get the field modulus 143 | * @return The field modulus 144 | */ 145 | function GetFieldModulus() public pure returns (uint256) { 146 | return FIELD_MODULUS; 147 | } 148 | 149 | function submod(uint256 a, uint256 b, uint256 n) internal pure returns (uint256) { 150 | return addmod(a, n - b, n); 151 | } 152 | 153 | function _FQ2Mul( 154 | uint256 xx, uint256 xy, 155 | uint256 yx, uint256 yy 156 | ) internal pure returns(uint256, uint256) { 157 | return ( 158 | submod(mulmod(xx, yx, FIELD_MODULUS), mulmod(xy, yy, FIELD_MODULUS), FIELD_MODULUS), 159 | addmod(mulmod(xx, yy, FIELD_MODULUS), mulmod(xy, yx, FIELD_MODULUS), FIELD_MODULUS) 160 | ); 161 | } 162 | 163 | function _FQ2Muc( 164 | uint256 xx, uint256 xy, 165 | uint256 c 166 | ) internal pure returns(uint256, uint256) { 167 | return ( 168 | mulmod(xx, c, FIELD_MODULUS), 169 | mulmod(xy, c, FIELD_MODULUS) 170 | ); 171 | } 172 | 173 | function _FQ2Add( 174 | uint256 xx, uint256 xy, 175 | uint256 yx, uint256 yy 176 | ) internal pure returns(uint256, uint256) { 177 | return ( 178 | addmod(xx, yx, FIELD_MODULUS), 179 | addmod(xy, yy, FIELD_MODULUS) 180 | ); 181 | } 182 | 183 | function _FQ2Sub( 184 | uint256 xx, uint256 xy, 185 | uint256 yx, uint256 yy 186 | ) internal pure returns(uint256 rx, uint256 ry) { 187 | return ( 188 | submod(xx, yx, FIELD_MODULUS), 189 | submod(xy, yy, FIELD_MODULUS) 190 | ); 191 | } 192 | 193 | function _FQ2Div( 194 | uint256 xx, uint256 xy, 195 | uint256 yx, uint256 yy 196 | ) internal pure returns(uint256, uint256) { 197 | (yx, yy) = _FQ2Inv(yx, yy); 198 | return _FQ2Mul(xx, xy, yx, yy); 199 | } 200 | 201 | function _FQ2Inv(uint256 x, uint256 y) internal pure returns(uint256, uint256) { 202 | uint256 inv = _modInv(addmod(mulmod(y, y, FIELD_MODULUS), mulmod(x, x, FIELD_MODULUS), FIELD_MODULUS), FIELD_MODULUS); 203 | return ( 204 | mulmod(x, inv, FIELD_MODULUS), 205 | FIELD_MODULUS - mulmod(y, inv, FIELD_MODULUS) 206 | ); 207 | } 208 | 209 | function _isOnCurve( 210 | uint256 xx, uint256 xy, 211 | uint256 yx, uint256 yy 212 | ) internal pure returns (bool) { 213 | uint256 yyx; 214 | uint256 yyy; 215 | uint256 xxxx; 216 | uint256 xxxy; 217 | (yyx, yyy) = _FQ2Mul(yx, yy, yx, yy); 218 | (xxxx, xxxy) = _FQ2Mul(xx, xy, xx, xy); 219 | (xxxx, xxxy) = _FQ2Mul(xxxx, xxxy, xx, xy); 220 | (yyx, yyy) = _FQ2Sub(yyx, yyy, xxxx, xxxy); 221 | (yyx, yyy) = _FQ2Sub(yyx, yyy, TWISTBX, TWISTBY); 222 | return yyx == 0 && yyy == 0; 223 | } 224 | 225 | function _modInv(uint256 a, uint256 n) internal pure returns(uint256 t) { 226 | t = 0; 227 | uint256 newT = 1; 228 | uint256 r = n; 229 | uint256 newR = a; 230 | uint256 q; 231 | while (newR != 0) { 232 | q = r / newR; 233 | (t, newT) = (newT, submod(t, mulmod(q, newT, n), n)); 234 | (r, newR) = (newR, r - q * newR); 235 | } 236 | } 237 | 238 | function _fromJacobian( 239 | uint256 pt1xx, uint256 pt1xy, 240 | uint256 pt1yx, uint256 pt1yy, 241 | uint256 pt1zx, uint256 pt1zy 242 | ) internal pure returns ( 243 | uint256 pt2xx, uint256 pt2xy, 244 | uint256 pt2yx, uint256 pt2yy 245 | ) { 246 | uint256 invzx; 247 | uint256 invzy; 248 | (invzx, invzy) = _FQ2Inv(pt1zx, pt1zy); 249 | (pt2xx, pt2xy) = _FQ2Mul(pt1xx, pt1xy, invzx, invzy); 250 | (pt2yx, pt2yy) = _FQ2Mul(pt1yx, pt1yy, invzx, invzy); 251 | } 252 | 253 | function _ECTwistAddJacobian( 254 | uint256 pt1xx, uint256 pt1xy, 255 | uint256 pt1yx, uint256 pt1yy, 256 | uint256 pt1zx, uint256 pt1zy, 257 | uint256 pt2xx, uint256 pt2xy, 258 | uint256 pt2yx, uint256 pt2yy, 259 | uint256 pt2zx, uint256 pt2zy) internal pure returns (uint256[6] memory pt3) { 260 | if (pt1zx == 0 && pt1zy == 0) { 261 | ( 262 | pt3[PTXX], pt3[PTXY], 263 | pt3[PTYX], pt3[PTYY], 264 | pt3[PTZX], pt3[PTZY] 265 | ) = ( 266 | pt2xx, pt2xy, 267 | pt2yx, pt2yy, 268 | pt2zx, pt2zy 269 | ); 270 | return pt3; 271 | } else if (pt2zx == 0 && pt2zy == 0) { 272 | ( 273 | pt3[PTXX], pt3[PTXY], 274 | pt3[PTYX], pt3[PTYY], 275 | pt3[PTZX], pt3[PTZY] 276 | ) = ( 277 | pt1xx, pt1xy, 278 | pt1yx, pt1yy, 279 | pt1zx, pt1zy 280 | ); 281 | return pt3; 282 | } 283 | 284 | (pt2yx, pt2yy) = _FQ2Mul(pt2yx, pt2yy, pt1zx, pt1zy); // U1 = y2 * z1 285 | (pt3[PTYX], pt3[PTYY]) = _FQ2Mul(pt1yx, pt1yy, pt2zx, pt2zy); // U2 = y1 * z2 286 | (pt2xx, pt2xy) = _FQ2Mul(pt2xx, pt2xy, pt1zx, pt1zy); // V1 = x2 * z1 287 | (pt3[PTZX], pt3[PTZY]) = _FQ2Mul(pt1xx, pt1xy, pt2zx, pt2zy); // V2 = x1 * z2 288 | 289 | if (pt2xx == pt3[PTZX] && pt2xy == pt3[PTZY]) { 290 | if (pt2yx == pt3[PTYX] && pt2yy == pt3[PTYY]) { 291 | ( 292 | pt3[PTXX], pt3[PTXY], 293 | pt3[PTYX], pt3[PTYY], 294 | pt3[PTZX], pt3[PTZY] 295 | ) = _ECTwistDoubleJacobian(pt1xx, pt1xy, pt1yx, pt1yy, pt1zx, pt1zy); 296 | return pt3; 297 | } 298 | ( 299 | pt3[PTXX], pt3[PTXY], 300 | pt3[PTYX], pt3[PTYY], 301 | pt3[PTZX], pt3[PTZY] 302 | ) = ( 303 | 1, 0, 304 | 1, 0, 305 | 0, 0 306 | ); 307 | return pt3; 308 | } 309 | 310 | (pt2zx, pt2zy) = _FQ2Mul(pt1zx, pt1zy, pt2zx, pt2zy); // W = z1 * z2 311 | (pt1xx, pt1xy) = _FQ2Sub(pt2yx, pt2yy, pt3[PTYX], pt3[PTYY]); // U = U1 - U2 312 | (pt1yx, pt1yy) = _FQ2Sub(pt2xx, pt2xy, pt3[PTZX], pt3[PTZY]); // V = V1 - V2 313 | (pt1zx, pt1zy) = _FQ2Mul(pt1yx, pt1yy, pt1yx, pt1yy); // V_squared = V * V 314 | (pt2yx, pt2yy) = _FQ2Mul(pt1zx, pt1zy, pt3[PTZX], pt3[PTZY]); // V_squared_times_V2 = V_squared * V2 315 | (pt1zx, pt1zy) = _FQ2Mul(pt1zx, pt1zy, pt1yx, pt1yy); // V_cubed = V * V_squared 316 | (pt3[PTZX], pt3[PTZY]) = _FQ2Mul(pt1zx, pt1zy, pt2zx, pt2zy); // newz = V_cubed * W 317 | (pt2xx, pt2xy) = _FQ2Mul(pt1xx, pt1xy, pt1xx, pt1xy); // U * U 318 | (pt2xx, pt2xy) = _FQ2Mul(pt2xx, pt2xy, pt2zx, pt2zy); // U * U * W 319 | (pt2xx, pt2xy) = _FQ2Sub(pt2xx, pt2xy, pt1zx, pt1zy); // U * U * W - V_cubed 320 | (pt2zx, pt2zy) = _FQ2Muc(pt2yx, pt2yy, 2); // 2 * V_squared_times_V2 321 | (pt2xx, pt2xy) = _FQ2Sub(pt2xx, pt2xy, pt2zx, pt2zy); // A = U * U * W - V_cubed - 2 * V_squared_times_V2 322 | (pt3[PTXX], pt3[PTXY]) = _FQ2Mul(pt1yx, pt1yy, pt2xx, pt2xy); // newx = V * A 323 | (pt1yx, pt1yy) = _FQ2Sub(pt2yx, pt2yy, pt2xx, pt2xy); // V_squared_times_V2 - A 324 | (pt1yx, pt1yy) = _FQ2Mul(pt1xx, pt1xy, pt1yx, pt1yy); // U * (V_squared_times_V2 - A) 325 | (pt1xx, pt1xy) = _FQ2Mul(pt1zx, pt1zy, pt3[PTYX], pt3[PTYY]); // V_cubed * U2 326 | (pt3[PTYX], pt3[PTYY]) = _FQ2Sub(pt1yx, pt1yy, pt1xx, pt1xy); // newy = U * (V_squared_times_V2 - A) - V_cubed * U2 327 | } 328 | 329 | function _ECTwistDoubleJacobian( 330 | uint256 pt1xx, uint256 pt1xy, 331 | uint256 pt1yx, uint256 pt1yy, 332 | uint256 pt1zx, uint256 pt1zy 333 | ) internal pure returns( 334 | uint256 pt2xx, uint256 pt2xy, 335 | uint256 pt2yx, uint256 pt2yy, 336 | uint256 pt2zx, uint256 pt2zy 337 | ) { 338 | (pt2xx, pt2xy) = _FQ2Muc(pt1xx, pt1xy, 3); // 3 * x 339 | (pt2xx, pt2xy) = _FQ2Mul(pt2xx, pt2xy, pt1xx, pt1xy); // W = 3 * x * x 340 | (pt1zx, pt1zy) = _FQ2Mul(pt1yx, pt1yy, pt1zx, pt1zy); // S = y * z 341 | (pt2yx, pt2yy) = _FQ2Mul(pt1xx, pt1xy, pt1yx, pt1yy); // x * y 342 | (pt2yx, pt2yy) = _FQ2Mul(pt2yx, pt2yy, pt1zx, pt1zy); // B = x * y * S 343 | (pt1xx, pt1xy) = _FQ2Mul(pt2xx, pt2xy, pt2xx, pt2xy); // W * W 344 | (pt2zx, pt2zy) = _FQ2Muc(pt2yx, pt2yy, 8); // 8 * B 345 | (pt1xx, pt1xy) = _FQ2Sub(pt1xx, pt1xy, pt2zx, pt2zy); // H = W * W - 8 * B 346 | (pt2zx, pt2zy) = _FQ2Mul(pt1zx, pt1zy, pt1zx, pt1zy); // S_squared = S * S 347 | (pt2yx, pt2yy) = _FQ2Muc(pt2yx, pt2yy, 4); // 4 * B 348 | (pt2yx, pt2yy) = _FQ2Sub(pt2yx, pt2yy, pt1xx, pt1xy); // 4 * B - H 349 | (pt2yx, pt2yy) = _FQ2Mul(pt2yx, pt2yy, pt2xx, pt2xy); // W * (4 * B - H) 350 | (pt2xx, pt2xy) = _FQ2Muc(pt1yx, pt1yy, 8); // 8 * y 351 | (pt2xx, pt2xy) = _FQ2Mul(pt2xx, pt2xy, pt1yx, pt1yy); // 8 * y * y 352 | (pt2xx, pt2xy) = _FQ2Mul(pt2xx, pt2xy, pt2zx, pt2zy); // 8 * y * y * S_squared 353 | (pt2yx, pt2yy) = _FQ2Sub(pt2yx, pt2yy, pt2xx, pt2xy); // newy = W * (4 * B - H) - 8 * y * y * S_squared 354 | (pt2xx, pt2xy) = _FQ2Muc(pt1xx, pt1xy, 2); // 2 * H 355 | (pt2xx, pt2xy) = _FQ2Mul(pt2xx, pt2xy, pt1zx, pt1zy); // newx = 2 * H * S 356 | (pt2zx, pt2zy) = _FQ2Mul(pt1zx, pt1zy, pt2zx, pt2zy); // S * S_squared 357 | (pt2zx, pt2zy) = _FQ2Muc(pt2zx, pt2zy, 8); // newz = 8 * S * S_squared 358 | } 359 | 360 | function _ECTwistMulJacobian( 361 | uint256 d, 362 | uint256 pt1xx, uint256 pt1xy, 363 | uint256 pt1yx, uint256 pt1yy, 364 | uint256 pt1zx, uint256 pt1zy 365 | ) internal pure returns(uint256[6] memory pt2) { 366 | while (d != 0) { 367 | if ((d & 1) != 0) { 368 | pt2 = _ECTwistAddJacobian( 369 | pt2[PTXX], pt2[PTXY], 370 | pt2[PTYX], pt2[PTYY], 371 | pt2[PTZX], pt2[PTZY], 372 | pt1xx, pt1xy, 373 | pt1yx, pt1yy, 374 | pt1zx, pt1zy); 375 | } 376 | ( 377 | pt1xx, pt1xy, 378 | pt1yx, pt1yy, 379 | pt1zx, pt1zy 380 | ) = _ECTwistDoubleJacobian( 381 | pt1xx, pt1xy, 382 | pt1yx, pt1yy, 383 | pt1zx, pt1zy 384 | ); 385 | 386 | d = d / 2; 387 | } 388 | } 389 | } 390 | 391 | 392 | // This file is MIT Licensed. 393 | // 394 | // Copyright 2017 Christian Reitwiessner 395 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 396 | // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 397 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 398 | 399 | pragma solidity ^0.5.0; 400 | library Pairing { 401 | struct G1Point { 402 | uint X; 403 | uint Y; 404 | } 405 | // Encoding of field elements is: X[0] * z + X[1] 406 | struct G2Point { 407 | uint[2] X; 408 | uint[2] Y; 409 | } 410 | /// @return the generator of G1 411 | function P1() pure internal returns (G1Point memory) { 412 | return G1Point(1, 2); 413 | } 414 | /// @return the generator of G2 415 | function P2() pure internal returns (G2Point memory) { 416 | return G2Point( 417 | [11559732032986387107991004021392285783925812861821192530917403151452391805634, 418 | 10857046999023057135944570762232829481370756359578518086990519993285655852781], 419 | [4082367875863433681332203403145435568316851327593401208105741076214120093531, 420 | 8495653923123431417604973247489272438418190587263600148770280649306958101930] 421 | ); 422 | } 423 | /// @return the negation of p, i.e. p.addition(p.negate()) should be zero. 424 | function negate(G1Point memory p) pure internal returns (G1Point memory) { 425 | // The prime q in the base field F_q for G1 426 | uint q = 21888242871839275222246405745257275088696311157297823662689037894645226208583; 427 | if (p.X == 0 && p.Y == 0) 428 | return G1Point(0, 0); 429 | return G1Point(p.X, q - (p.Y % q)); 430 | } 431 | /// @return the sum of two points of G1 432 | function addition(G1Point memory p1, G1Point memory p2) internal returns (G1Point memory r) { 433 | uint[4] memory input; 434 | input[0] = p1.X; 435 | input[1] = p1.Y; 436 | input[2] = p2.X; 437 | input[3] = p2.Y; 438 | bool success; 439 | assembly { 440 | success := call(sub(gas, 2000), 6, 0, input, 0xc0, r, 0x60) 441 | // Use "invalid" to make gas estimation work 442 | switch success case 0 { invalid() } 443 | } 444 | require(success); 445 | } 446 | /// @return the sum of two points of G2 447 | function addition(G2Point memory p1, G2Point memory p2) internal pure returns (G2Point memory r) { 448 | (r.X[1], r.X[0], r.Y[1], r.Y[0]) = BN256G2.ECTwistAdd(p1.X[1],p1.X[0],p1.Y[1],p1.Y[0],p2.X[1],p2.X[0],p2.Y[1],p2.Y[0]); 449 | } 450 | /// @return the product of a point on G1 and a scalar, i.e. 451 | /// p == p.scalar_mul(1) and p.addition(p) == p.scalar_mul(2) for all points p. 452 | function scalar_mul(G1Point memory p, uint s) internal returns (G1Point memory r) { 453 | uint[3] memory input; 454 | input[0] = p.X; 455 | input[1] = p.Y; 456 | input[2] = s; 457 | bool success; 458 | assembly { 459 | success := call(sub(gas, 2000), 7, 0, input, 0x80, r, 0x60) 460 | // Use "invalid" to make gas estimation work 461 | switch success case 0 { invalid() } 462 | } 463 | require (success); 464 | } 465 | /// @return the result of computing the pairing check 466 | /// e(p1[0], p2[0]) * .... * e(p1[n], p2[n]) == 1 467 | /// For example pairing([P1(), P1().negate()], [P2(), P2()]) should 468 | /// return true. 469 | function pairing(G1Point[] memory p1, G2Point[] memory p2) internal returns (bool) { 470 | require(p1.length == p2.length); 471 | uint elements = p1.length; 472 | uint inputSize = elements * 6; 473 | uint[] memory input = new uint[](inputSize); 474 | for (uint i = 0; i < elements; i++) 475 | { 476 | input[i * 6 + 0] = p1[i].X; 477 | input[i * 6 + 1] = p1[i].Y; 478 | input[i * 6 + 2] = p2[i].X[0]; 479 | input[i * 6 + 3] = p2[i].X[1]; 480 | input[i * 6 + 4] = p2[i].Y[0]; 481 | input[i * 6 + 5] = p2[i].Y[1]; 482 | } 483 | uint[1] memory out; 484 | bool success; 485 | assembly { 486 | success := call(sub(gas, 2000), 8, 0, add(input, 0x20), mul(inputSize, 0x20), out, 0x20) 487 | // Use "invalid" to make gas estimation work 488 | switch success case 0 { invalid() } 489 | } 490 | require(success); 491 | return out[0] != 0; 492 | } 493 | /// Convenience method for a pairing check for two pairs. 494 | function pairingProd2(G1Point memory a1, G2Point memory a2, G1Point memory b1, G2Point memory b2) internal returns (bool) { 495 | G1Point[] memory p1 = new G1Point[](2); 496 | G2Point[] memory p2 = new G2Point[](2); 497 | p1[0] = a1; 498 | p1[1] = b1; 499 | p2[0] = a2; 500 | p2[1] = b2; 501 | return pairing(p1, p2); 502 | } 503 | /// Convenience method for a pairing check for three pairs. 504 | function pairingProd3( 505 | G1Point memory a1, G2Point memory a2, 506 | G1Point memory b1, G2Point memory b2, 507 | G1Point memory c1, G2Point memory c2 508 | ) internal returns (bool) { 509 | G1Point[] memory p1 = new G1Point[](3); 510 | G2Point[] memory p2 = new G2Point[](3); 511 | p1[0] = a1; 512 | p1[1] = b1; 513 | p1[2] = c1; 514 | p2[0] = a2; 515 | p2[1] = b2; 516 | p2[2] = c2; 517 | return pairing(p1, p2); 518 | } 519 | /// Convenience method for a pairing check for four pairs. 520 | function pairingProd4( 521 | G1Point memory a1, G2Point memory a2, 522 | G1Point memory b1, G2Point memory b2, 523 | G1Point memory c1, G2Point memory c2, 524 | G1Point memory d1, G2Point memory d2 525 | ) internal returns (bool) { 526 | G1Point[] memory p1 = new G1Point[](4); 527 | G2Point[] memory p2 = new G2Point[](4); 528 | p1[0] = a1; 529 | p1[1] = b1; 530 | p1[2] = c1; 531 | p1[3] = d1; 532 | p2[0] = a2; 533 | p2[1] = b2; 534 | p2[2] = c2; 535 | p2[3] = d2; 536 | return pairing(p1, p2); 537 | } 538 | } 539 | 540 | contract Verifier { 541 | using Pairing for *; 542 | struct VerifyingKey { 543 | Pairing.G1Point a; 544 | Pairing.G2Point b; 545 | Pairing.G2Point gamma; 546 | Pairing.G2Point delta; 547 | Pairing.G1Point[] gammaABC; 548 | } 549 | struct Proof { 550 | Pairing.G1Point A; 551 | Pairing.G2Point B; 552 | Pairing.G1Point C; 553 | } 554 | function verifyingKey() pure internal returns (VerifyingKey memory vk) { 555 | vk.a = Pairing.G1Point(uint256(0x2e0a814dd75e4118233ddf6a916a813c40bae07d976fdcd01dbfa22bea641a96), uint256(0x1779e77cff5e54cf2cdc237e51cd6d95ef2c37ab6a7d5f9ce0a242188e1a1fe3)); 556 | vk.b = Pairing.G2Point([uint256(0x021548b93199574bdef2be8cb1908a1079b1664d8a041d2e297c3aa6c554855c), uint256(0x190b2d5d03854400e2c2a702f502813677a1d4be920d79648f810e320a30f2c5)], [uint256(0x0bc956fa715451d64e20b260759c2ae74a82b68f1eef86504051cd3ae547f282), uint256(0x011192ee83c0347e363b7c5fffe156fbadd91591b35dc8fe912d2b498c3a9301)]); 557 | vk.gamma = Pairing.G2Point([uint256(0x1c4c46720835faf06e35cd85f05c589a1a98f58112ecf7aacf0deac60681f5a4), uint256(0x1b438f01daf6402ff298981b74f80a5e79c39cce21c67770f74b89e65eb3b9ca)], [uint256(0x101b8c9c29aa1ac1a709878f6eb4d4a74f4ed1368a18f29c2762b76b8c389f4d), uint256(0x009538b3640e10082d0bf4b18b997fef6af2e7cceb942ebb26bd263e8805fedd)]); 558 | vk.delta = Pairing.G2Point([uint256(0x25161a4cc549ffabd2c4508038c12d49447c15e9c565b025183ff6114ffcc58b), uint256(0x110f2b773f6d9632162bc2c629467a58e7539ed0f0dc64ff4fd8f63baf4b5a32)], [uint256(0x0eb80be9e5a3f3f4cb0e39edc1db88dbf8de59b0c800b72dcc34d9c0fae14d55), uint256(0x0839d69bfc27640a59af741138d4f34500d925eb1a4e9fd57fcda269a7411c33)]); 559 | vk.gammaABC = new Pairing.G1Point[](6); 560 | vk.gammaABC[0] = Pairing.G1Point(uint256(0x2bb604557c5f1096973ab8afe980ea3ae23bd7457f3f11f67fb395f2d1f3b568), uint256(0x0f12fdb646ea572637ea6e1bbf04158bcabe6947cf614c67efb3f0278279f866)); 561 | vk.gammaABC[1] = Pairing.G1Point(uint256(0x228bbefb9d7457c97766bcae9412c6ddd1de8e3dbcf1606ca6b8f027836affee), uint256(0x01bf2712a663f5a72a469ea83a4c3d453c6023a0cd5d5f86330157f1505d62b3)); 562 | vk.gammaABC[2] = Pairing.G1Point(uint256(0x23af3409b4b3fb3f194dc683be70c5e442de55544edeace8f891a891a4701ca3), uint256(0x1d13edb38da07247e70158557cfa93097d90d92b9a2c99f190c1413f3fdf8828)); 563 | vk.gammaABC[3] = Pairing.G1Point(uint256(0x00572fbfedfe16fd1dcae266bf009907451cd8db485325ad322fb658cb0c30ff), uint256(0x25415b150b181b2cbecc6f84382b0bd8fd49f2cf498da1c775ad624e5e7b7eaf)); 564 | vk.gammaABC[4] = Pairing.G1Point(uint256(0x1a294f13fbf284a6e11c2f54ed2946fc5fd732dafbf49ac01ce741f224b57c29), uint256(0x182d4a788849c87d27548cbe3a511a0237cb0d4595425eee878d78c4eb4e5529)); 565 | vk.gammaABC[5] = Pairing.G1Point(uint256(0x10ec12d1090de44b1aecb41030d123df2d61318c1928d6de10f916c9bfc2f681), uint256(0x0621a1ea9bbbfa893358dfaa206ba1cb8af2ecca483c3c36f2a0c302da401c8f)); 566 | } 567 | function verify(uint[] memory input, Proof memory proof) internal returns (uint) { 568 | VerifyingKey memory vk = verifyingKey(); 569 | require(input.length + 1 == vk.gammaABC.length); 570 | // Compute the linear combination vk_x 571 | Pairing.G1Point memory vk_x = Pairing.G1Point(0, 0); 572 | for (uint i = 0; i < input.length; i++) 573 | vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.gammaABC[i + 1], input[i])); 574 | vk_x = Pairing.addition(vk_x, vk.gammaABC[0]); 575 | if(!Pairing.pairingProd4( 576 | proof.A, proof.B, 577 | Pairing.negate(vk_x), vk.gamma, 578 | Pairing.negate(proof.C), vk.delta, 579 | Pairing.negate(vk.a), vk.b)) return 1; 580 | return 0; 581 | } 582 | event Verified(string s); 583 | function verifyTx( 584 | uint[2] memory a, 585 | uint[2][2] memory b, 586 | uint[2] memory c, 587 | uint[5] memory input 588 | ) public returns (bool r) { 589 | Proof memory proof; 590 | proof.A = Pairing.G1Point(a[0], a[1]); 591 | proof.B = Pairing.G2Point([b[0][0], b[0][1]], [b[1][0], b[1][1]]); 592 | proof.C = Pairing.G1Point(c[0], c[1]); 593 | uint[] memory inputValues = new uint[](input.length); 594 | for(uint i = 0; i < input.length; i++){ 595 | inputValues[i] = input[i]; 596 | } 597 | if (verify(inputValues, proof) == 0) { 598 | emit Verified("Transaction successfully verified."); 599 | return true; 600 | } else { 601 | return false; 602 | } 603 | } 604 | } -------------------------------------------------------------------------------- /truffle/contracts/VerifierProxy.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.5.10; 2 | pragma experimental ABIEncoderV2; 3 | 4 | import "./IVerifier.sol"; 5 | import "./Verifier.sol"; 6 | 7 | 8 | contract VerifierProxy is IVerifier { 9 | Verifier internal verifier; 10 | 11 | constructor(Verifier ver) public { 12 | verifier = ver; 13 | } 14 | 15 | // Truffle gives `UnimplementedFeatureError: Encoding struct from calldata is not yet supported.` 16 | // that's why function is public and uses memory location modifier 17 | function isValid(Data memory data, Proof memory proof) public returns (bool) { 18 | bytes memory payload = abi.encodeWithSelector(verifier.verifyTx.selector, proof.a, proof.b, proof.c, data.input); 19 | (bool success, bytes memory r) = address(verifier).call(payload); 20 | return success && abi.decode(r, (bool)); 21 | // return verifier.verifyTx(proof.a, proof.b, proof.c, data.input); 22 | } 23 | } -------------------------------------------------------------------------------- /truffle/migrations/1_initial_migration.js: -------------------------------------------------------------------------------- 1 | const Migrations = artifacts.require("./Migrations.sol"); 2 | 3 | module.exports = function(deployer) { 4 | deployer.deploy(Migrations); 5 | }; 6 | -------------------------------------------------------------------------------- /truffle/migrations/2_deploy_lazy.js: -------------------------------------------------------------------------------- 1 | var Verifier = artifacts.require('./Verifier.sol'); 2 | var VerifierProxy = artifacts.require('./VerifierProxy.sol'); 3 | var Lazy = artifacts.require('./Lazy.sol'); 4 | 5 | const proof1 = [["0x24d858a8ffc1766e7cccf95643f1339cb10978a5b06a6f8abad82782a3ab3efd", "0x2d0b5206a856f75a93284728f7cfa61e998868b632b11886a439add8e6150f3e"],[["0x13e6a883986efe7bb0c6e99b00c157d31ea8479283ac6c4934e42368da31e6d8", "0x0718d8dfecf7726df8a27092bac85d58767230b33a66dd8c69ca54f576361fc1"], ["0x160f03315ee7766d576122244d12bcabd24ee3c7d33e1cb05d838337a0fd0dfb", "0x2ea4c7c18ed1b8f3544a4fb3c4d95efa5543182406fef71bfda8760e407a05c7"]],["0x1111708b97dac3f087a3d8e13cfd513d7a82c619d39e9148080b600b7dae210e", "0x2a6e76f3003e65afefae71d3fe18ba26a3940e81463bf94615478cdf5daa2249"]]; 6 | const input1 = [["0x00000000000000000000000000000000c6481e22c5ff4164af680b8cfaa5e8ed", "0x000000000000000000000000000000003120eeff89c4f307c4a6faaae059ce10", "0x000000000000000000000000000000005b6d7d198c48c17c9540d29275a04662", "0x00000000000000000000000000000000f7a9aa434629a33c84eec3e16e196f27", "0x0000000000000000000000000000000000000000000000000000000000000001"]]; 7 | 8 | module.exports = async function(deployer, network, accounts) { 9 | deployer.then(async() => { 10 | await deployer.deploy(Verifier); 11 | await deployer.deploy(VerifierProxy, Verifier.address); 12 | var contract = await deployer.deploy(Lazy, VerifierProxy.address); 13 | await contract.submit(input1, proof1); 14 | await contract.submit(input1, proof1); 15 | await contract.submit(input1, proof1); 16 | await contract.submit([[1, 2, 3, 4, 5]], [[1, 2], [[3, 4], [5, 6]], [7, 8]]); 17 | await contract.submit(input1, proof1); 18 | }); 19 | }; 20 | -------------------------------------------------------------------------------- /truffle/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "lazy-snark", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "truffle.js", 6 | "directories": { 7 | "test": "test" 8 | }, 9 | "dependencies": { 10 | "any-promise": "^1.3.0", 11 | "babel-polyfill": "^6.26.0", 12 | "babel-register": "^6.26.0", 13 | "bindings": "^1.5.0", 14 | "ganache-cli": "^6.4.1", 15 | "truffle": "5.0.25", 16 | "truffle-hdwallet-provider": "^1.0.0-web3one.5" 17 | }, 18 | "scripts": { 19 | "test": "./node_modules/.bin/truffle test" 20 | }, 21 | "author": "", 22 | "license": "ISC" 23 | } 24 | -------------------------------------------------------------------------------- /truffle/test/test.js: -------------------------------------------------------------------------------- 1 | const Lazy = artifacts.require('./Lazy.sol'); 2 | const Verifier = artifacts.require('./Verifier.sol'); 3 | 4 | 5 | contract("Testing Lazy", accounts => { 6 | 7 | it("should deploy with 2 tasks", async () => { 8 | let instance = await Lazy.deployed(); 9 | let tasksNum = await instance.tasksNum.call(); 10 | assert.equal(tasksNum.valueOf(), 2); 11 | }); 12 | 13 | it("should detect incorrect proof", async () => { 14 | let instance = await Lazy.deployed(); 15 | let task = await instance.tasks(0); 16 | assert.equal(task.status, 0); 17 | await instance.challenge(0); 18 | task = await instance.tasks(0); 19 | assert.equal(task.status, 2); 20 | }); 21 | 22 | it("should pass correct proof", async () => { 23 | let instance = await Lazy.deployed(); 24 | let task = await instance.tasks(1); 25 | assert.equal(task.status, 0); 26 | await instance.challenge(1); 27 | task = await instance.tasks(1); 28 | assert.equal(task.status, 1); 29 | }); 30 | 31 | }); 32 | 33 | 34 | 35 | contract("Testing Verifier", accounts => { 36 | const a = ["0x12d0dbcfc1da3ea29bc017288fceea3929401f4f12dbd0bba73781420d31aa2d", "0x2811c1eaa63f4a804951bd7f994cbb6bea9df64591793b8392400e8756d1bca7"]; 37 | const b = [["0x04c33f68e1bd55be0928b086c647debcdf7aa0e3c3efc6a8efbc2596a77a0e67", "0x17e7392e0e3ec2b5701e675e6e0569330d03ffffe476fc8d63cfeaa0ba1c8a97"], ["0x2fc402693a54cd1b176abeed209674f2f12ced1496c6ce27ba8cf16903daa4cc", "0x2c47efba3f4f260da643bb6427d08b551bb3446537d6ac4857d611be2355a446"]]; 38 | const c = ["0x04d40f14694092d0f70890a20492b2b68e7eaabdcee744e519678d687c9c3ed0", "0x28de140e393154b0e70b3ef12806af963a4a33b45c24e7864391093b6028fa2b"]; 39 | const input = ["0x00000000000000000000000000000000c6481e22c5ff4164af680b8cfaa5e8ed", "0x000000000000000000000000000000003120eeff89c4f307c4a6faaae059ce10", "0x000000000000000000000000000000005b6d7d198c48c17c9540d29275a04662", "0x00000000000000000000000000000000f7a9aa434629a33c84eec3e16e196f27", "0x0000000000000000000000000000000000000000000000000000000000000001"]; 40 | 41 | it("should process proofs", async () => { 42 | let instance = await Verifier.deployed(); 43 | let result = await instance.verifyTx.call(a,b,c,input); 44 | console.log("verfifier thinks that result is " + result) 45 | }); 46 | 47 | }); -------------------------------------------------------------------------------- /truffle/truffle.js: -------------------------------------------------------------------------------- 1 | require('babel-register'); 2 | require('babel-polyfill'); 3 | 4 | var HDWalletProvider = require("truffle-hdwallet-provider"); 5 | 6 | var mnemonicRinkeby = "oxygen crunch note tent verify chicken gossip shield essence runway clinic fortune"; 7 | var infuraLinkRinkeby = "https://rinkeby.infura.io/v3/198f519e2d9643d689649459edccc350"; 8 | 9 | module.exports = { 10 | networks: { 11 | rinkeby: { 12 | provider: function() { 13 | return new HDWalletProvider(mnemonicRinkeby, infuraLinkRinkeby, 1) 14 | }, 15 | from : "0x6d92a2d06758E014Da0C98d0bBBE9Ed78E964f34".toLowerCase(), 16 | network_id: 4 17 | }, 18 | development: { 19 | host: "127.0.0.1", 20 | port: 8545, 21 | network_id: "*" 22 | } 23 | }, 24 | compilers: { 25 | solc: { 26 | version: "0.5.10", 27 | settings: { 28 | optimizer: { 29 | enabled: true, 30 | runs: 200 31 | } 32 | } 33 | } 34 | } 35 | }; 36 | --------------------------------------------------------------------------------