├── .gitignore ├── README.md ├── battleship ├── battleships └── verifyingKey.go.nocompile ├── main.go ├── pk_key.txt ├── proof.txt ├── public ├── index.html ├── script.js └── style.css ├── server ├── proveHander.go └── verifyHander.go ├── verifier ├── libsnarkStructures.go ├── pairingProduct.go ├── proof.txt ├── proofParser.go ├── verificationKey.txt ├── verifier.go └── verifier_test.go └── vk_key.txt /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # The game of SNARKs (and STARKs later) 2 | 3 | # HODL the door! 4 | 5 | ## Description and rationale 6 | 7 | During the ETHBerlin we've tried to make a good demonstration of the power of zkSNARKs by implementing a "Battleships" game where an interaction between the players is governed by the SNARKs. During the development we understood that it's actually is quite abstract two-party state-channel with some kind of a smart-contract inside. Keeping the state updates is expensive in the mainnet, so such interaction can be moved to Plasma, where the operator verifies SNARKs upon transaction submissions and updates a "state". Many people forget that Plasma was introduced not only as L2 solution for payments, but also as kind of map-reduce system. 8 | 9 | Other repositories related to this work, developers were working in their own repos or reusing the current R&D code: 10 | - Gadget lib for `libsnark` developed by the Matter Inc. is [here](https://github.com/matterinc/libsnark_gadgetlib3/tree/test_branch). (test_branch branch) 11 | - Smart-contracts that are for game setup and further fraud proofs from Plasma operator - [here](https://github.com/matterinc/GameOfSnarks_contracts). 12 | - Simple UI brought to you [here](https://github.com/artall64/sea-battel). 13 | - Backend assembled [here](https://github.com/shamatar/go-snarks) (current repo). 14 | 15 | ## Limitations 16 | Due to a huge pain of building a `libsnark` anywhere but Linux this repo contains a binary assembled under Ubuntu16.04, that is called through the command line(!) from the Go backend. In principle Go backend is ready to verify proofs itself, it's just a matter of pain with proof serialization. 17 | 18 | ## How to run 19 | Keep in mind the limitations above! 20 | - `go get github.com/shamatar/go-snarks` 21 | - `cd $GOPATH/src/github/shamatar/go-snarks` 22 | - `go run -v ./main.go` 23 | - open your browser at `http://127.0.0.1:8080/public/index.html` 24 | - place the ships. Right now limits are hardcoded - 4 ships 1x1, 3 ships 1x2, 2 ships 1x3, 1 ship 1x4 25 | - if you made a mistake - reload a page 26 | - if you have placed ships properly (in the right amounts and without adjustency) - click a "submit" button to send the position to the backend to make a proof of the correct positioning 27 | - if you did make a mistake - you will see an error in a window below 28 | - if your position was correct you will see a quasi-serialized proof. You can either click "verify" to verify it at the backend, or change one of the big numbers (not zeroes!) there and click "verify" and get a negative result - you have corrupted a proof and it's not longer valid 29 | - right now commitment to the position is not produced, just the position in verified 30 | 31 | That's all for now 32 | 33 | ## Intended functionality 34 | - [x] zkSNARK that proves the correctness of position 35 | - [ ] produce a salted commitment to position (used further as a public input) 36 | - [x] create a smart-contract for players to start a game 37 | - [ ] make a zkSNARK for a state updates, that checks turns one by one 38 | - [ ] check whos turn it is now 39 | - [ ] check the signature of the current player (for shooting) 40 | - [ ] check that position under the commitment is correct 41 | - [ ] if there is a "hit" - update the corresponding score 42 | - [ ] keep the history of shots and don't allow duplicates 43 | - [ ] update the scores 44 | - [ ] have a win condition 45 | - [ ] bring further state updates to Plasma 46 | - [ ] implement fraud proofs 47 | 48 | Much work to do! 49 | 50 | ## Authors (team) 51 | 52 | Alex Vlasov, [shamatar](https://github.com/shamatar) 53 | 54 | Konstantin Panarin, [Konstantce](https://github.com/konstantce) 55 | 56 | Artem Vorobyev, [artall64](https://github.com/artall64) -------------------------------------------------------------------------------- /battleship: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shamatar/go-snarks/857ac6f2c5c6553980c966f23b902dc3c1359014/battleship -------------------------------------------------------------------------------- /battleships/verifyingKey.go.nocompile: -------------------------------------------------------------------------------- 1 | package battleships 2 | 3 | // unused, can now parse from file! 4 | 5 | 6 | import "github.com/shamatar/go-snarks/verifier" 7 | 8 | func GetVefiricationKey() *verifier.VerifyingKey { 9 | vk := &verifier.VerifyingKey{} 10 | vk.A, _ = NewG2FromStrings( 11 | [2]string{"0x95aacb3c23ba931cea76b29a19617c347943ecf1002fc0fcf798e0f8d74846c", 12 | "0x6d039a9508f5e58dd3646aec40b650cf2622990ef101628046382d9d0a11c2b"}, 13 | [2]string{"0x1396a7eda2554a0ddef4978de4de39b8618c0d170eaa3b4e3528c1e5e44c7050", 14 | "0x35186be372d0ef1ca7821d2eeb6575accda23f59fe655f4d087031b75ca9d48"}, 15 | 16) 16 | vk.B, _ = NewG1FromStrings("0x23b16b75c253c67a07b2dfb4642f916ce483f52d7d957c43f1cafa9e8efbd4b6", 17 | "0x10b9cf66c4b02c8eedc287dbfabde1d7e1be9c817eced0610e4232063b473347", 18 | 16) 19 | vk.C, _ = NewG2FromStrings( 20 | [2]string{"0x8d841a59c62049761286964354fbb9547aacb249038adcb0b8b393a0a71f872", 21 | "0x23bd90ef5307660e965fd3144418d2b5a8e6c22a87900541e12745ea62f6375f"}, 22 | [2]string{"0x10935f302a61d826b52731e5951219552832fe1be64ef191364fb8a264036d67", 23 | "0x608317e583295bdc60d86315f7923e2677143c6eeb381f8f4b828bf1a055fcd"}, 16) 24 | vk.gamma, _ = NewG2FromStrings( 25 | [2]string{"0x838d4dcd872e6bcc73ef8d9f2d61c1b1223672a4ce4483d14aea08acc895106", "0xc700c249203de561efcda3fd4ec7658d528701da3c1fca098a2d42f011fde37"}, 26 | [2]string{"0x2979bf58a5a9ef40265dea31187fd807257683846c5832c7b87951a78aa68841", "0x19e61fbd9e5b5e25dd7d110cd4b0071123975620e37c3cd72a101b63eff4f185"}, 27 | 16) 28 | vk.gammaBeta1, _ = NewG1FromStrings("0x22dc5c5252437b5f3feb464de52cb4306a0b45bbad6a4a19b36b1f991eabbe47", 29 | "0x177a001e3312096da4d75bfb2b4cc07bec195dccb48ecc6808f81c5f232e02e", 16) 30 | vk.gammaBeta2, _ = NewG2FromStrings( 31 | [2]string{"0x723f2cb7ff1065bbb44c112f68e1b632de6b6be20920beae4f28d9e0057cc47", "0xdd6e0ed155dbbc30988ad7bfd9cbcab76850d09bb6b668c1b831354fe2c1180"}, 32 | [2]string{"0x2fbb278596ffa9342d987295ada995129d5ed9b484a3337cbd095b38f1a834bd", "0x19bb949e51477e54f9ae892093beda448c33b21b43366502cd4d8a02897017a"}, 33 | 16) 34 | vk.Z, _ = NewG2FromStrings( 35 | [2]string{"0x15425ab686d62e846de5ca98c92843cad80f06401610fcce27cf6f94e07f7f8b", "0xe21bc3f9c196bb742aa2404a6550635fd632b86cb0fbae13962df909543c7c3"}, 36 | [2]string{"0x6538ba629c4809a327453895dade6110275faa25e14e4ce6390c3b095f6519c", "0x5aaf52260e7758c6cd487c1e88ef9791b518fbf09e0ec5402825687b75f3ab9"}, 37 | 16) 38 | vk.IC = make([]*G1, 7) 39 | vk.IC[0], _ = NewG1FromStrings("0x406d95f7ae8feb816b5a4b4cf4a949730f31de0b3ff1e8b800db9969514a256", 40 | "0xe0818f24fef31a82b9e7e587c9934f812e5a196a5e7aa7d495a8494f9557f4c", 16) 41 | vk.IC[1], _ = NewG1FromStrings("0xf394dc0e39f79bee4a1e0577299de796c7a03ad6e3949884d2d2fbd73f0d76c", 42 | "0x16a514b14810b2217478d803fb68372e34dde4fb624b9f4e156470364cb19402", 16) 43 | vk.IC[2], _ = NewG1FromStrings("0x134d26c1eec281bedabb8d4ee3fb61d2e9113668b3fa45f110d8547fd8f5b94d", 44 | "0x59f3d50872f8ee5662e25fc1f13e08acc01f5a7ac049b3661b87cd2b78bdd11", 16) 45 | vk.IC[3], _ = NewG1FromStrings("0xcd6823439d212cdf695ae58c3a9cb50bc31f285e986a1ca00aed91669401419", 46 | "0xbea35dbd15dd6e212050e923a6f748a981ea0f1bca31305e87a487c5c07f506", 16) 47 | vk.IC[4], _ = NewG1FromStrings("0x139af07e752cc39bc1a2c6b0468415afa072bddd5599f38e7cc4031031a5ec02", 48 | "0x27233e6a491cbdb09fd5b3b94917658ab20b2207f3d7e6aa556ca68bff5af037", 16) 49 | vk.IC[5], _ = NewG1FromStrings("0x20a7eda84420d312d03674aff46ae1202db426e9ae4ea1d400e385973ea31497", 50 | "0x61e54c3741544a6a99149a282cf1c9c08e1dd6061a593260bebba7d5c5e0b55", 16) 51 | vk.IC[6], _ = NewG1FromStrings("0x8ed7634c368516b852917dac2d165ac153204b550c5ba0456512066daef108b", 52 | "0x14c048afac3cdb256d375825101691093f73aeaf6802df2fba3c0e83de9feb86", 16) 53 | 54 | return vk 55 | } 56 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "log" 6 | "net/http" 7 | "os" 8 | "os/signal" 9 | "time" 10 | 11 | "github.com/gorilla/mux" 12 | handers "github.com/shamatar/go-snarks/server" 13 | ) 14 | 15 | func main() { 16 | var wait time.Duration = 15 17 | 18 | r := mux.NewRouter() 19 | 20 | // r.PathPrefix("/static/").Handler(http.StripPrefix("/static/", http.FileServer(http.Dir("static")))) 21 | r.HandleFunc("/prove", handers.ProveHander) 22 | r.HandleFunc("/verify", handers.VerifyHander) 23 | r.PathPrefix("/public/").Handler(http.StripPrefix("/public/", http.FileServer(http.Dir("./public/")))) 24 | // Add your routes as needed 25 | 26 | srv := &http.Server{ 27 | Addr: "0.0.0.0:8080", 28 | // Good practice to set timeouts to avoid Slowloris attacks. 29 | WriteTimeout: time.Second * 15, 30 | ReadTimeout: time.Second * 15, 31 | IdleTimeout: time.Second * 60, 32 | Handler: r, // Pass our instance of gorilla/mux in. 33 | } 34 | 35 | // Run our server in a goroutine so that it doesn't block. 36 | go func() { 37 | if err := srv.ListenAndServe(); err != nil { 38 | log.Println(err) 39 | } 40 | }() 41 | 42 | c := make(chan os.Signal, 1) 43 | // We'll accept graceful shutdowns when quit via SIGINT (Ctrl+C) 44 | // SIGKILL, SIGQUIT or SIGTERM (Ctrl+/) will not be caught. 45 | signal.Notify(c, os.Interrupt) 46 | 47 | // Block until we receive our signal. 48 | <-c 49 | 50 | // Create a deadline to wait for. 51 | ctx, cancel := context.WithTimeout(context.Background(), wait) 52 | defer cancel() 53 | // Doesn't block if no connections, but will otherwise wait 54 | // until the timeout deadline. 55 | srv.Shutdown(ctx) 56 | // Optionally, you could run srv.Shutdown in a goroutine and block on 57 | // <-ctx.Done() if your application should wait for other services 58 | // to finalize based on context cancellation. 59 | log.Println("shutting down") 60 | os.Exit(0) 61 | } 62 | -------------------------------------------------------------------------------- /proof.txt: -------------------------------------------------------------------------------- 1 | 0 13406134970258815286020159193556677680311636497910925344652836792409372070271 7669367580382090049515164521170390042319430362366737410803620667652367331135 0 14752546262293461491682556262092058999013016986944210160201437215467844026822 20736975199603694358813250551104608159693283514992053948650553443786028053839 2 | 0 20351030081815414065710098178245344975018969795093754963831609177936167413145 21620527533968649586996460113693586521916721820764998845182934117025408872322 3423810342454981513418403046577782466619027102100217563240710447965561182299 2953460060009580051925096532577680313016887409743550770812228980364955144482 0 10456963842447120820083203616936727362780689355547952962837195864520404646580 7589522155335463972057625765041827641770938513640441918031957965766032682308 3 | 0 16421925483448472237760933762131785560238172469465369119173183028306822731970 481084065041462187964540648774288140915202788154597170334703105191684886996 0 13976518697966610184420664440919406675937424597670536199690023144866397402185 1169081175510947954276646354699273525016401943828311637561971317672849792062 4 | 0 9790150398221785279804069943524116418449616470879201232120475840925117795286 13983529449590959600820508601260655334002027880520627522011636878612499937189 5 | 0 14359844563041462830778521163323396304778734943286254324585492159177807559677 3634303467683636505205655840383950576058584493933726344897387530480559293931 6 | -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Sea Battle 6 | 7 | 8 | 9 |
10 |
11 |
1
12 |
2
13 |
3
14 |
4
15 |
5
16 |
6
17 |
7
18 |
8
19 |
9
20 |
10
21 |
22 |
23 |
a
24 |
b
25 |
c
26 |
d
27 |
e
28 |
f
29 |
g
30 |
h
31 |
i
32 |
j
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 | -------------------------------------------------------------------------------- /public/script.js: -------------------------------------------------------------------------------- 1 | const grid = document.querySelector("#fieldGame"); // поле для игры 2 | const letterArray = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j']; 3 | let selectedShip = { // выбранный тип корабля 4 | 'line': '', 5 | 'size': '' 6 | }; 7 | let ship = []; // выделенный на поле корабль 8 | 9 | // game field 10 | const drawGrid = () => { 11 | for (let i = 0; i < 100; i++) { 12 | const cell = document.createElement('div'); 13 | const char = letterArray[i % 10]; 14 | const num = Math.trunc((i) / 10) + 1; 15 | 16 | cell.classList.add("cell"); 17 | cell.setAttribute("id", char + num); 18 | cell.setAttribute("onmouseover", "cellOnmouseOver(event)"); 19 | cell.setAttribute("onmouseout", "cellOnmouseOut()"); 20 | cell.setAttribute("onclick", "cellOnclick()"); 21 | 22 | grid.appendChild(cell); 23 | } 24 | }; 25 | drawGrid(); 26 | 27 | const getAllCells = () => { 28 | const cellsList = document.querySelectorAll(".cell"); 29 | let allCells = []; 30 | for (let i = 0; i < cellsList.length; i++) { 31 | allCells.push(cellsList[i].getAttribute('id')); 32 | } 33 | return allCells; 34 | } 35 | 36 | // выбор типа корабля 37 | const choiceShip = (element) => { 38 | selectedShip.line = element.dataset.line; 39 | selectedShip.size = Number(element.dataset.size); 40 | } 41 | 42 | // наведение курсора на ячейку поля 43 | const cellOnmouseOver = (e) => { 44 | const thisCell = e.target.getAttribute('id'); // клетка под курсором 45 | const coordinates = { // координаты клетки под курсором 46 | 'char': thisCell.charAt(0), 47 | 'num': Number(thisCell.substr(1)) 48 | }; 49 | let allCells = getAllCells(); 50 | let thisShipCills = []; // массив клеток "под кораблем" 51 | 52 | if (selectedShip.line === 'vertically') { 53 | allCells.map(cell => { 54 | const cellChar = letterArray.indexOf(cell.charAt(0)); 55 | if (Number(cell.substr(1)) === coordinates.num) { 56 | if (letterArray.indexOf(coordinates.char) - selectedShip.size < cellChar 57 | && cellChar <= letterArray.indexOf(coordinates.char)) { 58 | thisShipCills.push(cell); 59 | } 60 | } 61 | }); 62 | } else if (selectedShip.line === 'horizontally') { 63 | allCells.map(cell => { 64 | const cellNum = Number(cell.substr(1)); 65 | if (cell.charAt(0) === coordinates.char) { 66 | if (coordinates.num - selectedShip.size < cellNum && cellNum <= coordinates.num) { 67 | thisShipCills.push(cell); 68 | } 69 | } 70 | }); 71 | } 72 | thisShipCills.map(cell => { 73 | document.querySelector('#' + cell).classList.add("cellHover"); 74 | }); 75 | ship = thisShipCills; 76 | }; 77 | 78 | // уход курсора с ячейки поля 79 | const cellOnmouseOut = () => { 80 | let allCells = getAllCells(); 81 | allCells.map(cell => { 82 | const a = document.querySelector('#' + cell); 83 | if (a.classList.contains("cellHover")) { 84 | a.classList.remove("cellHover") 85 | } 86 | }) 87 | } 88 | 89 | // установка корабля на поле 90 | const cellOnclick = () => { 91 | ship.map(cell => { 92 | document.querySelector('#' + cell).classList.add('cell2'); 93 | }) 94 | }; 95 | 96 | // get layout of the ships as a 2D array 97 | const getLayout = () => { 98 | let num = 10; 99 | let char = letterArray; 100 | let card = []; 101 | for (let i = 0; i < char.length; i++) { 102 | card[i] = []; 103 | for (let j = 0; j < num; j++) { 104 | const a = document.querySelector(`#${char[i]}${j + 1}`); 105 | card[i][j] = a.classList.contains('cell2') ? 1 : 0; 106 | } 107 | } 108 | return card; 109 | }; 110 | 111 | 112 | const sendJSON = async (obj) => { 113 | 114 | const rawResponse = await fetch('/prove', { 115 | method: 'POST', 116 | headers: { 117 | 'Accept': 'application/json', 118 | 'Content-Type': 'application/json' 119 | }, 120 | body: JSON.stringify(obj) 121 | }); 122 | const content = await rawResponse.json(); 123 | console.log(content); 124 | return content; 125 | }; 126 | 127 | window.onload = () => { 128 | document.getElementById("sendLayoutBtn").addEventListener("click", sendLayout); 129 | document.getElementById("verifyBtn").addEventListener("click", sendVerify); 130 | }; 131 | 132 | const sendLayout = async () => { 133 | const layout = getLayout(); 134 | const resp = await sendJSON(layout); 135 | 136 | const textArea = document.getElementById("serverResponse"); 137 | textArea.style.display = "block"; 138 | 139 | const verifyBtn = document.getElementById("verifyBtn"); 140 | verifyBtn.style.display = "block"; 141 | 142 | textArea.value = JSON.stringify(resp); 143 | }; 144 | 145 | const sendVerify = async () => { 146 | 147 | const textArea = document.getElementById("serverResponse"); 148 | const rawResponse = await fetch('/verify', { 149 | method: 'POST', 150 | headers: { 151 | 'Accept': 'application/json', 152 | 'Content-Type': 'application/json' 153 | }, 154 | body: textArea.value 155 | }); 156 | 157 | const content = await rawResponse.json(); 158 | const verifyLabel = document.getElementById("verificationStatus"); 159 | 160 | if(!content.error){ 161 | verifyLabel.style.color= "green"; 162 | verifyLabel.innerHTML = "Verified"; 163 | } 164 | else { 165 | verifyLabel.style.color= "red"; 166 | verifyLabel.innerHTML = "Verification Failed"; 167 | } 168 | 169 | return content; 170 | }; 171 | -------------------------------------------------------------------------------- /public/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | padding: 50px; 3 | } 4 | #grid { 5 | position: relative; 6 | background-color: silver; 7 | } 8 | #gridHead, #gridHeadColumn, #fieldGame, .ship { 9 | display: grid; 10 | grid-auto-flow: column; 11 | grid-gap: 1px; 12 | overflow: auto; 13 | background: #fff; 14 | } 15 | #fieldGame { 16 | width: 209px; 17 | height: 209px; 18 | } 19 | #gridHead, #gridHeadColumn { 20 | position: absolute; 21 | } 22 | #gridHead { 23 | width: 209px; 24 | height: 21px; 25 | top: -21px; 26 | } 27 | #gridHeadColumn { 28 | height: 209px; 29 | width: 21px; 30 | left: -21px; 31 | } 32 | .gridHeadCell { 33 | text-align: center; 34 | } 35 | .cell, .shipCell { 36 | display: flex; 37 | flex-direction: column; 38 | justify-content: center; 39 | background: #4682B4; 40 | opacity: .7; 41 | border: 1px; 42 | height: 20px; 43 | width: 20px; 44 | } 45 | .shipCell { 46 | background: #000; 47 | } 48 | .cellHover { 49 | background: #000; 50 | opacity: .5; 51 | } 52 | .cell2 { 53 | background: #000; 54 | } 55 | .cellHover.cell2 { 56 | background: #000; 57 | opacity: .8; 58 | } 59 | #ships { 60 | margin-top: 20px; 61 | height: 100px; 62 | background-color: aliceblue; 63 | } 64 | .ship { 65 | margin: 5px; 66 | float: left; 67 | } 68 | .ship-4v, .ship-3v, .ship-2v, .ship-1v { 69 | width: 20px; 70 | } 71 | .ship-4g { 72 | width: 83px; 73 | } 74 | .ship-3g { 75 | width: 62px; 76 | } 77 | .ship-2g { 78 | width: 41px; 79 | } 80 | .ship-1v { 81 | width: 20px; 82 | } 83 | .ship:hover .cell { 84 | background: #FF6347; 85 | cursor: pointer; 86 | transition: .3s; 87 | } 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | -------------------------------------------------------------------------------- /server/proveHander.go: -------------------------------------------------------------------------------- 1 | package server 2 | 3 | import ( 4 | "encoding/json" 5 | "io/ioutil" 6 | "log" 7 | "fmt" 8 | "bytes" 9 | "math/rand" 10 | "net/http" 11 | "os/exec" 12 | "strconv" 13 | ) 14 | 15 | type proverResponse struct { 16 | Error bool `json:"error"` 17 | } 18 | 19 | type verificationRequest struct { 20 | Proof string `json:"proof"` 21 | Hash string `json:"hash"` 22 | } 23 | 24 | type proofResponse struct { 25 | Proof string `json:"proof"` 26 | Hash string `json:"hash"` 27 | } 28 | 29 | // type Battlefield struct { 30 | // Field [][]int `json:"field"` 31 | // Key1 string `json:"key_1"` 32 | // Key2 string `json:"key_2"` 33 | // Key3 string `json:"key_3"` 34 | // Points []Point `json:"points"` 35 | // } 36 | 37 | func ProveHander(w http.ResponseWriter, r *http.Request) { 38 | // if cmd, e := exec.Run("/bin/ls", nil, nil, exec.DevNull, exec.Pipe, exec.MergeWithStdout); e == nil { 39 | // b, _ := ioutil.ReadAll(cmd.Stdout) 40 | // println("output: " + string(b)) 41 | // } 42 | // dataJson := `[[1],[2],[3]]` 43 | var arr [][]int 44 | decoder := json.NewDecoder(r.Body) 45 | err := decoder.Decode(&arr) 46 | if err != nil { 47 | writeError(w) 48 | return 49 | } 50 | log.Printf("Unmarshaled: %v", arr) 51 | if len(arr) != 10 { 52 | writeError(w) 53 | return 54 | } 55 | for i := 0; i < len(arr); i++ { 56 | if len(arr[i]) != 10 { 57 | writeError(w) 58 | return 59 | } 60 | } 61 | fullString := "" 62 | for i := 0; i < len(arr); i++ { 63 | substr := "" 64 | for j := 0; j < len(arr[i]); j++ { 65 | substr = substr + strconv.Itoa(arr[i][j]) 66 | } 67 | fullString = fullString + substr 68 | } 69 | 70 | log.Println(fullString) 71 | stringForProver := "b" + fullString 72 | salt := rand.Uint64() 73 | saltString := strconv.FormatUint(salt, 16) 74 | // out, err := exec.Command("./battleship -p " + stringForProver + " " + saltString).Output() 75 | // log.Println(string(out)) 76 | //if cmd, e := exec.Run("./battleship -p", nil, nil, exec.DevNull, exec.Pipe, exec.MergeWithStdout); e == nil { 77 | // b, _ := ioutil.ReadAll(cmd.Stdout) 78 | // fmt.Println("output: " + string(b)) 79 | //} 80 | cmd := exec.Command("./battleship", "-p", stringForProver, saltString) 81 | var out bytes.Buffer 82 | cmd.Stdout = &out 83 | err = cmd.Run() 84 | if err != nil { 85 | log.Println(err) 86 | writeError(w) 87 | return 88 | } 89 | fmt.Printf("in all caps: %q\n", out.String()) 90 | testVerifier() 91 | fullFile, err := ioutil.ReadFile("proof.txt") 92 | if err != nil { 93 | writeError(w) 94 | return 95 | } 96 | fullContent := string(fullFile) 97 | writeResponse(w, fullContent, "") 98 | } 99 | 100 | func testVerifier() { 101 | cmd := exec.Command("./battleship", "-v") 102 | var out bytes.Buffer 103 | cmd.Stdout = &out 104 | err := cmd.Run() 105 | if err != nil { 106 | log.Println(err) 107 | return 108 | } 109 | fmt.Printf("in all caps: %q\n", out.String()) 110 | 111 | outString := out.String() 112 | log.Println(outString) 113 | length := len(outString) 114 | result := outString[length-5 : length-1] 115 | fmt.Println(result) 116 | 117 | } 118 | 119 | func writeError(w http.ResponseWriter) { 120 | resp := proverResponse{true} 121 | 122 | js, err := json.Marshal(resp) 123 | if err != nil { 124 | http.Error(w, err.Error(), http.StatusInternalServerError) 125 | return 126 | } 127 | 128 | w.Header().Set("Content-Type", "application/json") 129 | w.Write(js) 130 | } 131 | 132 | func writeResponse(w http.ResponseWriter, proof, hash string) { 133 | resp := proofResponse{proof, hash} 134 | 135 | js, err := json.Marshal(resp) 136 | if err != nil { 137 | http.Error(w, err.Error(), http.StatusInternalServerError) 138 | return 139 | } 140 | 141 | w.Header().Set("Content-Type", "application/json") 142 | w.Write(js) 143 | } 144 | -------------------------------------------------------------------------------- /server/verifyHander.go: -------------------------------------------------------------------------------- 1 | package server 2 | 3 | import ( 4 | "encoding/json" 5 | "io/ioutil" 6 | "log" 7 | "fmt" 8 | "bytes" 9 | "net/http" 10 | "os/exec" 11 | ) 12 | 13 | type verificationResponse struct { 14 | Error bool `json:"error"` 15 | } 16 | 17 | func VerifyHander(w http.ResponseWriter, r *http.Request) { 18 | // if cmd, e := exec.Run("/bin/ls", nil, nil, exec.DevNull, exec.Pipe, exec.MergeWithStdout); e == nil { 19 | // b, _ := ioutil.ReadAll(cmd.Stdout) 20 | // println("output: " + string(b)) 21 | // } 22 | 23 | // dataJson := `[[1],[2],[3]]` 24 | var req verificationRequest 25 | decoder := json.NewDecoder(r.Body) 26 | err := decoder.Decode(&req) 27 | if err != nil { 28 | writeError(w) 29 | return 30 | } 31 | 32 | log.Printf("Unmarshaled: %v", req) 33 | 34 | d1 := []byte(req.Proof) 35 | err = ioutil.WriteFile("proof.txt", d1, 0644) 36 | if err != nil { 37 | writeError(w) 38 | return 39 | } 40 | cmd := exec.Command("./battleship", "-v") 41 | var out bytes.Buffer 42 | cmd.Stdout = &out 43 | err = cmd.Run() 44 | if err != nil { 45 | log.Println(err) 46 | writeError(w) 47 | return 48 | } 49 | fmt.Printf("in all caps: %q\n", out.String()) 50 | 51 | outString := out.String() 52 | log.Println(outString) 53 | length := len(outString) 54 | result := outString[length-5 : length-1] 55 | fmt.Println(result) 56 | if result == "PASS" { 57 | writeSuccess(w) 58 | return 59 | } 60 | writeError(w) 61 | } 62 | 63 | func writeSuccess(w http.ResponseWriter) { 64 | resp := proverResponse{false} 65 | 66 | js, err := json.Marshal(resp) 67 | if err != nil { 68 | http.Error(w, err.Error(), http.StatusInternalServerError) 69 | return 70 | } 71 | 72 | w.Header().Set("Content-Type", "application/json") 73 | w.Write(js) 74 | } 75 | -------------------------------------------------------------------------------- /verifier/libsnarkStructures.go: -------------------------------------------------------------------------------- 1 | package verifier 2 | 3 | import ( 4 | "bufio" 5 | "errors" 6 | "fmt" 7 | "os" 8 | "strconv" 9 | ) 10 | 11 | func skipSpaces(r *bufio.Reader) { 12 | for { 13 | rune, _, err := r.ReadRune() 14 | if err != nil { 15 | if err.Error() == "EOF" { 16 | return 17 | } 18 | } 19 | c := string(rune) 20 | if c != " " { 21 | r.UnreadRune() 22 | return 23 | } 24 | } 25 | } 26 | 27 | func consumeNewLine(r *bufio.Reader) { 28 | rune, _, err := r.ReadRune() 29 | if err != nil { 30 | if err.Error() == "EOF" { 31 | return 32 | } 33 | } 34 | c := string(rune) 35 | if c != "\n" { 36 | r.UnreadRune() 37 | return 38 | } 39 | } 40 | 41 | func ReadInt(r *bufio.Reader) (uint64, error) { 42 | x := "" 43 | for { 44 | rune, _, err := r.ReadRune() 45 | if err != nil { 46 | if err.Error() == "EOF" { 47 | break 48 | } 49 | return 0, err 50 | } 51 | c := string(rune) 52 | if c != " " && c != "\n" { 53 | x = x + c 54 | } else { 55 | r.UnreadRune() 56 | break 57 | } 58 | } 59 | i, err := strconv.ParseUint(x, 10, 64) 60 | if err != nil { 61 | return 0, err 62 | } 63 | return i, nil 64 | } 65 | 66 | func ReadBigIntAsString(r *bufio.Reader) (string, error) { 67 | x := "" 68 | for { 69 | rune, _, err := r.ReadRune() 70 | if err != nil { 71 | if err.Error() == "EOF" { 72 | break 73 | } 74 | return "", err 75 | } 76 | c := string(rune) 77 | if c != " " && c != "\n" { 78 | x = x + c 79 | } else { 80 | r.UnreadRune() 81 | break 82 | } 83 | } 84 | return x, nil 85 | } 86 | 87 | func ReadG1(r *bufio.Reader) (*G1, error) { 88 | rune, _, err := r.ReadRune() 89 | if err != nil { 90 | return nil, err 91 | } 92 | str := string(rune) 93 | if str == "1" { 94 | return new(G1), nil 95 | } else if str != "0" { 96 | return nil, errors.New("Invalid encoding format") 97 | } 98 | 99 | skipSpaces(r) 100 | xCoord, err := ReadBigIntAsString(r) 101 | if err != nil { 102 | return nil, err 103 | } 104 | skipSpaces(r) 105 | yCoord, err := ReadBigIntAsString(r) 106 | if err != nil { 107 | return nil, err 108 | } 109 | consumeNewLine(r) 110 | if err != nil { 111 | return nil, err 112 | } 113 | fmt.Println("X = " + xCoord) 114 | fmt.Println("Y = " + yCoord) 115 | newPoint, err := NewG1FromStrings(xCoord, yCoord, 10) 116 | if err != nil { 117 | return nil, err 118 | } 119 | return newPoint, nil 120 | } 121 | 122 | func ReadG2(r *bufio.Reader) (*G2, error) { 123 | rune, _, err := r.ReadRune() 124 | if err != nil { 125 | return nil, err 126 | } 127 | str := string(rune) 128 | if str == "1" { 129 | return new(G2), nil 130 | } else if str != "0" { 131 | return nil, errors.New("Invalid encoding format") 132 | } 133 | skipSpaces(r) 134 | a, err := ReadBigIntAsString(r) 135 | if err != nil { 136 | return nil, err 137 | } 138 | skipSpaces(r) 139 | b, err := ReadBigIntAsString(r) 140 | if err != nil { 141 | return nil, err 142 | } 143 | skipSpaces(r) 144 | c, err := ReadBigIntAsString(r) 145 | if err != nil { 146 | return nil, err 147 | } 148 | skipSpaces(r) 149 | d, err := ReadBigIntAsString(r) 150 | if err != nil { 151 | return nil, err 152 | } 153 | consumeNewLine(r) 154 | fmt.Println("A = " + a) 155 | fmt.Println("B = " + b) 156 | fmt.Println("C = " + c) 157 | fmt.Println("D = " + d) 158 | newPoint, err := NewG2FromStrings([2]string{a, b}, [2]string{c, d}, 10) 159 | // if err != nil { 160 | // return nil, err 161 | // } 162 | return newPoint, nil 163 | } 164 | 165 | type SparseVector struct { 166 | first *G1 167 | rest []*G1 168 | } 169 | 170 | type LibsnarkVerifyingKey struct { 171 | A *G2 172 | B *G1 173 | C *G2 174 | Gamma *G2 175 | GammaBeta1 *G1 176 | GammaBeta2 *G2 177 | Z *G2 178 | IC *SparseVector 179 | } 180 | 181 | // func ParseFromBytes(b []byte) { 182 | // r := bytes.NewReader(b) 183 | // reader := bufio.NewReader(r) 184 | // for { 185 | // _, err := ReadG1(reader) 186 | // if err != nil { 187 | // return 188 | // } 189 | // } 190 | // } 191 | 192 | func (sv *SparseVector) ParseFromReader(r *bufio.Reader) error { 193 | first, err := ReadG1(r) 194 | if err != nil { 195 | return err 196 | } 197 | ReadInt(r) 198 | consumeNewLine(r) 199 | indSize, err := ReadInt(r) 200 | if err != nil { 201 | return err 202 | } 203 | consumeNewLine(r) 204 | for i := 0; i < int(indSize); i++ { 205 | _, err := ReadInt(r) 206 | if err != nil { 207 | return err 208 | } 209 | consumeNewLine(r) 210 | } 211 | valuesSize, err := ReadInt(r) 212 | if err != nil { 213 | return err 214 | } 215 | consumeNewLine(r) 216 | points := make([]*G1, valuesSize) 217 | fmt.Println("Verification has inputs = " + strconv.FormatUint(valuesSize, 10)) 218 | for i := 0; i < int(valuesSize); i++ { 219 | point, err := ReadG1(r) 220 | if err != nil { 221 | return err 222 | } 223 | consumeNewLine(r) 224 | points[i] = point 225 | } 226 | sv.first = first 227 | sv.rest = points 228 | return nil 229 | } 230 | 231 | func (vk *LibsnarkVerifyingKey) ParseFromFile(filename string) error { 232 | r, err := os.Open(filename) 233 | defer r.Close() 234 | if err != nil { 235 | return err 236 | } 237 | reader := bufio.NewReader(r) 238 | return vk.ParseFromReader(reader) 239 | } 240 | 241 | func (vk *LibsnarkVerifyingKey) ParseFromReader(reader *bufio.Reader) error { 242 | A, err := ReadG2(reader) 243 | if err != nil { 244 | return err 245 | } 246 | consumeNewLine(reader) 247 | 248 | B, err := ReadG1(reader) 249 | if err != nil { 250 | return err 251 | } 252 | consumeNewLine(reader) 253 | 254 | C, err := ReadG2(reader) 255 | if err != nil { 256 | return err 257 | } 258 | consumeNewLine(reader) 259 | 260 | Gamma, err := ReadG2(reader) 261 | if err != nil { 262 | return err 263 | } 264 | consumeNewLine(reader) 265 | 266 | GammaBeta1, err := ReadG1(reader) 267 | if err != nil { 268 | return err 269 | } 270 | consumeNewLine(reader) 271 | 272 | GammaBeta2, err := ReadG2(reader) 273 | if err != nil { 274 | return err 275 | } 276 | consumeNewLine(reader) 277 | 278 | Z, err := ReadG2(reader) 279 | if err != nil { 280 | return err 281 | } 282 | consumeNewLine(reader) 283 | 284 | ic := new(SparseVector) 285 | err = ic.ParseFromReader(reader) 286 | if err != nil { 287 | return nil 288 | } 289 | 290 | vk.A = A 291 | vk.B = B 292 | vk.C = C 293 | vk.Gamma = Gamma 294 | vk.GammaBeta1 = GammaBeta1 295 | vk.GammaBeta2 = GammaBeta2 296 | vk.Z = Z 297 | vk.IC = ic 298 | return nil 299 | } 300 | -------------------------------------------------------------------------------- /verifier/pairingProduct.go: -------------------------------------------------------------------------------- 1 | package verifier 2 | 3 | // uses only fast Cloudflare implementation 4 | 5 | // TODO use pools for reduced GC 6 | 7 | import ( 8 | "errors" 9 | "math/big" 10 | 11 | bn256 "github.com/ethereum/go-ethereum/crypto/bn256/cloudflare" 12 | ) 13 | 14 | // G1 is an abstract cyclic group. The zero value is suitable for use as the 15 | // output of an operation, but cannot be used as an input. 16 | type G1 = bn256.G1 17 | 18 | // G2 is an abstract cyclic group. The zero value is suitable for use as the 19 | // output of an operation, but cannot be used as an input. 20 | type G2 = bn256.G2 21 | 22 | // GT is a pairing group e(G1, G2) 23 | type GT = bn256.GT 24 | 25 | // GTIdentity is e(g1, g2) * 0 26 | var GTIdentity = new(GT) 27 | 28 | // IdentityBytes is e(g1, g2) * 0 serialized 29 | var IdentityBytes []byte 30 | 31 | func init() { 32 | GTIdentity = bn256.Miller(GetG1Base(), GetG2Base()) 33 | GTIdentity.Finalize() 34 | GTIdentity.ScalarMult(GTIdentity, big.NewInt(0)) 35 | IdentityBytes = GTIdentity.Marshal() 36 | } 37 | 38 | // PairingCheck calculates the Optimal Ate pairing for a set of points. 39 | func PairingCheck(a []*G1, b []*G2) bool { 40 | return bn256.PairingCheck(a, b) 41 | } 42 | 43 | // AddG1 parses raw data and does a G1 (small group) addition 44 | // Expects 64 + 64 bytes of data 45 | func AddG1(data []byte) ([]byte, error) { 46 | if len(data) != 128 { 47 | return nil, errors.New("Data should be 128 bytes long") 48 | } 49 | 50 | a := new(G1) 51 | _, err := a.Unmarshal(data[:64]) 52 | 53 | if err != nil { 54 | return nil, err 55 | } 56 | 57 | b := new(G1) 58 | _, err = b.Unmarshal(data[64:]) 59 | 60 | if err != nil { 61 | return nil, err 62 | } 63 | 64 | result := AddG1Parsed(a, b) 65 | return result.Marshal(), nil 66 | } 67 | 68 | // AddG1 parses raw data and does a G1 (small group) addition 69 | // Expects 64 + 64 bytes of data 70 | func AddG1Parsed(a, b *G1) *G1 { 71 | result := new(G1) 72 | result.Add(a, b) 73 | return result 74 | } 75 | 76 | // MulG1 parses raw data and does a G1 (small group) multiplication 77 | // Expected 32 + 64 bytes of data 78 | func MulG1(data []byte) ([]byte, error) { 79 | if len(data) != 96 { 80 | return nil, errors.New("Data should be 96 bytes long") 81 | } 82 | point := new(G1) 83 | _, err := point.Unmarshal(data[:64]) 84 | if err != nil { 85 | return nil, err 86 | } 87 | scalar := new(big.Int).SetBytes(data[64:]) 88 | result := MulG1Parsed(scalar, point) 89 | return result.Marshal(), nil 90 | } 91 | 92 | // MulG1Parsed parses does a G1 (small group) multiplication 93 | func MulG1Parsed(scalar *big.Int, point *G1) *G1 { 94 | resultPoint := new(G1) 95 | resultPoint.ScalarMult(point, scalar) 96 | return resultPoint 97 | } 98 | -------------------------------------------------------------------------------- /verifier/proof.txt: -------------------------------------------------------------------------------- 1 | 0 20933170699147567579033322641963108696395791188513690084963135910641532928274 2442431204756310761602153127686318554574960794578976757443433976540189788252 0 4887099059762129640302984526748584436465700498472647690070911027557383648471 1537761002038265777208458665898474687934111788158087930192782735780488615370 2 | 0 16573055444656122843537507139515729097968881044881963088535952613432732109576 15823969213404520820670755358760897637430302424438918422654019939237973220852 19043350362690960802787632939519229156536345342250133376920132587983219143570 5672529627952885536591336430691382520056316077527491874420269967257820619040 0 14461792803667918890803887317933444090830840712748147371492463942958574209725 13071829618513332891552585680079909704651276111106970019151699080596107269576 3 | 0 4553363573730177428827227824438616079346298937519779886664801330607001971471 21456699004685635406151940504311915468194491877421700836100090035559356021754 0 5750931461328290137207375961192256416814227690413125433502291640571740409967 8930892068663441607094145146857314111761878883131063200134413359379416014906 4 | 0 5627193368192982618917091473196986665093145528450803546070128784390583134960 7833536160441415171125072713335045341006722851990626699896991335087744993720 5 | 0 13096706332157259156060110671651801913587695020536048784149956198170577046492 14999138676268127536956531532613144042237861207626366537509655144817612266843 -------------------------------------------------------------------------------- /verifier/proofParser.go: -------------------------------------------------------------------------------- 1 | package verifier 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "io/ioutil" 7 | "strings" 8 | ) 9 | 10 | // 0 20933170699147567579033322641963108696395791188513690084963135910641532928274 2442431204756310761602153127686318554574960794578976757443433976540189788252 0 4887099059762129640302984526748584436465700498472647690070911027557383648471 1537761002038265777208458665898474687934111788158087930192782735780488615370 11 | // 0 16573055444656122843537507139515729097968881044881963088535952613432732109576 15823969213404520820670755358760897637430302424438918422654019939237973220852 19043350362690960802787632939519229156536345342250133376920132587983219143570 5672529627952885536591336430691382520056316077527491874420269967257820619040 0 14461792803667918890803887317933444090830840712748147371492463942958574209725 13071829618513332891552585680079909704651276111106970019151699080596107269576 12 | // 0 4553363573730177428827227824438616079346298937519779886664801330607001971471 21456699004685635406151940504311915468194491877421700836100090035559356021754 0 5750931461328290137207375961192256416814227690413125433502291640571740409967 8930892068663441607094145146857314111761878883131063200134413359379416014906 13 | // 0 5627193368192982618917091473196986665093145528450803546070128784390583134960 7833536160441415171125072713335045341006722851990626699896991335087744993720 14 | // 0 13096706332157259156060110671651801913587695020536048784149956198170577046492 14999138676268127536956531532613144042237861207626366537509655144817612266843 15 | 16 | func ParseProofFromFile(filename string) (*Proof, error) { 17 | fullFile, err := ioutil.ReadFile(filename) 18 | if err != nil { 19 | return nil, err 20 | } 21 | fullContent := string(fullFile) 22 | return ParseProofFromString(fullContent) 23 | } 24 | 25 | func ParseProofFromString(content string) (*Proof, error) { 26 | fullContent := strings.Replace(content, "\n", " ", -1) 27 | fullContent = strings.Replace(fullContent, "\t", " ", -1) 28 | 29 | elements := strings.Split(fullContent, " 0 ") 30 | firstElem := elements[0] 31 | firstElemSplit := strings.Split(firstElem, " ") 32 | elements[0] = firstElemSplit[1] + " " + firstElemSplit[2] 33 | // if len(elements) != 8 { 34 | // return nil, errors.New("Invalid number of elements") 35 | // } 36 | i := 0 37 | proof := &Proof{} 38 | for _, elem := range elements { 39 | cleaned := strings.Trim(elem, " \n\t") 40 | components := strings.Split(cleaned, " ") 41 | switch i { 42 | case 0: 43 | A, err := NewG1FromStrings(components[0], components[1], 10) 44 | if err != nil { 45 | return nil, err 46 | } 47 | proof.A = A 48 | case 1: 49 | Ap, err := NewG1FromStrings(components[0], components[1], 10) 50 | if err != nil { 51 | return nil, err 52 | } 53 | proof.Ap = Ap 54 | case 2: 55 | fmt.Println(elem) 56 | fmt.Println("Cleaned") 57 | fmt.Println(cleaned) 58 | fmt.Println("Components") 59 | fmt.Println(components) 60 | B, err := NewG2FromStrings([2]string{components[0], components[1]}, [2]string{components[2], components[3]}, 10) 61 | if err != nil { 62 | i++ 63 | continue 64 | return nil, err 65 | } 66 | proof.B = B 67 | case 3: 68 | Bp, err := NewG1FromStrings(components[0], components[1], 10) 69 | if err != nil { 70 | return nil, err 71 | } 72 | proof.Bp = Bp 73 | case 4: 74 | C, err := NewG1FromStrings(components[0], components[1], 10) 75 | if err != nil { 76 | return nil, err 77 | } 78 | proof.C = C 79 | case 5: 80 | Cp, err := NewG1FromStrings(components[0], components[1], 10) 81 | if err != nil { 82 | return nil, err 83 | } 84 | proof.Cp = Cp 85 | case 6: 86 | H, err := NewG1FromStrings(components[0], components[1], 10) 87 | if err != nil { 88 | return nil, err 89 | } 90 | proof.H = H 91 | case 7: 92 | K, err := NewG1FromStrings(components[0], components[1], 10) 93 | if err != nil { 94 | return nil, err 95 | } 96 | proof.K = K 97 | default: 98 | return nil, errors.New("Invalid number of elements") 99 | } 100 | i++ 101 | } 102 | if i != 8 { 103 | return nil, errors.New("Invalid number of elements") 104 | } 105 | return proof, nil 106 | } 107 | 108 | func ParseProofInLibsnarkFormat(filename string) (*Proof, error) { 109 | // file, err := os.Open(filename) // For read access. 110 | // if err != nil { 111 | // return nil, err 112 | // } 113 | // defer file.Close() 114 | fullFile, err := ioutil.ReadFile(filename) 115 | fullContent := string(fullFile) 116 | fullContent = strings.Replace(fullContent, "\n", " ", -1) 117 | fullContent = strings.Replace(fullContent, "\t", " ", -1) 118 | if err != nil { 119 | return nil, err 120 | } 121 | elements := strings.Split(fullContent, " 0 ") 122 | firstElem := elements[0] 123 | firstElemSplit := strings.Split(firstElem, " ") 124 | elements[0] = firstElemSplit[1] + " " + firstElemSplit[2] 125 | // if len(elements) != 8 { 126 | // return nil, errors.New("Invalid number of elements") 127 | // } 128 | i := 0 129 | proof := &Proof{} 130 | for _, elem := range elements { 131 | cleaned := strings.Trim(elem, " \n\t") 132 | components := strings.Split(cleaned, " ") 133 | switch i { 134 | case 0: 135 | A, err := NewG1FromStrings(components[0], components[1], 10) 136 | if err != nil { 137 | return nil, err 138 | } 139 | proof.A = A 140 | case 1: 141 | Ap, err := NewG1FromStrings(components[0], components[1], 10) 142 | if err != nil { 143 | return nil, err 144 | } 145 | proof.Ap = Ap 146 | case 2: 147 | fmt.Println(elem) 148 | fmt.Println("Cleaned") 149 | fmt.Println(cleaned) 150 | fmt.Println("Components") 151 | fmt.Println(components) 152 | B, err := NewG2FromStrings([2]string{components[0], components[1]}, [2]string{components[2], components[3]}, 10) 153 | if err != nil { 154 | i++ 155 | continue 156 | return nil, err 157 | } 158 | proof.B = B 159 | case 3: 160 | Bp, err := NewG1FromStrings(components[0], components[1], 10) 161 | if err != nil { 162 | return nil, err 163 | } 164 | proof.Bp = Bp 165 | case 4: 166 | C, err := NewG1FromStrings(components[0], components[1], 10) 167 | if err != nil { 168 | return nil, err 169 | } 170 | proof.C = C 171 | case 5: 172 | Cp, err := NewG1FromStrings(components[0], components[1], 10) 173 | if err != nil { 174 | return nil, err 175 | } 176 | proof.Cp = Cp 177 | case 6: 178 | H, err := NewG1FromStrings(components[0], components[1], 10) 179 | if err != nil { 180 | return nil, err 181 | } 182 | proof.H = H 183 | case 7: 184 | K, err := NewG1FromStrings(components[0], components[1], 10) 185 | if err != nil { 186 | return nil, err 187 | } 188 | proof.K = K 189 | default: 190 | return nil, errors.New("Invalid number of elements") 191 | } 192 | i++ 193 | } 194 | if i != 8 { 195 | return nil, errors.New("Invalid number of elements") 196 | } 197 | return proof, nil 198 | } 199 | -------------------------------------------------------------------------------- /verifier/verificationKey.txt: -------------------------------------------------------------------------------- 1 | 0 3108150941778880977471559710331950808276180521985656869446198771830159482976 4623169390117352032631864502780290323179495779467781627805656398979361240270 9472662552026237389621524682973405072669367202718326805893962976718838960052 3007715884949398461939767337845240421263006893417266439687795695749333237936 2 | 0 15088432346024849445665227109389883527508214445378096412119247151647096424361 19182938814927338102094351439523625473504565100282244769961188027241143578782 3 | 0 14184658139242854965429482137610607068559689654203471548852830118136338986310 17139647534346554852974200341053875121614798942400901582299797345362451570306 15312128090024309691716043972824407180187653767256636395282924987439774909698 8631176248541784313699734775069001541076882450890957663916529654267580781052 4 | 0 893179657435302371120052397511341927479094752419450491011417977403895470840 18869784209813035892358891933429164181766577333537862688068142602391925989205 21181512841450770369485110746825539049068963622383216303502179433470410499447 2568595916480855045396781367786408756534238400179549896524545750626028993220 5 | 0 11052165398125166992440836494722620308853418051530887877577958509282204140607 19017772120988470993433964980026799099833201459523621057474551400167805596912 6 | 0 17925549732591912529161471580960821308710858289946860168316595989950405905426 14350992777051869919831050877646362042747743962019452083321772727653803139869 15538436364414648078192712413976821753549474210613673647568447126136359421759 3670080110464340719974415558242201225355923239913948738934034428405272568131 7 | 0 20333467378457877509825787070509059260117202959285824095390532727894347334648 11978343473149621284324618196198555828164100330840763347336673521096051395493 10608153479794843276571606710549540161861992494926007300614500148569062055063 21264931081922325654404405297274834377293529206097901070008717352953491194089 8 | 0 19594855616699277192565783006406173478378437964395793760140743452533646783328 18848500442476931981014846493075725127165397585679472100584686714993246832047 9 | 1 10 | 1 11 | 0 12 | 1 13 | 0 1174463804729933180087052680285189416265042661521372566107971530582961656928 20350295387179972639902208602497895932897984536538220094684103009785093278475 -------------------------------------------------------------------------------- /verifier/verifier.go: -------------------------------------------------------------------------------- 1 | package verifier 2 | 3 | import ( 4 | "bytes" 5 | "errors" 6 | "math/big" 7 | "math/rand" 8 | "strings" 9 | 10 | bn256 "github.com/ethereum/go-ethereum/crypto/bn256/cloudflare" 11 | ) 12 | 13 | // verify a Pinocchio snark 14 | // 1 pairing equation, 9 group elements of a proof 15 | 16 | // VerifyingKey lists precomputed parameters 17 | // and points for multiplication of witness 18 | type VerifyingKey struct { 19 | A *G2 20 | B *G1 21 | C *G2 22 | gamma *G2 23 | gammaBeta1 *G1 24 | gammaBeta2 *G2 25 | Z *G2 26 | IC []*G1 // set of G1 point to multiply a witness on 27 | } 28 | 29 | // Proof lists a number of aparameters 30 | // and arbitrary number of inputs 31 | // note that where Verifying key has G2 group, Proof has G1 group 32 | // and vice versa 33 | type Proof struct { 34 | A *G1 35 | Ap *G1 36 | B *G2 37 | Bp *G1 38 | C *G1 39 | Cp *G1 40 | K *G1 41 | H *G1 42 | } 43 | 44 | // Witness is type alias for a set of scalars 45 | // Each scalar is in fact integer mod q, where q is BN256 G1 group order 46 | type Witness = []*big.Int 47 | 48 | func padBigInt(bn *big.Int) ([]byte, error) { 49 | marshalled := bn.Bytes() 50 | length := len(marshalled) 51 | if length > 32 { 52 | return nil, errors.New("Integer is too large") 53 | } else if length == 32 { 54 | return marshalled, nil 55 | } else { 56 | padding := make([]byte, 32-length) 57 | return append(padding, marshalled...), nil 58 | } 59 | } 60 | 61 | func base16bi(s string) (*big.Int, error) { 62 | val := strings.TrimPrefix(s, "0x") 63 | n, success := new(big.Int).SetString(val, 16) 64 | if !success { 65 | return nil, errors.New("Can not parse string to number") 66 | } 67 | return n, nil 68 | } 69 | 70 | func base10bi(s string) (*big.Int, error) { 71 | n, success := new(big.Int).SetString(s, 10) 72 | if !success { 73 | return nil, errors.New("Can not parse string to number") 74 | } 75 | return n, nil 76 | } 77 | 78 | func NewG1(xCoord, yCoord *big.Int) (*G1, error) { 79 | point := new(G1) 80 | xMarshalled, _ := padBigInt(xCoord) 81 | yMarshalled, _ := padBigInt(yCoord) 82 | _, err := point.Unmarshal(append(xMarshalled, yMarshalled...)) 83 | if err != nil { 84 | return nil, err 85 | } 86 | return point, nil 87 | } 88 | 89 | func NewG1FromStrings(xCoord, yCoord string, radix int) (*G1, error) { 90 | if radix == 10 { 91 | x, err := base10bi(xCoord) 92 | if err != nil { 93 | return nil, err 94 | } 95 | y, err := base10bi(yCoord) 96 | if err != nil { 97 | return nil, err 98 | } 99 | return NewG1(x, y) 100 | } else if radix == 16 { 101 | x, err := base16bi(xCoord) 102 | if err != nil { 103 | return nil, err 104 | } 105 | y, err := base16bi(yCoord) 106 | if err != nil { 107 | return nil, err 108 | } 109 | return NewG1(x, y) 110 | } 111 | return nil, errors.New("Work with radix 16 and 10 only") 112 | } 113 | 114 | func NewG2(aCoords, bCoords [2]*big.Int) (*G2, error) { 115 | point := new(G2) 116 | aMarshalled, _ := padBigInt(aCoords[0]) 117 | bMarshalled, _ := padBigInt(aCoords[1]) 118 | cMarshalled, _ := padBigInt(bCoords[0]) 119 | dMarshalled, _ := padBigInt(bCoords[1]) 120 | marshalled := append(aMarshalled, bMarshalled...) 121 | marshalled = append(marshalled, cMarshalled...) 122 | marshalled = append(marshalled, dMarshalled...) 123 | _, err := point.Unmarshal(marshalled) 124 | if err != nil { 125 | return nil, err 126 | } 127 | return point, nil 128 | } 129 | 130 | func NewG2FromStrings(aCoords, bCoords [2]string, radix int) (*G2, error) { 131 | if radix == 10 { 132 | a, err := base10bi(aCoords[0]) 133 | if err != nil { 134 | return nil, err 135 | } 136 | b, err := base10bi(aCoords[1]) 137 | if err != nil { 138 | return nil, err 139 | } 140 | c, err := base10bi(bCoords[0]) 141 | if err != nil { 142 | return nil, err 143 | } 144 | d, err := base10bi(bCoords[1]) 145 | if err != nil { 146 | return nil, err 147 | } 148 | return NewG2([2]*big.Int{a, b}, [2]*big.Int{c, d}) 149 | } else if radix == 16 { 150 | a, err := base16bi(aCoords[0]) 151 | if err != nil { 152 | return nil, err 153 | } 154 | b, err := base16bi(aCoords[1]) 155 | if err != nil { 156 | return nil, err 157 | } 158 | c, err := base16bi(bCoords[0]) 159 | if err != nil { 160 | return nil, err 161 | } 162 | d, err := base16bi(bCoords[1]) 163 | if err != nil { 164 | return nil, err 165 | } 166 | return NewG2([2]*big.Int{a, b}, [2]*big.Int{c, d}) 167 | } 168 | return nil, errors.New("Work with radix 16 and 10 only") 169 | } 170 | 171 | // GetG1Base gets G1 generator 172 | func GetG1Base() *G1 { 173 | generator, _ := NewG1FromStrings("1", "2", 10) 174 | return generator 175 | } 176 | 177 | // GetG2Base gets G2 generator 178 | func GetG2Base() *G2 { 179 | aCoords := [2]string{ 180 | "11559732032986387107991004021392285783925812861821192530917403151452391805634", 181 | "10857046999023057135944570762232829481370756359578518086990519993285655852781", 182 | } 183 | bCoords := [2]string{ 184 | "4082367875863433681332203403145435568316851327593401208105741076214120093531", 185 | "8495653923123431417604973247489272438418190587263600148770280649306958101930", 186 | } 187 | generator, _ := NewG2FromStrings(aCoords, bCoords, 10) 188 | return generator 189 | } 190 | 191 | // naiveSplitVerification computes A LOT of pairing 192 | // follows the ZoKrates logic for verification in smart-contracts 193 | // where randomness is not available 194 | func naiveSplitVerification(witness Witness, proof *Proof, vk *VerifyingKey) error { 195 | if len(witness)+1 != len(vk.IC) { 196 | return errors.New("Invalid length of the witness") 197 | } 198 | G2Base := GetG2Base() 199 | witnessAccululator := new(G1).Set(vk.IC[0]) 200 | temp := new(G1) 201 | for i, w := range witness { 202 | temp.ScalarMult(vk.IC[i+1], w) 203 | witnessAccululator.Add(temp, witnessAccululator) 204 | } 205 | // e(proof.A, vk.A) == e(-proof.Ap, G2) 206 | success := PairingCheck([]*G1{proof.A, temp.Neg(proof.Ap)}, []*G2{vk.A, G2Base}) 207 | if !success { 208 | return errors.New("First pairing equation has failed") 209 | } 210 | // e(vk.B, proof.B) + e(-proof.Bp, G2) 211 | success = PairingCheck([]*G1{vk.B, temp.Neg(proof.Bp)}, []*G2{proof.B, G2Base}) 212 | if !success { 213 | return errors.New("Second pairing equation has failed") 214 | } 215 | // e(proof.C, vk.C) + e(-proof.Cp, G2) 216 | success = PairingCheck([]*G1{proof.C, temp.Neg(proof.Cp)}, []*G2{vk.C, G2Base}) 217 | if !success { 218 | return errors.New("Third pairing equation has failed") 219 | } 220 | 221 | // e(proof.K, vk.gamma) + e(- witnessAccumulator - proof.A - proof.C, vk.gammaBeta2) + e(-vk.gammaBeta1, proof.B) 222 | t := new(G1) 223 | t.Add(witnessAccululator, proof.A) 224 | t.Add(t, proof.C) 225 | t.Neg(t) 226 | 227 | success = PairingCheck([]*G1{proof.K, t, temp.Neg(vk.gammaBeta1)}, []*G2{vk.gamma, vk.gammaBeta2, proof.B}) 228 | if !success { 229 | return errors.New("Fourth pairing equation has failed") 230 | } 231 | 232 | // e(witnessAccumulator + proof.A, proof.B) + e(- proof.H, vk.Z) + e(-proof.C, G2) 233 | u := new(G1) 234 | u.Add(witnessAccululator, proof.A) 235 | 236 | success = PairingCheck([]*G1{u, temp.Neg(proof.H), new(G1).Neg(proof.C)}, []*G2{proof.B, vk.Z, G2Base}) 237 | if !success { 238 | return errors.New("Fifth pairing equation has failed") 239 | } 240 | return nil 241 | } 242 | 243 | // agregatedVerification takes some entropy and tried to run ONE pairing check 244 | // if sum of pairing with arbitrary coefficients holds than most likely each of those holds 245 | func agregatedVerification(witness Witness, proof *Proof, vk *VerifyingKey) error { 246 | if len(witness)+1 != len(vk.IC) { 247 | return errors.New("Invalid length of the witness") 248 | } 249 | G2Base := GetG2Base() 250 | witnessAccululator := new(G1).Set(vk.IC[0]) 251 | temp := new(G1) 252 | 253 | for i, w := range witness { 254 | temp.ScalarMult(vk.IC[i+1], w) 255 | witnessAccululator.Add(temp, witnessAccululator) 256 | } 257 | // grab some entopy for pairing checks 258 | entropy := make([]*big.Int, 5) 259 | for i := range entropy { 260 | slice := make([]byte, 32) 261 | rand.Read(slice) 262 | entropy[i] = new(big.Int).SetBytes(slice) 263 | } 264 | 265 | pairings := make([]*GT, 5) 266 | 267 | // e(proof.A, vk.A) + e(-proof.Ap, G2) 268 | pair := bn256.Miller(proof.A, vk.A) 269 | pair = pair.Add(pair, bn256.Miller(temp.Neg(proof.Ap), G2Base)) 270 | pairings[0] = pair 271 | // emptyGT := new(GT) 272 | // emptyGT.Set(pair) 273 | // emptyGT.Finalize() 274 | // if bytes.Compare(emptyGT.Marshal(), IdentityBytes) != 0 { 275 | // return errors.New("Pairing check has failed") 276 | // } 277 | 278 | // e(vk.B, proof.B) + e(-proof.Bp, G2) 279 | pair = bn256.Miller(vk.B, proof.B) 280 | pair = pair.Add(pair, bn256.Miller(temp.Neg(proof.Bp), G2Base)) 281 | pairings[1] = pair 282 | // emptyGT.Set(pair) 283 | // emptyGT.Finalize() 284 | // if bytes.Compare(emptyGT.Marshal(), IdentityBytes) != 0 { 285 | // return errors.New("Pairing check has failed") 286 | // } 287 | 288 | // e(proof.C, vk.C) + e(-proof.Cp, G2) 289 | pair = bn256.Miller(proof.C, vk.C) 290 | pair = pair.Add(pair, bn256.Miller(temp.Neg(proof.Cp), G2Base)) 291 | pairings[2] = pair 292 | // emptyGT.Set(pair) 293 | // emptyGT.Finalize() 294 | // if bytes.Compare(emptyGT.Marshal(), IdentityBytes) != 0 { 295 | // return errors.New("Pairing check has failed") 296 | // } 297 | 298 | // e(proof.K, vk.gamma) + e(- witnessAccumulator - proof.A - proof.C, vk.gammaBeta2) + e(-vk.gammaBeta1, proof.B) 299 | t := new(G1) 300 | t.Add(witnessAccululator, proof.A) 301 | t.Add(t, proof.C) 302 | t.Neg(t) 303 | pair = bn256.Miller(proof.K, vk.gamma) 304 | pair = pair.Add(pair, bn256.Miller(t, vk.gammaBeta2)) 305 | pair = pair.Add(pair, bn256.Miller(temp.Neg(vk.gammaBeta1), proof.B)) 306 | pairings[3] = pair 307 | // emptyGT.Set(pair) 308 | // emptyGT.Finalize() 309 | // if bytes.Compare(emptyGT.Marshal(), IdentityBytes) != 0 { 310 | // return errors.New("Pairing check has failed") 311 | // } 312 | 313 | // e(witnessAccumulator + proof.A, proof.B) + e(- proof.H, vk.Z) + e(-proof.C, G2) 314 | u := new(G1) 315 | u.Add(witnessAccululator, proof.A) 316 | 317 | pair = bn256.Miller(u, proof.B) 318 | pair = pair.Add(pair, bn256.Miller(temp.Neg(proof.H), vk.Z)) 319 | pair = pair.Add(pair, bn256.Miller(new(G1).Neg(proof.C), G2Base)) 320 | pairings[4] = pair 321 | // emptyGT.Set(pair) 322 | // emptyGT.Finalize() 323 | // if bytes.Compare(emptyGT.Marshal(), IdentityBytes) != 0 { 324 | // return errors.New("Pairing check has failed") 325 | // } 326 | 327 | linearCombination := new(GT).Set(pairings[0]) 328 | for i := 1; i < len(pairings); i++ { 329 | linearCombination.Add(linearCombination, pairings[i].ScalarMult(pairings[i], entropy[i])) 330 | // emptyGT.Set(linearCombination) 331 | // emptyGT.Finalize() 332 | // if bytes.Compare(emptyGT.Marshal(), IdentityBytes) != 0 { 333 | // return errors.New("Pairing check has failed") 334 | // } 335 | } 336 | linearCombination.Finalize() 337 | if bytes.Compare(linearCombination.Marshal(), IdentityBytes) != 0 { 338 | return errors.New("Pairing check has failed") 339 | } 340 | return nil 341 | } 342 | -------------------------------------------------------------------------------- /verifier/verifier_test.go: -------------------------------------------------------------------------------- 1 | package verifier 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "math/big" 7 | "math/rand" 8 | "testing" 9 | 10 | bn256 "github.com/ethereum/go-ethereum/crypto/bn256/cloudflare" 11 | ) 12 | 13 | // TestVerification tests basic snark verification from ZoKrates 14 | func TestVerification(t *testing.T) { 15 | vk := &VerifyingKey{} 16 | // grab some example from ZoKrates 17 | vk.A, _ = NewG2FromStrings( 18 | [2]string{"0x95aacb3c23ba931cea76b29a19617c347943ecf1002fc0fcf798e0f8d74846c", 19 | "0x6d039a9508f5e58dd3646aec40b650cf2622990ef101628046382d9d0a11c2b"}, 20 | [2]string{"0x1396a7eda2554a0ddef4978de4de39b8618c0d170eaa3b4e3528c1e5e44c7050", 21 | "0x35186be372d0ef1ca7821d2eeb6575accda23f59fe655f4d087031b75ca9d48"}, 22 | 16) 23 | vk.B, _ = NewG1FromStrings("0x23b16b75c253c67a07b2dfb4642f916ce483f52d7d957c43f1cafa9e8efbd4b6", 24 | "0x10b9cf66c4b02c8eedc287dbfabde1d7e1be9c817eced0610e4232063b473347", 25 | 16) 26 | vk.C, _ = NewG2FromStrings( 27 | [2]string{"0x8d841a59c62049761286964354fbb9547aacb249038adcb0b8b393a0a71f872", 28 | "0x23bd90ef5307660e965fd3144418d2b5a8e6c22a87900541e12745ea62f6375f"}, 29 | [2]string{"0x10935f302a61d826b52731e5951219552832fe1be64ef191364fb8a264036d67", 30 | "0x608317e583295bdc60d86315f7923e2677143c6eeb381f8f4b828bf1a055fcd"}, 16) 31 | vk.gamma, _ = NewG2FromStrings( 32 | [2]string{"0x838d4dcd872e6bcc73ef8d9f2d61c1b1223672a4ce4483d14aea08acc895106", "0xc700c249203de561efcda3fd4ec7658d528701da3c1fca098a2d42f011fde37"}, 33 | [2]string{"0x2979bf58a5a9ef40265dea31187fd807257683846c5832c7b87951a78aa68841", "0x19e61fbd9e5b5e25dd7d110cd4b0071123975620e37c3cd72a101b63eff4f185"}, 34 | 16) 35 | vk.gammaBeta1, _ = NewG1FromStrings("0x22dc5c5252437b5f3feb464de52cb4306a0b45bbad6a4a19b36b1f991eabbe47", 36 | "0x177a001e3312096da4d75bfb2b4cc07bec195dccb48ecc6808f81c5f232e02e", 16) 37 | vk.gammaBeta2, _ = NewG2FromStrings( 38 | [2]string{"0x723f2cb7ff1065bbb44c112f68e1b632de6b6be20920beae4f28d9e0057cc47", "0xdd6e0ed155dbbc30988ad7bfd9cbcab76850d09bb6b668c1b831354fe2c1180"}, 39 | [2]string{"0x2fbb278596ffa9342d987295ada995129d5ed9b484a3337cbd095b38f1a834bd", "0x19bb949e51477e54f9ae892093beda448c33b21b43366502cd4d8a02897017a"}, 40 | 16) 41 | vk.Z, _ = NewG2FromStrings( 42 | [2]string{"0x15425ab686d62e846de5ca98c92843cad80f06401610fcce27cf6f94e07f7f8b", "0xe21bc3f9c196bb742aa2404a6550635fd632b86cb0fbae13962df909543c7c3"}, 43 | [2]string{"0x6538ba629c4809a327453895dade6110275faa25e14e4ce6390c3b095f6519c", "0x5aaf52260e7758c6cd487c1e88ef9791b518fbf09e0ec5402825687b75f3ab9"}, 44 | 16) 45 | vk.IC = make([]*G1, 7) 46 | vk.IC[0], _ = NewG1FromStrings("0x406d95f7ae8feb816b5a4b4cf4a949730f31de0b3ff1e8b800db9969514a256", "0xe0818f24fef31a82b9e7e587c9934f812e5a196a5e7aa7d495a8494f9557f4c", 16) 47 | vk.IC[1], _ = NewG1FromStrings("0xf394dc0e39f79bee4a1e0577299de796c7a03ad6e3949884d2d2fbd73f0d76c", "0x16a514b14810b2217478d803fb68372e34dde4fb624b9f4e156470364cb19402", 16) 48 | vk.IC[2], _ = NewG1FromStrings("0x134d26c1eec281bedabb8d4ee3fb61d2e9113668b3fa45f110d8547fd8f5b94d", "0x59f3d50872f8ee5662e25fc1f13e08acc01f5a7ac049b3661b87cd2b78bdd11", 16) 49 | vk.IC[3], _ = NewG1FromStrings("0xcd6823439d212cdf695ae58c3a9cb50bc31f285e986a1ca00aed91669401419", "0xbea35dbd15dd6e212050e923a6f748a981ea0f1bca31305e87a487c5c07f506", 16) 50 | vk.IC[4], _ = NewG1FromStrings("0x139af07e752cc39bc1a2c6b0468415afa072bddd5599f38e7cc4031031a5ec02", "0x27233e6a491cbdb09fd5b3b94917658ab20b2207f3d7e6aa556ca68bff5af037", 16) 51 | vk.IC[5], _ = NewG1FromStrings("0x20a7eda84420d312d03674aff46ae1202db426e9ae4ea1d400e385973ea31497", "0x61e54c3741544a6a99149a282cf1c9c08e1dd6061a593260bebba7d5c5e0b55", 16) 52 | vk.IC[6], _ = NewG1FromStrings("0x8ed7634c368516b852917dac2d165ac153204b550c5ba0456512066daef108b", "0x14c048afac3cdb256d375825101691093f73aeaf6802df2fba3c0e83de9feb86", 16) 53 | 54 | // Proof: 55 | proof := &Proof{} 56 | proof.A, _ = NewG1FromStrings("0x29a6ef0f8e73e5c389221e262b7f1695cd71d064667240bbb8a8aa143a5e3a3a", "0x2ce302d2d95bef56c48d6eba6c661e7190606e465e1bda2595f3782ab76901ed", 16) 57 | proof.Ap, _ = NewG1FromStrings("0x521375a85479309045805ca35252fa42e8eab986658d942c029caf7da2b53a", "0x85348b0d8402170a9f8d0358eaf8e0cdf5bff2d1bcad770e909045c434d87a2", 16) 58 | proof.B, _ = NewG2FromStrings( 59 | [2]string{"0x261f0899cd9ac24f6ea6b06a4d7db6fcebf39a632f4ffe99f85b85c2a9058127", "0x1ef64852f0192760310dda76a07da1bb0124869cd8f6fada287ce612e2c1987b"}, 60 | [2]string{"0x611c4c383c5e7d261ed96a1f5c145c940b1bcbdec28b74d58e3ee4f51658733", "0x2df7f862dfc698b0b944c7c8fab618c0d82a22c666632b060b4c3f92ecd80e0b"}, 16) 61 | proof.Bp, _ = NewG1FromStrings("0x173250553b786a5125ee76b1e539d36aa6209c86711485ccb28d66149869756b", "0x2d06f0def23ee2f9b0f0f32093d7f034f300c7abb762065dc2784052e8b635a7", 16) 62 | proof.C, _ = NewG1FromStrings("0x279279bc0ce40f286e300f5c339620d02c83a48a9a2a82cfc2dc386941508969", "0x3040f8131a73d41701b66257a3f23b0be0f01dcc1ee36ab65cc8e4c947331262", 16) 63 | proof.Cp, _ = NewG1FromStrings("0x1765ef75ba208e9c3ac184254e0b5386c5257c15150d8fbe22d22922343be9ab", "0x7ba5ae37e01dad31e8002be5839f475a35001c4dc6c02af2bee529a10ee8a7d", 16) 64 | proof.H, _ = NewG1FromStrings("0x2892ea5a02c1c3304f48e6dea85028916ff8796d9e7ac380b7ff1aac11f05326", "0x2425d5f1649f7d52ebdb68a2bdc70af0abe2d0146eb8d1ec28fd8f0c2f818c8a", 16) 65 | proof.K, _ = NewG1FromStrings("0x2f768eb3ffd67d561d0dd8cf09648fa3585080d32fff605cfc1fb15b83c6c2c6", "0x8d7bbf5a99e154824ecf6e2099cb50f5b16d053601b6c6c2824380e7bb5ae20", 16) 66 | 67 | // Witness: 68 | witness := make([]*big.Int, 6) 69 | witness[0] = big.NewInt(0) // nonce 0 70 | witness[1] = big.NewInt(1) // fib 1 71 | witness[2] = big.NewInt(1) // fib 1 72 | witness[3] = big.NewInt(1) // nonce 1 73 | witness[4] = big.NewInt(1) // fib 1 74 | witness[5] = big.NewInt(2) // fib 2 75 | 76 | err := naiveSplitVerification(witness, proof, vk) 77 | if err != nil { 78 | t.Fatal(err) 79 | } 80 | } 81 | 82 | func TestVerificationForInvalidWitness(t *testing.T) { 83 | vk := &VerifyingKey{} 84 | // grab some example from ZoKrates 85 | vk.A, _ = NewG2FromStrings( 86 | [2]string{"0x95aacb3c23ba931cea76b29a19617c347943ecf1002fc0fcf798e0f8d74846c", 87 | "0x6d039a9508f5e58dd3646aec40b650cf2622990ef101628046382d9d0a11c2b"}, 88 | [2]string{"0x1396a7eda2554a0ddef4978de4de39b8618c0d170eaa3b4e3528c1e5e44c7050", 89 | "0x35186be372d0ef1ca7821d2eeb6575accda23f59fe655f4d087031b75ca9d48"}, 90 | 16) 91 | vk.B, _ = NewG1FromStrings("0x23b16b75c253c67a07b2dfb4642f916ce483f52d7d957c43f1cafa9e8efbd4b6", 92 | "0x10b9cf66c4b02c8eedc287dbfabde1d7e1be9c817eced0610e4232063b473347", 93 | 16) 94 | vk.C, _ = NewG2FromStrings( 95 | [2]string{"0x8d841a59c62049761286964354fbb9547aacb249038adcb0b8b393a0a71f872", 96 | "0x23bd90ef5307660e965fd3144418d2b5a8e6c22a87900541e12745ea62f6375f"}, 97 | [2]string{"0x10935f302a61d826b52731e5951219552832fe1be64ef191364fb8a264036d67", 98 | "0x608317e583295bdc60d86315f7923e2677143c6eeb381f8f4b828bf1a055fcd"}, 16) 99 | vk.gamma, _ = NewG2FromStrings( 100 | [2]string{"0x838d4dcd872e6bcc73ef8d9f2d61c1b1223672a4ce4483d14aea08acc895106", "0xc700c249203de561efcda3fd4ec7658d528701da3c1fca098a2d42f011fde37"}, 101 | [2]string{"0x2979bf58a5a9ef40265dea31187fd807257683846c5832c7b87951a78aa68841", "0x19e61fbd9e5b5e25dd7d110cd4b0071123975620e37c3cd72a101b63eff4f185"}, 102 | 16) 103 | vk.gammaBeta1, _ = NewG1FromStrings("0x22dc5c5252437b5f3feb464de52cb4306a0b45bbad6a4a19b36b1f991eabbe47", 104 | "0x177a001e3312096da4d75bfb2b4cc07bec195dccb48ecc6808f81c5f232e02e", 16) 105 | vk.gammaBeta2, _ = NewG2FromStrings( 106 | [2]string{"0x723f2cb7ff1065bbb44c112f68e1b632de6b6be20920beae4f28d9e0057cc47", "0xdd6e0ed155dbbc30988ad7bfd9cbcab76850d09bb6b668c1b831354fe2c1180"}, 107 | [2]string{"0x2fbb278596ffa9342d987295ada995129d5ed9b484a3337cbd095b38f1a834bd", "0x19bb949e51477e54f9ae892093beda448c33b21b43366502cd4d8a02897017a"}, 108 | 16) 109 | vk.Z, _ = NewG2FromStrings( 110 | [2]string{"0x15425ab686d62e846de5ca98c92843cad80f06401610fcce27cf6f94e07f7f8b", "0xe21bc3f9c196bb742aa2404a6550635fd632b86cb0fbae13962df909543c7c3"}, 111 | [2]string{"0x6538ba629c4809a327453895dade6110275faa25e14e4ce6390c3b095f6519c", "0x5aaf52260e7758c6cd487c1e88ef9791b518fbf09e0ec5402825687b75f3ab9"}, 112 | 16) 113 | vk.IC = make([]*G1, 7) 114 | vk.IC[0], _ = NewG1FromStrings("0x406d95f7ae8feb816b5a4b4cf4a949730f31de0b3ff1e8b800db9969514a256", "0xe0818f24fef31a82b9e7e587c9934f812e5a196a5e7aa7d495a8494f9557f4c", 16) 115 | vk.IC[1], _ = NewG1FromStrings("0xf394dc0e39f79bee4a1e0577299de796c7a03ad6e3949884d2d2fbd73f0d76c", "0x16a514b14810b2217478d803fb68372e34dde4fb624b9f4e156470364cb19402", 16) 116 | vk.IC[2], _ = NewG1FromStrings("0x134d26c1eec281bedabb8d4ee3fb61d2e9113668b3fa45f110d8547fd8f5b94d", "0x59f3d50872f8ee5662e25fc1f13e08acc01f5a7ac049b3661b87cd2b78bdd11", 16) 117 | vk.IC[3], _ = NewG1FromStrings("0xcd6823439d212cdf695ae58c3a9cb50bc31f285e986a1ca00aed91669401419", "0xbea35dbd15dd6e212050e923a6f748a981ea0f1bca31305e87a487c5c07f506", 16) 118 | vk.IC[4], _ = NewG1FromStrings("0x139af07e752cc39bc1a2c6b0468415afa072bddd5599f38e7cc4031031a5ec02", "0x27233e6a491cbdb09fd5b3b94917658ab20b2207f3d7e6aa556ca68bff5af037", 16) 119 | vk.IC[5], _ = NewG1FromStrings("0x20a7eda84420d312d03674aff46ae1202db426e9ae4ea1d400e385973ea31497", "0x61e54c3741544a6a99149a282cf1c9c08e1dd6061a593260bebba7d5c5e0b55", 16) 120 | vk.IC[6], _ = NewG1FromStrings("0x8ed7634c368516b852917dac2d165ac153204b550c5ba0456512066daef108b", "0x14c048afac3cdb256d375825101691093f73aeaf6802df2fba3c0e83de9feb86", 16) 121 | 122 | // Proof: 123 | proof := &Proof{} 124 | proof.A, _ = NewG1FromStrings("0x29a6ef0f8e73e5c389221e262b7f1695cd71d064667240bbb8a8aa143a5e3a3a", "0x2ce302d2d95bef56c48d6eba6c661e7190606e465e1bda2595f3782ab76901ed", 16) 125 | proof.Ap, _ = NewG1FromStrings("0x521375a85479309045805ca35252fa42e8eab986658d942c029caf7da2b53a", "0x85348b0d8402170a9f8d0358eaf8e0cdf5bff2d1bcad770e909045c434d87a2", 16) 126 | proof.B, _ = NewG2FromStrings( 127 | [2]string{"0x261f0899cd9ac24f6ea6b06a4d7db6fcebf39a632f4ffe99f85b85c2a9058127", "0x1ef64852f0192760310dda76a07da1bb0124869cd8f6fada287ce612e2c1987b"}, 128 | [2]string{"0x611c4c383c5e7d261ed96a1f5c145c940b1bcbdec28b74d58e3ee4f51658733", "0x2df7f862dfc698b0b944c7c8fab618c0d82a22c666632b060b4c3f92ecd80e0b"}, 16) 129 | proof.Bp, _ = NewG1FromStrings("0x173250553b786a5125ee76b1e539d36aa6209c86711485ccb28d66149869756b", "0x2d06f0def23ee2f9b0f0f32093d7f034f300c7abb762065dc2784052e8b635a7", 16) 130 | proof.C, _ = NewG1FromStrings("0x279279bc0ce40f286e300f5c339620d02c83a48a9a2a82cfc2dc386941508969", "0x3040f8131a73d41701b66257a3f23b0be0f01dcc1ee36ab65cc8e4c947331262", 16) 131 | proof.Cp, _ = NewG1FromStrings("0x1765ef75ba208e9c3ac184254e0b5386c5257c15150d8fbe22d22922343be9ab", "0x7ba5ae37e01dad31e8002be5839f475a35001c4dc6c02af2bee529a10ee8a7d", 16) 132 | proof.H, _ = NewG1FromStrings("0x2892ea5a02c1c3304f48e6dea85028916ff8796d9e7ac380b7ff1aac11f05326", "0x2425d5f1649f7d52ebdb68a2bdc70af0abe2d0146eb8d1ec28fd8f0c2f818c8a", 16) 133 | proof.K, _ = NewG1FromStrings("0x2f768eb3ffd67d561d0dd8cf09648fa3585080d32fff605cfc1fb15b83c6c2c6", "0x8d7bbf5a99e154824ecf6e2099cb50f5b16d053601b6c6c2824380e7bb5ae20", 16) 134 | 135 | // Witness: 136 | witness := make([]*big.Int, 6) 137 | witness[0] = big.NewInt(0) // nonce 0 138 | witness[1] = big.NewInt(1) // fib 1 139 | witness[2] = big.NewInt(1) // fib 1 140 | witness[3] = big.NewInt(1) // nonce 1 141 | witness[4] = big.NewInt(1) // fib 1 142 | witness[5] = big.NewInt(3) // fib 3 -- invalid here! 143 | 144 | err := naiveSplitVerification(witness, proof, vk) 145 | if err == nil { 146 | t.Fatal(err) 147 | } 148 | } 149 | 150 | func TestTrivialPairingCheck(t *testing.T) { 151 | scalar := big.NewInt(2) 152 | G1Point := GetG1Base() 153 | G2Point := GetG2Base() 154 | 155 | TwoG1 := new(G1).ScalarMult(G1Point, scalar) 156 | TwoG2 := new(G2).ScalarMult(G2Point, scalar) 157 | 158 | temp := new(G1) 159 | 160 | success := PairingCheck([]*G1{G1Point, temp.Neg(TwoG1)}, []*G2{TwoG2, G2Point}) 161 | if !success { 162 | t.Fatal("Failed trivial pairing check") 163 | } 164 | } 165 | 166 | func TestDirectGT(t *testing.T) { 167 | scalar := big.NewInt(2) 168 | G1Point := GetG1Base() 169 | G2Point := GetG2Base() 170 | 171 | // equal to zero in "in exponentials" equation 172 | identity := bn256.Miller(G1Point, G2Point) 173 | identity.Finalize() 174 | identity.ScalarMult(identity, big.NewInt(0)) 175 | TwoG1 := new(G1).ScalarMult(G1Point, scalar) 176 | TwoG2 := new(G2).ScalarMult(G2Point, scalar) 177 | 178 | pair := bn256.Miller(new(G1).Neg(G1Point), TwoG2) 179 | anotherPair := bn256.Miller(TwoG1, G2Point) 180 | pair = pair.Add(pair, anotherPair) 181 | pair.Finalize() 182 | 183 | equalToIdentity := bytes.Compare(pair.Marshal(), identity.Marshal()) == 0 184 | if !equalToIdentity { 185 | t.Fail() 186 | } 187 | } 188 | 189 | // TestDirectGTwithEntropy One can delay a final exponentiation as much as needed if has access to entropy 190 | func TestDirectGTwithEntropy(t *testing.T) { 191 | two := big.NewInt(2) 192 | three := big.NewInt(3) 193 | entropy := big.NewInt(int64(rand.Uint32())) 194 | G1Point := GetG1Base() 195 | G2Point := GetG2Base() 196 | 197 | // equal to zero in "in exponentials" equation 198 | identity := bn256.Miller(G1Point, G2Point) 199 | identity.Finalize() 200 | identity.ScalarMult(identity, big.NewInt(0)) 201 | TwoG1 := new(G1).ScalarMult(G1Point, two) 202 | TwoG2 := new(G2).ScalarMult(G2Point, two) 203 | 204 | ThreeG1 := new(G1).ScalarMult(G1Point, three) 205 | ThreeG2 := new(G2).ScalarMult(G2Point, three) 206 | 207 | pair := bn256.Miller(new(G1).Neg(G1Point), TwoG2) 208 | pair = pair.Add(pair, bn256.Miller(TwoG1, G2Point)) 209 | 210 | anotherPair := bn256.Miller(new(G1).Neg(G1Point), ThreeG2) 211 | anotherPair = anotherPair.Add(anotherPair, bn256.Miller(ThreeG1, G2Point)) 212 | 213 | someCombination := pair.Add(pair, anotherPair.ScalarMult(anotherPair, entropy)) 214 | 215 | someCombination.Finalize() 216 | 217 | equalToIdentity := bytes.Compare(someCombination.Marshal(), identity.Marshal()) == 0 218 | if !equalToIdentity { 219 | t.Fail() 220 | } 221 | } 222 | 223 | func TestFastVerification(t *testing.T) { 224 | vk := &VerifyingKey{} 225 | // grab some example from ZoKrates 226 | vk.A, _ = NewG2FromStrings( 227 | [2]string{"0x95aacb3c23ba931cea76b29a19617c347943ecf1002fc0fcf798e0f8d74846c", 228 | "0x6d039a9508f5e58dd3646aec40b650cf2622990ef101628046382d9d0a11c2b"}, 229 | [2]string{"0x1396a7eda2554a0ddef4978de4de39b8618c0d170eaa3b4e3528c1e5e44c7050", 230 | "0x35186be372d0ef1ca7821d2eeb6575accda23f59fe655f4d087031b75ca9d48"}, 231 | 16) 232 | vk.B, _ = NewG1FromStrings("0x23b16b75c253c67a07b2dfb4642f916ce483f52d7d957c43f1cafa9e8efbd4b6", 233 | "0x10b9cf66c4b02c8eedc287dbfabde1d7e1be9c817eced0610e4232063b473347", 234 | 16) 235 | vk.C, _ = NewG2FromStrings( 236 | [2]string{"0x8d841a59c62049761286964354fbb9547aacb249038adcb0b8b393a0a71f872", 237 | "0x23bd90ef5307660e965fd3144418d2b5a8e6c22a87900541e12745ea62f6375f"}, 238 | [2]string{"0x10935f302a61d826b52731e5951219552832fe1be64ef191364fb8a264036d67", 239 | "0x608317e583295bdc60d86315f7923e2677143c6eeb381f8f4b828bf1a055fcd"}, 16) 240 | vk.gamma, _ = NewG2FromStrings( 241 | [2]string{"0x838d4dcd872e6bcc73ef8d9f2d61c1b1223672a4ce4483d14aea08acc895106", "0xc700c249203de561efcda3fd4ec7658d528701da3c1fca098a2d42f011fde37"}, 242 | [2]string{"0x2979bf58a5a9ef40265dea31187fd807257683846c5832c7b87951a78aa68841", "0x19e61fbd9e5b5e25dd7d110cd4b0071123975620e37c3cd72a101b63eff4f185"}, 243 | 16) 244 | vk.gammaBeta1, _ = NewG1FromStrings("0x22dc5c5252437b5f3feb464de52cb4306a0b45bbad6a4a19b36b1f991eabbe47", 245 | "0x177a001e3312096da4d75bfb2b4cc07bec195dccb48ecc6808f81c5f232e02e", 16) 246 | vk.gammaBeta2, _ = NewG2FromStrings( 247 | [2]string{"0x723f2cb7ff1065bbb44c112f68e1b632de6b6be20920beae4f28d9e0057cc47", "0xdd6e0ed155dbbc30988ad7bfd9cbcab76850d09bb6b668c1b831354fe2c1180"}, 248 | [2]string{"0x2fbb278596ffa9342d987295ada995129d5ed9b484a3337cbd095b38f1a834bd", "0x19bb949e51477e54f9ae892093beda448c33b21b43366502cd4d8a02897017a"}, 249 | 16) 250 | vk.Z, _ = NewG2FromStrings( 251 | [2]string{"0x15425ab686d62e846de5ca98c92843cad80f06401610fcce27cf6f94e07f7f8b", "0xe21bc3f9c196bb742aa2404a6550635fd632b86cb0fbae13962df909543c7c3"}, 252 | [2]string{"0x6538ba629c4809a327453895dade6110275faa25e14e4ce6390c3b095f6519c", "0x5aaf52260e7758c6cd487c1e88ef9791b518fbf09e0ec5402825687b75f3ab9"}, 253 | 16) 254 | vk.IC = make([]*G1, 7) 255 | vk.IC[0], _ = NewG1FromStrings("0x406d95f7ae8feb816b5a4b4cf4a949730f31de0b3ff1e8b800db9969514a256", "0xe0818f24fef31a82b9e7e587c9934f812e5a196a5e7aa7d495a8494f9557f4c", 16) 256 | vk.IC[1], _ = NewG1FromStrings("0xf394dc0e39f79bee4a1e0577299de796c7a03ad6e3949884d2d2fbd73f0d76c", "0x16a514b14810b2217478d803fb68372e34dde4fb624b9f4e156470364cb19402", 16) 257 | vk.IC[2], _ = NewG1FromStrings("0x134d26c1eec281bedabb8d4ee3fb61d2e9113668b3fa45f110d8547fd8f5b94d", "0x59f3d50872f8ee5662e25fc1f13e08acc01f5a7ac049b3661b87cd2b78bdd11", 16) 258 | vk.IC[3], _ = NewG1FromStrings("0xcd6823439d212cdf695ae58c3a9cb50bc31f285e986a1ca00aed91669401419", "0xbea35dbd15dd6e212050e923a6f748a981ea0f1bca31305e87a487c5c07f506", 16) 259 | vk.IC[4], _ = NewG1FromStrings("0x139af07e752cc39bc1a2c6b0468415afa072bddd5599f38e7cc4031031a5ec02", "0x27233e6a491cbdb09fd5b3b94917658ab20b2207f3d7e6aa556ca68bff5af037", 16) 260 | vk.IC[5], _ = NewG1FromStrings("0x20a7eda84420d312d03674aff46ae1202db426e9ae4ea1d400e385973ea31497", "0x61e54c3741544a6a99149a282cf1c9c08e1dd6061a593260bebba7d5c5e0b55", 16) 261 | vk.IC[6], _ = NewG1FromStrings("0x8ed7634c368516b852917dac2d165ac153204b550c5ba0456512066daef108b", "0x14c048afac3cdb256d375825101691093f73aeaf6802df2fba3c0e83de9feb86", 16) 262 | 263 | // Proof: 264 | proof := &Proof{} 265 | proof.A, _ = NewG1FromStrings("0x29a6ef0f8e73e5c389221e262b7f1695cd71d064667240bbb8a8aa143a5e3a3a", "0x2ce302d2d95bef56c48d6eba6c661e7190606e465e1bda2595f3782ab76901ed", 16) 266 | proof.Ap, _ = NewG1FromStrings("0x521375a85479309045805ca35252fa42e8eab986658d942c029caf7da2b53a", "0x85348b0d8402170a9f8d0358eaf8e0cdf5bff2d1bcad770e909045c434d87a2", 16) 267 | proof.B, _ = NewG2FromStrings( 268 | [2]string{"0x261f0899cd9ac24f6ea6b06a4d7db6fcebf39a632f4ffe99f85b85c2a9058127", "0x1ef64852f0192760310dda76a07da1bb0124869cd8f6fada287ce612e2c1987b"}, 269 | [2]string{"0x611c4c383c5e7d261ed96a1f5c145c940b1bcbdec28b74d58e3ee4f51658733", "0x2df7f862dfc698b0b944c7c8fab618c0d82a22c666632b060b4c3f92ecd80e0b"}, 16) 270 | proof.Bp, _ = NewG1FromStrings("0x173250553b786a5125ee76b1e539d36aa6209c86711485ccb28d66149869756b", "0x2d06f0def23ee2f9b0f0f32093d7f034f300c7abb762065dc2784052e8b635a7", 16) 271 | proof.C, _ = NewG1FromStrings("0x279279bc0ce40f286e300f5c339620d02c83a48a9a2a82cfc2dc386941508969", "0x3040f8131a73d41701b66257a3f23b0be0f01dcc1ee36ab65cc8e4c947331262", 16) 272 | proof.Cp, _ = NewG1FromStrings("0x1765ef75ba208e9c3ac184254e0b5386c5257c15150d8fbe22d22922343be9ab", "0x7ba5ae37e01dad31e8002be5839f475a35001c4dc6c02af2bee529a10ee8a7d", 16) 273 | proof.H, _ = NewG1FromStrings("0x2892ea5a02c1c3304f48e6dea85028916ff8796d9e7ac380b7ff1aac11f05326", "0x2425d5f1649f7d52ebdb68a2bdc70af0abe2d0146eb8d1ec28fd8f0c2f818c8a", 16) 274 | proof.K, _ = NewG1FromStrings("0x2f768eb3ffd67d561d0dd8cf09648fa3585080d32fff605cfc1fb15b83c6c2c6", "0x8d7bbf5a99e154824ecf6e2099cb50f5b16d053601b6c6c2824380e7bb5ae20", 16) 275 | 276 | // Witness: 277 | witness := make([]*big.Int, 6) 278 | witness[0] = big.NewInt(0) // nonce 0 279 | witness[1] = big.NewInt(1) // fib 1 280 | witness[2] = big.NewInt(1) // fib 1 281 | witness[3] = big.NewInt(1) // nonce 1 282 | witness[4] = big.NewInt(1) // fib 1 283 | witness[5] = big.NewInt(2) // fib 2 284 | 285 | err := agregatedVerification(witness, proof, vk) 286 | if err != nil { 287 | t.Fatal(err) 288 | } 289 | } 290 | 291 | func TestFastVerificationForInvalidWitness(t *testing.T) { 292 | vk := &VerifyingKey{} 293 | // grab some example from ZoKrates 294 | vk.A, _ = NewG2FromStrings( 295 | [2]string{"0x95aacb3c23ba931cea76b29a19617c347943ecf1002fc0fcf798e0f8d74846c", 296 | "0x6d039a9508f5e58dd3646aec40b650cf2622990ef101628046382d9d0a11c2b"}, 297 | [2]string{"0x1396a7eda2554a0ddef4978de4de39b8618c0d170eaa3b4e3528c1e5e44c7050", 298 | "0x35186be372d0ef1ca7821d2eeb6575accda23f59fe655f4d087031b75ca9d48"}, 299 | 16) 300 | vk.B, _ = NewG1FromStrings("0x23b16b75c253c67a07b2dfb4642f916ce483f52d7d957c43f1cafa9e8efbd4b6", 301 | "0x10b9cf66c4b02c8eedc287dbfabde1d7e1be9c817eced0610e4232063b473347", 302 | 16) 303 | vk.C, _ = NewG2FromStrings( 304 | [2]string{"0x8d841a59c62049761286964354fbb9547aacb249038adcb0b8b393a0a71f872", 305 | "0x23bd90ef5307660e965fd3144418d2b5a8e6c22a87900541e12745ea62f6375f"}, 306 | [2]string{"0x10935f302a61d826b52731e5951219552832fe1be64ef191364fb8a264036d67", 307 | "0x608317e583295bdc60d86315f7923e2677143c6eeb381f8f4b828bf1a055fcd"}, 16) 308 | vk.gamma, _ = NewG2FromStrings( 309 | [2]string{"0x838d4dcd872e6bcc73ef8d9f2d61c1b1223672a4ce4483d14aea08acc895106", "0xc700c249203de561efcda3fd4ec7658d528701da3c1fca098a2d42f011fde37"}, 310 | [2]string{"0x2979bf58a5a9ef40265dea31187fd807257683846c5832c7b87951a78aa68841", "0x19e61fbd9e5b5e25dd7d110cd4b0071123975620e37c3cd72a101b63eff4f185"}, 311 | 16) 312 | vk.gammaBeta1, _ = NewG1FromStrings("0x22dc5c5252437b5f3feb464de52cb4306a0b45bbad6a4a19b36b1f991eabbe47", 313 | "0x177a001e3312096da4d75bfb2b4cc07bec195dccb48ecc6808f81c5f232e02e", 16) 314 | vk.gammaBeta2, _ = NewG2FromStrings( 315 | [2]string{"0x723f2cb7ff1065bbb44c112f68e1b632de6b6be20920beae4f28d9e0057cc47", "0xdd6e0ed155dbbc30988ad7bfd9cbcab76850d09bb6b668c1b831354fe2c1180"}, 316 | [2]string{"0x2fbb278596ffa9342d987295ada995129d5ed9b484a3337cbd095b38f1a834bd", "0x19bb949e51477e54f9ae892093beda448c33b21b43366502cd4d8a02897017a"}, 317 | 16) 318 | vk.Z, _ = NewG2FromStrings( 319 | [2]string{"0x15425ab686d62e846de5ca98c92843cad80f06401610fcce27cf6f94e07f7f8b", "0xe21bc3f9c196bb742aa2404a6550635fd632b86cb0fbae13962df909543c7c3"}, 320 | [2]string{"0x6538ba629c4809a327453895dade6110275faa25e14e4ce6390c3b095f6519c", "0x5aaf52260e7758c6cd487c1e88ef9791b518fbf09e0ec5402825687b75f3ab9"}, 321 | 16) 322 | vk.IC = make([]*G1, 7) 323 | vk.IC[0], _ = NewG1FromStrings("0x406d95f7ae8feb816b5a4b4cf4a949730f31de0b3ff1e8b800db9969514a256", "0xe0818f24fef31a82b9e7e587c9934f812e5a196a5e7aa7d495a8494f9557f4c", 16) 324 | vk.IC[1], _ = NewG1FromStrings("0xf394dc0e39f79bee4a1e0577299de796c7a03ad6e3949884d2d2fbd73f0d76c", "0x16a514b14810b2217478d803fb68372e34dde4fb624b9f4e156470364cb19402", 16) 325 | vk.IC[2], _ = NewG1FromStrings("0x134d26c1eec281bedabb8d4ee3fb61d2e9113668b3fa45f110d8547fd8f5b94d", "0x59f3d50872f8ee5662e25fc1f13e08acc01f5a7ac049b3661b87cd2b78bdd11", 16) 326 | vk.IC[3], _ = NewG1FromStrings("0xcd6823439d212cdf695ae58c3a9cb50bc31f285e986a1ca00aed91669401419", "0xbea35dbd15dd6e212050e923a6f748a981ea0f1bca31305e87a487c5c07f506", 16) 327 | vk.IC[4], _ = NewG1FromStrings("0x139af07e752cc39bc1a2c6b0468415afa072bddd5599f38e7cc4031031a5ec02", "0x27233e6a491cbdb09fd5b3b94917658ab20b2207f3d7e6aa556ca68bff5af037", 16) 328 | vk.IC[5], _ = NewG1FromStrings("0x20a7eda84420d312d03674aff46ae1202db426e9ae4ea1d400e385973ea31497", "0x61e54c3741544a6a99149a282cf1c9c08e1dd6061a593260bebba7d5c5e0b55", 16) 329 | vk.IC[6], _ = NewG1FromStrings("0x8ed7634c368516b852917dac2d165ac153204b550c5ba0456512066daef108b", "0x14c048afac3cdb256d375825101691093f73aeaf6802df2fba3c0e83de9feb86", 16) 330 | 331 | // Proof: 332 | proof := &Proof{} 333 | proof.A, _ = NewG1FromStrings("0x29a6ef0f8e73e5c389221e262b7f1695cd71d064667240bbb8a8aa143a5e3a3a", "0x2ce302d2d95bef56c48d6eba6c661e7190606e465e1bda2595f3782ab76901ed", 16) 334 | proof.Ap, _ = NewG1FromStrings("0x521375a85479309045805ca35252fa42e8eab986658d942c029caf7da2b53a", "0x85348b0d8402170a9f8d0358eaf8e0cdf5bff2d1bcad770e909045c434d87a2", 16) 335 | proof.B, _ = NewG2FromStrings( 336 | [2]string{"0x261f0899cd9ac24f6ea6b06a4d7db6fcebf39a632f4ffe99f85b85c2a9058127", "0x1ef64852f0192760310dda76a07da1bb0124869cd8f6fada287ce612e2c1987b"}, 337 | [2]string{"0x611c4c383c5e7d261ed96a1f5c145c940b1bcbdec28b74d58e3ee4f51658733", "0x2df7f862dfc698b0b944c7c8fab618c0d82a22c666632b060b4c3f92ecd80e0b"}, 16) 338 | proof.Bp, _ = NewG1FromStrings("0x173250553b786a5125ee76b1e539d36aa6209c86711485ccb28d66149869756b", "0x2d06f0def23ee2f9b0f0f32093d7f034f300c7abb762065dc2784052e8b635a7", 16) 339 | proof.C, _ = NewG1FromStrings("0x279279bc0ce40f286e300f5c339620d02c83a48a9a2a82cfc2dc386941508969", "0x3040f8131a73d41701b66257a3f23b0be0f01dcc1ee36ab65cc8e4c947331262", 16) 340 | proof.Cp, _ = NewG1FromStrings("0x1765ef75ba208e9c3ac184254e0b5386c5257c15150d8fbe22d22922343be9ab", "0x7ba5ae37e01dad31e8002be5839f475a35001c4dc6c02af2bee529a10ee8a7d", 16) 341 | proof.H, _ = NewG1FromStrings("0x2892ea5a02c1c3304f48e6dea85028916ff8796d9e7ac380b7ff1aac11f05326", "0x2425d5f1649f7d52ebdb68a2bdc70af0abe2d0146eb8d1ec28fd8f0c2f818c8a", 16) 342 | proof.K, _ = NewG1FromStrings("0x2f768eb3ffd67d561d0dd8cf09648fa3585080d32fff605cfc1fb15b83c6c2c6", "0x8d7bbf5a99e154824ecf6e2099cb50f5b16d053601b6c6c2824380e7bb5ae20", 16) 343 | 344 | // Witness: there is an error here! 345 | witness := make([]*big.Int, 6) 346 | witness[0] = big.NewInt(0) // nonce 0 347 | witness[1] = big.NewInt(1) // fib 1 348 | witness[2] = big.NewInt(1) // fib 1 349 | witness[3] = big.NewInt(1) // nonce 1 350 | witness[4] = big.NewInt(1) // fib 1 351 | witness[5] = big.NewInt(3) // fib 3 - invalid here! 352 | 353 | err := agregatedVerification(witness, proof, vk) 354 | if err == nil { 355 | t.Fatal(err) 356 | } 357 | } 358 | 359 | func BenchmarkNormalVerification(b *testing.B) { 360 | vk := &VerifyingKey{} 361 | // grab some example from ZoKrates 362 | vk.A, _ = NewG2FromStrings( 363 | [2]string{"0x95aacb3c23ba931cea76b29a19617c347943ecf1002fc0fcf798e0f8d74846c", 364 | "0x6d039a9508f5e58dd3646aec40b650cf2622990ef101628046382d9d0a11c2b"}, 365 | [2]string{"0x1396a7eda2554a0ddef4978de4de39b8618c0d170eaa3b4e3528c1e5e44c7050", 366 | "0x35186be372d0ef1ca7821d2eeb6575accda23f59fe655f4d087031b75ca9d48"}, 367 | 16) 368 | vk.B, _ = NewG1FromStrings("0x23b16b75c253c67a07b2dfb4642f916ce483f52d7d957c43f1cafa9e8efbd4b6", 369 | "0x10b9cf66c4b02c8eedc287dbfabde1d7e1be9c817eced0610e4232063b473347", 370 | 16) 371 | vk.C, _ = NewG2FromStrings( 372 | [2]string{"0x8d841a59c62049761286964354fbb9547aacb249038adcb0b8b393a0a71f872", 373 | "0x23bd90ef5307660e965fd3144418d2b5a8e6c22a87900541e12745ea62f6375f"}, 374 | [2]string{"0x10935f302a61d826b52731e5951219552832fe1be64ef191364fb8a264036d67", 375 | "0x608317e583295bdc60d86315f7923e2677143c6eeb381f8f4b828bf1a055fcd"}, 16) 376 | vk.gamma, _ = NewG2FromStrings( 377 | [2]string{"0x838d4dcd872e6bcc73ef8d9f2d61c1b1223672a4ce4483d14aea08acc895106", "0xc700c249203de561efcda3fd4ec7658d528701da3c1fca098a2d42f011fde37"}, 378 | [2]string{"0x2979bf58a5a9ef40265dea31187fd807257683846c5832c7b87951a78aa68841", "0x19e61fbd9e5b5e25dd7d110cd4b0071123975620e37c3cd72a101b63eff4f185"}, 379 | 16) 380 | vk.gammaBeta1, _ = NewG1FromStrings("0x22dc5c5252437b5f3feb464de52cb4306a0b45bbad6a4a19b36b1f991eabbe47", 381 | "0x177a001e3312096da4d75bfb2b4cc07bec195dccb48ecc6808f81c5f232e02e", 16) 382 | vk.gammaBeta2, _ = NewG2FromStrings( 383 | [2]string{"0x723f2cb7ff1065bbb44c112f68e1b632de6b6be20920beae4f28d9e0057cc47", "0xdd6e0ed155dbbc30988ad7bfd9cbcab76850d09bb6b668c1b831354fe2c1180"}, 384 | [2]string{"0x2fbb278596ffa9342d987295ada995129d5ed9b484a3337cbd095b38f1a834bd", "0x19bb949e51477e54f9ae892093beda448c33b21b43366502cd4d8a02897017a"}, 385 | 16) 386 | vk.Z, _ = NewG2FromStrings( 387 | [2]string{"0x15425ab686d62e846de5ca98c92843cad80f06401610fcce27cf6f94e07f7f8b", "0xe21bc3f9c196bb742aa2404a6550635fd632b86cb0fbae13962df909543c7c3"}, 388 | [2]string{"0x6538ba629c4809a327453895dade6110275faa25e14e4ce6390c3b095f6519c", "0x5aaf52260e7758c6cd487c1e88ef9791b518fbf09e0ec5402825687b75f3ab9"}, 389 | 16) 390 | vk.IC = make([]*G1, 7) 391 | vk.IC[0], _ = NewG1FromStrings("0x406d95f7ae8feb816b5a4b4cf4a949730f31de0b3ff1e8b800db9969514a256", "0xe0818f24fef31a82b9e7e587c9934f812e5a196a5e7aa7d495a8494f9557f4c", 16) 392 | vk.IC[1], _ = NewG1FromStrings("0xf394dc0e39f79bee4a1e0577299de796c7a03ad6e3949884d2d2fbd73f0d76c", "0x16a514b14810b2217478d803fb68372e34dde4fb624b9f4e156470364cb19402", 16) 393 | vk.IC[2], _ = NewG1FromStrings("0x134d26c1eec281bedabb8d4ee3fb61d2e9113668b3fa45f110d8547fd8f5b94d", "0x59f3d50872f8ee5662e25fc1f13e08acc01f5a7ac049b3661b87cd2b78bdd11", 16) 394 | vk.IC[3], _ = NewG1FromStrings("0xcd6823439d212cdf695ae58c3a9cb50bc31f285e986a1ca00aed91669401419", "0xbea35dbd15dd6e212050e923a6f748a981ea0f1bca31305e87a487c5c07f506", 16) 395 | vk.IC[4], _ = NewG1FromStrings("0x139af07e752cc39bc1a2c6b0468415afa072bddd5599f38e7cc4031031a5ec02", "0x27233e6a491cbdb09fd5b3b94917658ab20b2207f3d7e6aa556ca68bff5af037", 16) 396 | vk.IC[5], _ = NewG1FromStrings("0x20a7eda84420d312d03674aff46ae1202db426e9ae4ea1d400e385973ea31497", "0x61e54c3741544a6a99149a282cf1c9c08e1dd6061a593260bebba7d5c5e0b55", 16) 397 | vk.IC[6], _ = NewG1FromStrings("0x8ed7634c368516b852917dac2d165ac153204b550c5ba0456512066daef108b", "0x14c048afac3cdb256d375825101691093f73aeaf6802df2fba3c0e83de9feb86", 16) 398 | 399 | // Proof: 400 | proof := &Proof{} 401 | proof.A, _ = NewG1FromStrings("0x29a6ef0f8e73e5c389221e262b7f1695cd71d064667240bbb8a8aa143a5e3a3a", "0x2ce302d2d95bef56c48d6eba6c661e7190606e465e1bda2595f3782ab76901ed", 16) 402 | proof.Ap, _ = NewG1FromStrings("0x521375a85479309045805ca35252fa42e8eab986658d942c029caf7da2b53a", "0x85348b0d8402170a9f8d0358eaf8e0cdf5bff2d1bcad770e909045c434d87a2", 16) 403 | proof.B, _ = NewG2FromStrings( 404 | [2]string{"0x261f0899cd9ac24f6ea6b06a4d7db6fcebf39a632f4ffe99f85b85c2a9058127", "0x1ef64852f0192760310dda76a07da1bb0124869cd8f6fada287ce612e2c1987b"}, 405 | [2]string{"0x611c4c383c5e7d261ed96a1f5c145c940b1bcbdec28b74d58e3ee4f51658733", "0x2df7f862dfc698b0b944c7c8fab618c0d82a22c666632b060b4c3f92ecd80e0b"}, 16) 406 | proof.Bp, _ = NewG1FromStrings("0x173250553b786a5125ee76b1e539d36aa6209c86711485ccb28d66149869756b", "0x2d06f0def23ee2f9b0f0f32093d7f034f300c7abb762065dc2784052e8b635a7", 16) 407 | proof.C, _ = NewG1FromStrings("0x279279bc0ce40f286e300f5c339620d02c83a48a9a2a82cfc2dc386941508969", "0x3040f8131a73d41701b66257a3f23b0be0f01dcc1ee36ab65cc8e4c947331262", 16) 408 | proof.Cp, _ = NewG1FromStrings("0x1765ef75ba208e9c3ac184254e0b5386c5257c15150d8fbe22d22922343be9ab", "0x7ba5ae37e01dad31e8002be5839f475a35001c4dc6c02af2bee529a10ee8a7d", 16) 409 | proof.H, _ = NewG1FromStrings("0x2892ea5a02c1c3304f48e6dea85028916ff8796d9e7ac380b7ff1aac11f05326", "0x2425d5f1649f7d52ebdb68a2bdc70af0abe2d0146eb8d1ec28fd8f0c2f818c8a", 16) 410 | proof.K, _ = NewG1FromStrings("0x2f768eb3ffd67d561d0dd8cf09648fa3585080d32fff605cfc1fb15b83c6c2c6", "0x8d7bbf5a99e154824ecf6e2099cb50f5b16d053601b6c6c2824380e7bb5ae20", 16) 411 | 412 | // Witness: 413 | witness := make([]*big.Int, 6) 414 | witness[0] = big.NewInt(0) // nonce 0 415 | witness[1] = big.NewInt(1) // fib 1 416 | witness[2] = big.NewInt(1) // fib 1 417 | witness[3] = big.NewInt(1) // nonce 1 418 | witness[4] = big.NewInt(1) // fib 1 419 | witness[5] = big.NewInt(2) // fib 2 420 | for i := 0; i < b.N; i++ { 421 | naiveSplitVerification(witness, proof, vk) 422 | } 423 | } 424 | 425 | func BenchmarkFastVerification(b *testing.B) { 426 | vk := &VerifyingKey{} 427 | // grab some example from ZoKrates 428 | vk.A, _ = NewG2FromStrings( 429 | [2]string{"0x95aacb3c23ba931cea76b29a19617c347943ecf1002fc0fcf798e0f8d74846c", 430 | "0x6d039a9508f5e58dd3646aec40b650cf2622990ef101628046382d9d0a11c2b"}, 431 | [2]string{"0x1396a7eda2554a0ddef4978de4de39b8618c0d170eaa3b4e3528c1e5e44c7050", 432 | "0x35186be372d0ef1ca7821d2eeb6575accda23f59fe655f4d087031b75ca9d48"}, 433 | 16) 434 | vk.B, _ = NewG1FromStrings("0x23b16b75c253c67a07b2dfb4642f916ce483f52d7d957c43f1cafa9e8efbd4b6", 435 | "0x10b9cf66c4b02c8eedc287dbfabde1d7e1be9c817eced0610e4232063b473347", 436 | 16) 437 | vk.C, _ = NewG2FromStrings( 438 | [2]string{"0x8d841a59c62049761286964354fbb9547aacb249038adcb0b8b393a0a71f872", 439 | "0x23bd90ef5307660e965fd3144418d2b5a8e6c22a87900541e12745ea62f6375f"}, 440 | [2]string{"0x10935f302a61d826b52731e5951219552832fe1be64ef191364fb8a264036d67", 441 | "0x608317e583295bdc60d86315f7923e2677143c6eeb381f8f4b828bf1a055fcd"}, 16) 442 | vk.gamma, _ = NewG2FromStrings( 443 | [2]string{"0x838d4dcd872e6bcc73ef8d9f2d61c1b1223672a4ce4483d14aea08acc895106", "0xc700c249203de561efcda3fd4ec7658d528701da3c1fca098a2d42f011fde37"}, 444 | [2]string{"0x2979bf58a5a9ef40265dea31187fd807257683846c5832c7b87951a78aa68841", "0x19e61fbd9e5b5e25dd7d110cd4b0071123975620e37c3cd72a101b63eff4f185"}, 445 | 16) 446 | vk.gammaBeta1, _ = NewG1FromStrings("0x22dc5c5252437b5f3feb464de52cb4306a0b45bbad6a4a19b36b1f991eabbe47", 447 | "0x177a001e3312096da4d75bfb2b4cc07bec195dccb48ecc6808f81c5f232e02e", 16) 448 | vk.gammaBeta2, _ = NewG2FromStrings( 449 | [2]string{"0x723f2cb7ff1065bbb44c112f68e1b632de6b6be20920beae4f28d9e0057cc47", "0xdd6e0ed155dbbc30988ad7bfd9cbcab76850d09bb6b668c1b831354fe2c1180"}, 450 | [2]string{"0x2fbb278596ffa9342d987295ada995129d5ed9b484a3337cbd095b38f1a834bd", "0x19bb949e51477e54f9ae892093beda448c33b21b43366502cd4d8a02897017a"}, 451 | 16) 452 | vk.Z, _ = NewG2FromStrings( 453 | [2]string{"0x15425ab686d62e846de5ca98c92843cad80f06401610fcce27cf6f94e07f7f8b", "0xe21bc3f9c196bb742aa2404a6550635fd632b86cb0fbae13962df909543c7c3"}, 454 | [2]string{"0x6538ba629c4809a327453895dade6110275faa25e14e4ce6390c3b095f6519c", "0x5aaf52260e7758c6cd487c1e88ef9791b518fbf09e0ec5402825687b75f3ab9"}, 455 | 16) 456 | vk.IC = make([]*G1, 7) 457 | vk.IC[0], _ = NewG1FromStrings("0x406d95f7ae8feb816b5a4b4cf4a949730f31de0b3ff1e8b800db9969514a256", "0xe0818f24fef31a82b9e7e587c9934f812e5a196a5e7aa7d495a8494f9557f4c", 16) 458 | vk.IC[1], _ = NewG1FromStrings("0xf394dc0e39f79bee4a1e0577299de796c7a03ad6e3949884d2d2fbd73f0d76c", "0x16a514b14810b2217478d803fb68372e34dde4fb624b9f4e156470364cb19402", 16) 459 | vk.IC[2], _ = NewG1FromStrings("0x134d26c1eec281bedabb8d4ee3fb61d2e9113668b3fa45f110d8547fd8f5b94d", "0x59f3d50872f8ee5662e25fc1f13e08acc01f5a7ac049b3661b87cd2b78bdd11", 16) 460 | vk.IC[3], _ = NewG1FromStrings("0xcd6823439d212cdf695ae58c3a9cb50bc31f285e986a1ca00aed91669401419", "0xbea35dbd15dd6e212050e923a6f748a981ea0f1bca31305e87a487c5c07f506", 16) 461 | vk.IC[4], _ = NewG1FromStrings("0x139af07e752cc39bc1a2c6b0468415afa072bddd5599f38e7cc4031031a5ec02", "0x27233e6a491cbdb09fd5b3b94917658ab20b2207f3d7e6aa556ca68bff5af037", 16) 462 | vk.IC[5], _ = NewG1FromStrings("0x20a7eda84420d312d03674aff46ae1202db426e9ae4ea1d400e385973ea31497", "0x61e54c3741544a6a99149a282cf1c9c08e1dd6061a593260bebba7d5c5e0b55", 16) 463 | vk.IC[6], _ = NewG1FromStrings("0x8ed7634c368516b852917dac2d165ac153204b550c5ba0456512066daef108b", "0x14c048afac3cdb256d375825101691093f73aeaf6802df2fba3c0e83de9feb86", 16) 464 | 465 | // Proof: 466 | proof := &Proof{} 467 | proof.A, _ = NewG1FromStrings("0x29a6ef0f8e73e5c389221e262b7f1695cd71d064667240bbb8a8aa143a5e3a3a", "0x2ce302d2d95bef56c48d6eba6c661e7190606e465e1bda2595f3782ab76901ed", 16) 468 | proof.Ap, _ = NewG1FromStrings("0x521375a85479309045805ca35252fa42e8eab986658d942c029caf7da2b53a", "0x85348b0d8402170a9f8d0358eaf8e0cdf5bff2d1bcad770e909045c434d87a2", 16) 469 | proof.B, _ = NewG2FromStrings( 470 | [2]string{"0x261f0899cd9ac24f6ea6b06a4d7db6fcebf39a632f4ffe99f85b85c2a9058127", "0x1ef64852f0192760310dda76a07da1bb0124869cd8f6fada287ce612e2c1987b"}, 471 | [2]string{"0x611c4c383c5e7d261ed96a1f5c145c940b1bcbdec28b74d58e3ee4f51658733", "0x2df7f862dfc698b0b944c7c8fab618c0d82a22c666632b060b4c3f92ecd80e0b"}, 16) 472 | proof.Bp, _ = NewG1FromStrings("0x173250553b786a5125ee76b1e539d36aa6209c86711485ccb28d66149869756b", "0x2d06f0def23ee2f9b0f0f32093d7f034f300c7abb762065dc2784052e8b635a7", 16) 473 | proof.C, _ = NewG1FromStrings("0x279279bc0ce40f286e300f5c339620d02c83a48a9a2a82cfc2dc386941508969", "0x3040f8131a73d41701b66257a3f23b0be0f01dcc1ee36ab65cc8e4c947331262", 16) 474 | proof.Cp, _ = NewG1FromStrings("0x1765ef75ba208e9c3ac184254e0b5386c5257c15150d8fbe22d22922343be9ab", "0x7ba5ae37e01dad31e8002be5839f475a35001c4dc6c02af2bee529a10ee8a7d", 16) 475 | proof.H, _ = NewG1FromStrings("0x2892ea5a02c1c3304f48e6dea85028916ff8796d9e7ac380b7ff1aac11f05326", "0x2425d5f1649f7d52ebdb68a2bdc70af0abe2d0146eb8d1ec28fd8f0c2f818c8a", 16) 476 | proof.K, _ = NewG1FromStrings("0x2f768eb3ffd67d561d0dd8cf09648fa3585080d32fff605cfc1fb15b83c6c2c6", "0x8d7bbf5a99e154824ecf6e2099cb50f5b16d053601b6c6c2824380e7bb5ae20", 16) 477 | 478 | // Witness: 479 | witness := make([]*big.Int, 6) 480 | witness[0] = big.NewInt(0) // nonce 0 481 | witness[1] = big.NewInt(1) // fib 1 482 | witness[2] = big.NewInt(1) // fib 1 483 | witness[3] = big.NewInt(1) // nonce 1 484 | witness[4] = big.NewInt(1) // fib 1 485 | witness[5] = big.NewInt(2) // fib 2 486 | for i := 0; i < b.N; i++ { 487 | agregatedVerification(witness, proof, vk) 488 | } 489 | } 490 | 491 | func TestProofParsing(t *testing.T) { 492 | proof, err := ParseProofFromFile("proof.txt") 493 | if err != nil { 494 | t.Fatal(err) 495 | } 496 | fmt.Println(proof) 497 | } 498 | 499 | func TestLibsnarkVKParsing(t *testing.T) { 500 | vk := new(LibsnarkVerifyingKey) 501 | err := vk.ParseFromFile("verificationKey.txt") 502 | if err != nil { 503 | t.Fatal(err) 504 | } 505 | } 506 | -------------------------------------------------------------------------------- /vk_key.txt: -------------------------------------------------------------------------------- 1 | 0 16079412032852476990258825591264679631331086641573757470912228188849051502636 7154554874845586045149927577655003297337643472559877709531337813331805921051 19471972291456148688683070508884803059439381952852013850182031358063644432810 1963790416223335601038866259361326637053751132387518451676526570847036589276 2 | 0 14245896988822074634462877189130456453645710579220880326378295300544217334541 13145057583913966937374073982376382847213343027856136018006417526623251435925 3 | 0 5926497178701430581582431663681384587510904777308463665554909867697561222025 1544857099723274912817090501011348303844158495348607337613881826357197207688 11502311134490459469064580215639555161950935204195534309941838267462962410929 9948097954847577058749162145638816094533968428080838603100360878282278709867 4 | 0 17563346111346853090667203283886849915469165048726380263132531131059121005692 7547912234370500270675596898080315974422513360011391586462814413259951906964 3715838285100241290676957468359657017417496900909702310645821733913228783473 18118149082075541363310036067814227408441679092948264726863210080901087744299 5 | 0 18688701442342316385617000146604471849471541064776858016324645300386175854738 10552034469017071644547987544042703435686808879514382202819510234916746242863 6 | 0 14829736824661412286721588194197966062560004319025305195875624620681847230575 1937107413368490177600728321306586673978409241580367168594171458204455971668 21733770152362479855289626004658056066167491489866240880709202143594601270156 6562876899383021368439491171471945214608232886227553744021926926277088973725 7 | 0 1118469806595379233822423079189651007020279291918199756748730557081506092756 19640587598935461408365677500226419587272897449184392450479223437056504629259 18004283520468784513109579677512378022608587753559248454571976398271692010988 20772711795582926445892076206033765098325746708739351129881811180615649816708 8 | 0 6975235895751766156418510758419783669004114612510323598919843470949358895478 19713860420483891372662864693635323546870168856911532234853794838434542894737 9 | 0 10 | 0 11 | 0 12 | 13 | 14 | --------------------------------------------------------------------------------