├── .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 |
45 |
51 |
56 |
61 |
65 |
69 |
72 |
73 |
74 |
75 | Send Battleships Layout
76 |
77 |
78 |
79 |
80 |
81 |
82 | Verify
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 |
--------------------------------------------------------------------------------