├── .github
└── workflows
│ ├── lint.yml
│ └── test.yml
├── .gitignore
├── .golangci.yml
├── LICENSE
├── README.md
├── cli
├── .gitignore
└── cli.go
├── go.mod
├── go.sum
├── parsers
├── parsers.go
└── parsers_test.go
├── prover
├── arithmetic.go
├── arithmetic_test.go
├── gextra.go
├── gextra_test.go
├── ifft.go
├── prover.go
├── prover_test.go
└── tables.md
├── testdata
├── .gitignore
├── circuit10k
│ ├── circuit.circom
│ └── inputs.json
├── circuit1k
│ ├── circuit.circom
│ └── inputs.json
├── circuit20k
│ ├── circuit.circom
│ └── inputs.json
├── circuit5k
│ ├── circuit.circom
│ └── inputs.json
├── clean-gereated-files.sh
├── compile-circuits.sh
├── package-lock.json
└── package.json
├── types
└── types.go
└── verifier
├── verifier.go
└── verifier_test.go
/.github/workflows/lint.yml:
--------------------------------------------------------------------------------
1 | name: Lint
2 | on: [ push, pull_request ]
3 | jobs:
4 | lint:
5 | runs-on: ubuntu-latest
6 | steps:
7 | - name: Install Go
8 | uses: actions/setup-go@v1
9 | with:
10 | go-version: 1.16.x
11 | - name: Checkout code
12 | uses: actions/checkout@v2
13 | - name: Lint
14 | run: |
15 | curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.30.0
16 | $(go env GOPATH)/bin/golangci-lint run --timeout=5m -c .golangci.yml
17 |
--------------------------------------------------------------------------------
/.github/workflows/test.yml:
--------------------------------------------------------------------------------
1 |
2 | name: Test
3 | on: [push, pull_request]
4 | jobs:
5 | test:
6 | # matrix strategy from: https://github.com/mvdan/github-actions-golang/blob/master/.github/workflows/test.yml
7 | strategy:
8 | matrix:
9 | go-version: [1.16.x]
10 | platform: [ubuntu-latest]
11 | runs-on: ${{ matrix.platform }}
12 | steps:
13 | - name: Install Go
14 | uses: actions/setup-go@v1
15 | with:
16 | go-version: ${{ matrix.go-version }}
17 | - name: Install Nodejs
18 | uses: actions/setup-node@v1
19 | with:
20 | node-version: '10.x'
21 | - name: Checkout code
22 | uses: actions/checkout@v2
23 | - name: Compile circuits and execute Go tests
24 | run: |
25 | cd testdata && sh ./compile-circuits.sh && cd ..
26 | go run cli/cli.go -prove -pk=testdata/circuit1k/proving_key.json -witness=testdata/circuit1k/witness.json -proof=testdata/circuit1k/proof.json -public=testdata/circuit1k/public.json
27 | go run cli/cli.go -prove -pk=testdata/circuit5k/proving_key.json -witness=testdata/circuit5k/witness.json -proof=testdata/circuit5k/proof.json -public=testdata/circuit5k/public.json
28 | go test ./...
29 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | testdata/*/*.json
2 | testdata/*/*.wasm
3 | testdata/*/*.cpp
4 | testdata/*/*.sym
5 | testdata/*/*.r1cs
6 | testdata/*/*.sol
7 | testdata/*/*.bin
8 | !testdata/*/inputs.json
9 | cli/*.json
10 |
--------------------------------------------------------------------------------
/.golangci.yml:
--------------------------------------------------------------------------------
1 | issues:
2 | max-same-issues: 0
3 | exclude-use-default: false
4 | linters:
5 | enable:
6 | - whitespace
7 | - gosec
8 | - gci
9 | - misspell
10 | - gomnd
11 | - gofmt
12 | - goimports
13 | - lll
14 | - golint
15 | - gocyclo
16 | linters-settings:
17 | lll:
18 | line-length: 100
19 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | GNU GENERAL PUBLIC LICENSE
2 | Version 3, 29 June 2007
3 |
4 | Copyright (C) 2007 Free Software Foundation, Inc.
5 | Copyright (C) 2021 Argon Labs AG
6 | Everyone is permitted to copy and distribute verbatim copies
7 | of this license document, but changing it is not allowed.
8 |
9 | Preamble
10 |
11 | The GNU General Public License is a free, copyleft license for
12 | software and other kinds of works.
13 |
14 | The licenses for most software and other practical works are designed
15 | to take away your freedom to share and change the works. By contrast,
16 | the GNU General Public License is intended to guarantee your freedom to
17 | share and change all versions of a program--to make sure it remains free
18 | software for all its users. We, the Free Software Foundation, use the
19 | GNU General Public License for most of our software; it applies also to
20 | any other work released this way by its authors. You can apply it to
21 | your programs, too.
22 |
23 | When we speak of free software, we are referring to freedom, not
24 | price. Our General Public Licenses are designed to make sure that you
25 | have the freedom to distribute copies of free software (and charge for
26 | them if you wish), that you receive source code or can get it if you
27 | want it, that you can change the software or use pieces of it in new
28 | free programs, and that you know you can do these things.
29 |
30 | To protect your rights, we need to prevent others from denying you
31 | these rights or asking you to surrender the rights. Therefore, you have
32 | certain responsibilities if you distribute copies of the software, or if
33 | you modify it: responsibilities to respect the freedom of others.
34 |
35 | For example, if you distribute copies of such a program, whether
36 | gratis or for a fee, you must pass on to the recipients the same
37 | freedoms that you received. You must make sure that they, too, receive
38 | or can get the source code. And you must show them these terms so they
39 | know their rights.
40 |
41 | Developers that use the GNU GPL protect your rights with two steps:
42 | (1) assert copyright on the software, and (2) offer you this License
43 | giving you legal permission to copy, distribute and/or modify it.
44 |
45 | For the developers' and authors' protection, the GPL clearly explains
46 | that there is no warranty for this free software. For both users' and
47 | authors' sake, the GPL requires that modified versions be marked as
48 | changed, so that their problems will not be attributed erroneously to
49 | authors of previous versions.
50 |
51 | Some devices are designed to deny users access to install or run
52 | modified versions of the software inside them, although the manufacturer
53 | can do so. This is fundamentally incompatible with the aim of
54 | protecting users' freedom to change the software. The systematic
55 | pattern of such abuse occurs in the area of products for individuals to
56 | use, which is precisely where it is most unacceptable. Therefore, we
57 | have designed this version of the GPL to prohibit the practice for those
58 | products. If such problems arise substantially in other domains, we
59 | stand ready to extend this provision to those domains in future versions
60 | of the GPL, as needed to protect the freedom of users.
61 |
62 | Finally, every program is threatened constantly by software patents.
63 | States should not allow patents to restrict development and use of
64 | software on general-purpose computers, but in those that do, we wish to
65 | avoid the special danger that patents applied to a free program could
66 | make it effectively proprietary. To prevent this, the GPL assures that
67 | patents cannot be used to render the program non-free.
68 |
69 | The precise terms and conditions for copying, distribution and
70 | modification follow.
71 |
72 | TERMS AND CONDITIONS
73 |
74 | 0. Definitions.
75 |
76 | "This License" refers to version 3 of the GNU General Public License.
77 |
78 | "Copyright" also means copyright-like laws that apply to other kinds of
79 | works, such as semiconductor masks.
80 |
81 | "The Program" refers to any copyrightable work licensed under this
82 | License. Each licensee is addressed as "you". "Licensees" and
83 | "recipients" may be individuals or organizations.
84 |
85 | To "modify" a work means to copy from or adapt all or part of the work
86 | in a fashion requiring copyright permission, other than the making of an
87 | exact copy. The resulting work is called a "modified version" of the
88 | earlier work or a work "based on" the earlier work.
89 |
90 | A "covered work" means either the unmodified Program or a work based
91 | on the Program.
92 |
93 | To "propagate" a work means to do anything with it that, without
94 | permission, would make you directly or secondarily liable for
95 | infringement under applicable copyright law, except executing it on a
96 | computer or modifying a private copy. Propagation includes copying,
97 | distribution (with or without modification), making available to the
98 | public, and in some countries other activities as well.
99 |
100 | To "convey" a work means any kind of propagation that enables other
101 | parties to make or receive copies. Mere interaction with a user through
102 | a computer network, with no transfer of a copy, is not conveying.
103 |
104 | An interactive user interface displays "Appropriate Legal Notices"
105 | to the extent that it includes a convenient and prominently visible
106 | feature that (1) displays an appropriate copyright notice, and (2)
107 | tells the user that there is no warranty for the work (except to the
108 | extent that warranties are provided), that licensees may convey the
109 | work under this License, and how to view a copy of this License. If
110 | the interface presents a list of user commands or options, such as a
111 | menu, a prominent item in the list meets this criterion.
112 |
113 | 1. Source Code.
114 |
115 | The "source code" for a work means the preferred form of the work
116 | for making modifications to it. "Object code" means any non-source
117 | form of a work.
118 |
119 | A "Standard Interface" means an interface that either is an official
120 | standard defined by a recognized standards body, or, in the case of
121 | interfaces specified for a particular programming language, one that
122 | is widely used among developers working in that language.
123 |
124 | The "System Libraries" of an executable work include anything, other
125 | than the work as a whole, that (a) is included in the normal form of
126 | packaging a Major Component, but which is not part of that Major
127 | Component, and (b) serves only to enable use of the work with that
128 | Major Component, or to implement a Standard Interface for which an
129 | implementation is available to the public in source code form. A
130 | "Major Component", in this context, means a major essential component
131 | (kernel, window system, and so on) of the specific operating system
132 | (if any) on which the executable work runs, or a compiler used to
133 | produce the work, or an object code interpreter used to run it.
134 |
135 | The "Corresponding Source" for a work in object code form means all
136 | the source code needed to generate, install, and (for an executable
137 | work) run the object code and to modify the work, including scripts to
138 | control those activities. However, it does not include the work's
139 | System Libraries, or general-purpose tools or generally available free
140 | programs which are used unmodified in performing those activities but
141 | which are not part of the work. For example, Corresponding Source
142 | includes interface definition files associated with source files for
143 | the work, and the source code for shared libraries and dynamically
144 | linked subprograms that the work is specifically designed to require,
145 | such as by intimate data communication or control flow between those
146 | subprograms and other parts of the work.
147 |
148 | The Corresponding Source need not include anything that users
149 | can regenerate automatically from other parts of the Corresponding
150 | Source.
151 |
152 | The Corresponding Source for a work in source code form is that
153 | same work.
154 |
155 | 2. Basic Permissions.
156 |
157 | All rights granted under this License are granted for the term of
158 | copyright on the Program, and are irrevocable provided the stated
159 | conditions are met. This License explicitly affirms your unlimited
160 | permission to run the unmodified Program. The output from running a
161 | covered work is covered by this License only if the output, given its
162 | content, constitutes a covered work. This License acknowledges your
163 | rights of fair use or other equivalent, as provided by copyright law.
164 |
165 | You may make, run and propagate covered works that you do not
166 | convey, without conditions so long as your license otherwise remains
167 | in force. You may convey covered works to others for the sole purpose
168 | of having them make modifications exclusively for you, or provide you
169 | with facilities for running those works, provided that you comply with
170 | the terms of this License in conveying all material for which you do
171 | not control copyright. Those thus making or running the covered works
172 | for you must do so exclusively on your behalf, under your direction
173 | and control, on terms that prohibit them from making any copies of
174 | your copyrighted material outside their relationship with you.
175 |
176 | Conveying under any other circumstances is permitted solely under
177 | the conditions stated below. Sublicensing is not allowed; section 10
178 | makes it unnecessary.
179 |
180 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
181 |
182 | No covered work shall be deemed part of an effective technological
183 | measure under any applicable law fulfilling obligations under article
184 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or
185 | similar laws prohibiting or restricting circumvention of such
186 | measures.
187 |
188 | When you convey a covered work, you waive any legal power to forbid
189 | circumvention of technological measures to the extent such circumvention
190 | is effected by exercising rights under this License with respect to
191 | the covered work, and you disclaim any intention to limit operation or
192 | modification of the work as a means of enforcing, against the work's
193 | users, your or third parties' legal rights to forbid circumvention of
194 | technological measures.
195 |
196 | 4. Conveying Verbatim Copies.
197 |
198 | You may convey verbatim copies of the Program's source code as you
199 | receive it, in any medium, provided that you conspicuously and
200 | appropriately publish on each copy an appropriate copyright notice;
201 | keep intact all notices stating that this License and any
202 | non-permissive terms added in accord with section 7 apply to the code;
203 | keep intact all notices of the absence of any warranty; and give all
204 | recipients a copy of this License along with the Program.
205 |
206 | You may charge any price or no price for each copy that you convey,
207 | and you may offer support or warranty protection for a fee.
208 |
209 | 5. Conveying Modified Source Versions.
210 |
211 | You may convey a work based on the Program, or the modifications to
212 | produce it from the Program, in the form of source code under the
213 | terms of section 4, provided that you also meet all of these conditions:
214 |
215 | a) The work must carry prominent notices stating that you modified
216 | it, and giving a relevant date.
217 |
218 | b) The work must carry prominent notices stating that it is
219 | released under this License and any conditions added under section
220 | 7. This requirement modifies the requirement in section 4 to
221 | "keep intact all notices".
222 |
223 | c) You must license the entire work, as a whole, under this
224 | License to anyone who comes into possession of a copy. This
225 | License will therefore apply, along with any applicable section 7
226 | additional terms, to the whole of the work, and all its parts,
227 | regardless of how they are packaged. This License gives no
228 | permission to license the work in any other way, but it does not
229 | invalidate such permission if you have separately received it.
230 |
231 | d) If the work has interactive user interfaces, each must display
232 | Appropriate Legal Notices; however, if the Program has interactive
233 | interfaces that do not display Appropriate Legal Notices, your
234 | work need not make them do so.
235 |
236 | A compilation of a covered work with other separate and independent
237 | works, which are not by their nature extensions of the covered work,
238 | and which are not combined with it such as to form a larger program,
239 | in or on a volume of a storage or distribution medium, is called an
240 | "aggregate" if the compilation and its resulting copyright are not
241 | used to limit the access or legal rights of the compilation's users
242 | beyond what the individual works permit. Inclusion of a covered work
243 | in an aggregate does not cause this License to apply to the other
244 | parts of the aggregate.
245 |
246 | 6. Conveying Non-Source Forms.
247 |
248 | You may convey a covered work in object code form under the terms
249 | of sections 4 and 5, provided that you also convey the
250 | machine-readable Corresponding Source under the terms of this License,
251 | in one of these ways:
252 |
253 | a) Convey the object code in, or embodied in, a physical product
254 | (including a physical distribution medium), accompanied by the
255 | Corresponding Source fixed on a durable physical medium
256 | customarily used for software interchange.
257 |
258 | b) Convey the object code in, or embodied in, a physical product
259 | (including a physical distribution medium), accompanied by a
260 | written offer, valid for at least three years and valid for as
261 | long as you offer spare parts or customer support for that product
262 | model, to give anyone who possesses the object code either (1) a
263 | copy of the Corresponding Source for all the software in the
264 | product that is covered by this License, on a durable physical
265 | medium customarily used for software interchange, for a price no
266 | more than your reasonable cost of physically performing this
267 | conveying of source, or (2) access to copy the
268 | Corresponding Source from a network server at no charge.
269 |
270 | c) Convey individual copies of the object code with a copy of the
271 | written offer to provide the Corresponding Source. This
272 | alternative is allowed only occasionally and noncommercially, and
273 | only if you received the object code with such an offer, in accord
274 | with subsection 6b.
275 |
276 | d) Convey the object code by offering access from a designated
277 | place (gratis or for a charge), and offer equivalent access to the
278 | Corresponding Source in the same way through the same place at no
279 | further charge. You need not require recipients to copy the
280 | Corresponding Source along with the object code. If the place to
281 | copy the object code is a network server, the Corresponding Source
282 | may be on a different server (operated by you or a third party)
283 | that supports equivalent copying facilities, provided you maintain
284 | clear directions next to the object code saying where to find the
285 | Corresponding Source. Regardless of what server hosts the
286 | Corresponding Source, you remain obligated to ensure that it is
287 | available for as long as needed to satisfy these requirements.
288 |
289 | e) Convey the object code using peer-to-peer transmission, provided
290 | you inform other peers where the object code and Corresponding
291 | Source of the work are being offered to the general public at no
292 | charge under subsection 6d.
293 |
294 | A separable portion of the object code, whose source code is excluded
295 | from the Corresponding Source as a System Library, need not be
296 | included in conveying the object code work.
297 |
298 | A "User Product" is either (1) a "consumer product", which means any
299 | tangible personal property which is normally used for personal, family,
300 | or household purposes, or (2) anything designed or sold for incorporation
301 | into a dwelling. In determining whether a product is a consumer product,
302 | doubtful cases shall be resolved in favor of coverage. For a particular
303 | product received by a particular user, "normally used" refers to a
304 | typical or common use of that class of product, regardless of the status
305 | of the particular user or of the way in which the particular user
306 | actually uses, or expects or is expected to use, the product. A product
307 | is a consumer product regardless of whether the product has substantial
308 | commercial, industrial or non-consumer uses, unless such uses represent
309 | the only significant mode of use of the product.
310 |
311 | "Installation Information" for a User Product means any methods,
312 | procedures, authorization keys, or other information required to install
313 | and execute modified versions of a covered work in that User Product from
314 | a modified version of its Corresponding Source. The information must
315 | suffice to ensure that the continued functioning of the modified object
316 | code is in no case prevented or interfered with solely because
317 | modification has been made.
318 |
319 | If you convey an object code work under this section in, or with, or
320 | specifically for use in, a User Product, and the conveying occurs as
321 | part of a transaction in which the right of possession and use of the
322 | User Product is transferred to the recipient in perpetuity or for a
323 | fixed term (regardless of how the transaction is characterized), the
324 | Corresponding Source conveyed under this section must be accompanied
325 | by the Installation Information. But this requirement does not apply
326 | if neither you nor any third party retains the ability to install
327 | modified object code on the User Product (for example, the work has
328 | been installed in ROM).
329 |
330 | The requirement to provide Installation Information does not include a
331 | requirement to continue to provide support service, warranty, or updates
332 | for a work that has been modified or installed by the recipient, or for
333 | the User Product in which it has been modified or installed. Access to a
334 | network may be denied when the modification itself materially and
335 | adversely affects the operation of the network or violates the rules and
336 | protocols for communication across the network.
337 |
338 | Corresponding Source conveyed, and Installation Information provided,
339 | in accord with this section must be in a format that is publicly
340 | documented (and with an implementation available to the public in
341 | source code form), and must require no special password or key for
342 | unpacking, reading or copying.
343 |
344 | 7. Additional Terms.
345 |
346 | "Additional permissions" are terms that supplement the terms of this
347 | License by making exceptions from one or more of its conditions.
348 | Additional permissions that are applicable to the entire Program shall
349 | be treated as though they were included in this License, to the extent
350 | that they are valid under applicable law. If additional permissions
351 | apply only to part of the Program, that part may be used separately
352 | under those permissions, but the entire Program remains governed by
353 | this License without regard to the additional permissions.
354 |
355 | When you convey a copy of a covered work, you may at your option
356 | remove any additional permissions from that copy, or from any part of
357 | it. (Additional permissions may be written to require their own
358 | removal in certain cases when you modify the work.) You may place
359 | additional permissions on material, added by you to a covered work,
360 | for which you have or can give appropriate copyright permission.
361 |
362 | Notwithstanding any other provision of this License, for material you
363 | add to a covered work, you may (if authorized by the copyright holders of
364 | that material) supplement the terms of this License with terms:
365 |
366 | a) Disclaiming warranty or limiting liability differently from the
367 | terms of sections 15 and 16 of this License; or
368 |
369 | b) Requiring preservation of specified reasonable legal notices or
370 | author attributions in that material or in the Appropriate Legal
371 | Notices displayed by works containing it; or
372 |
373 | c) Prohibiting misrepresentation of the origin of that material, or
374 | requiring that modified versions of such material be marked in
375 | reasonable ways as different from the original version; or
376 |
377 | d) Limiting the use for publicity purposes of names of licensors or
378 | authors of the material; or
379 |
380 | e) Declining to grant rights under trademark law for use of some
381 | trade names, trademarks, or service marks; or
382 |
383 | f) Requiring indemnification of licensors and authors of that
384 | material by anyone who conveys the material (or modified versions of
385 | it) with contractual assumptions of liability to the recipient, for
386 | any liability that these contractual assumptions directly impose on
387 | those licensors and authors.
388 |
389 | All other non-permissive additional terms are considered "further
390 | restrictions" within the meaning of section 10. If the Program as you
391 | received it, or any part of it, contains a notice stating that it is
392 | governed by this License along with a term that is a further
393 | restriction, you may remove that term. If a license document contains
394 | a further restriction but permits relicensing or conveying under this
395 | License, you may add to a covered work material governed by the terms
396 | of that license document, provided that the further restriction does
397 | not survive such relicensing or conveying.
398 |
399 | If you add terms to a covered work in accord with this section, you
400 | must place, in the relevant source files, a statement of the
401 | additional terms that apply to those files, or a notice indicating
402 | where to find the applicable terms.
403 |
404 | Additional terms, permissive or non-permissive, may be stated in the
405 | form of a separately written license, or stated as exceptions;
406 | the above requirements apply either way.
407 |
408 | 8. Termination.
409 |
410 | You may not propagate or modify a covered work except as expressly
411 | provided under this License. Any attempt otherwise to propagate or
412 | modify it is void, and will automatically terminate your rights under
413 | this License (including any patent licenses granted under the third
414 | paragraph of section 11).
415 |
416 | However, if you cease all violation of this License, then your
417 | license from a particular copyright holder is reinstated (a)
418 | provisionally, unless and until the copyright holder explicitly and
419 | finally terminates your license, and (b) permanently, if the copyright
420 | holder fails to notify you of the violation by some reasonable means
421 | prior to 60 days after the cessation.
422 |
423 | Moreover, your license from a particular copyright holder is
424 | reinstated permanently if the copyright holder notifies you of the
425 | violation by some reasonable means, this is the first time you have
426 | received notice of violation of this License (for any work) from that
427 | copyright holder, and you cure the violation prior to 30 days after
428 | your receipt of the notice.
429 |
430 | Termination of your rights under this section does not terminate the
431 | licenses of parties who have received copies or rights from you under
432 | this License. If your rights have been terminated and not permanently
433 | reinstated, you do not qualify to receive new licenses for the same
434 | material under section 10.
435 |
436 | 9. Acceptance Not Required for Having Copies.
437 |
438 | You are not required to accept this License in order to receive or
439 | run a copy of the Program. Ancillary propagation of a covered work
440 | occurring solely as a consequence of using peer-to-peer transmission
441 | to receive a copy likewise does not require acceptance. However,
442 | nothing other than this License grants you permission to propagate or
443 | modify any covered work. These actions infringe copyright if you do
444 | not accept this License. Therefore, by modifying or propagating a
445 | covered work, you indicate your acceptance of this License to do so.
446 |
447 | 10. Automatic Licensing of Downstream Recipients.
448 |
449 | Each time you convey a covered work, the recipient automatically
450 | receives a license from the original licensors, to run, modify and
451 | propagate that work, subject to this License. You are not responsible
452 | for enforcing compliance by third parties with this License.
453 |
454 | An "entity transaction" is a transaction transferring control of an
455 | organization, or substantially all assets of one, or subdividing an
456 | organization, or merging organizations. If propagation of a covered
457 | work results from an entity transaction, each party to that
458 | transaction who receives a copy of the work also receives whatever
459 | licenses to the work the party's predecessor in interest had or could
460 | give under the previous paragraph, plus a right to possession of the
461 | Corresponding Source of the work from the predecessor in interest, if
462 | the predecessor has it or can get it with reasonable efforts.
463 |
464 | You may not impose any further restrictions on the exercise of the
465 | rights granted or affirmed under this License. For example, you may
466 | not impose a license fee, royalty, or other charge for exercise of
467 | rights granted under this License, and you may not initiate litigation
468 | (including a cross-claim or counterclaim in a lawsuit) alleging that
469 | any patent claim is infringed by making, using, selling, offering for
470 | sale, or importing the Program or any portion of it.
471 |
472 | 11. Patents.
473 |
474 | A "contributor" is a copyright holder who authorizes use under this
475 | License of the Program or a work on which the Program is based. The
476 | work thus licensed is called the contributor's "contributor version".
477 |
478 | A contributor's "essential patent claims" are all patent claims
479 | owned or controlled by the contributor, whether already acquired or
480 | hereafter acquired, that would be infringed by some manner, permitted
481 | by this License, of making, using, or selling its contributor version,
482 | but do not include claims that would be infringed only as a
483 | consequence of further modification of the contributor version. For
484 | purposes of this definition, "control" includes the right to grant
485 | patent sublicenses in a manner consistent with the requirements of
486 | this License.
487 |
488 | Each contributor grants you a non-exclusive, worldwide, royalty-free
489 | patent license under the contributor's essential patent claims, to
490 | make, use, sell, offer for sale, import and otherwise run, modify and
491 | propagate the contents of its contributor version.
492 |
493 | In the following three paragraphs, a "patent license" is any express
494 | agreement or commitment, however denominated, not to enforce a patent
495 | (such as an express permission to practice a patent or covenant not to
496 | sue for patent infringement). To "grant" such a patent license to a
497 | party means to make such an agreement or commitment not to enforce a
498 | patent against the party.
499 |
500 | If you convey a covered work, knowingly relying on a patent license,
501 | and the Corresponding Source of the work is not available for anyone
502 | to copy, free of charge and under the terms of this License, through a
503 | publicly available network server or other readily accessible means,
504 | then you must either (1) cause the Corresponding Source to be so
505 | available, or (2) arrange to deprive yourself of the benefit of the
506 | patent license for this particular work, or (3) arrange, in a manner
507 | consistent with the requirements of this License, to extend the patent
508 | license to downstream recipients. "Knowingly relying" means you have
509 | actual knowledge that, but for the patent license, your conveying the
510 | covered work in a country, or your recipient's use of the covered work
511 | in a country, would infringe one or more identifiable patents in that
512 | country that you have reason to believe are valid.
513 |
514 | If, pursuant to or in connection with a single transaction or
515 | arrangement, you convey, or propagate by procuring conveyance of, a
516 | covered work, and grant a patent license to some of the parties
517 | receiving the covered work authorizing them to use, propagate, modify
518 | or convey a specific copy of the covered work, then the patent license
519 | you grant is automatically extended to all recipients of the covered
520 | work and works based on it.
521 |
522 | A patent license is "discriminatory" if it does not include within
523 | the scope of its coverage, prohibits the exercise of, or is
524 | conditioned on the non-exercise of one or more of the rights that are
525 | specifically granted under this License. You may not convey a covered
526 | work if you are a party to an arrangement with a third party that is
527 | in the business of distributing software, under which you make payment
528 | to the third party based on the extent of your activity of conveying
529 | the work, and under which the third party grants, to any of the
530 | parties who would receive the covered work from you, a discriminatory
531 | patent license (a) in connection with copies of the covered work
532 | conveyed by you (or copies made from those copies), or (b) primarily
533 | for and in connection with specific products or compilations that
534 | contain the covered work, unless you entered into that arrangement,
535 | or that patent license was granted, prior to 28 March 2007.
536 |
537 | Nothing in this License shall be construed as excluding or limiting
538 | any implied license or other defenses to infringement that may
539 | otherwise be available to you under applicable patent law.
540 |
541 | 12. No Surrender of Others' Freedom.
542 |
543 | If conditions are imposed on you (whether by court order, agreement or
544 | otherwise) that contradict the conditions of this License, they do not
545 | excuse you from the conditions of this License. If you cannot convey a
546 | covered work so as to satisfy simultaneously your obligations under this
547 | License and any other pertinent obligations, then as a consequence you may
548 | not convey it at all. For example, if you agree to terms that obligate you
549 | to collect a royalty for further conveying from those to whom you convey
550 | the Program, the only way you could satisfy both those terms and this
551 | License would be to refrain entirely from conveying the Program.
552 |
553 | 13. Use with the GNU Affero General Public License.
554 |
555 | Notwithstanding any other provision of this License, you have
556 | permission to link or combine any covered work with a work licensed
557 | under version 3 of the GNU Affero General Public License into a single
558 | combined work, and to convey the resulting work. The terms of this
559 | License will continue to apply to the part which is the covered work,
560 | but the special requirements of the GNU Affero General Public License,
561 | section 13, concerning interaction through a network will apply to the
562 | combination as such.
563 |
564 | 14. Revised Versions of this License.
565 |
566 | The Free Software Foundation may publish revised and/or new versions of
567 | the GNU General Public License from time to time. Such new versions will
568 | be similar in spirit to the present version, but may differ in detail to
569 | address new problems or concerns.
570 |
571 | Each version is given a distinguishing version number. If the
572 | Program specifies that a certain numbered version of the GNU General
573 | Public License "or any later version" applies to it, you have the
574 | option of following the terms and conditions either of that numbered
575 | version or of any later version published by the Free Software
576 | Foundation. If the Program does not specify a version number of the
577 | GNU General Public License, you may choose any version ever published
578 | by the Free Software Foundation.
579 |
580 | If the Program specifies that a proxy can decide which future
581 | versions of the GNU General Public License can be used, that proxy's
582 | public statement of acceptance of a version permanently authorizes you
583 | to choose that version for the Program.
584 |
585 | Later license versions may give you additional or different
586 | permissions. However, no additional obligations are imposed on any
587 | author or copyright holder as a result of your choosing to follow a
588 | later version.
589 |
590 | 15. Disclaimer of Warranty.
591 |
592 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
593 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
594 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
595 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
596 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
597 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
598 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
599 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
600 |
601 | 16. Limitation of Liability.
602 |
603 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
604 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
605 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
606 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
607 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
608 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
609 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
610 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
611 | SUCH DAMAGES.
612 |
613 | 17. Interpretation of Sections 15 and 16.
614 |
615 | If the disclaimer of warranty and limitation of liability provided
616 | above cannot be given local legal effect according to their terms,
617 | reviewing courts shall apply local law that most closely approximates
618 | an absolute waiver of all civil liability in connection with the
619 | Program, unless a warranty or assumption of liability accompanies a
620 | copy of the Program in return for a fee.
621 |
622 | END OF TERMS AND CONDITIONS
623 |
624 | How to Apply These Terms to Your New Programs
625 |
626 | If you develop a new program, and you want it to be of the greatest
627 | possible use to the public, the best way to achieve this is to make it
628 | free software which everyone can redistribute and change under these terms.
629 |
630 | To do so, attach the following notices to the program. It is safest
631 | to attach them to the start of each source file to most effectively
632 | state the exclusion of warranty; and each file should have at least
633 | the "copyright" line and a pointer to where the full notice is found.
634 |
635 |
636 | Copyright (C)
637 |
638 | This program is free software: you can redistribute it and/or modify
639 | it under the terms of the GNU General Public License as published by
640 | the Free Software Foundation, either version 3 of the License, or
641 | (at your option) any later version.
642 |
643 | This program is distributed in the hope that it will be useful,
644 | but WITHOUT ANY WARRANTY; without even the implied warranty of
645 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
646 | GNU General Public License for more details.
647 |
648 | You should have received a copy of the GNU General Public License
649 | along with this program. If not, see .
650 |
651 | Also add information on how to contact you by electronic and paper mail.
652 |
653 | If the program does terminal interaction, make it output a short
654 | notice like this when it starts in an interactive mode:
655 |
656 | Copyright (C)
657 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
658 | This is free software, and you are welcome to redistribute it
659 | under certain conditions; type `show c' for details.
660 |
661 | The hypothetical commands `show w' and `show c' should show the appropriate
662 | parts of the General Public License. Of course, your program's commands
663 | might be different; for a GUI interface, you would use an "about box".
664 |
665 | You should also get your employer (if you work as a programmer) or school,
666 | if any, to sign a "copyright disclaimer" for the program, if necessary.
667 | For more information on this, and how to apply and follow the GNU GPL, see
668 | .
669 |
670 | The GNU General Public License does not permit incorporating your program
671 | into proprietary programs. If your program is a subroutine library, you
672 | may consider it more useful to permit linking proprietary applications with
673 | the library. If this is what you want to do, use the GNU Lesser General
674 | Public License instead of this License. But first, please read
675 | .
676 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # go-snark [](https://godoc.org/github.com/vocdoni/go-snark) [](https://goreportcard.com/report/github.com/vocdoni/go-snark) [](https://github.com/vocdoni/go-snark/actions?query=workflow%3ATest)
2 |
3 | Go implementation of the [Groth16 protocol](https://eprint.iacr.org/2016/260.pdf) zkSNARK prover & verifier compatible with:
4 |
5 | - [circom](https://github.com/iden3/circom) (WIP)
6 | - [bellman](https://github.com/zkcrypto/bellman) (TODO)
7 |
8 |
9 | Using [bn256](https://github.com/ethereum/go-ethereum/tree/master/crypto/bn256/cloudflare) (used by [go-ethereum](https://github.com/ethereum/go-ethereum)) for the Pairing curve operations.
10 |
11 | ### Usage
12 |
13 | - Generate Proof
14 |
15 | ```go
16 | import (
17 | "github.com/vocdoni/go-snark/parsers"
18 | "github.com/vocdoni/go-snark/prover"
19 | "github.com/vocdoni/go-snark/verifier"
20 | )
21 |
22 | [...]
23 |
24 | // read ProvingKey & Witness files
25 | provingKeyJSON, _ := ioutil.ReadFile("../testdata/circuit1k/proving_key.json")
26 | witnessJSON, _ := ioutil.ReadFile("../testdata/circuit1k/witness.json")
27 |
28 | // parse Proving Key
29 | pk, _ := parsers.ParsePk(provingKeyJSON)
30 |
31 | // parse Witness
32 | w, _ := parsers.ParseWitness(witnessJSON)
33 |
34 | // generate the proof
35 | proof, pubSignals, _ := prover.GenerateProof(pk, w)
36 |
37 | // print proof & publicSignals
38 | proofStr, _ := parsers.ProofToJSON(proof)
39 | publicStr, _ := json.Marshal(parsers.ArrayBigIntToString(pubSignals))
40 | fmt.Println(proofStr)
41 | fmt.Println(publicStr)
42 | ```
43 |
44 | - Verify Proof
45 |
46 | ```go
47 | // read proof & verificationKey & publicSignals
48 | proofJSON, _ := ioutil.ReadFile("../testdata/circuit1k/proof.json")
49 | vkJSON, _ := ioutil.ReadFile("../testdata/circuit1k/verification_key.json")
50 | publicJSON, _ := ioutil.ReadFile("../testdata/circuit1k/public.json")
51 |
52 | // parse proof & verificationKey & publicSignals
53 | public, _ := parsers.ParsePublicSignals(publicJSON)
54 | proof, _ := parsers.ParseProof(proofJSON)
55 | vk, _ := parsers.ParseVk(vkJSON)
56 |
57 | // verify the proof with the given verificationKey & publicSignals
58 | v := verifier.Verify(vk, proof, public)
59 | fmt.Println(v)
60 | ```
61 |
62 | ### CLI
63 |
64 | From the `cli` directory:
65 |
66 | - Show options
67 |
68 | ```
69 | > go run cli.go -help
70 | go-snark
71 | v0.0.1
72 | Usage of go-snark:
73 | -proof string
74 | proof path (default "proof.json")
75 | -prove
76 | prover mode
77 | -provingkey string
78 | provingKey path (default "proving_key.json")
79 | -public string
80 | public signals path (default "public.json")
81 | -verificationkey string
82 | verificationKey path (default "verification_key.json")
83 | -verify
84 | verifier mode
85 | -witness string
86 | witness path (default "witness.json")
87 | ```
88 |
89 | - Prove
90 |
91 | ```
92 | > go run cli.go -prove -provingkey=../testdata/circuit5k/proving_key.json -witness=../testdata/circuit5k/witness.json
93 | ```
94 |
95 | - Verify
96 |
97 | ```
98 | > go run cli.go -verify -verificationkey=../testdata/circuit5k/verification_key.json
99 | ```
100 |
--------------------------------------------------------------------------------
/cli/.gitignore:
--------------------------------------------------------------------------------
1 | cli
2 |
--------------------------------------------------------------------------------
/cli/cli.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "encoding/json"
5 | "flag"
6 | "fmt"
7 | "io/ioutil"
8 | "os"
9 | "time"
10 |
11 | "github.com/vocdoni/go-snark/parsers"
12 | "github.com/vocdoni/go-snark/prover"
13 | "github.com/vocdoni/go-snark/verifier"
14 | )
15 |
16 | const version = "v0.0.1"
17 |
18 | func main() {
19 | fmt.Println("go-snark")
20 | fmt.Println(" ", version)
21 |
22 | prove := flag.Bool("prove", false, "prover mode")
23 | verify := flag.Bool("verify", false, "verifier mode")
24 | convert := flag.Bool("convert", false, "convert mode, to convert between"+
25 | " proving_key.json to proving_key.go.bin")
26 |
27 | provingKeyPath := flag.String("pk", "proving_key.json", "provingKey path")
28 | witnessPath := flag.String("witness", "witness.json", "witness path")
29 | proofPath := flag.String("proof", "proof.json", "proof path")
30 | verificationKeyPath := flag.String("vk", "verification_key.json", "verificationKey path")
31 | publicPath := flag.String("public", "public.json", "public signals path")
32 | provingKeyBinPath := flag.String("pkbin", "proving_key.go.bin", "provingKey Bin path")
33 |
34 | flag.Parse()
35 |
36 | if *prove {
37 | err := cmdProve(*provingKeyPath, *witnessPath, *proofPath, *publicPath)
38 | if err != nil {
39 | fmt.Println("Error:", err)
40 | }
41 | os.Exit(0)
42 | } else if *verify {
43 | err := cmdVerify(*proofPath, *verificationKeyPath, *publicPath)
44 | if err != nil {
45 | fmt.Println("Error:", err)
46 | }
47 | os.Exit(0)
48 | } else if *convert {
49 | err := cmdConvert(*provingKeyPath, *provingKeyBinPath)
50 | if err != nil {
51 | fmt.Println("Error:", err)
52 | }
53 | os.Exit(0)
54 | }
55 | flag.PrintDefaults()
56 | }
57 |
58 | func cmdProve(provingKeyPath, witnessPath, proofPath, publicPath string) error {
59 | fmt.Println("zkSNARK Groth16 prover")
60 |
61 | fmt.Println("Reading proving key file:", provingKeyPath)
62 | provingKeyJSON, err := ioutil.ReadFile(provingKeyPath) //nolint:gosec
63 | if err != nil {
64 | return err
65 | }
66 | pk, err := parsers.ParsePk(provingKeyJSON)
67 | if err != nil {
68 | return err
69 | }
70 |
71 | fmt.Println("Reading witness file:", witnessPath)
72 | witnessJSON, err := ioutil.ReadFile(witnessPath) //nolint:gosec
73 | if err != nil {
74 | return err
75 | }
76 | w, err := parsers.ParseWitness(witnessJSON)
77 | if err != nil {
78 | return err
79 | }
80 |
81 | fmt.Println("Generating the proof")
82 | beforeT := time.Now()
83 | proof, pubSignals, err := prover.GenerateProof(pk, w)
84 | if err != nil {
85 | return err
86 | }
87 | fmt.Println("proof generation time elapsed:", time.Since(beforeT))
88 |
89 | proofStr, err := parsers.ProofToJSON(proof)
90 | if err != nil {
91 | return err
92 | }
93 |
94 | // write output
95 | err = ioutil.WriteFile(proofPath, proofStr, 0600)
96 | if err != nil {
97 | return err
98 | }
99 | publicStr, err := json.Marshal(parsers.ArrayBigIntToString(pubSignals))
100 | if err != nil {
101 | return err
102 | }
103 | err = ioutil.WriteFile(publicPath, publicStr, 0600)
104 | if err != nil {
105 | return err
106 | }
107 | fmt.Println("Proof stored at:", proofPath)
108 | fmt.Println("PublicSignals stored at:", publicPath)
109 | return nil
110 | }
111 |
112 | func cmdVerify(proofPath, verificationKeyPath, publicPath string) error {
113 | fmt.Println("zkSNARK Groth16 verifier")
114 |
115 | proofJSON, err := ioutil.ReadFile(proofPath) //nolint:gosec
116 | if err != nil {
117 | return err
118 | }
119 | vkJSON, err := ioutil.ReadFile(verificationKeyPath) //nolint:gosec
120 | if err != nil {
121 | return err
122 | }
123 | publicJSON, err := ioutil.ReadFile(publicPath) //nolint:gosec
124 | if err != nil {
125 | return err
126 | }
127 |
128 | public, err := parsers.ParsePublicSignals(publicJSON)
129 | if err != nil {
130 | return err
131 | }
132 | proof, err := parsers.ParseProof(proofJSON)
133 | if err != nil {
134 | return err
135 | }
136 | vk, err := parsers.ParseVk(vkJSON)
137 | if err != nil {
138 | return err
139 | }
140 |
141 | v := verifier.Verify(vk, proof, public)
142 | fmt.Println("verification:", v)
143 | return nil
144 | }
145 |
146 | func cmdConvert(provingKeyPath, provingKeyBinPath string) error {
147 | fmt.Println("Conversion tool")
148 |
149 | provingKeyJSON, err := ioutil.ReadFile(provingKeyPath) //nolint:gosec
150 | if err != nil {
151 | return err
152 | }
153 | pk, err := parsers.ParsePk(provingKeyJSON)
154 | if err != nil {
155 | return err
156 | }
157 |
158 | fmt.Printf("Converting proving key json (%s)\nto go proving key binary (%s)\n",
159 | provingKeyPath, provingKeyBinPath)
160 | pkGBin, err := parsers.PkToGoBin(pk)
161 | if err != nil {
162 | return err
163 | }
164 | if err = ioutil.WriteFile(provingKeyBinPath, pkGBin, 0600); err != nil {
165 | return err
166 | }
167 |
168 | return nil
169 | }
170 |
--------------------------------------------------------------------------------
/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/vocdoni/go-snark
2 |
3 | go 1.16
4 |
5 | require (
6 | github.com/ethereum/go-ethereum v1.9.13
7 | github.com/iden3/go-iden3-crypto v0.0.5
8 | github.com/stretchr/testify v1.4.0
9 | )
10 |
--------------------------------------------------------------------------------
/go.sum:
--------------------------------------------------------------------------------
1 | github.com/Azure/azure-pipeline-go v0.2.1/go.mod h1:UGSo8XybXnIGZ3epmeBw7Jdz+HiUVpqIlpz/HKHylF4=
2 | github.com/Azure/azure-pipeline-go v0.2.2/go.mod h1:4rQ/NZncSvGqNkkOsNpOU1tgoNuIlp9AfUH5G1tvCHc=
3 | github.com/Azure/azure-storage-blob-go v0.7.0/go.mod h1:f9YQKtsG1nMisotuTPpO0tjNuEjKRYAcJU8/ydDI++4=
4 | github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI=
5 | github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0=
6 | github.com/Azure/go-autorest/autorest/adal v0.8.0/go.mod h1:Z6vX6WXXuyieHAXwMj0S6HY6e6wcHn37qQMBQlvY3lc=
7 | github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA=
8 | github.com/Azure/go-autorest/autorest/date v0.2.0/go.mod h1:vcORJHLJEh643/Ioh9+vPmf1Ij9AEBM5FuBIXLmIy0g=
9 | github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0=
10 | github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0=
11 | github.com/Azure/go-autorest/autorest/mocks v0.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN3SVSiiO77gL2j2ronKKP0syM=
12 | github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc=
13 | github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk=
14 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
15 | github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
16 | github.com/OneOfOne/xxhash v1.2.5/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q=
17 | github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=
18 | github.com/VictoriaMetrics/fastcache v1.5.3/go.mod h1:+jv9Ckb+za/P1ZRg/sulP5Ni1v49daAVERr0H3CuscE=
19 | github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
20 | github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
21 | github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM=
22 | github.com/aristanetworks/goarista v0.0.0-20170210015632-ea17b1a17847/go.mod h1:D/tb0zPVXnP7fmsLZjtdUhSsumbK/ij54UXjjVgMGxQ=
23 | github.com/aws/aws-sdk-go v1.25.48/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
24 | github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
25 | github.com/btcsuite/btcd v0.0.0-20171128150713-2e60448ffcc6/go.mod h1:Dmm/EzmjnCiweXmzRIAiUWCInVmPgjkzgv5k4tVyXiQ=
26 | github.com/cespare/cp v0.1.0/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s=
27 | github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
28 | github.com/cespare/xxhash/v2 v2.0.1-0.20190104013014-3767db7a7e18/go.mod h1:HD5P3vAIAh+Y2GAxg0PrPN1P8WkepXGpjbUPDHJqqKM=
29 | github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
30 | github.com/cloudflare/cloudflare-go v0.10.2-0.20190916151808-a80f83b9add9/go.mod h1:1MxXX1Ux4x6mqPmjkUgTP1CdXIBXKX7T+Jk9Gxrmx+U=
31 | github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
32 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
33 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
34 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
35 | github.com/dchest/blake512 v1.0.0/go.mod h1:FV1x7xPPLWukZlpDpWQ88rF/SFwZ5qbskrzhLMB92JI=
36 | github.com/deckarep/golang-set v0.0.0-20180603214616-504e848d77ea/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ=
37 | github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
38 | github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
39 | github.com/dlclark/regexp2 v1.2.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
40 | github.com/docker/docker v1.4.2-0.20180625184442-8e610b2b55bf/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
41 | github.com/dop251/goja v0.0.0-20200219165308-d1232e640a87/go.mod h1:Mw6PkjjMXWbTj+nnj4s3QPXq1jaT0s5pC0iFD4+BOAA=
42 | github.com/edsrzf/mmap-go v0.0.0-20160512033002-935e0e8a636c/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
43 | github.com/elastic/gosigar v0.8.1-0.20180330100440-37f05ff46ffa/go.mod h1:cdorVVzy1fhmEqmtgqkoE3bYtCfSCkVyjTyCIo22xvs=
44 | github.com/ethereum/go-ethereum v1.9.12/go.mod h1:PvsVkQmhZFx92Y+h2ylythYlheEDt/uBgFbl61Js/jo=
45 | github.com/ethereum/go-ethereum v1.9.13 h1:rOPqjSngvs1VSYH2H+PMPiWt4VEulvNRbFgqiGqJM3E=
46 | github.com/ethereum/go-ethereum v1.9.13/go.mod h1:qwN9d1GLyDh0N7Ab8bMGd0H9knaji2jOBm2RrMGjXls=
47 | github.com/fatih/color v1.3.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
48 | github.com/fjl/memsize v0.0.0-20180418122429-ca190fb6ffbc/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0=
49 | github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
50 | github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww=
51 | github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
52 | github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
53 | github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8=
54 | github.com/go-sourcemap/sourcemap v2.1.2+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg=
55 | github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
56 | github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
57 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
58 | github.com/golang/protobuf v1.3.2-0.20190517061210-b285ee9cfc6c/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
59 | github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
60 | github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
61 | github.com/gorilla/websocket v1.4.1-0.20190629185528-ae1634f6a989/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
62 | github.com/graph-gophers/graphql-go v0.0.0-20191115155744-f33e81362277/go.mod h1:9CQHMSxwO4MprSdzoIEobiHpoLtHm77vfxsvsIN5Vuc=
63 | github.com/hashicorp/golang-lru v0.0.0-20160813221303-0a025b7e63ad/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
64 | github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
65 | github.com/huin/goupnp v0.0.0-20161224104101-679507af18f3/go.mod h1:MZ2ZmwcBpvOoJ22IJsc7va19ZwoheaBk43rKg12SKag=
66 | github.com/iden3/go-iden3-crypto v0.0.5 h1:inCSm5a+ry+nbpVTL/9+m6UcIwSv6nhUm0tnIxEbcps=
67 | github.com/iden3/go-iden3-crypto v0.0.5/go.mod h1:XKw1oDwYn2CIxKOtr7m/mL5jMn4mLOxAxtZBRxQBev8=
68 | github.com/influxdata/influxdb v1.2.3-0.20180221223340-01288bdb0883/go.mod h1:qZna6X/4elxqT3yI9iZYdZrWWdeFOOprn86kgg4+IzY=
69 | github.com/jackpal/go-nat-pmp v1.0.2-0.20160603034137-1fa385a6f458/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc=
70 | github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
71 | github.com/julienschmidt/httprouter v1.1.1-0.20170430222011-975b5c4c7c21/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
72 | github.com/karalabe/usb v0.0.0-20190919080040-51dc0efba356/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU=
73 | github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
74 | github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
75 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
76 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
77 | github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
78 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
79 | github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
80 | github.com/mattn/go-colorable v0.1.0/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
81 | github.com/mattn/go-ieproxy v0.0.0-20190610004146-91bb50d98149/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc=
82 | github.com/mattn/go-ieproxy v0.0.0-20190702010315-6dee0af9227d/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc=
83 | github.com/mattn/go-isatty v0.0.5-0.20180830101745-3fb116b82035/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
84 | github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
85 | github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
86 | github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
87 | github.com/naoina/go-stringutil v0.1.0/go.mod h1:XJ2SJL9jCtBh+P9q5btrd/Ylo8XwT/h1USek5+NqSA0=
88 | github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416/go.mod h1:NBIhNtsFMo3G2szEBne+bO4gS192HuIYRqfvOWb4i1E=
89 | github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
90 | github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
91 | github.com/olekukonko/tablewriter v0.0.2-0.20190409134802-7e037d187b0c/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
92 | github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
93 | github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
94 | github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
95 | github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
96 | github.com/pborman/uuid v0.0.0-20170112150404-1b00554d8222/go.mod h1:VyrYX9gd7irzKovcSS6BIIEwPRkP2Wm2m9ufcdFSJ34=
97 | github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7/go.mod h1:CRroGNssyjTd/qIG2FyxByd2S8JEAZXBl4qUrZf8GS0=
98 | github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
99 | github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
100 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
101 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
102 | github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
103 | github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
104 | github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
105 | github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
106 | github.com/prometheus/tsdb v0.6.2-0.20190402121629-4f204dcbc150/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
107 | github.com/rjeczalik/notify v0.9.1/go.mod h1:rKwnCoCGeuQnwBtTSPL9Dad03Vh2n40ePRrjvIXnJho=
108 | github.com/rs/cors v0.0.0-20160617231935-a62a804a8a00/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
109 | github.com/rs/xhandler v0.0.0-20160618193221-ed27b6fd6521/go.mod h1:RvLn4FgxWubrpZHtQLnOf6EwhN2hEMusxZOhcW9H3UQ=
110 | github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
111 | github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
112 | github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
113 | github.com/spaolacci/murmur3 v1.0.1-0.20190317074736-539464a789e9/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
114 | github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4/go.mod h1:RZLeN1LMWmRsyYjvAu+I6Dm9QmlDaIIt+Y+4Kd7Tp+Q=
115 | github.com/steakknife/bloomfilter v0.0.0-20180922174646-6819c0d2a570/go.mod h1:8OR4w3TdeIHIh1g6EMY5p0gVNOovcWC+1vpc7naMuAw=
116 | github.com/steakknife/hamming v0.0.0-20180906055917-c99c65617cd3/go.mod h1:hpGUWaI9xL8pRQCTXQgocU38Qw1g0Us7n5PxxTwTCYU=
117 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
118 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
119 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
120 | github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
121 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
122 | github.com/syndtr/goleveldb v1.0.1-0.20190923125748-758128399b1d/go.mod h1:9OrXJhf154huy1nPWmuSrkgjPUtUNhA+Zmy+6AESzuA=
123 | github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs=
124 | github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
125 | github.com/wsddn/go-ecdh v0.0.0-20161211032359-48726bab9208/go.mod h1:IotVbo4F+mw0EzQ08zFqg7pK3FebNXpaMsRy2RT+Ees=
126 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
127 | golang.org/x/crypto v0.0.0-20200311171314-f7b00557c8c4/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
128 | golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
129 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
130 | golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
131 | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
132 | golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
133 | golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
134 | golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
135 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
136 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
137 | golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527 h1:uYVVQ9WP/Ds2ROhcaGPeIdVq0RIXVLwsHlnvJ+cT1So=
138 | golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
139 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
140 | golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
141 | golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
142 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
143 | gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
144 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
145 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
146 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
147 | gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
148 | gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c=
149 | gopkg.in/olebedev/go-duktape.v3 v3.0.0-20190213234257-ec84240a7772/go.mod h1:uAJfkITjFhyEEuUfm7bsmCZRbW5WRq8s9EY8HZ6hCns=
150 | gopkg.in/olebedev/go-duktape.v3 v3.0.0-20200316214253-d7b0ff38cac9/go.mod h1:uAJfkITjFhyEEuUfm7bsmCZRbW5WRq8s9EY8HZ6hCns=
151 | gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
152 | gopkg.in/urfave/cli.v1 v1.20.0/go.mod h1:vuBzUtMdQeixQj8LVd+/98pzhxNGQoyuPBlsXHOQNO0=
153 | gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
154 | gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
155 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
156 | gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
157 |
--------------------------------------------------------------------------------
/parsers/parsers.go:
--------------------------------------------------------------------------------
1 | package parsers
2 |
3 | import (
4 | "bufio"
5 | "bytes"
6 | "encoding/binary"
7 | "encoding/hex"
8 | "encoding/json"
9 | "fmt"
10 | "io"
11 | "math/big"
12 | "os"
13 | "sort"
14 | "strconv"
15 | "strings"
16 |
17 | bn256 "github.com/ethereum/go-ethereum/crypto/bn256/cloudflare"
18 | "github.com/vocdoni/go-snark/types"
19 | )
20 |
21 | // PkString is the equivalent to the Pk struct in string representation, containing the ProvingKey
22 | type PkString struct {
23 | A [][]string `json:"A"`
24 | B2 [][][]string `json:"B2"`
25 | B1 [][]string `json:"B1"`
26 | C [][]string `json:"C"`
27 | NVars int `json:"nVars"`
28 | NPublic int `json:"nPublic"`
29 | VkAlpha1 []string `json:"vk_alpha_1"`
30 | VkDelta1 []string `json:"vk_delta_1"`
31 | VkBeta1 []string `json:"vk_beta_1"`
32 | VkBeta2 [][]string `json:"vk_beta_2"`
33 | VkDelta2 [][]string `json:"vk_delta_2"`
34 | HExps [][]string `json:"hExps"`
35 | DomainSize int `json:"domainSize"`
36 | PolsA []map[string]string `json:"polsA"`
37 | PolsB []map[string]string `json:"polsB"`
38 | }
39 |
40 | // WitnessString contains the Witness in string representation
41 | type WitnessString []string
42 |
43 | // ProofString is the equivalent to the Proof struct in string representation
44 | type ProofString struct {
45 | A []string `json:"pi_a"`
46 | B [][]string `json:"pi_b"`
47 | C []string `json:"pi_c"`
48 | Protocol string `json:"protocol"`
49 | }
50 |
51 | // VkString is the Verification Key data structure in string format (from json)
52 | type VkString struct {
53 | Alpha []string `json:"vk_alpha_1"`
54 | Beta [][]string `json:"vk_beta_2"`
55 | Gamma [][]string `json:"vk_gamma_2"`
56 | Delta [][]string `json:"vk_delta_2"`
57 | IC [][]string `json:"IC"`
58 | }
59 |
60 | // ParseWitness parses the json []byte data into the Witness struct
61 | func ParseWitness(wJSON []byte) (types.Witness, error) {
62 | var ws WitnessString
63 | err := json.Unmarshal(wJSON, &ws)
64 | if err != nil {
65 | return nil, err
66 | }
67 |
68 | var w types.Witness
69 | for i := 0; i < len(ws); i++ {
70 | bi, err := stringToBigInt(ws[i])
71 | if err != nil {
72 | return nil, err
73 | }
74 | w = append(w, bi)
75 | }
76 | return w, nil
77 | }
78 |
79 | // ParsePk parses the json []byte data into the Pk struct
80 | func ParsePk(pkJSON []byte) (*types.Pk, error) {
81 | var pkStr PkString
82 | err := json.Unmarshal(pkJSON, &pkStr)
83 | if err != nil {
84 | return nil, err
85 | }
86 | pk, err := pkStringToPk(pkStr)
87 | return pk, err
88 | }
89 |
90 | func pkStringToPk(ps PkString) (*types.Pk, error) {
91 | var p types.Pk
92 | var err error
93 |
94 | p.A, err = arrayStringToG1(ps.A)
95 | if err != nil {
96 | return nil, err
97 | }
98 | p.B2, err = arrayStringToG2(ps.B2)
99 | if err != nil {
100 | return nil, err
101 | }
102 | p.B1, err = arrayStringToG1(ps.B1)
103 | if err != nil {
104 | return nil, err
105 | }
106 | p.C, err = arrayStringToG1(ps.C)
107 | if err != nil {
108 | return nil, err
109 | }
110 |
111 | p.NVars = ps.NVars
112 | p.NPublic = ps.NPublic
113 |
114 | p.VkAlpha1, err = stringToG1(ps.VkAlpha1)
115 | if err != nil {
116 | return nil, err
117 | }
118 |
119 | p.VkDelta1, err = stringToG1(ps.VkDelta1)
120 | if err != nil {
121 | return nil, err
122 | }
123 |
124 | p.VkBeta1, err = stringToG1(ps.VkBeta1)
125 | if err != nil {
126 | return nil, err
127 | }
128 | p.VkBeta2, err = stringToG2(ps.VkBeta2)
129 | if err != nil {
130 | return nil, err
131 | }
132 | p.VkDelta2, err = stringToG2(ps.VkDelta2)
133 | if err != nil {
134 | return nil, err
135 | }
136 |
137 | p.HExps, err = arrayStringToG1(ps.HExps)
138 | if err != nil {
139 | return nil, err
140 | }
141 |
142 | p.DomainSize = ps.DomainSize
143 |
144 | p.PolsA, err = polsStringToBigInt(ps.PolsA)
145 | if err != nil {
146 | return nil, err
147 | }
148 | p.PolsB, err = polsStringToBigInt(ps.PolsB)
149 | if err != nil {
150 | return nil, err
151 | }
152 |
153 | return &p, nil
154 | }
155 |
156 | func proofStringToProof(pr ProofString) (*types.Proof, error) {
157 | var p types.Proof
158 | var err error
159 | p.A, err = stringToG1(pr.A)
160 | if err != nil {
161 | return nil, err
162 | }
163 |
164 | p.B, err = stringToG2(pr.B)
165 | if err != nil {
166 | return nil, err
167 | }
168 |
169 | p.C, err = stringToG1(pr.C)
170 | if err != nil {
171 | return nil, err
172 | }
173 |
174 | return &p, nil
175 | }
176 |
177 | // ParseProof takes a json []byte and outputs the *Proof struct
178 | func ParseProof(pj []byte) (*types.Proof, error) {
179 | var pr ProofString
180 | err := json.Unmarshal(pj, &pr)
181 | if err != nil {
182 | return nil, err
183 | }
184 | p, err := proofStringToProof(pr)
185 | return p, err
186 | }
187 |
188 | // ParsePublicSignals takes a json []byte and outputs the []*big.Int struct
189 | func ParsePublicSignals(pj []byte) ([]*big.Int, error) {
190 | var pr []string
191 | err := json.Unmarshal(pj, &pr)
192 | if err != nil {
193 | return nil, err
194 | }
195 | var public []*big.Int
196 | for _, s := range pr {
197 | sb, err := stringToBigInt(s)
198 | if err != nil {
199 | return nil, err
200 | }
201 | public = append(public, sb)
202 | }
203 | return public, nil
204 | }
205 |
206 | // ParseVk takes a json []byte and outputs the *Vk struct
207 | func ParseVk(vj []byte) (*types.Vk, error) {
208 | var vr VkString
209 | err := json.Unmarshal(vj, &vr)
210 | if err != nil {
211 | return nil, err
212 | }
213 | v, err := vkStringToVk(vr)
214 | return v, err
215 | }
216 |
217 | func vkStringToVk(vr VkString) (*types.Vk, error) {
218 | var v types.Vk
219 | var err error
220 | v.Alpha, err = stringToG1(vr.Alpha)
221 | if err != nil {
222 | return nil, err
223 | }
224 |
225 | v.Beta, err = stringToG2(vr.Beta)
226 | if err != nil {
227 | return nil, err
228 | }
229 |
230 | v.Gamma, err = stringToG2(vr.Gamma)
231 | if err != nil {
232 | return nil, err
233 | }
234 |
235 | v.Delta, err = stringToG2(vr.Delta)
236 | if err != nil {
237 | return nil, err
238 | }
239 |
240 | for i := 0; i < len(vr.IC); i++ {
241 | p, err := stringToG1(vr.IC[i])
242 | if err != nil {
243 | return nil, err
244 | }
245 | v.IC = append(v.IC, p)
246 | }
247 |
248 | return &v, nil
249 | }
250 |
251 | // polsStringToBigInt is for taking string polynomials and converting it to *big.Int polynomials
252 | func polsStringToBigInt(s []map[string]string) ([]map[int]*big.Int, error) {
253 | var o []map[int]*big.Int
254 | for i := 0; i < len(s); i++ {
255 | // var oi map[int]*big.Int
256 | oi := make(map[int]*big.Int)
257 | for j, v := range s[i] {
258 | si, err := stringToBigInt(v)
259 | if err != nil {
260 | return o, err
261 | }
262 | // oi = append(oi, si)
263 | jInt, err := strconv.Atoi(j)
264 | if err != nil {
265 | return o, err
266 | }
267 | oi[jInt] = si
268 | }
269 | o = append(o, oi)
270 | }
271 | return o, nil
272 | }
273 |
274 | // ArrayBigIntToString converts an []*big.Int into []string, used to output the Public Signals
275 | func ArrayBigIntToString(bi []*big.Int) []string {
276 | var s []string
277 | for i := 0; i < len(bi); i++ {
278 | s = append(s, bi[i].String())
279 | }
280 | return s
281 | }
282 |
283 | //nolint:unused,deadcode // TODO check
284 | func arrayStringToBigInt(s []string) ([]*big.Int, error) {
285 | var o []*big.Int
286 | for i := 0; i < len(s); i++ {
287 | si, err := stringToBigInt(s[i])
288 | if err != nil {
289 | return o, nil
290 | }
291 | o = append(o, si)
292 | }
293 | return o, nil
294 | }
295 |
296 | func stringToBigInt(s string) (*big.Int, error) {
297 | base := 10
298 | if bytes.HasPrefix([]byte(s), []byte("0x")) {
299 | base = 16
300 | s = strings.TrimPrefix(s, "0x")
301 | }
302 | n, ok := new(big.Int).SetString(s, base)
303 | if !ok {
304 | return nil, fmt.Errorf("Can not parse string to *big.Int: %s", s)
305 | }
306 | return n, nil
307 | }
308 |
309 | func addPadding32(b []byte) []byte {
310 | if len(b) != 32 { //nolint:gomnd
311 | b = addZPadding(b)
312 | }
313 | return b
314 | }
315 |
316 | func addZPadding(b []byte) []byte {
317 | var z [32]byte
318 | var r []byte
319 | r = append(r, z[len(b):]...) // add padding on the left
320 | r = append(r, b...)
321 | return r[:32]
322 | }
323 |
324 | func stringToBytes(s string) ([]byte, error) {
325 | if s == "1" {
326 | s = "0"
327 | }
328 | bi, ok := new(big.Int).SetString(s, 10)
329 | if !ok {
330 | return nil, fmt.Errorf("error parsing bigint stringToBytes")
331 | }
332 | b := bi.Bytes()
333 | if len(b) != 32 { //nolint:gomnd
334 | b = addZPadding(b)
335 | }
336 | return b, nil
337 | }
338 |
339 | func arrayStringToG1(h [][]string) ([]*bn256.G1, error) {
340 | var o []*bn256.G1
341 | for i := 0; i < len(h); i++ {
342 | hi, err := stringToG1(h[i])
343 | if err != nil {
344 | return o, err
345 | }
346 | o = append(o, hi)
347 | }
348 | return o, nil
349 | }
350 |
351 | func arrayStringToG2(h [][][]string) ([]*bn256.G2, error) {
352 | var o []*bn256.G2
353 | for i := 0; i < len(h); i++ {
354 | hi, err := stringToG2(h[i])
355 | if err != nil {
356 | return o, err
357 | }
358 | o = append(o, hi)
359 | }
360 | return o, nil
361 | }
362 |
363 | //nolint:gomnd
364 | func stringToG1(h []string) (*bn256.G1, error) {
365 | if len(h) <= 2 {
366 | return nil, fmt.Errorf("not enough data for stringToG1")
367 | }
368 | h = h[:2]
369 | hexa := false
370 | if len(h[0]) > 1 {
371 | if "0x" == h[0][:2] {
372 | hexa = true
373 | }
374 | }
375 | in := ""
376 |
377 | var b []byte
378 | var err error
379 | if hexa {
380 | for i := range h {
381 | in += strings.TrimPrefix(h[i], "0x")
382 | }
383 | b, err = hex.DecodeString(in)
384 | if err != nil {
385 | return nil, err
386 | }
387 | } else {
388 | // TODO TMP
389 | // TODO use stringToBytes()
390 | if h[0] == "1" {
391 | h[0] = "0"
392 | }
393 | if h[1] == "1" {
394 | h[1] = "0"
395 | }
396 | bi0, ok := new(big.Int).SetString(h[0], 10)
397 | if !ok {
398 | return nil, fmt.Errorf("error parsing stringToG1")
399 | }
400 | bi1, ok := new(big.Int).SetString(h[1], 10)
401 | if !ok {
402 | return nil, fmt.Errorf("error parsing stringToG1")
403 | }
404 | b0 := bi0.Bytes()
405 | b1 := bi1.Bytes()
406 | if len(b0) != 32 {
407 | b0 = addZPadding(b0)
408 | }
409 | if len(b1) != 32 {
410 | b1 = addZPadding(b1)
411 | }
412 |
413 | b = append(b, b0...)
414 | b = append(b, b1...)
415 | }
416 | p := new(bn256.G1)
417 | _, err = p.Unmarshal(b)
418 |
419 | return p, err
420 | }
421 |
422 | func stringToG2(h [][]string) (*bn256.G2, error) {
423 | if len(h) <= 2 { //nolint:gomnd
424 | return nil, fmt.Errorf("not enough data for stringToG2")
425 | }
426 | h = h[:2]
427 | hexa := false
428 | if len(h[0][0]) > 1 {
429 | if "0x" == h[0][0][:2] {
430 | hexa = true
431 | }
432 | }
433 | in := ""
434 | var b []byte
435 | var err error
436 | if hexa {
437 | for i := 0; i < len(h); i++ {
438 | for j := 0; j < len(h[i]); j++ {
439 | in += strings.TrimPrefix(h[i][j], "0x")
440 | }
441 | }
442 | b, err = hex.DecodeString(in)
443 | if err != nil {
444 | return nil, err
445 | }
446 | } else {
447 | // TODO TMP
448 | bH, err := stringToBytes(h[0][1])
449 | if err != nil {
450 | return nil, err
451 | }
452 | b = append(b, bH...)
453 | bH, err = stringToBytes(h[0][0])
454 | if err != nil {
455 | return nil, err
456 | }
457 | b = append(b, bH...)
458 | bH, err = stringToBytes(h[1][1])
459 | if err != nil {
460 | return nil, err
461 | }
462 | b = append(b, bH...)
463 | bH, err = stringToBytes(h[1][0])
464 | if err != nil {
465 | return nil, err
466 | }
467 | b = append(b, bH...)
468 | }
469 |
470 | p := new(bn256.G2)
471 | _, err = p.Unmarshal(b)
472 | return p, err
473 | }
474 |
475 | // ProofStringToSmartContractFormat converts the ProofString to a ProofString in
476 | // the SmartContract format in a ProofString structure
477 | func ProofStringToSmartContractFormat(s ProofString) ProofString {
478 | var rs ProofString
479 | rs.A = make([]string, 2)
480 | rs.B = make([][]string, 2)
481 | rs.B[0] = make([]string, 2)
482 | rs.B[1] = make([]string, 2)
483 | rs.C = make([]string, 2)
484 |
485 | rs.A[0] = s.A[0]
486 | rs.A[1] = s.A[1]
487 | rs.B[0][0] = s.B[0][1]
488 | rs.B[0][1] = s.B[0][0]
489 | rs.B[1][0] = s.B[1][1]
490 | rs.B[1][1] = s.B[1][0]
491 | rs.C[0] = s.C[0]
492 | rs.C[1] = s.C[1]
493 | rs.Protocol = s.Protocol
494 | return rs
495 | }
496 |
497 | // ProofToSmartContractFormat converts the *types.Proof to a ProofString in the
498 | // SmartContract format in a ProofString structure
499 | func ProofToSmartContractFormat(p *types.Proof) ProofString {
500 | s := ProofToString(p)
501 | return ProofStringToSmartContractFormat(s)
502 | }
503 |
504 | // ProofToString converts the Proof to ProofString
505 | func ProofToString(p *types.Proof) ProofString {
506 | var ps ProofString
507 | ps.A = make([]string, 3)
508 | ps.B = make([][]string, 3)
509 | ps.B[0] = make([]string, 2)
510 | ps.B[1] = make([]string, 2)
511 | ps.B[2] = make([]string, 2)
512 | ps.C = make([]string, 3)
513 |
514 | a := p.A.Marshal()
515 | ps.A[0] = new(big.Int).SetBytes(a[:32]).String()
516 | ps.A[1] = new(big.Int).SetBytes(a[32:64]).String()
517 | ps.A[2] = "1"
518 |
519 | b := p.B.Marshal()
520 | ps.B[0][1] = new(big.Int).SetBytes(b[:32]).String()
521 | ps.B[0][0] = new(big.Int).SetBytes(b[32:64]).String()
522 | ps.B[1][1] = new(big.Int).SetBytes(b[64:96]).String()
523 | ps.B[1][0] = new(big.Int).SetBytes(b[96:128]).String()
524 | ps.B[2][0] = "1"
525 | ps.B[2][1] = "0"
526 |
527 | c := p.C.Marshal()
528 | ps.C[0] = new(big.Int).SetBytes(c[:32]).String()
529 | ps.C[1] = new(big.Int).SetBytes(c[32:64]).String()
530 | ps.C[2] = "1"
531 |
532 | ps.Protocol = "groth"
533 |
534 | return ps
535 | }
536 |
537 | // ProofToJSON outputs the Proof i JSON format
538 | func ProofToJSON(p *types.Proof) ([]byte, error) {
539 | ps := ProofToString(p)
540 | return json.Marshal(ps)
541 | }
542 |
543 | // ProofToHex converts the Proof to ProofString with hexadecimal strings
544 | func ProofToHex(p *types.Proof) ProofString {
545 | var ps ProofString
546 | ps.A = make([]string, 3)
547 | ps.B = make([][]string, 3)
548 | ps.B[0] = make([]string, 2)
549 | ps.B[1] = make([]string, 2)
550 | ps.B[2] = make([]string, 2)
551 | ps.C = make([]string, 3)
552 |
553 | a := p.A.Marshal()
554 | ps.A[0] = "0x" + hex.EncodeToString(new(big.Int).SetBytes(a[:32]).Bytes())
555 | ps.A[1] = "0x" + hex.EncodeToString(new(big.Int).SetBytes(a[32:64]).Bytes())
556 | ps.A[2] = "1"
557 |
558 | b := p.B.Marshal()
559 | ps.B[0][1] = "0x" + hex.EncodeToString(new(big.Int).SetBytes(b[:32]).Bytes())
560 | ps.B[0][0] = "0x" + hex.EncodeToString(new(big.Int).SetBytes(b[32:64]).Bytes())
561 | ps.B[1][1] = "0x" + hex.EncodeToString(new(big.Int).SetBytes(b[64:96]).Bytes())
562 | ps.B[1][0] = "0x" + hex.EncodeToString(new(big.Int).SetBytes(b[96:128]).Bytes())
563 | ps.B[2][0] = "1"
564 | ps.B[2][1] = "0"
565 |
566 | c := p.C.Marshal()
567 | ps.C[0] = "0x" + hex.EncodeToString(new(big.Int).SetBytes(c[:32]).Bytes())
568 | ps.C[1] = "0x" + hex.EncodeToString(new(big.Int).SetBytes(c[32:64]).Bytes())
569 | ps.C[2] = "1"
570 |
571 | ps.Protocol = "groth"
572 |
573 | return ps
574 | }
575 |
576 | // ProofToJSONHex outputs the Proof i JSON format with hexadecimal strings
577 | func ProofToJSONHex(p *types.Proof) ([]byte, error) {
578 | ps := ProofToHex(p)
579 | return json.Marshal(ps)
580 | }
581 |
582 | // ParseWitnessBin parses binary file representation of the Witness into the Witness struct
583 | func ParseWitnessBin(f *os.File) (types.Witness, error) {
584 | var w types.Witness
585 | r := bufio.NewReader(f)
586 | for {
587 | b := make([]byte, 32)
588 | n, err := r.Read(b)
589 | if err == io.EOF {
590 | return w, nil
591 | } else if err != nil {
592 | return nil, err
593 | }
594 | if n != 32 { //nolint:gomnd
595 | return nil, fmt.Errorf("error on value format, expected 32 bytes, got %v", n)
596 | }
597 | w = append(w, new(big.Int).SetBytes(swapEndianness(b[0:32])))
598 | }
599 | }
600 |
601 | // swapEndianness swaps the order of the bytes in the slice.
602 | func swapEndianness(b []byte) []byte {
603 | o := make([]byte, len(b))
604 | for i := range b {
605 | o[len(b)-1-i] = b[i]
606 | }
607 | return o
608 | }
609 |
610 | func readNBytes(r io.Reader, n int) ([]byte, error) {
611 | b := make([]byte, n)
612 | _, err := io.ReadFull(r, b)
613 | if err != nil {
614 | return b, err
615 | }
616 | return b, nil
617 | }
618 |
619 | // ParsePkBin parses binary file representation of the ProvingKey into the
620 | // ProvingKey struct
621 | //nolint:gocyclo // TODO WIP
622 | func ParsePkBin(f *os.File) (*types.Pk, error) {
623 | o := 0
624 | var pk types.Pk
625 | r := bufio.NewReader(f)
626 |
627 | b, err := readNBytes(r, 12)
628 | if err != nil {
629 | return nil, err
630 | }
631 | pk.NVars = int(binary.LittleEndian.Uint32(b[:4]))
632 | pk.NPublic = int(binary.LittleEndian.Uint32(b[4:8]))
633 | pk.DomainSize = int(binary.LittleEndian.Uint32(b[8:12]))
634 | o += 12
635 |
636 | b, err = readNBytes(r, 8)
637 | if err != nil {
638 | return nil, err
639 | }
640 | pPolsA := int(binary.LittleEndian.Uint32(b[:4]))
641 | pPolsB := int(binary.LittleEndian.Uint32(b[4:8]))
642 | o += 8
643 |
644 | b, err = readNBytes(r, 20)
645 | if err != nil {
646 | return nil, err
647 | }
648 | pPointsA := int(binary.LittleEndian.Uint32(b[:4]))
649 | pPointsB1 := int(binary.LittleEndian.Uint32(b[4:8]))
650 | pPointsB2 := int(binary.LittleEndian.Uint32(b[8:12]))
651 | pPointsC := int(binary.LittleEndian.Uint32(b[12:16]))
652 | pPointsHExps := int(binary.LittleEndian.Uint32(b[16:20]))
653 | o += 20
654 |
655 | b, err = readNBytes(r, 64)
656 | if err != nil {
657 | return nil, err
658 | }
659 | pk.VkAlpha1 = new(bn256.G1)
660 | _, err = pk.VkAlpha1.Unmarshal(fromMont1Q(b))
661 | if err != nil {
662 | return nil, err
663 | }
664 |
665 | b, err = readNBytes(r, 64)
666 | if err != nil {
667 | return nil, err
668 | }
669 | pk.VkBeta1 = new(bn256.G1)
670 | _, err = pk.VkBeta1.Unmarshal(fromMont1Q(b))
671 | if err != nil {
672 | return nil, err
673 | }
674 |
675 | b, err = readNBytes(r, 64)
676 | if err != nil {
677 | return nil, err
678 | }
679 | pk.VkDelta1 = new(bn256.G1)
680 | _, err = pk.VkDelta1.Unmarshal(fromMont1Q(b))
681 | if err != nil {
682 | return nil, err
683 | }
684 | b, err = readNBytes(r, 128)
685 | if err != nil {
686 | return nil, err
687 | }
688 | pk.VkBeta2 = new(bn256.G2)
689 | _, err = pk.VkBeta2.Unmarshal(fromMont2Q(b))
690 | if err != nil {
691 | return nil, err
692 | }
693 | b, err = readNBytes(r, 128)
694 | if err != nil {
695 | return nil, err
696 | }
697 | pk.VkDelta2 = new(bn256.G2)
698 | _, err = pk.VkDelta2.Unmarshal(fromMont2Q(b))
699 | if err != nil {
700 | return nil, err
701 | }
702 | o += 448
703 | if o != pPolsA {
704 | return nil, fmt.Errorf("Unexpected offset, expected: %v, actual: %v", pPolsA, o)
705 | }
706 |
707 | // PolsA
708 | for i := 0; i < pk.NVars; i++ {
709 | b, err = readNBytes(r, 4)
710 | if err != nil {
711 | return nil, err
712 | }
713 | keysLength := int(binary.LittleEndian.Uint32(b[:4]))
714 | o += 4
715 | polsMap := make(map[int]*big.Int)
716 | for j := 0; j < keysLength; j++ {
717 | bK, err := readNBytes(r, 4)
718 | if err != nil {
719 | return nil, err
720 | }
721 | key := int(binary.LittleEndian.Uint32(bK[:4]))
722 | o += 4
723 |
724 | b, err := readNBytes(r, 32)
725 | if err != nil {
726 | return nil, err
727 | }
728 | polsMap[key] = new(big.Int).SetBytes(fromMont1R(b[:32]))
729 | o += 32
730 | }
731 | pk.PolsA = append(pk.PolsA, polsMap)
732 | }
733 | if o != pPolsB {
734 | return nil, fmt.Errorf("Unexpected offset, expected: %v, actual: %v", pPolsB, o)
735 | }
736 | // PolsB
737 | for i := 0; i < pk.NVars; i++ {
738 | b, err = readNBytes(r, 4)
739 | if err != nil {
740 | return nil, err
741 | }
742 | keysLength := int(binary.LittleEndian.Uint32(b[:4]))
743 | o += 4
744 | polsMap := make(map[int]*big.Int)
745 | for j := 0; j < keysLength; j++ {
746 | bK, err := readNBytes(r, 4)
747 | if err != nil {
748 | return nil, err
749 | }
750 | key := int(binary.LittleEndian.Uint32(bK[:4]))
751 | o += 4
752 |
753 | b, err := readNBytes(r, 32)
754 | if err != nil {
755 | return nil, err
756 | }
757 | polsMap[key] = new(big.Int).SetBytes(fromMont1R(b[:32]))
758 | o += 32
759 | }
760 | pk.PolsB = append(pk.PolsB, polsMap)
761 | }
762 | if o != pPointsA {
763 | return nil, fmt.Errorf("Unexpected offset, expected: %v, actual: %v", pPointsA, o)
764 | }
765 | // A
766 | for i := 0; i < pk.NVars; i++ {
767 | b, err = readNBytes(r, 64)
768 | if err != nil {
769 | return nil, err
770 | }
771 | p1 := new(bn256.G1)
772 | _, err = p1.Unmarshal(fromMont1Q(b))
773 | if err != nil {
774 | return nil, err
775 | }
776 | pk.A = append(pk.A, p1)
777 | o += 64
778 | }
779 | if o != pPointsB1 {
780 | return nil, fmt.Errorf("Unexpected offset, expected: %v, actual: %v", pPointsB1, o)
781 | }
782 | // B1
783 | for i := 0; i < pk.NVars; i++ {
784 | b, err = readNBytes(r, 64)
785 | if err != nil {
786 | return nil, err
787 | }
788 | p1 := new(bn256.G1)
789 | _, err = p1.Unmarshal(fromMont1Q(b))
790 | if err != nil {
791 | return nil, err
792 | }
793 | pk.B1 = append(pk.B1, p1)
794 | o += 64
795 | }
796 | if o != pPointsB2 {
797 | return nil, fmt.Errorf("Unexpected offset, expected: %v, actual: %v", pPointsB2, o)
798 | }
799 | // B2
800 | for i := 0; i < pk.NVars; i++ {
801 | b, err = readNBytes(r, 128)
802 | if err != nil {
803 | return nil, err
804 | }
805 | p2 := new(bn256.G2)
806 | _, err = p2.Unmarshal(fromMont2Q(b))
807 | if err != nil {
808 | return nil, err
809 | }
810 | pk.B2 = append(pk.B2, p2)
811 | o += 128
812 | }
813 | if o != pPointsC {
814 | return nil, fmt.Errorf("Unexpected offset, expected: %v, actual: %v", pPointsC, o)
815 | }
816 | // C
817 | zb := make([]byte, 64)
818 | z := new(bn256.G1)
819 | _, err = z.Unmarshal(zb)
820 | if err != nil {
821 | return nil, err
822 | }
823 | for i := 0; i < pk.NPublic+1; i++ {
824 | pk.C = append(pk.C, z)
825 | }
826 | for i := pk.NPublic + 1; i < pk.NVars; i++ {
827 | b, err = readNBytes(r, 64)
828 | if err != nil {
829 | return nil, err
830 | }
831 | p1 := new(bn256.G1)
832 | _, err = p1.Unmarshal(fromMont1Q(b))
833 | if err != nil {
834 | return nil, err
835 | }
836 | pk.C = append(pk.C, p1)
837 | o += 64
838 | }
839 | if o != pPointsHExps {
840 | return nil, fmt.Errorf("Unexpected offset, expected: %v, actual: %v", pPointsHExps, o)
841 | }
842 | // HExps
843 | for i := 0; i < pk.DomainSize; i++ {
844 | b, err = readNBytes(r, 64)
845 | if err != nil {
846 | return nil, err
847 | }
848 | p1 := new(bn256.G1)
849 | _, err = p1.Unmarshal(fromMont1Q(b))
850 | if err != nil {
851 | return nil, err
852 | }
853 | pk.HExps = append(pk.HExps, p1)
854 | }
855 | return &pk, nil
856 | }
857 |
858 | //nolint:gomnd
859 | func fromMont1Q(m []byte) []byte {
860 | a := new(big.Int).SetBytes(swapEndianness(m[:32]))
861 | b := new(big.Int).SetBytes(swapEndianness(m[32:64]))
862 |
863 | x := coordFromMont(a, types.Q)
864 | y := coordFromMont(b, types.Q)
865 | if bytes.Equal(x.Bytes(), big.NewInt(1).Bytes()) {
866 | x = big.NewInt(0)
867 | }
868 | if bytes.Equal(y.Bytes(), big.NewInt(1).Bytes()) {
869 | y = big.NewInt(0)
870 | }
871 |
872 | xBytes := x.Bytes()
873 | yBytes := y.Bytes()
874 | if len(xBytes) != 32 {
875 | xBytes = addZPadding(xBytes)
876 | }
877 | if len(yBytes) != 32 {
878 | yBytes = addZPadding(yBytes)
879 | }
880 |
881 | var p []byte
882 | p = append(p, xBytes...)
883 | p = append(p, yBytes...)
884 |
885 | return p
886 | }
887 |
888 | //nolint:gomnd
889 | func fromMont2Q(m []byte) []byte {
890 | a := new(big.Int).SetBytes(swapEndianness(m[:32]))
891 | b := new(big.Int).SetBytes(swapEndianness(m[32:64]))
892 | c := new(big.Int).SetBytes(swapEndianness(m[64:96]))
893 | d := new(big.Int).SetBytes(swapEndianness(m[96:128]))
894 |
895 | x := coordFromMont(a, types.Q)
896 | y := coordFromMont(b, types.Q)
897 | z := coordFromMont(c, types.Q)
898 | t := coordFromMont(d, types.Q)
899 |
900 | if bytes.Equal(x.Bytes(), big.NewInt(1).Bytes()) {
901 | x = big.NewInt(0)
902 | }
903 | if bytes.Equal(y.Bytes(), big.NewInt(1).Bytes()) {
904 | y = big.NewInt(0)
905 | }
906 | if bytes.Equal(z.Bytes(), big.NewInt(1).Bytes()) {
907 | z = big.NewInt(0)
908 | }
909 | if bytes.Equal(t.Bytes(), big.NewInt(1).Bytes()) {
910 | t = big.NewInt(0)
911 | }
912 |
913 | xBytes := x.Bytes()
914 | yBytes := y.Bytes()
915 | zBytes := z.Bytes()
916 | tBytes := t.Bytes()
917 | if len(xBytes) != 32 {
918 | xBytes = addZPadding(xBytes)
919 | }
920 | if len(yBytes) != 32 {
921 | yBytes = addZPadding(yBytes)
922 | }
923 | if len(zBytes) != 32 {
924 | zBytes = addZPadding(zBytes)
925 | }
926 | if len(tBytes) != 32 {
927 | tBytes = addZPadding(tBytes)
928 | }
929 |
930 | var p []byte
931 | p = append(p, yBytes...) // swap
932 | p = append(p, xBytes...)
933 | p = append(p, tBytes...)
934 | p = append(p, zBytes...)
935 |
936 | return p
937 | }
938 |
939 | func fromMont1R(m []byte) []byte {
940 | a := new(big.Int).SetBytes(swapEndianness(m[:32]))
941 |
942 | x := coordFromMont(a, types.R)
943 |
944 | return x.Bytes()
945 | }
946 |
947 | //nolint:unused,deadcode // TODO check
948 | func fromMont2R(m []byte) []byte {
949 | a := new(big.Int).SetBytes(swapEndianness(m[:32]))
950 | b := new(big.Int).SetBytes(swapEndianness(m[32:64]))
951 | c := new(big.Int).SetBytes(swapEndianness(m[64:96]))
952 | d := new(big.Int).SetBytes(swapEndianness(m[96:128]))
953 |
954 | x := coordFromMont(a, types.R)
955 | y := coordFromMont(b, types.R)
956 | z := coordFromMont(c, types.R)
957 | t := coordFromMont(d, types.R)
958 |
959 | var p []byte
960 | p = append(p, y.Bytes()...) // swap
961 | p = append(p, x.Bytes()...)
962 | p = append(p, t.Bytes()...)
963 | p = append(p, z.Bytes()...)
964 |
965 | return p
966 | }
967 |
968 | func coordFromMont(u, q *big.Int) *big.Int {
969 | return new(big.Int).Mod(
970 | new(big.Int).Mul(
971 | u,
972 | new(big.Int).ModInverse(
973 | new(big.Int).Lsh(big.NewInt(1), 256),
974 | q,
975 | ),
976 | ),
977 | q,
978 | )
979 | }
980 |
981 | func sortedKeys(m map[int]*big.Int) []int {
982 | keys := make([]int, 0, len(m))
983 | for k := range m {
984 | keys = append(keys, k)
985 | }
986 | sort.Ints(keys)
987 | return keys
988 | }
989 |
990 | // PkToGoBin converts the ProvingKey (*types.Pk) into binary format defined by
991 | // go-snark. PkGoBin is a own go-snark binary format that allows to go faster
992 | // when parsing.
993 | // nolint:gomnd
994 | func PkToGoBin(pk *types.Pk) ([]byte, error) {
995 | var r []byte
996 | o := 0
997 | var b [4]byte
998 | binary.LittleEndian.PutUint32(b[:], uint32(pk.NVars))
999 | r = append(r, b[:]...)
1000 |
1001 | binary.LittleEndian.PutUint32(b[:], uint32(pk.NPublic))
1002 | r = append(r, b[:]...)
1003 |
1004 | binary.LittleEndian.PutUint32(b[:], uint32(pk.DomainSize))
1005 | r = append(r, b[:]...)
1006 | o += 12
1007 |
1008 | // reserve space for pols (A, B) pos
1009 | b = [4]byte{}
1010 | r = append(r, b[:]...) // 12:16
1011 | r = append(r, b[:]...) // 16:20
1012 | o += 8
1013 | // reserve space for points (A, B1, B2, C, HExps) pos
1014 | r = append(r, b[:]...) // 20:24
1015 | r = append(r, b[:]...) // 24
1016 | r = append(r, b[:]...) // 28
1017 | r = append(r, b[:]...) // 32
1018 | r = append(r, b[:]...) // 36:40
1019 | o += 20
1020 |
1021 | pb1 := pk.VkAlpha1.Marshal()
1022 | r = append(r, pb1[:]...)
1023 | pb1 = pk.VkBeta1.Marshal()
1024 | r = append(r, pb1[:]...)
1025 | pb1 = pk.VkDelta1.Marshal()
1026 | r = append(r, pb1[:]...)
1027 | pb2 := pk.VkBeta2.Marshal()
1028 | r = append(r, pb2[:]...)
1029 | pb2 = pk.VkDelta2.Marshal()
1030 | r = append(r, pb2[:]...)
1031 | o += 448
1032 |
1033 | // polsA
1034 | binary.LittleEndian.PutUint32(r[12:16], uint32(o))
1035 | for i := 0; i < pk.NVars; i++ {
1036 | binary.LittleEndian.PutUint32(b[:], uint32(len(pk.PolsA[i])))
1037 | r = append(r, b[:]...)
1038 | o += 4
1039 | for _, j := range sortedKeys(pk.PolsA[i]) {
1040 | v := pk.PolsA[i][j]
1041 | binary.LittleEndian.PutUint32(b[:], uint32(j))
1042 | r = append(r, b[:]...)
1043 | r = append(r, addPadding32(v.Bytes())...)
1044 | o += 32 + 4
1045 | }
1046 | }
1047 | // polsB
1048 | binary.LittleEndian.PutUint32(r[16:20], uint32(o))
1049 | for i := 0; i < pk.NVars; i++ {
1050 | binary.LittleEndian.PutUint32(b[:], uint32(len(pk.PolsB[i])))
1051 | r = append(r, b[:]...)
1052 | o += 4
1053 | for _, j := range sortedKeys(pk.PolsB[i]) {
1054 | v := pk.PolsB[i][j]
1055 | binary.LittleEndian.PutUint32(b[:], uint32(j))
1056 | r = append(r, b[:]...)
1057 | r = append(r, addPadding32(v.Bytes())...)
1058 | o += 32 + 4
1059 | }
1060 | }
1061 | // A
1062 | binary.LittleEndian.PutUint32(r[20:24], uint32(o))
1063 | for i := 0; i < pk.NVars; i++ {
1064 | pb1 = pk.A[i].Marshal()
1065 | r = append(r, pb1[:]...)
1066 | o += 64
1067 | }
1068 | // B1
1069 | binary.LittleEndian.PutUint32(r[24:28], uint32(o))
1070 | for i := 0; i < pk.NVars; i++ {
1071 | pb1 = pk.B1[i].Marshal()
1072 | r = append(r, pb1[:]...)
1073 | o += 64
1074 | }
1075 | // B2
1076 | binary.LittleEndian.PutUint32(r[28:32], uint32(o))
1077 | for i := 0; i < pk.NVars; i++ {
1078 | pb2 = pk.B2[i].Marshal()
1079 | r = append(r, pb2[:]...)
1080 | o += 128
1081 | }
1082 | // C
1083 | binary.LittleEndian.PutUint32(r[32:36], uint32(o))
1084 | for i := pk.NPublic + 1; i < pk.NVars; i++ {
1085 | pb1 = pk.C[i].Marshal()
1086 | r = append(r, pb1[:]...)
1087 | o += 64
1088 | }
1089 | // HExps
1090 | binary.LittleEndian.PutUint32(r[36:40], uint32(o))
1091 | for i := 0; i < pk.DomainSize+1; i++ {
1092 | pb1 = pk.HExps[i].Marshal()
1093 | r = append(r, pb1[:]...)
1094 | o += 64
1095 | }
1096 |
1097 | return r[:], nil
1098 | }
1099 |
1100 | // ParsePkGoBin parses go-snark binary file representation of the ProvingKey
1101 | // into ProvingKey struct (*types.Pk). PkGoBin is a own go-snark binary format
1102 | // that allows to go faster when parsing.
1103 | //nolint:gocyclo // TODO WIP
1104 | func ParsePkGoBin(f *os.File) (*types.Pk, error) {
1105 | o := 0
1106 | var pk types.Pk
1107 | r := bufio.NewReader(f)
1108 |
1109 | b, err := readNBytes(r, 12)
1110 | if err != nil {
1111 | return nil, err
1112 | }
1113 | pk.NVars = int(binary.LittleEndian.Uint32(b[:4]))
1114 | pk.NPublic = int(binary.LittleEndian.Uint32(b[4:8]))
1115 | pk.DomainSize = int(binary.LittleEndian.Uint32(b[8:12]))
1116 | o += 12
1117 |
1118 | b, err = readNBytes(r, 8)
1119 | if err != nil {
1120 | return nil, err
1121 | }
1122 | pPolsA := int(binary.LittleEndian.Uint32(b[:4]))
1123 | pPolsB := int(binary.LittleEndian.Uint32(b[4:8]))
1124 | o += 8
1125 |
1126 | b, err = readNBytes(r, 20)
1127 | if err != nil {
1128 | return nil, err
1129 | }
1130 | pPointsA := int(binary.LittleEndian.Uint32(b[:4]))
1131 | pPointsB1 := int(binary.LittleEndian.Uint32(b[4:8]))
1132 | pPointsB2 := int(binary.LittleEndian.Uint32(b[8:12]))
1133 | pPointsC := int(binary.LittleEndian.Uint32(b[12:16]))
1134 | pPointsHExps := int(binary.LittleEndian.Uint32(b[16:20]))
1135 | o += 20
1136 |
1137 | b, err = readNBytes(r, 64)
1138 | if err != nil {
1139 | return nil, err
1140 | }
1141 | pk.VkAlpha1 = new(bn256.G1)
1142 | _, err = pk.VkAlpha1.Unmarshal(b)
1143 | if err != nil {
1144 | return &pk, err
1145 | }
1146 | b, err = readNBytes(r, 64)
1147 | if err != nil {
1148 | return nil, err
1149 | }
1150 | pk.VkBeta1 = new(bn256.G1)
1151 | _, err = pk.VkBeta1.Unmarshal(b)
1152 | if err != nil {
1153 | return &pk, err
1154 | }
1155 | b, err = readNBytes(r, 64)
1156 | if err != nil {
1157 | return nil, err
1158 | }
1159 | pk.VkDelta1 = new(bn256.G1)
1160 | _, err = pk.VkDelta1.Unmarshal(b)
1161 | if err != nil {
1162 | return &pk, err
1163 | }
1164 | b, err = readNBytes(r, 128)
1165 | if err != nil {
1166 | return nil, err
1167 | }
1168 | pk.VkBeta2 = new(bn256.G2)
1169 | _, err = pk.VkBeta2.Unmarshal(b)
1170 | if err != nil {
1171 | return &pk, err
1172 | }
1173 | b, err = readNBytes(r, 128)
1174 | if err != nil {
1175 | return nil, err
1176 | }
1177 | pk.VkDelta2 = new(bn256.G2)
1178 | _, err = pk.VkDelta2.Unmarshal(b)
1179 | if err != nil {
1180 | return &pk, err
1181 | }
1182 | o += 448
1183 | if o != pPolsA {
1184 | return nil, fmt.Errorf("Unexpected offset, expected: %v, actual: %v", pPolsA, o)
1185 | }
1186 |
1187 | // PolsA
1188 | for i := 0; i < pk.NVars; i++ {
1189 | b, err = readNBytes(r, 4)
1190 | if err != nil {
1191 | return nil, err
1192 | }
1193 | keysLength := int(binary.LittleEndian.Uint32(b[:4]))
1194 | o += 4
1195 | polsMap := make(map[int]*big.Int)
1196 | for j := 0; j < keysLength; j++ {
1197 | bK, err := readNBytes(r, 4)
1198 | if err != nil {
1199 | return nil, err
1200 | }
1201 | key := int(binary.LittleEndian.Uint32(bK[:4]))
1202 | o += 4
1203 |
1204 | b, err := readNBytes(r, 32)
1205 | if err != nil {
1206 | return nil, err
1207 | }
1208 | polsMap[key] = new(big.Int).SetBytes(b[:32])
1209 | o += 32
1210 | }
1211 | pk.PolsA = append(pk.PolsA, polsMap)
1212 | }
1213 | if o != pPolsB {
1214 | return nil, fmt.Errorf("Unexpected offset, expected: %v, actual: %v", pPolsB, o)
1215 | }
1216 | // PolsB
1217 | for i := 0; i < pk.NVars; i++ {
1218 | b, err = readNBytes(r, 4)
1219 | if err != nil {
1220 | return nil, err
1221 | }
1222 | keysLength := int(binary.LittleEndian.Uint32(b[:4]))
1223 | o += 4
1224 | polsMap := make(map[int]*big.Int)
1225 | for j := 0; j < keysLength; j++ {
1226 | bK, err := readNBytes(r, 4)
1227 | if err != nil {
1228 | return nil, err
1229 | }
1230 | key := int(binary.LittleEndian.Uint32(bK[:4]))
1231 | o += 4
1232 |
1233 | b, err := readNBytes(r, 32)
1234 | if err != nil {
1235 | return nil, err
1236 | }
1237 | polsMap[key] = new(big.Int).SetBytes(b[:32])
1238 | o += 32
1239 | }
1240 | pk.PolsB = append(pk.PolsB, polsMap)
1241 | }
1242 | if o != pPointsA {
1243 | return nil, fmt.Errorf("Unexpected offset, expected: %v, actual: %v", pPointsA, o)
1244 | }
1245 | // A
1246 | for i := 0; i < pk.NVars; i++ {
1247 | b, err = readNBytes(r, 64)
1248 | if err != nil {
1249 | return nil, err
1250 | }
1251 | p1 := new(bn256.G1)
1252 | _, err = p1.Unmarshal(b)
1253 | if err != nil {
1254 | return nil, err
1255 | }
1256 | pk.A = append(pk.A, p1)
1257 | o += 64
1258 | }
1259 | if o != pPointsB1 {
1260 | return nil, fmt.Errorf("Unexpected offset, expected: %v, actual: %v", pPointsB1, o)
1261 | }
1262 | // B1
1263 | for i := 0; i < pk.NVars; i++ {
1264 | b, err = readNBytes(r, 64)
1265 | if err != nil {
1266 | return nil, err
1267 | }
1268 | p1 := new(bn256.G1)
1269 | _, err = p1.Unmarshal(b)
1270 | if err != nil {
1271 | return nil, err
1272 | }
1273 | pk.B1 = append(pk.B1, p1)
1274 | o += 64
1275 | }
1276 | if o != pPointsB2 {
1277 | return nil, fmt.Errorf("Unexpected offset, expected: %v, actual: %v", pPointsB2, o)
1278 | }
1279 | // B2
1280 | for i := 0; i < pk.NVars; i++ {
1281 | b, err = readNBytes(r, 128)
1282 | if err != nil {
1283 | return nil, err
1284 | }
1285 | p2 := new(bn256.G2)
1286 | _, err = p2.Unmarshal(b)
1287 | if err != nil {
1288 | return nil, err
1289 | }
1290 | pk.B2 = append(pk.B2, p2)
1291 | o += 128
1292 | }
1293 | if o != pPointsC {
1294 | return nil, fmt.Errorf("Unexpected offset, expected: %v, actual: %v", pPointsC, o)
1295 | }
1296 | // C
1297 | zb := make([]byte, 64)
1298 | z := new(bn256.G1)
1299 | _, err = z.Unmarshal(zb)
1300 | if err != nil {
1301 | return nil, err
1302 | }
1303 | for i := 0; i < pk.NPublic+1; i++ {
1304 | pk.C = append(pk.C, z)
1305 | }
1306 | for i := pk.NPublic + 1; i < pk.NVars; i++ {
1307 | b, err = readNBytes(r, 64)
1308 | if err != nil {
1309 | return nil, err
1310 | }
1311 | p1 := new(bn256.G1)
1312 | _, err = p1.Unmarshal(b)
1313 | if err != nil {
1314 | return nil, err
1315 | }
1316 | pk.C = append(pk.C, p1)
1317 | o += 64
1318 | }
1319 | if o != pPointsHExps {
1320 | return nil, fmt.Errorf("Unexpected offset, expected: %v, actual: %v", pPointsHExps, o)
1321 | }
1322 | // HExps
1323 | for i := 0; i < pk.DomainSize+1; i++ {
1324 | b, err = readNBytes(r, 64)
1325 | if err != nil {
1326 | return nil, err
1327 | }
1328 | p1 := new(bn256.G1)
1329 | _, err = p1.Unmarshal(b)
1330 | if err != nil {
1331 | return nil, err
1332 | }
1333 | pk.HExps = append(pk.HExps, p1)
1334 | }
1335 |
1336 | return &pk, nil
1337 | }
1338 |
--------------------------------------------------------------------------------
/parsers/parsers_test.go:
--------------------------------------------------------------------------------
1 | package parsers
2 |
3 | import (
4 | "encoding/json"
5 | "io/ioutil"
6 | "os"
7 | "testing"
8 |
9 | "github.com/stretchr/testify/assert"
10 | "github.com/stretchr/testify/require"
11 | "github.com/vocdoni/go-snark/types"
12 | )
13 |
14 | func TestParseArrayG1(t *testing.T) {
15 | aS := [][]string{
16 | {
17 | "16145916318196730299582072104388453231952213805668281741813587224450782397538",
18 | "4434505318477484327659527264104806919103674231447634885054368605283938696207",
19 | "1",
20 | },
21 | {
22 | "10618406967550056457559358662746625591602641004174976323307214433994084907915",
23 | "1843236360452735081347085412539192450068665510574800388201121698908391533923",
24 | "1",
25 | },
26 | {
27 | "1208972877970123411566574123860641832032384890981476033353526096830198333194",
28 | "777503551507025252294438107100944741641946695980350712141258191590862204805",
29 | "1",
30 | },
31 | {
32 | "0",
33 | "1",
34 | "0",
35 | },
36 | }
37 |
38 | a, err := arrayStringToG1(aS)
39 | assert.Nil(t, err)
40 | assert.Equal(t, "bn256.G1(23b243c928ce40c4cc2dad366e9f61723aef65866e1c66f42a08697f2f030462,"+
41 | " 09cdd7500688fb487ec9f27b5a732d68fa0f3ddca5c2c790e330fdfb03b77c0f)", a[0].String())
42 | assert.Equal(t, "bn256.G1(1779ce2c586b5fc523e72e755d969a63473052aaad7c11eb5bf0ecdcfdfefb8b,"+
43 | " 04133c1c74206dace57cd3d76ce59be381bbf08f51a5b3edc2b0c183d43eed63)", a[1].String())
44 | assert.Equal(t, "bn256.G1(02ac4120598d2f2bb81bc09b8df596403360577b0c5ff52485d1ef2200f23f0a,"+
45 | " 01b80d298de75f867d6484c55c3da02c042bb4eb9a1734d3386786aaa669af85)", a[2].String())
46 | assert.Equal(t, "bn256.G1(0000000000000000000000000000000000000000000000000000000000000000,"+
47 | " 0000000000000000000000000000000000000000000000000000000000000001)", a[3].String())
48 | }
49 |
50 | func TestParseG2(t *testing.T) {
51 | aS := [][]string{
52 | {
53 | "9283666785342556550467669770956850930982548182701254051508520248901282197973",
54 | "11369378229277445316894458966429873744779877313900506577160370623273013178252",
55 | },
56 | {
57 | "10625777544326349817513295021482494426101347915428005055375725845993157551870",
58 | "21401790227434807639472120486932615400751346915707967674912972446672152512583",
59 | },
60 | {
61 | "1",
62 | "0",
63 | },
64 | }
65 |
66 | a, err := stringToG2(aS)
67 | assert.Nil(t, err)
68 | assert.Equal(t, "bn256.G2((1922d70c934543aa655ec3277f7fa10a25ec973a4f001a7c54ce4954b4916f8c,"+
69 | " 14865e836947c42cf35b47d30e06535fff9dab319c4296e28afde368960671d5),"+
70 | " (2f50fbe77925b0a9d718c9ab38638bafa7c65f43f0d09035e518df97ad294847,"+
71 | " 177dfa1a3b8627faf0425d9511bcb4c6ca986ea05e3803b5c643c35b94a7e6fe))", a.String())
72 |
73 | aS = [][]string{
74 | {
75 | "13973091636763944887728510851169742544309374663995476311690518173988838518856",
76 | "12903946180439304546475897520537621821375470264150438270817301786763517825250",
77 | },
78 | {
79 | "370374369234123593044872519351942112043402224488849374153134091815693350697",
80 | "17423079115073430837335625309232513526393852743032331213038909731579295753224",
81 | },
82 | {
83 | "1",
84 | "0",
85 | },
86 | }
87 | a, err = stringToG2(aS)
88 | assert.Nil(t, err)
89 | assert.Equal(t, "bn256.G2((1c875fed67fff3b35f115b03706ec45f281b5f6cc71a99107240e09fce4910e2,"+
90 | " 1ee47d566e9a099626b9860bcd96f6d4a1ed65f115d3efa8e05e5f42cc793048),"+
91 | " (26851d022ce9961df65a430811824aaf3118710ac03b0614a50c05ee27d8e408,"+
92 | " 00d19fdce25b0d78fb317a5f1789823b7ed76274b0d1be9c685792c73b347729))", a.String())
93 | }
94 |
95 | func TestParseArrayG2(t *testing.T) {
96 | aS := [][][]string{
97 | {
98 | {
99 | "0",
100 | "0",
101 | },
102 | {
103 | "1",
104 | "0",
105 | },
106 | {
107 | "0",
108 | "0",
109 | },
110 | },
111 | {
112 | {
113 | "0",
114 | "0",
115 | },
116 | {
117 | "1",
118 | "0",
119 | },
120 | {
121 | "0",
122 | "0",
123 | },
124 | },
125 | {
126 | {
127 | "0",
128 | "0",
129 | },
130 | {
131 | "1",
132 | "0",
133 | },
134 | {
135 | "0",
136 | "0",
137 | },
138 | },
139 | {
140 | {
141 | "9283666785342556550467669770956850930982548182701254051508520248901282197973",
142 | "11369378229277445316894458966429873744779877313900506577160370623273013178252",
143 | },
144 | {
145 | "10625777544326349817513295021482494426101347915428005055375725845993157551870",
146 | "21401790227434807639472120486932615400751346915707967674912972446672152512583",
147 | },
148 | {
149 | "1",
150 | "0",
151 | },
152 | },
153 | }
154 |
155 | a, err := arrayStringToG2(aS)
156 | assert.Nil(t, err)
157 | assert.Equal(t, "bn256.G2((0000000000000000000000000000000000000000000000000000000000000000,"+
158 | " 0000000000000000000000000000000000000000000000000000000000000000),"+
159 | " (0000000000000000000000000000000000000000000000000000000000000000,"+
160 | " 0000000000000000000000000000000000000000000000000000000000000001))",
161 | a[0].String())
162 | assert.Equal(t, "bn256.G2((1922d70c934543aa655ec3277f7fa10a25ec973a4f001a7c54ce4954b4916f8c,"+
163 | " 14865e836947c42cf35b47d30e06535fff9dab319c4296e28afde368960671d5),"+
164 | " (2f50fbe77925b0a9d718c9ab38638bafa7c65f43f0d09035e518df97ad294847,"+
165 | " 177dfa1a3b8627faf0425d9511bcb4c6ca986ea05e3803b5c643c35b94a7e6fe))",
166 | a[3].String())
167 | }
168 |
169 | func testCircuitParseWitnessBin(t *testing.T, circuit string) {
170 | witnessBinFile, err := os.Open("../testdata/" + circuit + "/witness.bin") //nolint:gosec
171 | require.Nil(t, err)
172 | defer witnessBinFile.Close() //nolint:errcheck,gosec
173 | witness, err := ParseWitnessBin(witnessBinFile)
174 | require.Nil(t, err)
175 |
176 | witnessJSON, err := ioutil.ReadFile("../testdata/" + circuit + "/witness.json") //nolint:gosec
177 | require.Nil(t, err)
178 | w, err := ParseWitness(witnessJSON)
179 | require.Nil(t, err)
180 |
181 | assert.Equal(t, len(w), len(witness))
182 | assert.Equal(t, w[0], witness[0])
183 | assert.Equal(t, w[1], witness[1])
184 | assert.Equal(t, w[10], witness[10])
185 | assert.Equal(t, w[len(w)-3], witness[len(w)-3])
186 | assert.Equal(t, w[len(w)-2], witness[len(w)-2])
187 | assert.Equal(t, w[len(w)-1], witness[len(w)-1])
188 | }
189 |
190 | func TestParseWitnessBin(t *testing.T) {
191 | testCircuitParseWitnessBin(t, "circuit1k")
192 | testCircuitParseWitnessBin(t, "circuit5k")
193 | }
194 |
195 | func TestProofSmartContractFormat(t *testing.T) {
196 | proofJSON, err := ioutil.ReadFile("../testdata/circuit1k/proof.json")
197 | require.Nil(t, err)
198 | proof, err := ParseProof(proofJSON)
199 | require.Nil(t, err)
200 | pS := ProofToString(proof)
201 |
202 | pSC := ProofToSmartContractFormat(proof)
203 | assert.Nil(t, err)
204 | assert.Equal(t, pS.A[0], pSC.A[0])
205 | assert.Equal(t, pS.A[1], pSC.A[1])
206 | assert.Equal(t, pS.B[0][0], pSC.B[0][1])
207 | assert.Equal(t, pS.B[0][1], pSC.B[0][0])
208 | assert.Equal(t, pS.B[1][0], pSC.B[1][1])
209 | assert.Equal(t, pS.B[1][1], pSC.B[1][0])
210 | assert.Equal(t, pS.C[0], pSC.C[0])
211 | assert.Equal(t, pS.C[1], pSC.C[1])
212 | assert.Equal(t, pS.Protocol, pSC.Protocol)
213 |
214 | pSC2 := ProofStringToSmartContractFormat(pS)
215 | assert.Equal(t, pSC, pSC2)
216 | }
217 |
218 | func TestProofJSON(t *testing.T) {
219 | proofJSON, err := ioutil.ReadFile("../testdata/circuit1k/proof.json")
220 | require.Nil(t, err)
221 | proof, err := ParseProof(proofJSON)
222 | require.Nil(t, err)
223 |
224 | proof1JSON, err := json.Marshal(proof)
225 | require.Nil(t, err)
226 | var proof1 types.Proof
227 | err = json.Unmarshal(proof1JSON, &proof1)
228 | require.Nil(t, err)
229 | require.Equal(t, *proof, proof1)
230 | }
231 |
232 | func testCircuitParsePkBin(t *testing.T, circuit string) {
233 | pkBinFile, err := os.Open("../testdata/" + circuit + "/proving_key.bin") //nolint:gosec
234 | require.Nil(t, err)
235 | defer pkBinFile.Close() //nolint:errcheck,gosec
236 | pk, err := ParsePkBin(pkBinFile)
237 | require.Nil(t, err)
238 |
239 | pkJSON, err := ioutil.ReadFile("../testdata/" + circuit + "/proving_key.json") //nolint:gosec
240 | require.Nil(t, err)
241 | pkJ, err := ParsePk(pkJSON)
242 | require.Nil(t, err)
243 |
244 | assert.Equal(t, pkJ.NVars, pk.NVars)
245 | assert.Equal(t, pkJ.NPublic, pk.NPublic)
246 | assert.Equal(t, pkJ.DomainSize, pk.DomainSize)
247 | assert.Equal(t, pkJ.VkAlpha1, pk.VkAlpha1)
248 | assert.Equal(t, pkJ.VkBeta1, pk.VkBeta1)
249 | assert.Equal(t, pkJ.VkDelta1, pk.VkDelta1)
250 | assert.Equal(t, pkJ.VkDelta2, pk.VkDelta2)
251 | assert.Equal(t, pkJ.PolsA, pk.PolsA)
252 | assert.Equal(t, pkJ.PolsB, pk.PolsB)
253 | assert.Equal(t, pkJ.A, pk.A)
254 | assert.Equal(t, pkJ.B1, pk.B1)
255 | assert.Equal(t, pkJ.B2, pk.B2)
256 | assert.Equal(t, pkJ.C, pk.C)
257 | assert.Equal(t, pkJ.HExps[:pkJ.DomainSize], pk.HExps[:pk.DomainSize]) // circom behaviour
258 |
259 | assert.Equal(t, pkJ.NVars, pk.NVars)
260 | assert.Equal(t, pkJ.NPublic, pk.NPublic)
261 | assert.Equal(t, pkJ.DomainSize, pk.DomainSize)
262 | }
263 |
264 | func TestParsePkBin(t *testing.T) {
265 | testCircuitParsePkBin(t, "circuit1k")
266 | testCircuitParsePkBin(t, "circuit5k")
267 | }
268 |
269 | func testGoCircomPkFormat(t *testing.T, circuit string) {
270 | pkJSON, err := ioutil.ReadFile("../testdata/" + circuit + "/proving_key.json") //nolint:gosec
271 | require.Nil(t, err)
272 | pk, err := ParsePk(pkJSON)
273 | require.Nil(t, err)
274 |
275 | pkGBin, err := PkToGoBin(pk)
276 | require.Nil(t, err)
277 | err = ioutil.WriteFile("../testdata/"+circuit+"/proving_key.go.bin", pkGBin, 0600) //nolint:gosec
278 | assert.Nil(t, err)
279 |
280 | // parse ProvingKeyGo
281 | pkGoBinFile, err := os.Open("../testdata/" + circuit + "/proving_key.go.bin") //nolint:gosec
282 | require.Nil(t, err)
283 | defer pkGoBinFile.Close() //nolint:errcheck,gosec
284 | pkG, err := ParsePkGoBin(pkGoBinFile)
285 | require.Nil(t, err)
286 | assert.Equal(t, pk.VkAlpha1, pkG.VkAlpha1)
287 | assert.Equal(t, pk.VkBeta1, pkG.VkBeta1)
288 | assert.Equal(t, pk.VkDelta1, pkG.VkDelta1)
289 | assert.Equal(t, pk.VkBeta2, pkG.VkBeta2)
290 | assert.Equal(t, pk.VkDelta2, pkG.VkDelta2)
291 | assert.Equal(t, pk.A, pkG.A)
292 | assert.Equal(t, pk.B1, pkG.B1)
293 | assert.Equal(t, pk.B2, pkG.B2)
294 | assert.Equal(t, pk.C, pkG.C)
295 | assert.Equal(t, pk.HExps, pkG.HExps)
296 | assert.Equal(t, pk.PolsA, pkG.PolsA)
297 | assert.Equal(t, pk.PolsB, pkG.PolsB)
298 |
299 | assert.Equal(t, pk.NVars, pkG.NVars)
300 | assert.Equal(t, pk.NPublic, pkG.NPublic)
301 | assert.Equal(t, pk.DomainSize, pkG.DomainSize)
302 | }
303 |
304 | func TestGoCircomPkFormat(t *testing.T) {
305 | testGoCircomPkFormat(t, "circuit1k")
306 | testGoCircomPkFormat(t, "circuit5k")
307 | // testGoCircomPkFormat(t, "circuit10k")
308 | // testGoCircomPkFormat(t, "circuit20k")
309 | }
310 |
311 | func benchmarkParsePk(b *testing.B, circuit string) {
312 | pkJSON, err := ioutil.ReadFile("../testdata/" + circuit + "/proving_key.json") //nolint:gosec
313 | require.Nil(b, err)
314 |
315 | pkBinFile, err := os.Open("../testdata/" + circuit + "/proving_key.bin") //nolint:gosec
316 | require.Nil(b, err)
317 | defer pkBinFile.Close() //nolint:errcheck,gosec
318 |
319 | pkGoBinFile, err := os.Open("../testdata/" + circuit + "/proving_key.go.bin") //nolint:gosec
320 | require.Nil(b, err)
321 | defer pkGoBinFile.Close() //nolint:errcheck,gosec
322 |
323 | b.Run("ParsePkJSON "+circuit, func(b *testing.B) {
324 | for i := 0; i < b.N; i++ {
325 | _, err = ParsePk(pkJSON)
326 | require.Nil(b, err)
327 | }
328 | })
329 | b.Run("ParsePkBin "+circuit, func(b *testing.B) {
330 | for i := 0; i < b.N; i++ {
331 | pkBinFile.Seek(0, 0) //nolint:errcheck,gosec
332 | _, err = ParsePkBin(pkBinFile)
333 | require.Nil(b, err)
334 | }
335 | })
336 | b.Run("ParsePkGoBin "+circuit, func(b *testing.B) {
337 | for i := 0; i < b.N; i++ {
338 | pkGoBinFile.Seek(0, 0) //nolint:errcheck,gosec
339 | _, err = ParsePkGoBin(pkGoBinFile)
340 | require.Nil(b, err)
341 | }
342 | })
343 | }
344 |
345 | func BenchmarkParsePk(b *testing.B) {
346 | benchmarkParsePk(b, "circuit1k")
347 | benchmarkParsePk(b, "circuit5k")
348 | // benchmarkParsePk(b, "circuit10k")
349 | // benchmarkParsePk(b, "circuit20k")
350 | }
351 |
--------------------------------------------------------------------------------
/prover/arithmetic.go:
--------------------------------------------------------------------------------
1 | package prover
2 |
3 | import (
4 | "bytes"
5 | "math/big"
6 |
7 | bn256 "github.com/ethereum/go-ethereum/crypto/bn256/cloudflare"
8 | "github.com/iden3/go-iden3-crypto/ff"
9 | "github.com/vocdoni/go-snark/types"
10 | )
11 |
12 | func arrayOfZeroes(n int) []*big.Int {
13 | r := make([]*big.Int, n)
14 | for i := 0; i < n; i++ {
15 | r[i] = new(big.Int).SetInt64(0)
16 | }
17 | return r[:]
18 | }
19 |
20 | func arrayOfZeroesE(n int) []*ff.Element {
21 | r := make([]*ff.Element, n)
22 | for i := 0; i < n; i++ {
23 | r[i] = ff.NewElement()
24 | }
25 | return r[:]
26 | }
27 |
28 | func arrayOfZeroesG1(n int) []*bn256.G1 {
29 | r := make([]*bn256.G1, n)
30 | for i := 0; i < n; i++ {
31 | r[i] = new(bn256.G1).ScalarBaseMult(big.NewInt(0))
32 | }
33 | return r[:]
34 | }
35 |
36 | func arrayOfZeroesG2(n int) []*bn256.G2 {
37 | r := make([]*bn256.G2, n)
38 | for i := 0; i < n; i++ {
39 | r[i] = new(bn256.G2).ScalarBaseMult(big.NewInt(0))
40 | }
41 | return r[:]
42 | }
43 |
44 | func fAdd(a, b *big.Int) *big.Int {
45 | ab := new(big.Int).Add(a, b)
46 | return ab.Mod(ab, types.R)
47 | }
48 |
49 | func fSub(a, b *big.Int) *big.Int {
50 | ab := new(big.Int).Sub(a, b)
51 | return new(big.Int).Mod(ab, types.R)
52 | }
53 |
54 | func fMul(a, b *big.Int) *big.Int {
55 | ab := new(big.Int).Mul(a, b)
56 | return ab.Mod(ab, types.R)
57 | }
58 |
59 | func fDiv(a, b *big.Int) *big.Int {
60 | ab := new(big.Int).Mul(a, new(big.Int).ModInverse(b, types.R))
61 | return new(big.Int).Mod(ab, types.R)
62 | }
63 |
64 | //nolint:unused,deadcode // TODO check
65 | func fNeg(a *big.Int) *big.Int {
66 | return new(big.Int).Mod(new(big.Int).Neg(a), types.R)
67 | }
68 |
69 | func fInv(a *big.Int) *big.Int {
70 | return new(big.Int).ModInverse(a, types.R)
71 | }
72 |
73 | func fExp(base *big.Int, e *big.Int) *big.Int {
74 | res := big.NewInt(1)
75 | rem := new(big.Int).Set(e)
76 | exp := base
77 |
78 | for !bytes.Equal(rem.Bytes(), big.NewInt(int64(0)).Bytes()) {
79 | // if BigIsOdd(rem) {
80 | if rem.Bit(0) == 1 { // .Bit(0) returns 1 when is odd
81 | res = fMul(res, exp)
82 | }
83 | exp = fMul(exp, exp)
84 | rem.Rsh(rem, 1)
85 | }
86 | return res
87 | }
88 |
89 | func max(a, b int) int {
90 | if a > b {
91 | return a
92 | }
93 | return b
94 | }
95 |
96 | func polynomialSub(a, b []*big.Int) []*big.Int {
97 | r := arrayOfZeroes(max(len(a), len(b)))
98 | for i := 0; i < len(a); i++ {
99 | r[i] = fAdd(r[i], a[i])
100 | }
101 | for i := 0; i < len(b); i++ {
102 | r[i] = fSub(r[i], b[i])
103 | }
104 | return r
105 | }
106 |
107 | func polynomialSubE(a, b []*ff.Element) []*ff.Element {
108 | r := arrayOfZeroesE(max(len(a), len(b)))
109 | for i := 0; i < len(a); i++ {
110 | r[i].Add(r[i], a[i])
111 | }
112 | for i := 0; i < len(b); i++ {
113 | r[i].Sub(r[i], b[i])
114 | }
115 | return r
116 | }
117 |
118 | func polynomialMul(a, b []*big.Int) []*big.Int {
119 | r := arrayOfZeroes(len(a) + len(b) - 1)
120 | for i := 0; i < len(a); i++ {
121 | for j := 0; j < len(b); j++ {
122 | r[i+j] = fAdd(r[i+j], fMul(a[i], b[j]))
123 | }
124 | }
125 | return r
126 | }
127 |
128 | func polynomialMulE(a, b []*ff.Element) []*ff.Element {
129 | r := arrayOfZeroesE(len(a) + len(b) - 1)
130 | for i := 0; i < len(a); i++ {
131 | for j := 0; j < len(b); j++ {
132 | r[i+j].Add(r[i+j], ff.NewElement().Mul(a[i], b[j]))
133 | }
134 | }
135 | return r
136 | }
137 |
138 | func polynomialDiv(a, b []*big.Int) ([]*big.Int, []*big.Int) {
139 | // https://en.wikipedia.org/wiki/Division_algorithm
140 | r := arrayOfZeroes(len(a) - len(b) + 1)
141 | rem := a
142 | for len(rem) >= len(b) {
143 | l := fDiv(rem[len(rem)-1], b[len(b)-1])
144 | pos := len(rem) - len(b)
145 | r[pos] = l
146 | aux := arrayOfZeroes(pos)
147 | aux1 := append(aux, l)
148 | aux2 := polynomialSub(rem, polynomialMul(b, aux1))
149 | rem = aux2[:len(aux2)-1]
150 | }
151 | return r, rem
152 | }
153 |
154 | func polynomialDivE(a, b []*ff.Element) ([]*ff.Element, []*ff.Element) {
155 | // https://en.wikipedia.org/wiki/Division_algorithm
156 | r := arrayOfZeroesE(len(a) - len(b) + 1)
157 | rem := a
158 | for len(rem) >= len(b) {
159 | l := ff.NewElement().Div(rem[len(rem)-1], b[len(b)-1])
160 | pos := len(rem) - len(b)
161 | r[pos] = l
162 | aux := arrayOfZeroesE(pos)
163 | aux1 := append(aux, l)
164 | aux2 := polynomialSubE(rem, polynomialMulE(b, aux1))
165 | rem = aux2[:len(aux2)-1]
166 | }
167 | return r, rem
168 | }
169 |
--------------------------------------------------------------------------------
/prover/arithmetic_test.go:
--------------------------------------------------------------------------------
1 | package prover
2 |
3 | import (
4 | "crypto/rand"
5 | "math/big"
6 | "testing"
7 |
8 | cryptoConstants "github.com/iden3/go-iden3-crypto/constants"
9 | "github.com/iden3/go-iden3-crypto/utils"
10 | )
11 |
12 | func randBI() *big.Int {
13 | maxbits := 256
14 | b := make([]byte, (maxbits/8)-1)
15 | _, err := rand.Read(b)
16 | if err != nil {
17 | panic(err)
18 | }
19 | r := new(big.Int).SetBytes(b)
20 | return new(big.Int).Mod(r, cryptoConstants.Q)
21 | }
22 |
23 | func BenchmarkArithmetic(b *testing.B) {
24 | // generate arrays with bigint
25 | var p, q []*big.Int
26 | for i := 0; i < 1000; i++ {
27 | pi := randBI()
28 | p = append(p, pi)
29 | }
30 | for i := 1000 - 1; i >= 0; i-- {
31 | q = append(q, p[i])
32 | }
33 | pe := utils.BigIntArrayToElementArray(p)
34 | qe := utils.BigIntArrayToElementArray(q)
35 |
36 | b.Run("polynomialSub", func(b *testing.B) {
37 | for i := 0; i < b.N; i++ {
38 | polynomialSub(p, q)
39 | }
40 | })
41 | b.Run("polynomialSubE", func(b *testing.B) {
42 | for i := 0; i < b.N; i++ {
43 | polynomialSubE(pe, qe)
44 | }
45 | })
46 | b.Run("polynomialMul", func(b *testing.B) {
47 | for i := 0; i < b.N; i++ {
48 | polynomialMul(p, q)
49 | }
50 | })
51 | b.Run("polynomialMulE", func(b *testing.B) {
52 | for i := 0; i < b.N; i++ {
53 | polynomialMulE(pe, qe)
54 | }
55 | })
56 | b.Run("polynomialDiv", func(b *testing.B) {
57 | for i := 0; i < b.N; i++ {
58 | polynomialDiv(p, q)
59 | }
60 | })
61 | b.Run("polynomialDivE", func(b *testing.B) {
62 | for i := 0; i < b.N; i++ {
63 | polynomialDivE(pe, qe)
64 | }
65 | })
66 | }
67 |
--------------------------------------------------------------------------------
/prover/gextra.go:
--------------------------------------------------------------------------------
1 | package prover
2 |
3 | import (
4 | "math/big"
5 |
6 | bn256 "github.com/ethereum/go-ethereum/crypto/bn256/cloudflare"
7 | cryptoConstants "github.com/iden3/go-iden3-crypto/constants"
8 | )
9 |
10 | type tableG1 struct {
11 | data []*bn256.G1
12 | }
13 |
14 | //nolint:unused // TODO check
15 | func (t tableG1) getData() []*bn256.G1 {
16 | return t.data
17 | }
18 |
19 | // Compute table of gsize elements as ::
20 | // Table[0] = Inf
21 | // Table[1] = a[0]
22 | // Table[2] = a[1]
23 | // Table[3] = a[0]+a[1]
24 | // .....
25 | // Table[(1<= 0; i-- {
89 | // TODO. bn256 doesn't export double operation. We will need to fork repo and export it
90 | Q = new(bn256.G1).Add(Q, Q)
91 | b := getBit(kExt, i)
92 | if b != 0 {
93 | // TODO. bn256 doesn't export mixed addition (Jacobian + Affine), which is more efficient.
94 | Q.Add(Q, t.data[b])
95 | }
96 | }
97 | if qPrev != nil {
98 | return Q.Add(Q, qPrev)
99 | }
100 | return Q
101 | }
102 |
103 | // Multiply scalar by precomputed table of G1 elements without intermediate doubling
104 | func mulTableNoDoubleG1(t []tableG1, k []*big.Int, qPrev *bn256.G1, gsize int) *bn256.G1 {
105 | // We need at least gsize elements. If not enough, fill with 0
106 | minNElems := len(t) * gsize
107 | kExt := make([]*big.Int, 0)
108 | kExt = append(kExt, k...)
109 | for i := len(k); i < minNElems; i++ {
110 | kExt = append(kExt, new(big.Int).SetUint64(0))
111 | }
112 | // Init Adders
113 | nbitsQ := cryptoConstants.Q.BitLen()
114 | Q := make([]*bn256.G1, nbitsQ)
115 |
116 | for i := 0; i < nbitsQ; i++ {
117 | Q[i] = new(bn256.G1).ScalarBaseMult(big.NewInt(0))
118 | }
119 |
120 | // Perform bitwise addition
121 | for j := 0; j < len(t); j++ {
122 | msb := getMsb(kExt[j*gsize : (j+1)*gsize])
123 |
124 | for i := msb - 1; i >= 0; i-- {
125 | b := getBit(kExt[j*gsize:(j+1)*gsize], i)
126 | if b != 0 {
127 | // TODO. bn256 doesn't export mixed addition (Jacobian + Affine), which is more efficient.
128 | Q[i].Add(Q[i], t[j].data[b])
129 | }
130 | }
131 | }
132 |
133 | // Consolidate Addition
134 | R := new(bn256.G1).Set(Q[nbitsQ-1])
135 | for i := nbitsQ - 1; i > 0; i-- {
136 | // TODO. bn256 doesn't export double operation. We will need to fork repo and export it
137 | R = new(bn256.G1).Add(R, R)
138 | R.Add(R, Q[i-1])
139 | }
140 |
141 | if qPrev != nil {
142 | return R.Add(R, qPrev)
143 | }
144 | return R
145 | }
146 |
147 | // Compute tables within function. This solution should still be faster than std multiplication
148 | // for gsize = 7
149 | func scalarMultG1(a []*bn256.G1, k []*big.Int, qPrev *bn256.G1, gsize int) *bn256.G1 {
150 | ntables := int((len(a) + gsize - 1) / gsize)
151 | table := tableG1{}
152 | Q := new(bn256.G1).ScalarBaseMult(new(big.Int))
153 |
154 | for i := 0; i < ntables-1; i++ {
155 | table.newTableG1(a[i*gsize:(i+1)*gsize], gsize, false)
156 | Q = table.mulTableG1(k[i*gsize:(i+1)*gsize], Q, gsize)
157 | }
158 | table.newTableG1(a[(ntables-1)*gsize:], gsize, false)
159 | Q = table.mulTableG1(k[(ntables-1)*gsize:], Q, gsize)
160 |
161 | if qPrev != nil {
162 | return Q.Add(Q, qPrev)
163 | }
164 | return Q
165 | }
166 |
167 | // Multiply scalar by precomputed table of G1 elements without intermediate doubling
168 | func scalarMultNoDoubleG1(a []*bn256.G1, k []*big.Int, qPrev *bn256.G1, gsize int) *bn256.G1 {
169 | ntables := int((len(a) + gsize - 1) / gsize)
170 | table := tableG1{}
171 |
172 | // We need at least gsize elements. If not enough, fill with 0
173 | minNElems := ntables * gsize
174 | kExt := make([]*big.Int, 0)
175 | kExt = append(kExt, k...)
176 | for i := len(k); i < minNElems; i++ {
177 | kExt = append(kExt, new(big.Int).SetUint64(0))
178 | }
179 | // Init Adders
180 | nbitsQ := cryptoConstants.Q.BitLen()
181 | Q := make([]*bn256.G1, nbitsQ)
182 |
183 | for i := 0; i < nbitsQ; i++ {
184 | Q[i] = new(bn256.G1).ScalarBaseMult(big.NewInt(0))
185 | }
186 |
187 | // Perform bitwise addition
188 | for j := 0; j < ntables-1; j++ {
189 | table.newTableG1(a[j*gsize:(j+1)*gsize], gsize, false)
190 | msb := getMsb(kExt[j*gsize : (j+1)*gsize])
191 |
192 | for i := msb - 1; i >= 0; i-- {
193 | b := getBit(kExt[j*gsize:(j+1)*gsize], i)
194 | if b != 0 {
195 | // TODO. bn256 doesn't export mixed addition (Jacobian + Affine), which is more efficient.
196 | Q[i].Add(Q[i], table.data[b])
197 | }
198 | }
199 | }
200 | table.newTableG1(a[(ntables-1)*gsize:], gsize, false)
201 | msb := getMsb(kExt[(ntables-1)*gsize:])
202 |
203 | for i := msb - 1; i >= 0; i-- {
204 | b := getBit(kExt[(ntables-1)*gsize:], i)
205 | if b != 0 {
206 | // TODO. bn256 doesn't export mixed addition (Jacobian + Affine), which is more efficient.
207 | Q[i].Add(Q[i], table.data[b])
208 | }
209 | }
210 |
211 | // Consolidate Addition
212 | R := new(bn256.G1).Set(Q[nbitsQ-1])
213 | for i := nbitsQ - 1; i > 0; i-- {
214 | // TODO. bn256 doesn't export double operation. We will need to fork repo and export it
215 | R = new(bn256.G1).Add(R, R)
216 | R.Add(R, Q[i-1])
217 | }
218 | if qPrev != nil {
219 | return R.Add(R, qPrev)
220 | }
221 | return R
222 | }
223 |
224 | /////
225 |
226 | // TODO - How can avoid replicating code in G2?
227 | //G2
228 |
229 | type tableG2 struct {
230 | data []*bn256.G2
231 | }
232 |
233 | //nolint:unused // TODO check
234 | func (t tableG2) getData() []*bn256.G2 {
235 | return t.data
236 | }
237 |
238 | // Compute table of gsize elements as ::
239 | // Table[0] = Inf
240 | // Table[1] = a[0]
241 | // Table[2] = a[1]
242 | // Table[3] = a[0]+a[1]
243 | // .....
244 | // Table[(1< toaffine = True doesnt work. Problem with Marshal/Unmarshal
246 | func (t *tableG2) newTableG2(a []*bn256.G2, gsize int, toaffine bool) {
247 | // EC table
248 | table := make([]*bn256.G2, 0)
249 |
250 | // We need at least gsize elements. If not enough, fill with 0
251 | aExt := make([]*bn256.G2, 0)
252 | aExt = append(aExt, a...)
253 |
254 | for i := len(a); i < gsize; i++ {
255 | aExt = append(aExt, new(bn256.G2).ScalarBaseMult(big.NewInt(0)))
256 | }
257 |
258 | elG2 := new(bn256.G2).ScalarBaseMult(big.NewInt(0))
259 | table = append(table, elG2)
260 | lastPow2 := 1
261 | nelems := 0
262 | for i := 1; i < 1<= 0; i-- {
309 | // TODO. bn256 doesn't export double operation. We will need to fork repo and export it
310 | Q = new(bn256.G2).Add(Q, Q)
311 | b := getBit(kExt, i)
312 | if b != 0 {
313 | // TODO. bn256 doesn't export mixed addition (Jacobian + Affine), which is more efficient.
314 | Q.Add(Q, t.data[b])
315 | }
316 | }
317 | if qPrev != nil {
318 | return Q.Add(Q, qPrev)
319 | }
320 | return Q
321 | }
322 |
323 | // Multiply scalar by precomputed table of G2 elements without intermediate doubling
324 | func mulTableNoDoubleG2(t []tableG2, k []*big.Int, qPrev *bn256.G2, gsize int) *bn256.G2 {
325 | // We need at least gsize elements. If not enough, fill with 0
326 | minNElems := len(t) * gsize
327 | kExt := make([]*big.Int, 0)
328 | kExt = append(kExt, k...)
329 | for i := len(k); i < minNElems; i++ {
330 | kExt = append(kExt, new(big.Int).SetUint64(0))
331 | }
332 | // Init Adders
333 | nbitsQ := cryptoConstants.Q.BitLen()
334 | Q := make([]*bn256.G2, nbitsQ)
335 |
336 | for i := 0; i < nbitsQ; i++ {
337 | Q[i] = new(bn256.G2).ScalarBaseMult(big.NewInt(0))
338 | }
339 |
340 | // Perform bitwise addition
341 | for j := 0; j < len(t); j++ {
342 | msb := getMsb(kExt[j*gsize : (j+1)*gsize])
343 |
344 | for i := msb - 1; i >= 0; i-- {
345 | b := getBit(kExt[j*gsize:(j+1)*gsize], i)
346 | if b != 0 {
347 | // TODO. bn256 doesn't export mixed addition (Jacobian + Affine), which is more efficient.
348 | Q[i].Add(Q[i], t[j].data[b])
349 | }
350 | }
351 | }
352 |
353 | // Consolidate Addition
354 | R := new(bn256.G2).Set(Q[nbitsQ-1])
355 | for i := nbitsQ - 1; i > 0; i-- {
356 | // TODO. bn256 doesn't export double operation. We will need to fork repo and export it
357 | R = new(bn256.G2).Add(R, R)
358 | R.Add(R, Q[i-1])
359 | }
360 | if qPrev != nil {
361 | return R.Add(R, qPrev)
362 | }
363 | return R
364 | }
365 |
366 | // Compute tables within function. This solution should still be faster than std multiplication
367 | // for gsize = 7
368 | func scalarMultG2(a []*bn256.G2, k []*big.Int, qPrev *bn256.G2, gsize int) *bn256.G2 {
369 | ntables := int((len(a) + gsize - 1) / gsize)
370 | table := tableG2{}
371 | Q := new(bn256.G2).ScalarBaseMult(new(big.Int))
372 |
373 | for i := 0; i < ntables-1; i++ {
374 | table.newTableG2(a[i*gsize:(i+1)*gsize], gsize, false)
375 | Q = table.mulTableG2(k[i*gsize:(i+1)*gsize], Q, gsize)
376 | }
377 | table.newTableG2(a[(ntables-1)*gsize:], gsize, false)
378 | Q = table.mulTableG2(k[(ntables-1)*gsize:], Q, gsize)
379 |
380 | if qPrev != nil {
381 | return Q.Add(Q, qPrev)
382 | }
383 | return Q
384 | }
385 |
386 | // Multiply scalar by precomputed table of G2 elements without intermediate doubling
387 | func scalarMultNoDoubleG2(a []*bn256.G2, k []*big.Int, qPrev *bn256.G2, gsize int) *bn256.G2 {
388 | ntables := int((len(a) + gsize - 1) / gsize)
389 | table := tableG2{}
390 |
391 | // We need at least gsize elements. If not enough, fill with 0
392 | minNElems := ntables * gsize
393 | kExt := make([]*big.Int, 0)
394 | kExt = append(kExt, k...)
395 | for i := len(k); i < minNElems; i++ {
396 | kExt = append(kExt, new(big.Int).SetUint64(0))
397 | }
398 | // Init Adders
399 | nbitsQ := cryptoConstants.Q.BitLen()
400 | Q := make([]*bn256.G2, nbitsQ)
401 |
402 | for i := 0; i < nbitsQ; i++ {
403 | Q[i] = new(bn256.G2).ScalarBaseMult(big.NewInt(0))
404 | }
405 |
406 | // Perform bitwise addition
407 | for j := 0; j < ntables-1; j++ {
408 | table.newTableG2(a[j*gsize:(j+1)*gsize], gsize, false)
409 | msb := getMsb(kExt[j*gsize : (j+1)*gsize])
410 |
411 | for i := msb - 1; i >= 0; i-- {
412 | b := getBit(kExt[j*gsize:(j+1)*gsize], i)
413 | if b != 0 {
414 | // TODO. bn256 doesn't export mixed addition (Jacobian + Affine), which is more efficient.
415 | Q[i].Add(Q[i], table.data[b])
416 | }
417 | }
418 | }
419 | table.newTableG2(a[(ntables-1)*gsize:], gsize, false)
420 | msb := getMsb(kExt[(ntables-1)*gsize:])
421 |
422 | for i := msb - 1; i >= 0; i-- {
423 | b := getBit(kExt[(ntables-1)*gsize:], i)
424 | if b != 0 {
425 | // TODO. bn256 doesn't export mixed addition (Jacobian + Affine), which is more efficient.
426 | Q[i].Add(Q[i], table.data[b])
427 | }
428 | }
429 |
430 | // Consolidate Addition
431 | R := new(bn256.G2).Set(Q[nbitsQ-1])
432 | for i := nbitsQ - 1; i > 0; i-- {
433 | // TODO. bn256 doesn't export double operation. We will need to fork repo and export it
434 | R = new(bn256.G2).Add(R, R)
435 | R.Add(R, Q[i-1])
436 | }
437 | if qPrev != nil {
438 | return R.Add(R, qPrev)
439 | }
440 | return R
441 | }
442 |
443 | // Return most significant bit position in a group of Big Integers
444 | func getMsb(k []*big.Int) int {
445 | msb := 0
446 |
447 | for _, el := range k {
448 | tmpMsb := el.BitLen()
449 | if tmpMsb > msb {
450 | msb = tmpMsb
451 | }
452 | }
453 | return msb
454 | }
455 |
456 | // Return ith bit in group of Big Integers
457 | func getBit(k []*big.Int, i int) uint {
458 | tableIdx := uint(0)
459 |
460 | for idx, el := range k {
461 | b := el.Bit(i)
462 | tableIdx += (b << idx)
463 | }
464 | return tableIdx
465 | }
466 |
--------------------------------------------------------------------------------
/prover/gextra_test.go:
--------------------------------------------------------------------------------
1 | package prover
2 |
3 | import (
4 | "bytes"
5 | "crypto/rand"
6 | "fmt"
7 | "math/big"
8 | "testing"
9 | "time"
10 |
11 | bn256 "github.com/ethereum/go-ethereum/crypto/bn256/cloudflare"
12 | )
13 |
14 | const (
15 | n1 = 5000
16 | n2 = 5000
17 | )
18 |
19 | func randomBigIntArray(n int) []*big.Int {
20 | var p []*big.Int
21 | for i := 0; i < n; i++ {
22 | pi := randBI()
23 | p = append(p, pi)
24 | }
25 |
26 | return p
27 | }
28 |
29 | func randomG1Array(n int) []*bn256.G1 {
30 | arrayG1 := make([]*bn256.G1, n)
31 |
32 | for i := 0; i < n; i++ {
33 | _, arrayG1[i], _ = bn256.RandomG1(rand.Reader)
34 | }
35 | return arrayG1
36 | }
37 |
38 | func randomG2Array(n int) []*bn256.G2 {
39 | arrayG2 := make([]*bn256.G2, n)
40 |
41 | for i := 0; i < n; i++ {
42 | _, arrayG2[i], _ = bn256.RandomG2(rand.Reader)
43 | }
44 | return arrayG2
45 | }
46 |
47 | func TestTableG1(t *testing.T) {
48 | n := n1
49 |
50 | // init scalar
51 | var arrayW = randomBigIntArray(n)
52 | // init G1 array
53 | var arrayG1 = randomG1Array(n)
54 |
55 | beforeT := time.Now()
56 | Q1 := new(bn256.G1).ScalarBaseMult(new(big.Int))
57 | for i := 0; i < n; i++ {
58 | Q1.Add(Q1, new(bn256.G1).ScalarMult(arrayG1[i], arrayW[i]))
59 | }
60 | fmt.Println("Std. Mult. time elapsed:", time.Since(beforeT))
61 |
62 | for gsize := 2; gsize < 10; gsize++ {
63 | ntables := int((n + gsize - 1) / gsize)
64 | table := make([]tableG1, ntables)
65 |
66 | for i := 0; i < ntables-1; i++ {
67 | table[i].newTableG1(arrayG1[i*gsize:(i+1)*gsize], gsize, true)
68 | }
69 | table[ntables-1].newTableG1(arrayG1[(ntables-1)*gsize:], gsize, true)
70 |
71 | beforeT = time.Now()
72 | Q2 := new(bn256.G1).ScalarBaseMult(new(big.Int))
73 | for i := 0; i < ntables-1; i++ {
74 | Q2 = table[i].mulTableG1(arrayW[i*gsize:(i+1)*gsize], Q2, gsize)
75 | }
76 | Q2 = table[ntables-1].mulTableG1(arrayW[(ntables-1)*gsize:], Q2, gsize)
77 | fmt.Printf("Gsize : %d, TMult time elapsed: %s\n", gsize, time.Since(beforeT))
78 |
79 | beforeT = time.Now()
80 | Q3 := scalarMultG1(arrayG1, arrayW, nil, gsize)
81 | fmt.Printf("Gsize : %d, TMult time elapsed (inc table comp): %s\n", gsize, time.Since(beforeT))
82 |
83 | beforeT = time.Now()
84 | Q4 := mulTableNoDoubleG1(table, arrayW, nil, gsize)
85 | fmt.Printf("Gsize : %d, TMultNoDouble time elapsed: %s\n", gsize, time.Since(beforeT))
86 |
87 | beforeT = time.Now()
88 | Q5 := scalarMultNoDoubleG1(arrayG1, arrayW, nil, gsize)
89 | fmt.Printf("Gsize : %d, TMultNoDouble time elapsed (inc table comp): %s\n",
90 | gsize, time.Since(beforeT))
91 |
92 | if !bytes.Equal(Q1.Marshal(), Q2.Marshal()) {
93 | t.Error("Error in TMult")
94 | }
95 | if !bytes.Equal(Q1.Marshal(), Q3.Marshal()) {
96 | t.Error("Error in TMult with table comp")
97 | }
98 | if !bytes.Equal(Q1.Marshal(), Q4.Marshal()) {
99 | t.Error("Error in TMultNoDouble")
100 | }
101 | if !bytes.Equal(Q1.Marshal(), Q5.Marshal()) {
102 | t.Error("Error in TMultNoDoublee with table comp")
103 | }
104 | }
105 | }
106 |
107 | func TestTableG2(t *testing.T) {
108 | n := n2
109 |
110 | // init scalar
111 | var arrayW = randomBigIntArray(n)
112 | // init G2 array
113 | var arrayG2 = randomG2Array(n)
114 |
115 | beforeT := time.Now()
116 | Q1 := new(bn256.G2).ScalarBaseMult(new(big.Int))
117 | for i := 0; i < n; i++ {
118 | Q1.Add(Q1, new(bn256.G2).ScalarMult(arrayG2[i], arrayW[i]))
119 | }
120 | fmt.Println("Std. Mult. time elapsed:", time.Since(beforeT))
121 |
122 | for gsize := 2; gsize < 10; gsize++ {
123 | ntables := int((n + gsize - 1) / gsize)
124 | table := make([]tableG2, ntables)
125 |
126 | for i := 0; i < ntables-1; i++ {
127 | table[i].newTableG2(arrayG2[i*gsize:(i+1)*gsize], gsize, false)
128 | }
129 | table[ntables-1].newTableG2(arrayG2[(ntables-1)*gsize:], gsize, false)
130 |
131 | beforeT = time.Now()
132 | Q2 := new(bn256.G2).ScalarBaseMult(new(big.Int))
133 | for i := 0; i < ntables-1; i++ {
134 | Q2 = table[i].mulTableG2(arrayW[i*gsize:(i+1)*gsize], Q2, gsize)
135 | }
136 | Q2 = table[ntables-1].mulTableG2(arrayW[(ntables-1)*gsize:], Q2, gsize)
137 | fmt.Printf("Gsize : %d, TMult time elapsed: %s\n", gsize, time.Since(beforeT))
138 |
139 | beforeT = time.Now()
140 | Q3 := scalarMultG2(arrayG2, arrayW, nil, gsize)
141 | fmt.Printf("Gsize : %d, TMult time elapsed (inc table comp): %s\n", gsize, time.Since(beforeT))
142 |
143 | beforeT = time.Now()
144 | Q4 := mulTableNoDoubleG2(table, arrayW, nil, gsize)
145 | fmt.Printf("Gsize : %d, TMultNoDouble time elapsed: %s\n", gsize, time.Since(beforeT))
146 |
147 | beforeT = time.Now()
148 | Q5 := scalarMultNoDoubleG2(arrayG2, arrayW, nil, gsize)
149 | fmt.Printf("Gsize : %d, TMultNoDouble time elapsed (inc table comp): %s\n",
150 | gsize, time.Since(beforeT))
151 |
152 | if !bytes.Equal(Q1.Marshal(), Q2.Marshal()) {
153 | t.Error("Error in TMult")
154 | }
155 | if !bytes.Equal(Q1.Marshal(), Q3.Marshal()) {
156 | t.Error("Error in TMult with table comp")
157 | }
158 | if !bytes.Equal(Q1.Marshal(), Q4.Marshal()) {
159 | t.Error("Error in TMultNoDouble")
160 | }
161 | if !bytes.Equal(Q1.Marshal(), Q5.Marshal()) {
162 | t.Error("Error in TMultNoDoublee with table comp")
163 | }
164 | }
165 | }
166 |
--------------------------------------------------------------------------------
/prover/ifft.go:
--------------------------------------------------------------------------------
1 | package prover
2 |
3 | import (
4 | "math"
5 | "math/big"
6 |
7 | "github.com/iden3/go-iden3-crypto/ff"
8 | "github.com/vocdoni/go-snark/types"
9 | )
10 |
11 | type rootsT struct {
12 | roots [][]*ff.Element
13 | w []*ff.Element
14 | }
15 |
16 | func newRootsT() rootsT {
17 | var roots rootsT
18 |
19 | rem := new(big.Int).Sub(types.R, big.NewInt(1))
20 | s := 0
21 | for rem.Bit(0) == 0 { // rem.Bit==0 when even
22 | s++
23 | rem = new(big.Int).Rsh(rem, 1)
24 | }
25 | roots.w = make([]*ff.Element, s+1)
26 | roots.w[s] = ff.NewElement().SetBigInt(fExp(big.NewInt(5), rem)) //nolint:gomnd
27 |
28 | n := s - 1
29 | for n >= 0 {
30 | roots.w[n] = ff.NewElement().Mul(roots.w[n+1], roots.w[n+1])
31 | n--
32 | }
33 | roots.roots = make([][]*ff.Element, 50) // TODO WIP
34 |
35 | roots.setRoots(15) //nolint:gomnd // TODO WIP
36 | return roots
37 | }
38 |
39 | func (roots rootsT) setRoots(n int) {
40 | for i := n; i >= 0 && nil == roots.roots[i]; i-- { // TODO tmp i<=len(r)
41 | r := ff.NewElement().SetBigInt(big.NewInt(1))
42 | nroots := 1 << i
43 | var rootsi []*ff.Element
44 | for j := 0; j < nroots; j++ {
45 | rootsi = append(rootsi, r)
46 | r = ff.NewElement().Mul(r, roots.w[i])
47 | }
48 | roots.roots[i] = rootsi
49 | }
50 | }
51 |
52 | func fftroots(roots rootsT, pall []*ff.Element, bits, offset, step int) []*ff.Element {
53 | n := 1 << bits
54 | if n == 1 {
55 | return []*ff.Element{pall[offset]}
56 | } else if n == 2 { //nolint:gomnd
57 | return []*ff.Element{
58 | ff.NewElement().Add(pall[offset], pall[offset+step]), // TODO tmp
59 | ff.NewElement().Sub(pall[offset], pall[offset+step]),
60 | }
61 | }
62 |
63 | ndiv2 := n >> 1
64 | p1 := fftroots(roots, pall, bits-1, offset, step*2) //nolint:gomnd
65 | p2 := fftroots(roots, pall, bits-1, offset+step, step*2) //nolint:gomnd
66 |
67 | out := make([]*ff.Element, n)
68 | for i := 0; i < ndiv2; i++ {
69 | out[i] = ff.NewElement().Add(p1[i], ff.NewElement().Mul(roots.roots[bits][i], p2[i]))
70 | out[i+ndiv2] = ff.NewElement().Sub(p1[i], ff.NewElement().Mul(roots.roots[bits][i], p2[i]))
71 | }
72 | return out
73 | }
74 |
75 | func fft(p []*ff.Element) []*ff.Element {
76 | if len(p) <= 1 {
77 | return p
78 | }
79 | bits := math.Log2(float64(len(p)-1)) + 1
80 | roots := newRootsT()
81 | roots.setRoots(int(bits))
82 | m := 1 << int(bits)
83 | ep := extend(p, m)
84 | res := fftroots(roots, ep, int(bits), 0, 1)
85 | return res
86 | }
87 |
88 | func ifft(p []*ff.Element) []*ff.Element {
89 | res := fft(p)
90 | bits := math.Log2(float64(len(p)-1)) + 1
91 | m := 1 << int(bits)
92 |
93 | twoinvm := ff.NewElement().SetBigInt(fInv(fMul(big.NewInt(1), big.NewInt(int64(m)))))
94 |
95 | var resn []*ff.Element
96 | for i := 0; i < m; i++ {
97 | resn = append(resn, ff.NewElement().Mul(res[(m-i)%m], twoinvm))
98 | }
99 |
100 | return resn
101 | }
102 |
103 | func extend(p []*ff.Element, e int) []*ff.Element {
104 | if e == len(p) {
105 | return p
106 | }
107 | z := arrayOfZeroesE(e - len(p))
108 | return append(p, z...)
109 | }
110 |
--------------------------------------------------------------------------------
/prover/prover.go:
--------------------------------------------------------------------------------
1 | package prover
2 |
3 | import (
4 | "crypto/rand"
5 | "math"
6 | "math/big"
7 | "runtime"
8 | "sync"
9 |
10 | bn256 "github.com/ethereum/go-ethereum/crypto/bn256/cloudflare"
11 | "github.com/iden3/go-iden3-crypto/utils"
12 | "github.com/vocdoni/go-snark/types"
13 | )
14 |
15 | // Group Size
16 | const (
17 | gSize = 6
18 | )
19 |
20 | func randBigInt() (*big.Int, error) {
21 | maxbits := types.R.BitLen()
22 | b := make([]byte, (maxbits/8)-1)
23 | _, err := rand.Read(b)
24 | if err != nil {
25 | return nil, err
26 | }
27 | r := new(big.Int).SetBytes(b)
28 | rq := new(big.Int).Mod(r, types.R)
29 |
30 | return rq, nil
31 | }
32 |
33 | // GenerateProof generates the Groth16 zkSNARK proof
34 | func GenerateProof(pk *types.Pk, w types.Witness) (*types.Proof, []*big.Int, error) {
35 | var proof types.Proof
36 |
37 | r, err := randBigInt()
38 | if err != nil {
39 | return nil, nil, err
40 | }
41 | s, err := randBigInt()
42 | if err != nil {
43 | return nil, nil, err
44 | }
45 |
46 | // BEGIN PAR
47 | numcpu := runtime.NumCPU()
48 |
49 | proofA := arrayOfZeroesG1(numcpu)
50 | proofB := arrayOfZeroesG2(numcpu)
51 | proofC := arrayOfZeroesG1(numcpu)
52 | proofBG1 := arrayOfZeroesG1(numcpu)
53 | gsize := gSize
54 | var wg1 sync.WaitGroup
55 | wg1.Add(numcpu)
56 | for _cpu, _ranges := range ranges(pk.NVars, numcpu) {
57 | // split 1
58 | go func(cpu int, ranges [2]int) {
59 | proofA[cpu] = scalarMultNoDoubleG1(pk.A[ranges[0]:ranges[1]],
60 | w[ranges[0]:ranges[1]],
61 | proofA[cpu],
62 | gsize)
63 | proofB[cpu] = scalarMultNoDoubleG2(pk.B2[ranges[0]:ranges[1]],
64 | w[ranges[0]:ranges[1]],
65 | proofB[cpu],
66 | gsize)
67 | proofBG1[cpu] = scalarMultNoDoubleG1(pk.B1[ranges[0]:ranges[1]],
68 | w[ranges[0]:ranges[1]],
69 | proofBG1[cpu],
70 | gsize)
71 | minLim := pk.NPublic + 1
72 | if ranges[0] > pk.NPublic+1 {
73 | minLim = ranges[0]
74 | }
75 | if ranges[1] > pk.NPublic+1 {
76 | proofC[cpu] = scalarMultNoDoubleG1(pk.C[minLim:ranges[1]],
77 | w[minLim:ranges[1]],
78 | proofC[cpu],
79 | gsize)
80 | }
81 | wg1.Done()
82 | }(_cpu, _ranges)
83 | }
84 | wg1.Wait()
85 | // join 1
86 | for cpu := 1; cpu < numcpu; cpu++ {
87 | proofA[0].Add(proofA[0], proofA[cpu])
88 | proofB[0].Add(proofB[0], proofB[cpu])
89 | proofC[0].Add(proofC[0], proofC[cpu])
90 | proofBG1[0].Add(proofBG1[0], proofBG1[cpu])
91 | }
92 | proof.A = proofA[0]
93 | proof.B = proofB[0]
94 | proof.C = proofC[0]
95 | // END PAR
96 |
97 | h := calculateH(pk, w)
98 |
99 | proof.A.Add(proof.A, pk.VkAlpha1)
100 | proof.A.Add(proof.A, new(bn256.G1).ScalarMult(pk.VkDelta1, r))
101 |
102 | proof.B.Add(proof.B, pk.VkBeta2)
103 | proof.B.Add(proof.B, new(bn256.G2).ScalarMult(pk.VkDelta2, s))
104 |
105 | proofBG1[0].Add(proofBG1[0], pk.VkBeta1)
106 | proofBG1[0].Add(proofBG1[0], new(bn256.G1).ScalarMult(pk.VkDelta1, s))
107 |
108 | proofC = arrayOfZeroesG1(numcpu)
109 | var wg2 sync.WaitGroup
110 | wg2.Add(numcpu)
111 | for _cpu, _ranges := range ranges(len(h), numcpu) {
112 | // split 2
113 | go func(cpu int, ranges [2]int) {
114 | proofC[cpu] = scalarMultNoDoubleG1(pk.HExps[ranges[0]:ranges[1]],
115 | h[ranges[0]:ranges[1]],
116 | proofC[cpu],
117 | gsize)
118 | wg2.Done()
119 | }(_cpu, _ranges)
120 | }
121 | wg2.Wait()
122 | // join 2
123 | for cpu := 1; cpu < numcpu; cpu++ {
124 | proofC[0].Add(proofC[0], proofC[cpu])
125 | }
126 | proof.C.Add(proof.C, proofC[0])
127 |
128 | proof.C.Add(proof.C, new(bn256.G1).ScalarMult(proof.A, s))
129 | proof.C.Add(proof.C, new(bn256.G1).ScalarMult(proofBG1[0], r))
130 | rsneg := new(big.Int).Mod(new(big.Int).Neg(new(big.Int).Mul(r, s)), types.R)
131 | proof.C.Add(proof.C, new(bn256.G1).ScalarMult(pk.VkDelta1, rsneg))
132 |
133 | pubSignals := w[1 : pk.NPublic+1]
134 |
135 | return &proof, pubSignals, nil
136 | }
137 |
138 | func calculateH(pk *types.Pk, w types.Witness) []*big.Int {
139 | m := pk.DomainSize
140 | polAT := arrayOfZeroes(m)
141 | polBT := arrayOfZeroes(m)
142 |
143 | numcpu := runtime.NumCPU()
144 |
145 | var wg1 sync.WaitGroup
146 | wg1.Add(2) //nolint:gomnd
147 | go func() {
148 | for i := 0; i < pk.NVars; i++ {
149 | for j := range pk.PolsA[i] {
150 | polAT[j] = fAdd(polAT[j], fMul(w[i], pk.PolsA[i][j]))
151 | }
152 | }
153 | wg1.Done()
154 | }()
155 | go func() {
156 | for i := 0; i < pk.NVars; i++ {
157 | for j := range pk.PolsB[i] {
158 | polBT[j] = fAdd(polBT[j], fMul(w[i], pk.PolsB[i][j]))
159 | }
160 | }
161 | wg1.Done()
162 | }()
163 | wg1.Wait()
164 | polATe := utils.BigIntArrayToElementArray(polAT)
165 | polBTe := utils.BigIntArrayToElementArray(polBT)
166 |
167 | polASe := ifft(polATe)
168 | polBSe := ifft(polBTe)
169 |
170 | r := int(math.Log2(float64(m))) + 1
171 | roots := newRootsT()
172 | roots.setRoots(r)
173 |
174 | var wg2 sync.WaitGroup
175 | wg2.Add(numcpu)
176 | for _cpu, _ranges := range ranges(len(polASe), numcpu) {
177 | go func(cpu int, ranges [2]int) {
178 | for i := ranges[0]; i < ranges[1]; i++ {
179 | polASe[i].Mul(polASe[i], roots.roots[r][i])
180 | polBSe[i].Mul(polBSe[i], roots.roots[r][i])
181 | }
182 | wg2.Done()
183 | }(_cpu, _ranges)
184 | }
185 | wg2.Wait()
186 |
187 | polATodd := fft(polASe)
188 | polBTodd := fft(polBSe)
189 |
190 | polABT := arrayOfZeroesE(len(polASe) * 2) //nolint:gomnd
191 | var wg3 sync.WaitGroup
192 | wg3.Add(numcpu)
193 | for _cpu, _ranges := range ranges(len(polASe), numcpu) {
194 | go func(cpu int, ranges [2]int) {
195 | for i := ranges[0]; i < ranges[1]; i++ {
196 | polABT[2*i].Mul(polATe[i], polBTe[i])
197 | polABT[2*i+1].Mul(polATodd[i], polBTodd[i])
198 | }
199 | wg3.Done()
200 | }(_cpu, _ranges)
201 | }
202 | wg3.Wait()
203 |
204 | hSeFull := ifft(polABT)
205 |
206 | hSe := hSeFull[m:]
207 | return utils.ElementArrayToBigIntArray(hSe)
208 | }
209 |
210 | func ranges(n, parts int) [][2]int {
211 | s := make([][2]int, parts)
212 | p := float64(n) / float64(parts)
213 | for i := 0; i < parts; i++ {
214 | a, b := int(float64(i)*p), int(float64(i+1)*p)
215 | s[i] = [2]int{a, b}
216 | }
217 | return s
218 | }
219 |
--------------------------------------------------------------------------------
/prover/prover_test.go:
--------------------------------------------------------------------------------
1 | package prover
2 |
3 | import (
4 | "encoding/json"
5 | "fmt"
6 | "io/ioutil"
7 | "os"
8 | "testing"
9 | "time"
10 |
11 | "github.com/stretchr/testify/assert"
12 | "github.com/stretchr/testify/require"
13 | "github.com/vocdoni/go-snark/parsers"
14 | "github.com/vocdoni/go-snark/verifier"
15 | )
16 |
17 | func TestCircuitsGenerateProof(t *testing.T) {
18 | testCircuitGenerateProof(t, "circuit1k") // 1000 constraints
19 | testCircuitGenerateProof(t, "circuit5k") // 5000 constraints
20 | // testCircuitGenerateProof(t, "circuit10k") // 10000 constraints
21 | // testCircuitGenerateProof(t, "circuit20k") // 20000 constraints
22 | }
23 |
24 | func testCircuitGenerateProof(t *testing.T, circuit string) {
25 | // Using json provingKey file:
26 | // provingKeyJSON, err := ioutil.ReadFile("../testdata/" + circuit + "/proving_key.json")
27 | // require.Nil(t, err)
28 | // pk, err := parsers.ParsePk(provingKeyJSON)
29 | // require.Nil(t, err)
30 | // witnessJSON, err := ioutil.ReadFile("../testdata/" + circuit + "/witness.json")
31 | // require.Nil(t, err)
32 | // w, err := parsers.ParseWitness(witnessJSON)
33 | // require.Nil(t, err)
34 |
35 | // Using bin provingKey file:
36 | // pkBinFile, err := os.Open("../testdata/" + circuit + "/proving_key.bin")
37 | // require.Nil(t, err)
38 | // defer pkBinFile.Close()
39 | // pk, err := parsers.ParsePkBin(pkBinFile)
40 | // require.Nil(t, err)
41 |
42 | // Using go bin provingKey file:
43 | pkGoBinFile, err := os.Open("../testdata/" + circuit + "/proving_key.go.bin") //nolint:gosec
44 | require.Nil(t, err)
45 | defer pkGoBinFile.Close() //nolint:errcheck, gosec
46 | pk, err := parsers.ParsePkGoBin(pkGoBinFile)
47 | require.Nil(t, err)
48 |
49 | witnessBinFile, err := os.Open("../testdata/" + circuit + "/witness.bin") //nolint:gosec
50 | require.Nil(t, err)
51 | defer witnessBinFile.Close() //nolint:errcheck,gosec
52 | w, err := parsers.ParseWitnessBin(witnessBinFile)
53 | require.Nil(t, err)
54 |
55 | beforeT := time.Now()
56 | proof, pubSignals, err := GenerateProof(pk, w)
57 | assert.Nil(t, err)
58 | fmt.Println("proof generation time for "+circuit+" elapsed:", time.Since(beforeT))
59 |
60 | proofStr, err := parsers.ProofToJSON(proof)
61 | assert.Nil(t, err)
62 |
63 | err = ioutil.WriteFile("../testdata/"+circuit+"/proof.json", proofStr, 0600)
64 | assert.Nil(t, err)
65 | publicStr, err := json.Marshal(parsers.ArrayBigIntToString(pubSignals))
66 | assert.Nil(t, err)
67 | err = ioutil.WriteFile("../testdata/"+circuit+"/public.json", publicStr, 0600)
68 | assert.Nil(t, err)
69 |
70 | // verify the proof
71 | vkJSON, err := ioutil.ReadFile("../testdata/" + circuit + "/verification_key.json") //nolint:gosec
72 | require.Nil(t, err)
73 | vk, err := parsers.ParseVk(vkJSON)
74 | require.Nil(t, err)
75 |
76 | v := verifier.Verify(vk, proof, pubSignals)
77 | assert.True(t, v)
78 |
79 | // to verify the proof with snarkjs:
80 | //nolint:lll
81 | // snarkjs verify --vk testdata/circuitX/verification_key.json -p testdata/circuitX/proof.json --pub testdata/circuitX/public.json
82 | }
83 |
84 | func BenchmarkGenerateProof(b *testing.B) {
85 | // benchmark with a circuit of 10000 constraints
86 | provingKeyJSON, err := ioutil.ReadFile("../testdata/circuit5k/proving_key.json")
87 | require.Nil(b, err)
88 | pk, err := parsers.ParsePk(provingKeyJSON)
89 | require.Nil(b, err)
90 |
91 | witnessJSON, err := ioutil.ReadFile("../testdata/circuit5k/witness.json")
92 | require.Nil(b, err)
93 | w, err := parsers.ParseWitness(witnessJSON)
94 | require.Nil(b, err)
95 |
96 | for i := 0; i < b.N; i++ {
97 | GenerateProof(pk, w) //nolint:errcheck,gosec
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/prover/tables.md:
--------------------------------------------------------------------------------
1 | # Tables Pre-calculation
2 | The most time consuming part of a ZKSnark proof calculation is the scalar multiplication of elliptic curve points. Direct mechanism accumulates each multiplication. However, prover only needs the total accumulation.
3 |
4 | There are two potential improvements to the naive approach:
5 |
6 | 1. Apply Strauss-Shamir method (https://stackoverflow.com/questions/50993471/ec-scalar-multiplication-with-strauss-shamir-method).
7 | 2. Leave the doubling operation for the last step
8 |
9 | Both options can be combined.
10 |
11 | In the following table, we show the results of using the naive method, Srauss-Shamir and Strauss-Shamir + No doubling. These last two options are repeated for different table grouping order.
12 |
13 | There are 50000 G1 Elliptical Curve Points, and the scalars are 254 bits (BN256 curve).
14 |
15 | There may be some concern on the additional size of the tables since they need to be loaded into a smartphone during the proof, and the time required to load these tables may exceed the benefits. If this is a problem, another althernative is to compute the tables during the proof itself. Depending on the Group Size, timing may be better than the naive approach.
16 |
17 |
18 | | Algorithm (G1) | GS 2 | GS 3 | GS 4 | GS 5 | GS 6 | GS 7 | GS 8 | GS 9 |
19 | |---|---|---|--|---|---|---|---|---|
20 | | Naive | 6.63s | - | - | - | - | - | - | - |
21 | | Strauss | 13.16s | 9.03s | 6.95s | 5.61s | 4.91s | 4.26s | 3.88s | 3.54 s |
22 | | Strauss + Table Computation | 16.13s | 11.32s | 8.47s | 7.10s | 6.2s | 5.94s | 6.01s | 6.69s |
23 | | No Doubling | 3.74s | 3.00s | 2.38s | 1.96s | 1.79s | 1.54s | 1.50s | 1.44s|
24 | | No Doubling + Table Computation | 6.83s | 5.1s | 4.16s | 3.52s| 3.22s | 3.21s | 3.57s | 4.56s |
25 |
26 | There are 5000 G2 Elliptical Curve Points, and the scalars are 254 bits (BN256 curve).
27 |
28 | | Algorithm (G2) | GS 2 | GS 3 | GS 4 | GS 5 | GS 6 | GS 7 | GS 8 | GS 9 |
29 | |---|---|---|--|---|---|---|---|---|
30 | | Naive | 3.55s | | | | | | | |
31 | | Strauss | 3.55s | 2.54s | 1.96s | 1.58s | 1.38s | 1.20s | 1.03s | 937ms |
32 | | Strauss + Table Computation | 3.59s | 2.58s | 2.04s | 1.71s | 1.51s | 1.46s | 1.51s | 1.82s |
33 | | No Doubling | 1.49s | 1.16s | 952ms | 719ms | 661ms | 548ms | 506ms| 444ms |
34 | | No Doubling + Table Computation | 1.55s | 1.21s | 984ms | 841ms | 826ms | 847ms | 1.03s | 1.39s |
35 |
36 | | GS | Extra Disk Space per Constraint (G1)|
37 | |----|--------|
38 | | 2 | 64 B |
39 | | 3 | 106 B |
40 | | 4 | 192 B |
41 | | 5 | 346 B |
42 | | 6 | 618 B |
43 | | 7 | 1106 B |
44 | | 8 | 1984 B |
45 | | 9 | 3577 B |
46 | | N | 2^(N+6)/N - 64 B |
47 |
48 | Extra disk space per constraint in G2 is twice the requirements for G1
49 |
50 |
--------------------------------------------------------------------------------
/testdata/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 |
--------------------------------------------------------------------------------
/testdata/circuit10k/circuit.circom:
--------------------------------------------------------------------------------
1 | template TestConstraints(n) {
2 | signal input in;
3 | signal output out;
4 |
5 | signal intermediate[n];
6 |
7 | intermediate[0] <== in;
8 | for (var i=1; i