mirror of
https://github.com/tornadocash/websnark.git
synced 2024-11-27 04:10:07 +01:00
Initial commit
This commit is contained in:
commit
a0680804a5
37
.eslintrc.js
Normal file
37
.eslintrc.js
Normal file
@ -0,0 +1,37 @@
|
||||
module.exports = {
|
||||
"plugins": [
|
||||
"mocha",
|
||||
"webassembly"
|
||||
],
|
||||
"env": {
|
||||
"es6": true,
|
||||
"node": true,
|
||||
"mocha": true
|
||||
},
|
||||
"globals": {
|
||||
"WebAssembly": true
|
||||
},
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 2017
|
||||
},
|
||||
"extends": "eslint:recommended",
|
||||
"rules": {
|
||||
"indent": [
|
||||
"error",
|
||||
4
|
||||
],
|
||||
"linebreak-style": [
|
||||
"error",
|
||||
"unix"
|
||||
],
|
||||
"quotes": [
|
||||
"error",
|
||||
"double"
|
||||
],
|
||||
"semi": [
|
||||
"error",
|
||||
"always"
|
||||
],
|
||||
"mocha/no-exclusive-tests": "error"
|
||||
}
|
||||
};
|
68
.gitignore
vendored
Normal file
68
.gitignore
vendored
Normal file
@ -0,0 +1,68 @@
|
||||
vk_proof.json
|
||||
vk_verifier.json
|
||||
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
*.pid.lock
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
lib-cov
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
|
||||
# nyc test coverage
|
||||
.nyc_output
|
||||
|
||||
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
|
||||
.grunt
|
||||
|
||||
# Bower dependency directory (https://bower.io/)
|
||||
bower_components
|
||||
|
||||
# node-waf configuration
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||
build/Release
|
||||
|
||||
# Dependency directories
|
||||
node_modules/
|
||||
jspm_packages/
|
||||
|
||||
# Typescript v1 declaration files
|
||||
typings/
|
||||
|
||||
# Optional npm cache directory
|
||||
.npm
|
||||
|
||||
# Optional eslint cache
|
||||
.eslintcache
|
||||
|
||||
# Optional REPL history
|
||||
.node_repl_history
|
||||
|
||||
# Output of 'npm pack'
|
||||
*.tgz
|
||||
|
||||
# Yarn Integrity file
|
||||
.yarn-integrity
|
||||
|
||||
# dotenv environment variables file
|
||||
.env
|
||||
|
||||
# next.js build output
|
||||
.next
|
||||
|
||||
tmp
|
||||
|
||||
.DS_Store
|
674
COPYING
Normal file
674
COPYING
Normal file
@ -0,0 +1,674 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU General Public License is a free, copyleft license for
|
||||
software and other kinds of works.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
the GNU General Public License is intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users. We, the Free Software Foundation, use the
|
||||
GNU General Public License for most of our software; it applies also to
|
||||
any other work released this way by its authors. You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to prevent others from denying you
|
||||
these rights or asking you to surrender the rights. Therefore, you have
|
||||
certain responsibilities if you distribute copies of the software, or if
|
||||
you modify it: responsibilities to respect the freedom of others.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must pass on to the recipients the same
|
||||
freedoms that you received. You must make sure that they, too, receive
|
||||
or can get the source code. And you must show them these terms so they
|
||||
know their rights.
|
||||
|
||||
Developers that use the GNU GPL protect your rights with two steps:
|
||||
(1) assert copyright on the software, and (2) offer you this License
|
||||
giving you legal permission to copy, distribute and/or modify it.
|
||||
|
||||
For the developers' and authors' protection, the GPL clearly explains
|
||||
that there is no warranty for this free software. For both users' and
|
||||
authors' sake, the GPL requires that modified versions be marked as
|
||||
changed, so that their problems will not be attributed erroneously to
|
||||
authors of previous versions.
|
||||
|
||||
Some devices are designed to deny users access to install or run
|
||||
modified versions of the software inside them, although the manufacturer
|
||||
can do so. This is fundamentally incompatible with the aim of
|
||||
protecting users' freedom to change the software. The systematic
|
||||
pattern of such abuse occurs in the area of products for individuals to
|
||||
use, which is precisely where it is most unacceptable. Therefore, we
|
||||
have designed this version of the GPL to prohibit the practice for those
|
||||
products. If such problems arise substantially in other domains, we
|
||||
stand ready to extend this provision to those domains in future versions
|
||||
of the GPL, as needed to protect the freedom of users.
|
||||
|
||||
Finally, every program is threatened constantly by software patents.
|
||||
States should not allow patents to restrict development and use of
|
||||
software on general-purpose computers, but in those that do, we wish to
|
||||
avoid the special danger that patents applied to a free program could
|
||||
make it effectively proprietary. To prevent this, the GPL assures that
|
||||
patents cannot be used to render the program non-free.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey verbatim copies of the Program's source code as you
|
||||
receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Use with the GNU Affero General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU Affero General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the special requirements of the GNU Affero General Public License,
|
||||
section 13, concerning interaction through a network will apply to the
|
||||
combination as such.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Program specifies that a certain numbered version of the GNU General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGES.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
{one line to give the program's name and a brief idea of what it does.}
|
||||
Copyright (C) {year} {name of author}
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program does terminal interaction, make it output a short
|
||||
notice like this when it starts in an interactive mode:
|
||||
|
||||
{project} Copyright (C) {year} {fullname}
|
||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, your program's commands
|
||||
might be different; for a GUI interface, you would use an "about box".
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU GPL, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
The GNU General Public License does not permit incorporating your program
|
||||
into proprietary programs. If your program is a subroutine library, you
|
||||
may consider it more useful to permit linking proprietary applications with
|
||||
the library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License. But first, please read
|
||||
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
|
119
README.md
Normal file
119
README.md
Normal file
@ -0,0 +1,119 @@
|
||||
# websnark
|
||||
|
||||
A fast zkSnark proof generator written in native Web Assembly.
|
||||
|
||||
websnark is used to generate zkSnark Proofs from the browser.
|
||||
|
||||
This module generates highly optimized Web Assembly modules for the low level
|
||||
cryptographic primitives.
|
||||
|
||||
It also makes use of the Web Workers feature to parallelize the generation
|
||||
of the zero knoledge proofs.
|
||||
|
||||
The result is a fast library with times close to libsnarks but fully compatible for
|
||||
browsers.
|
||||
|
||||
## Usage
|
||||
|
||||
You just need to import the websnark.js found in the build directory.
|
||||
|
||||
```html
|
||||
<script src="websnark.js" />
|
||||
```
|
||||
|
||||
This library has a single javascript function:
|
||||
|
||||
genZKSnarkProof(witness, provingKey, cb)
|
||||
|
||||
cb is the callback. If cb is undefined, then the function will return a promise.
|
||||
|
||||
witness is a binary buffer with all the signals in binnary format. The buffer is packt in 32bytes Little Endian Encoded Field Elements.
|
||||
|
||||
You can use the tool to build the binary file from the witness.json file generated by [snarkjs](https://github.com/iden3/snarkjs).
|
||||
|
||||
```
|
||||
node ../tools/buildwitness.js -i witness.json -o witness.bin
|
||||
```
|
||||
|
||||
provingKey is the binary buffer with the binary representation of the proving key.
|
||||
|
||||
Check the tool tools/buildpkey.js to convert a proving_key.json file generated
|
||||
in [snarkjs](https://github.com/iden3/snarkjs) to a proving_key.bin file that can
|
||||
be used directly with this library.
|
||||
|
||||
```
|
||||
node ../tools/buildpkey.js -i proving_key.json -o proving_key.bin
|
||||
```
|
||||
|
||||
The result is a JSON object with pi_a, pi_b and pi_c points.
|
||||
|
||||
You can use the stringified version of this JSON as a proof.json in [snarkjs](https://github.com/iden3/snarkjs)
|
||||
|
||||
|
||||
Here is a simple example of a web page that loads a key and a witness and generates the proof when the button is pressed.
|
||||
|
||||
```html
|
||||
<html>
|
||||
<header>
|
||||
</header>
|
||||
<script src="websnark.js"></script>
|
||||
<script>
|
||||
|
||||
var witness;
|
||||
var proving_key;
|
||||
|
||||
function onLoad() {
|
||||
|
||||
fetch("proving_key.bin").then( (response) => {
|
||||
return response.arrayBuffer();
|
||||
}).then( (b) => {
|
||||
provingKey = b;
|
||||
});
|
||||
|
||||
fetch("witness.bin").then( (response) => {
|
||||
return response.arrayBuffer();
|
||||
}).then( (b) => {
|
||||
witness = b;
|
||||
});
|
||||
}
|
||||
|
||||
function calcProof() {
|
||||
const start = new Date().getTime();
|
||||
document.getElementById("time").innerHTML = "processing....";
|
||||
document.getElementById("proof").innerHTML = "";
|
||||
|
||||
window.genZKSnarkProof(witness, provingKey).then((p)=> {
|
||||
const end = new Date().getTime();
|
||||
const time = end - start;
|
||||
document.getElementById("time").innerHTML = `Time to compute: ${time}ms`;
|
||||
document.getElementById("proof").innerHTML = JSON.stringify(p, null, 1);
|
||||
});
|
||||
}
|
||||
|
||||
</script>
|
||||
<body onLoad="onLoad()">
|
||||
<h1>iden3</h1>
|
||||
<h2>Zero knowledge proof generator</h2>
|
||||
<button onClick="calcProof()">Test</button>
|
||||
<div id="time"></div>
|
||||
<pre id="proof"></pre>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
## Building wasm.js
|
||||
|
||||
```
|
||||
npm run build
|
||||
```
|
||||
|
||||
## Testing
|
||||
|
||||
```
|
||||
npm test
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
websnark is part of the iden3 project copyright 2019 0KIMS association and published with GPL-3 license. Please check the COPYING file for more details.
|
3
TODO
Normal file
3
TODO
Normal file
@ -0,0 +1,3 @@
|
||||
It's not necessary to multiply by 1/2^n in the ifft (Can be put in the points).
|
||||
The points can also be resorted so it's not necessary to permute.
|
||||
Expand memory of the threads dynamically.
|
5
build/groth16_wasm.js
Normal file
5
build/groth16_wasm.js
Normal file
File diff suppressed because one or more lines are too long
5421
build/websnark.js
Normal file
5421
build/websnark.js
Normal file
File diff suppressed because one or more lines are too long
1293980
example/claimrootupdate_test.json
Normal file
1293980
example/claimrootupdate_test.json
Normal file
File diff suppressed because one or more lines are too long
47
example/index.html
Normal file
47
example/index.html
Normal file
@ -0,0 +1,47 @@
|
||||
<html>
|
||||
<header>
|
||||
</header>
|
||||
<script src="websnark.js"></script>
|
||||
<script>
|
||||
|
||||
var witness;
|
||||
var proving_key;
|
||||
|
||||
function onLoad() {
|
||||
|
||||
fetch("proving_key.bin").then( (response) => {
|
||||
return response.arrayBuffer();
|
||||
}).then( (b) => {
|
||||
provingKey = b;
|
||||
});
|
||||
|
||||
fetch("witness.bin").then( (response) => {
|
||||
return response.arrayBuffer();
|
||||
}).then( (b) => {
|
||||
witness = b;
|
||||
});
|
||||
}
|
||||
|
||||
function calcProof() {
|
||||
const start = new Date().getTime();
|
||||
document.getElementById("time").innerHTML = "processing....";
|
||||
document.getElementById("proof").innerHTML = "";
|
||||
|
||||
window.genZKSnarkProof(witness, provingKey).then((p)=> {
|
||||
const end = new Date().getTime();
|
||||
const time = end - start;
|
||||
document.getElementById("time").innerHTML = `Time to compute: ${time}ms`;
|
||||
document.getElementById("proof").innerHTML = JSON.stringify(p, null, 1);
|
||||
});
|
||||
}
|
||||
|
||||
</script>
|
||||
<body onLoad="onLoad()">
|
||||
<h1>iden3</h1>
|
||||
<h2>Zero knowledge proof generator</h2>
|
||||
<button onClick="calcProof()">Test</button>
|
||||
<div id="time"></div>
|
||||
<pre id="proof"></pre>
|
||||
|
||||
</body>
|
||||
</html>
|
1
example/input.json
Normal file
1
example/input.json
Normal file
@ -0,0 +1 @@
|
||||
{"oldRelayerRoot":"7149014917815960042505969439971619119991011354574443484106856202048948095881","newRelayerRoot":"12195095808573067990042857686504557510035235683154016308243419405358680169250","oldUserRoot":"9164435831827345487378393454304824441756195871900421654673163382659437536500","idIdentity":"1234","era":0,"newUserRoot":"16374068974774336469776493892198386626211184005839336945221081336304141111920","newUserRootVersion":1,"sigKeyX":"2610057752638682202795145288373380503107623443963127956230801721756904484787","sigKeyY":"16617171478497210597712478520507818259149717466230047843969353176573634386897","sigS":"1790107960388390971897835168022684452552187545968846840523968533783427112708","sigR8x":"13303187477790464289185372704934741905530397009889514067884373165312221183226","sigR8y":"20934614636390406120326149903842640726858112697509676494085990398714931055996","signingKeyInclussion_siblings":["0","0","0","0","0","0","0","0","0","0"],"signingKeyExclusion_siblings":["0","0","0","0","0","0","0","0","0","0"],"signingKeyExclusion_oldKey":"11968552468543593335149856751038426364722479921732335754114707699811978359681","signingKeyExclusion_oldValue":"9614565467070354290860829491102892458030262142650662112245199748688182033133","signingKeyExclusion_isOld0":0,"oldRootInclusion_siblings":["0","0","0","0","0","0","0","0","0","0"],"relayerInsert_siblings":["0","0","0","0","0","0","0","0","0","0"],"relayerInsert_oldKey":"3900887248494684663431642341114683844061898198331562653906267847513911890751","relayerInsert_oldValue":"17279342286447729775991865155392847976865724336068569228942936646576478041635","relayerInsert_isOld0":0}
|
8125
example/main.js
Normal file
8125
example/main.js
Normal file
File diff suppressed because it is too large
Load Diff
26
example/proof.json
Normal file
26
example/proof.json
Normal file
@ -0,0 +1,26 @@
|
||||
{
|
||||
"pi_a": [
|
||||
"21299468428975157907971509843242790611956840031982109540080148460860054961068",
|
||||
"16218562239871505083548927620326532327685583756957331621908222303280694697058",
|
||||
"1"
|
||||
],
|
||||
"pi_b": [
|
||||
[
|
||||
"3990093423700828311838231842021296772880795509915393919119908397509245494630",
|
||||
"9935722568224593716709531459846007601397798580251740830053012576354022332241"
|
||||
],
|
||||
[
|
||||
"21666639296245372573730164687386555903413178611772851802112755493707480411718",
|
||||
"20480827377835335108619082478623567541229122073863081725837512367680199835917"
|
||||
],
|
||||
[
|
||||
"1",
|
||||
"0"
|
||||
]
|
||||
],
|
||||
"pi_c": [
|
||||
"13342643079462362387238709887432684790096854916120073722409236990698569347488",
|
||||
"10435157339334380790943583827752333771606989087519357640989102922869580065639",
|
||||
"1"
|
||||
]
|
||||
}
|
27
example/proof_good.json
Normal file
27
example/proof_good.json
Normal file
@ -0,0 +1,27 @@
|
||||
{
|
||||
"pi_a": [
|
||||
"4079377793023106218512612357765372589768722855223712806966636132351673694864",
|
||||
"6566701505631587594300668764465002577667940939724294184889060580408175264223",
|
||||
"1"
|
||||
],
|
||||
"pi_b": [
|
||||
[
|
||||
"10229472734234567060827285543719384707311782072914056449693552036023109171847",
|
||||
"19221402771967836177735686222150390564374189169137545456666574276672590263360"
|
||||
],
|
||||
[
|
||||
"2786860939692351242257918997229840984102960184685645575791978007906286422088",
|
||||
"10021175839529701757109112605170962383952606809681822589856848768204360929450"
|
||||
],
|
||||
[
|
||||
"1",
|
||||
"0"
|
||||
]
|
||||
],
|
||||
"pi_c": [
|
||||
"9363859620973663458522420110090081304057983070024291679842746379857982014806",
|
||||
"6385829274037862642342875048877106731645253089940673226494300806909196143724",
|
||||
"1"
|
||||
],
|
||||
"protocol": "groth"
|
||||
}
|
27
example/proof_good0.json
Normal file
27
example/proof_good0.json
Normal file
@ -0,0 +1,27 @@
|
||||
{
|
||||
"pi_a": [
|
||||
"3062730782762002328629914277499331679098691329067817827858238393352428657914",
|
||||
"5366542418610121317481512331293614117614953703064567412247740045718864852085",
|
||||
"1"
|
||||
],
|
||||
"pi_b": [
|
||||
[
|
||||
"3045994327894554162195482729863531780971335850897447371047717080147827978800",
|
||||
"12812559522132497549371177206065715361272226812886322048541722186944534083071"
|
||||
],
|
||||
[
|
||||
"6040966987261594852859860335785081590954889618202901140912191539330541257453",
|
||||
"12718974094224691902404658448603973488651554858138629417886060677977036298939"
|
||||
],
|
||||
[
|
||||
"1",
|
||||
"0"
|
||||
]
|
||||
],
|
||||
"pi_c": [
|
||||
"15671479210106639737005465988418836888142113064660446402010239803058251468620",
|
||||
"15814578234239847161394963936985801386342113870941495220019545449689599744588",
|
||||
"1"
|
||||
],
|
||||
"protocol": "groth"
|
||||
}
|
BIN
example/proving_key.bin
Normal file
BIN
example/proving_key.bin
Normal file
Binary file not shown.
2884583
example/proving_key.json
Normal file
2884583
example/proving_key.json
Normal file
File diff suppressed because it is too large
Load Diff
60
example/public.json
Normal file
60
example/public.json
Normal file
@ -0,0 +1,60 @@
|
||||
[
|
||||
"12195095808573067990042857686504557510035235683154016308243419405358680169250",
|
||||
"7149014917815960042505969439971619119991011354574443484106856202048948095881",
|
||||
"9164435831827345487378393454304824441756195871900421654673163382659437536500",
|
||||
"1234",
|
||||
"0",
|
||||
"16374068974774336469776493892198386626211184005839336945221081336304141111920",
|
||||
"1",
|
||||
"2610057752638682202795145288373380503107623443963127956230801721756904484787",
|
||||
"16617171478497210597712478520507818259149717466230047843969353176573634386897",
|
||||
"1790107960388390971897835168022684452552187545968846840523968533783427112708",
|
||||
"13303187477790464289185372704934741905530397009889514067884373165312221183226",
|
||||
"20934614636390406120326149903842640726858112697509676494085990398714931055996",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"11968552468543593335149856751038426364722479921732335754114707699811978359681",
|
||||
"9614565467070354290860829491102892458030262142650662112245199748688182033133",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"3900887248494684663431642341114683844061898198331562653906267847513911890751",
|
||||
"17279342286447729775991865155392847976865724336068569228942936646576478041635",
|
||||
"0"
|
||||
]
|
378
example/verification_key.json
Normal file
378
example/verification_key.json
Normal file
@ -0,0 +1,378 @@
|
||||
{
|
||||
"protocol": "groth",
|
||||
"nPublic": 58,
|
||||
"IC": [
|
||||
[
|
||||
"19526011409366579990588025301030213951715906703577073975290871624466881592401",
|
||||
"19704225241808120619466308438935447262963873917264064669080753233318969572957",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"7218481415766897306762916767110075847697992625643495798846732092896344771677",
|
||||
"1810734562057506037864970683351135446505342561419524855305385566525430554608",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"1640189422982581804826644035748296239719141803014116052080598186211151031797",
|
||||
"7781696247496343071100255748895449136227964112761638882773761539066568268925",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"1019783362851718589135884871584846731091007700702318392055072177004648561589",
|
||||
"18812499958741900484687753662765966120897029726834689506634674431261159346840",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"15561759052567336872552966722770915260975101273887034098005539514081530527925",
|
||||
"11730428660167585547193351712992338394459044787769016092386316685070099352472",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"1024450630178286178450853989597618731194658350885429138953206234739921258345",
|
||||
"7948069502311904001229660361963340784026126140723442378626252475516635024822",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"8134630773713074896857037173371019670883865326581932178449629660512993310425",
|
||||
"6162538535380093935174079566719686610557565288806461488942825301577983962127",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"8713144302139572077210052963377568333718037671811574593525902475107121219071",
|
||||
"13618940145565575426081729012812756247313835929620966248623806311505567102432",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"2208161957288886407409949471646360867727094427710349204075749603229409811551",
|
||||
"19165194795626512061280419859788136098199019550268978813401285308580039446381",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"1481335695502173099248239238900758768801091349137030249276629661318408132871",
|
||||
"5156686038021439018308366275250160506883007416398589471786874665591845100113",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"20337511777673950886185756823107347060969023608337968294278846656718023200150",
|
||||
"3997644781553846440387918107564571745476924483850609244466307282628877247562",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"10588095668159724333142658097242748201084821311539505166654240692525635653949",
|
||||
"1183100960889281823631938371556943968916169482989513163517955652814147785270",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"14899200894902404684338252010495693209614589615201102355683265977943244426004",
|
||||
"6733181143166489149612223364873851869451680106085133952329639843716177370522",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"1683537073912953978091278971997049690818520143499563010072565648446561661056",
|
||||
"19419929908654053003650694876848111465754667348310947518133436565700017002483",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"14657090907982846377445922373510406393589381865954917955559100596313207100861",
|
||||
"13642650140642299314216565478747411703974469867765487295597972222030646618581",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"16529622819344543978903257968152672100303712811187008674706734962518660200534",
|
||||
"9047308189580806381060024072651025924757275727793326189939157176373582276423",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"3080248660073481279234987580633467131838554544589313213304320336447912874502",
|
||||
"12178549914181501174961289691127530013023904264051503031309740303517490947766",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"15487788123318013174142216619036794699452999597075149645621900875574186695610",
|
||||
"1626752354094836838615855864490581912181205603023556119206923761362325487488",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"1666930804642622665542570167075210228582250288184353798587314779395900191926",
|
||||
"19705035825701732447104451708888835197574105722528610005429830999713513944135",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"6864231653145100847184101019813757441375546934931929553137150578511457821468",
|
||||
"11030717897717091434566238005756773466216938437645365639326676041449665933687",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"17708960029000737859399187469088839058910680034659542429747423649838721586318",
|
||||
"17966398620544733014948000033194587396780241478697380962648049866838729264654",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"13757192009142934986497800326740625614298535990393743419508862715438850214278",
|
||||
"21608544818365956429804089572501400134306590793845664759121305528719014468539",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"2387150367018947723453720841613212674042625869787597370012597855542196564772",
|
||||
"11695602459063663755646871470499162454273937998667584326916784819522675676030",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"3969932184785511719481056173532036069678557655561039720091342741570026295152",
|
||||
"17993913767992706963197080864583362193024219058878156591482644926890948868797",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"9423946557684255938323840651123017285324730158168043839780806631003806918939",
|
||||
"20601140822008955908584760520762447153677611366925313301286794723328845538334",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"12962476762153853692961359313770195651287320370991012193410923729342519400410",
|
||||
"16790095546018287000758153406357558316483550179182040426959851702714662233350",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"11513038453371099732062533711296648120504101464641839310671168933784980314882",
|
||||
"19906375207605336857368669180394946464921182728087574346715161382734582996091",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"2121497929168641193320430463750735744335423634358969475213438628839145775097",
|
||||
"14279619451032406093176776946256910631214549125624592712768709224713246159330",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"11226191782273968706267268899222700962751661296528346044234995849296626637818",
|
||||
"13010144704231455483130550798892383439128876102102878476813890284532924199082",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"11110550860460015317490388108081233932145530993142470924675507899413835184448",
|
||||
"16564127121244024114702603123214129039853156994745132309985985728814892932482",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"16778941937031321722070777716071699346818608459977560423095851882699057661238",
|
||||
"4697439800149822368300068885116892100711854565071104448591753229703512600800",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"15872083856166627537790395064677676672858055702693032209281782235450963069960",
|
||||
"10359824654894233948940829295414182326916813602184261612555323269593953713959",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"15247415861798118260310199809217153579347967502938862593203253520242564857778",
|
||||
"17943608471215894498734622964827265729455290707752355804444644415538765187171",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"19910646054904277798554639079332859903830938020106054338361835817749036204289",
|
||||
"14251173391661908313942511660900252216342610385205017933107964019360045794603",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"15617270263010441782314109350958570541215852291212818016021084008333418208875",
|
||||
"21881089065537370063139940701535262435555591536651612422900371838614353113281",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"6421115626779256473944138173048502514066702768381496596650324103983916504835",
|
||||
"3477316365965567489844246613122076671753354745444827471590577962440540253825",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"16473272305165140318293304721756072118952895979824993476741656445985532109687",
|
||||
"11966737459889574739163354519745663782810240444604837406970095410044504857114",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"5372377827028613665959777806978819222622231879950628237059135069445403406617",
|
||||
"10754772058946143812874307806006613255761709338906946759757401504859407645417",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"14186175579895909616185878057026760618866356046925560400399807036820346884046",
|
||||
"4815071274998802335087493250322971182140859271153573841178680570745042169758",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"18587428576009373156679145442597168345936336951096103073893982856175630643693",
|
||||
"16551515971501720092878042838225840381462545412649977468782450446861560095079",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"20092704064518140906336001291719220397791993391927049447238747943557979137332",
|
||||
"14309044514703625249681667739033504979034764749598333744088213698477089190167",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"18094211252427269277727737867758525438768651774457808013501513791100524400111",
|
||||
"1953616651202224570087320348179078176455230140050934991264156573541656440177",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"8306150994125890187737385803981541016404020628778896850769772941676552580695",
|
||||
"9692340394713555790690111046383485596714503094426824962694563185658648842716",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"2310757642461495319988919139078520159193510139788049016019877513576089825606",
|
||||
"8889867579822094460826499233108459267599315072851707155589562022968565836877",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"18308698969834252376687927943697318806874330259437519073367865794809196122421",
|
||||
"14739033668305736376862695711443548284923118719280017423642214528572384515934",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"21281456929816658128965712205802466600645879143675783709584584463978062814070",
|
||||
"11318407702446502058218573109267233739777220569151759825244543584735350643466",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"7520703426805357030477495741143669754535245601456768825659455316560615971189",
|
||||
"11716692431794868904945130966329488889062393077100622718344498934379412336473",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"12755699673150967843636678152611549820209710341861685811272938968227849444490",
|
||||
"8041405236201023920708302321965742245298279037603394500679202870952036944455",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"4767324308822656869298992811825434492721876454715254600244690065028848020971",
|
||||
"7698254074025215726826011606321771959580174521108656914865701606041868015929",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"5069108519819643877425272525791845153259463918796090785858826854873469677567",
|
||||
"19441624293073788344676145862916585919555281266024685026467295031220552700054",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"19615829997657139098357071858533416653704257439734430213792369647973566826347",
|
||||
"20354691099796661979686973753889173391948033275751613338970065504168017804337",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"11027190822371723497281530686863090859613245206871440157541315964572815271179",
|
||||
"10675136011261330036038351905981966853190049667679786632322902689639273096714",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"6073908302198369305254211170927314788182979554648782100497505455266731015204",
|
||||
"230783342774856919928214058753287925592697137855334446779967352493825837423",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"8065349080015031289241881658385531453814503979517539346801510330252327420241",
|
||||
"14735126201189209265547932564409552262152445686850481557202138107408115327464",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"6452037663171386579712621793513191966255625190206245575651250486849182460440",
|
||||
"7209242914697571385995884156916495284148841850843926922191745144563603631497",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"10593401732655136290887720645830905766352213200230343334980873391309958939320",
|
||||
"666955912278201937315337912832661869841839611440234361211929441370598456858",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"3479342154509588972525995110657563238207085236375361439444008581380409197198",
|
||||
"2842082156517941562270865475681450943187927072014071620218399830230257691351",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"692434019399694517146046655769177702432905351223416354821366078192182076820",
|
||||
"3395628146877374571895195099601711702304342467654447561346689703803124051395",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"897877668313362010234827860073421630587020756077760567259587493004095744184",
|
||||
"7566955279869906474734064013485588345675973359196540621993138844162613375198",
|
||||
"1"
|
||||
]
|
||||
],
|
||||
"vk_alfa_1": [
|
||||
"8354125022402491146096524632602954406606496454803779043544940201207527912027",
|
||||
"719066282644331645717102069170608708195162774370272260015202086661089311234",
|
||||
"1"
|
||||
],
|
||||
"vk_beta_2": [
|
||||
[
|
||||
"15819609270299917787101227421057497064555252095398692710896314899171935449228",
|
||||
"12410557311433316645833461472858428751547879560031808599488331029313135860054"
|
||||
],
|
||||
[
|
||||
"5915247915713704640408458318654604569396223348462269801166279014325877172920",
|
||||
"3151765353208434115856893997427239125947497909307782934497369635848305207349"
|
||||
],
|
||||
[
|
||||
"1",
|
||||
"0"
|
||||
]
|
||||
],
|
||||
"vk_gamma_2": [
|
||||
[
|
||||
"20998635465704765944234729848213271190298703821739579245252166965359275379567",
|
||||
"18569698049261699868049342823691041461765011065833511061731150982712719058931"
|
||||
],
|
||||
[
|
||||
"19643309731014428269860044007048729642835975708160558919248553748448226867008",
|
||||
"4057552944219884903616160090555822269203226833340888130271232201855723185188"
|
||||
],
|
||||
[
|
||||
"1",
|
||||
"0"
|
||||
]
|
||||
],
|
||||
"vk_delta_2": [
|
||||
[
|
||||
"1699455723545013724352264641481223849638169293269636387255739145105164643572",
|
||||
"10951443100057856372062056768155654835091940387457226546452206121970064287769"
|
||||
],
|
||||
[
|
||||
"18091804447302921360663814931698141642678950451776128240905512956330370630584",
|
||||
"11051171602925343050692043383444760908270199727214620699742880132687007451610"
|
||||
],
|
||||
[
|
||||
"1",
|
||||
"0"
|
||||
]
|
||||
],
|
||||
"vk_alfabeta_12": [
|
||||
[
|
||||
[
|
||||
"18723835367546013216669396584879552615309554640417855595864851968454850794686",
|
||||
"2751734539677780406895433411352652269903002350864560518448916000577298711044"
|
||||
],
|
||||
[
|
||||
"6091631998457053869677482825687515224140938572474416320681319181954212930660",
|
||||
"14750817718913847167640471421588191103071235885472070890891565424818957616506"
|
||||
],
|
||||
[
|
||||
"1503045325833070525242109471593215150873992909765587341806427485400509901763",
|
||||
"19595263023959996895029566929430291188201738108321510303592033282761719078927"
|
||||
]
|
||||
],
|
||||
[
|
||||
[
|
||||
"14243067455511068097745434183222546746125426041491764346913202956845188552019",
|
||||
"17462170864881388598981702392557723387786493323913878401432726985509236575485"
|
||||
],
|
||||
[
|
||||
"15670136540447067653418982806709348681767811130611329178707663135867906047157",
|
||||
"8632459998104744185409696090239906876607793844814496641442049837459287937900"
|
||||
],
|
||||
[
|
||||
"1147927280145543088837981995583243716796018112475088793287724642814036528129",
|
||||
"15939953021942181393804832630429756290981160876828402349069996652097158880389"
|
||||
]
|
||||
]
|
||||
]
|
||||
}
|
5421
example/websnark.js
Normal file
5421
example/websnark.js
Normal file
File diff suppressed because one or more lines are too long
BIN
example/witness.bin
Normal file
BIN
example/witness.bin
Normal file
Binary file not shown.
66234
example/witness.json
Normal file
66234
example/witness.json
Normal file
File diff suppressed because it is too large
Load Diff
22
index.js
Normal file
22
index.js
Normal file
@ -0,0 +1,22 @@
|
||||
/*
|
||||
Copyright 2019 0KIMS association.
|
||||
|
||||
This file is part of websnark (Web Assembly zkSnark Prover).
|
||||
|
||||
websnark is a free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
websnark is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with websnark. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
module.exports.buildF1 = require("./src/f1.js");
|
||||
module.exports.buildBn128 = require("./src/bn128.js");
|
||||
module.exports.buildGroth16 = require("./src/groth16.js");
|
41
main.js
Normal file
41
main.js
Normal file
@ -0,0 +1,41 @@
|
||||
/*
|
||||
Copyright 2019 0KIMS association.
|
||||
|
||||
This file is part of websnark (Web Assembly zkSnark Prover).
|
||||
|
||||
websnark is a free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
websnark is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with websnark. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* globals window */
|
||||
|
||||
const buildGroth16 = require("./src/groth16.js");
|
||||
|
||||
buildGroth16().then( (groth16) => {
|
||||
window.genZKSnarkProof = function(witness, provingKey, cb) {
|
||||
|
||||
const p = groth16.proof(witness, provingKey);
|
||||
|
||||
if (cb) {
|
||||
p.then( (proof) => {
|
||||
cb(null, proof);
|
||||
}, (err) => {
|
||||
cb(err);
|
||||
});
|
||||
} else {
|
||||
return p;
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
|
1856
package-lock.json
generated
Normal file
1856
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
39
package.json
Normal file
39
package.json
Normal file
@ -0,0 +1,39 @@
|
||||
{
|
||||
"name": "websnark",
|
||||
"version": "0.0.1",
|
||||
"description": "big integer library to work in Zq",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "mocha --experimental-worker",
|
||||
"buildwasm": "node tools/buildwasm.js",
|
||||
"build": "node tools/buildwasm.js; browserify main.js -o build/websnark.js --exclude worker_threads --exclude crypto; cp build/websnark.js example/websnark.js"
|
||||
},
|
||||
"keywords": [
|
||||
"bigint",
|
||||
"bignum",
|
||||
"biginteger",
|
||||
"zq",
|
||||
"elliptic",
|
||||
"curve",
|
||||
"prime",
|
||||
"field"
|
||||
],
|
||||
"author": "Jordi Baylina",
|
||||
"license": "GPL-3.0",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/iden3/websnark.git"
|
||||
},
|
||||
"devDependencies": {
|
||||
"eslint": "^5.14.0",
|
||||
"eslint-plugin-mocha": "^5.3.0",
|
||||
"eslint-plugin-webassembly": "^1.8.4",
|
||||
"mocha": "^6.1.2",
|
||||
"package": "^1.0.1",
|
||||
"snarkjs": "^0.1.12",
|
||||
"wasmbuilder": "0.0.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"big-integer": "^1.6.42"
|
||||
}
|
||||
}
|
240
src/bn128.js
Normal file
240
src/bn128.js
Normal file
@ -0,0 +1,240 @@
|
||||
/*
|
||||
Copyright 2019 0KIMS association.
|
||||
|
||||
This file is part of websnark (Web Assembly zkSnark Prover).
|
||||
|
||||
websnark is a free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
websnark is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with websnark. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/* globals WebAssembly */
|
||||
const bigInt = require("big-integer");
|
||||
const ModuleBuilder = require("wasmbuilder");
|
||||
const buildF1m = require("./build_f1m.js");
|
||||
const buildF2m = require("./build_f2m.js");
|
||||
const buildF1 = require("./build_f1.js");
|
||||
const buildCurve = require("./build_curve.js");
|
||||
const buildTest = require("./build_testg1");
|
||||
const buildFFT = require("./build_fft");
|
||||
const buildMultiexp = require("./build_multiexp");
|
||||
const buildPol = require("./build_pol");
|
||||
const utils = require("./utils");
|
||||
|
||||
async function build() {
|
||||
const bn128 = new Bn128();
|
||||
|
||||
bn128.q = bigInt("21888242871839275222246405745257275088696311157297823662689037894645226208583");
|
||||
bn128.r = bigInt("21888242871839275222246405745257275088548364400416034343698204186575808495617");
|
||||
bn128.n64 = Math.floor((bn128.q.minus(1).bitLength() - 1)/64) +1;
|
||||
bn128.n32 = bn128.n64*2;
|
||||
bn128.n8 = bn128.n64*8;
|
||||
|
||||
bn128.memory = new WebAssembly.Memory({initial:10000});
|
||||
bn128.i32 = new Uint32Array(bn128.memory.buffer);
|
||||
|
||||
const moduleBuilder = new ModuleBuilder();
|
||||
moduleBuilder.setMemory(10000);
|
||||
buildF1m(moduleBuilder, bn128.q, "f1m");
|
||||
buildF1(moduleBuilder, bn128.r, "fr", "frm");
|
||||
buildCurve(moduleBuilder, "g1", "f1m");
|
||||
buildMultiexp(moduleBuilder, "g1", "g1", "f1m", "fr");
|
||||
buildFFT(moduleBuilder, "fft", "frm");
|
||||
buildPol(moduleBuilder, "pol", "frm");
|
||||
|
||||
const pNonResidueF2 = moduleBuilder.alloc(
|
||||
utils.bigInt2BytesLE(
|
||||
bigInt("15537367993719455909907449462855742678907882278146377936676643359958227611562"), // -1 in montgomery
|
||||
bn128.n8
|
||||
)
|
||||
);
|
||||
|
||||
buildF2m(moduleBuilder, pNonResidueF2, "f2m", "f1m");
|
||||
buildCurve(moduleBuilder, "g2", "f2m");
|
||||
buildMultiexp(moduleBuilder, "g2", "g2", "f2m", "fr");
|
||||
|
||||
buildTest(moduleBuilder);
|
||||
|
||||
const code = moduleBuilder.build();
|
||||
|
||||
const wasmModule = await WebAssembly.compile(code);
|
||||
|
||||
bn128.instance = await WebAssembly.instantiate(wasmModule, {
|
||||
env: {
|
||||
"memory": bn128.memory
|
||||
}
|
||||
});
|
||||
|
||||
bn128.pq = moduleBuilder.modules.f1m.pq;
|
||||
bn128.pr = moduleBuilder.modules.frm.pq;
|
||||
|
||||
bn128.pg1 = bn128.g1_allocPoint([bigInt(1), bigInt(2), bigInt(1)]);
|
||||
|
||||
Object.assign(bn128, bn128.instance.exports);
|
||||
|
||||
return bn128;
|
||||
}
|
||||
|
||||
class Bn128 {
|
||||
|
||||
constructor() {
|
||||
|
||||
}
|
||||
|
||||
alloc(length) {
|
||||
while (this.i32[0] & 3) this.i32[0]++; // Return always aligned pointers
|
||||
const res = this.i32[0];
|
||||
this.i32[0] += length;
|
||||
return res;
|
||||
}
|
||||
|
||||
putInt(pos, _a) {
|
||||
const a = bigInt(_a);
|
||||
if (pos & 0x7) throw new Error("Pointer must be aligned");
|
||||
if (a.bitLength > this.n64*64) {
|
||||
return this.putInt(a.mod(this.q));
|
||||
}
|
||||
for (let i=0; i<this.n32; i++) {
|
||||
this.i32[(pos>>2)+i] = a.shiftRight(i*32).and(0xFFFFFFFF).toJSNumber();
|
||||
}
|
||||
}
|
||||
|
||||
getInt(pos) {
|
||||
if (pos & 0x7) throw new Error("Pointer must be aligned");
|
||||
let acc = bigInt(this.i32[(pos>>2)+this.n32-1]);
|
||||
for (let i=this.n32-2; i>=0; i--) {
|
||||
acc = acc.shiftLeft(32);
|
||||
acc = acc.add(this.i32[(pos>>2)+i]);
|
||||
}
|
||||
return acc;
|
||||
}
|
||||
|
||||
allocInt(_a) {
|
||||
const p = this.alloc(this.n8);
|
||||
if (_a) this.putInt(p, _a);
|
||||
return p;
|
||||
}
|
||||
|
||||
putIntF2(pos, a) {
|
||||
this.putInt(pos, a[0]);
|
||||
this.putInt(pos+this.n8, a[1]);
|
||||
}
|
||||
|
||||
getIntF2(pos) {
|
||||
const p = Array(2);
|
||||
p[0] = this.getInt(pos);
|
||||
p[1] = this.getInt(pos+this.n8);
|
||||
return p;
|
||||
}
|
||||
|
||||
allocIntF2(a) {
|
||||
const pP = this.alloc(this.n8*2);
|
||||
if (a) {
|
||||
this.putIntF2(pP, a);
|
||||
}
|
||||
return pP;
|
||||
}
|
||||
|
||||
g1_putPoint(pos, p) {
|
||||
this.putInt(pos, p[0]);
|
||||
this.putInt(pos+this.n8, p[1]);
|
||||
if (p.length == 3) {
|
||||
this.putInt(pos+this.n8*2, p[2]);
|
||||
} else {
|
||||
this.putInt(pos+this.n8*2, 1);
|
||||
}
|
||||
}
|
||||
|
||||
g1_getPoint(pos) {
|
||||
const p = Array(3);
|
||||
p[0] = this.getInt(pos);
|
||||
p[1] = this.getInt(pos+this.n8);
|
||||
p[2] = this.getInt(pos+this.n8*2);
|
||||
return p;
|
||||
}
|
||||
|
||||
g1_allocPoint(p) {
|
||||
const pP = this.alloc(this.n8*3);
|
||||
if (p) {
|
||||
this.g1_putPoint(pP, p);
|
||||
}
|
||||
return pP;
|
||||
}
|
||||
|
||||
|
||||
g2_putPoint(pos, p) {
|
||||
this.putIntF2(pos, p[0]);
|
||||
this.putIntF2(pos+this.n8*2, p[1]);
|
||||
if (p.length == 3) {
|
||||
this.putIntF2(pos+this.n8*4, p[2]);
|
||||
} else {
|
||||
this.putIntF2(pos+this.n8*4, 1);
|
||||
}
|
||||
}
|
||||
|
||||
g2_getPoint(pos) {
|
||||
const p = Array(3);
|
||||
p[0] = this.getIntF2(pos);
|
||||
p[1] = this.getIntF2(pos+this.n8*2);
|
||||
p[2] = this.getIntF2(pos+this.n8*4);
|
||||
return p;
|
||||
}
|
||||
|
||||
g2_allocPoint(p) {
|
||||
const pP = this.alloc(this.n8*6);
|
||||
if (p) {
|
||||
this.g2_putPoint(pP, p);
|
||||
}
|
||||
return pP;
|
||||
}
|
||||
|
||||
putBin(b) {
|
||||
const p = this.alloc(b.byteLength);
|
||||
const s32 = new Uint32Array(b);
|
||||
this.i32.set(s32, p/4);
|
||||
return p;
|
||||
}
|
||||
|
||||
test_AddG1(n) {
|
||||
const start = new Date().getTime();
|
||||
|
||||
const pg = this.g1_allocPoint([bigInt(1), bigInt(2), bigInt(1)]);
|
||||
this.g1_toMontgomery(pg,pg);
|
||||
const p2 = this.g1_allocPoint();
|
||||
this.instance.exports.testAddG1(n, pg, p2);
|
||||
this.g1_fromMontgomery(p2,p2);
|
||||
|
||||
const end = new Date().getTime();
|
||||
const time = end - start;
|
||||
|
||||
return time;
|
||||
}
|
||||
|
||||
test_fft(n) {
|
||||
|
||||
const N=n;
|
||||
|
||||
const p = this.i32[0];
|
||||
for (let i=0; i<N; i++) {
|
||||
this.putInt(p+i*32, i);
|
||||
}
|
||||
|
||||
const start = new Date().getTime();
|
||||
this.fft_ifft(p, N);
|
||||
const end = new Date().getTime();
|
||||
const time = end - start;
|
||||
|
||||
return time;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = build;
|
436
src/build_curve.js
Normal file
436
src/build_curve.js
Normal file
@ -0,0 +1,436 @@
|
||||
/*
|
||||
Copyright 2019 0KIMS association.
|
||||
|
||||
This file is part of websnark (Web Assembly zkSnark Prover).
|
||||
|
||||
websnark is a free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
websnark is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with websnark. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
const buildTimesScalar = require("./build_timesscalar");
|
||||
|
||||
module.exports = function buildCurve(module, prefix, prefixField) {
|
||||
|
||||
|
||||
const n64 = module.modules[prefixField].n64;
|
||||
const n8 = n64*8;
|
||||
|
||||
if (module.modules[prefix]) return prefix; // already builded
|
||||
module.modules[prefix] = {
|
||||
n64: n64*3
|
||||
};
|
||||
|
||||
function buildIsZero() {
|
||||
const f = module.addFunction(prefix + "_isZero");
|
||||
f.addParam("p1", "i32");
|
||||
f.setReturnType("i32");
|
||||
|
||||
const c = f.getCodeBuilder();
|
||||
|
||||
f.addCode(c.call(
|
||||
prefixField + "_isZero",
|
||||
c.i32_add(
|
||||
c.getLocal("p1"),
|
||||
c.i32_const(n8*2)
|
||||
)
|
||||
));
|
||||
}
|
||||
|
||||
function buildCopy() {
|
||||
const f = module.addFunction(prefix + "_copy");
|
||||
f.addParam("p1", "i32");
|
||||
f.addParam("pr", "i32");
|
||||
|
||||
const c = f.getCodeBuilder();
|
||||
|
||||
f.addCode(c.call(
|
||||
prefixField + "_copy",
|
||||
c.getLocal("p1"),
|
||||
c.getLocal("pr")
|
||||
));
|
||||
|
||||
f.addCode(c.call(
|
||||
prefixField + "_copy",
|
||||
c.i32_add(
|
||||
c.getLocal("p1"),
|
||||
c.i32_const(n8)
|
||||
),
|
||||
c.i32_add(
|
||||
c.getLocal("pr"),
|
||||
c.i32_const(n8)
|
||||
)
|
||||
));
|
||||
|
||||
f.addCode(c.call(
|
||||
prefixField + "_copy",
|
||||
c.i32_add(
|
||||
c.getLocal("p1"),
|
||||
c.i32_const(n8*2)
|
||||
),
|
||||
c.i32_add(
|
||||
c.getLocal("pr"),
|
||||
c.i32_const(n8*2)
|
||||
)
|
||||
));
|
||||
}
|
||||
|
||||
function buildZero() {
|
||||
const f = module.addFunction(prefix + "_zero");
|
||||
f.addParam("pr", "i32");
|
||||
|
||||
const c = f.getCodeBuilder();
|
||||
|
||||
f.addCode(c.call(
|
||||
prefixField + "_zero",
|
||||
c.getLocal("pr")
|
||||
));
|
||||
|
||||
f.addCode(c.call(
|
||||
prefixField + "_one",
|
||||
c.i32_add(
|
||||
c.getLocal("pr"),
|
||||
c.i32_const(n8)
|
||||
)
|
||||
));
|
||||
|
||||
f.addCode(c.call(
|
||||
prefixField + "_zero",
|
||||
c.i32_add(
|
||||
c.getLocal("pr"),
|
||||
c.i32_const(n8*2)
|
||||
)
|
||||
));
|
||||
}
|
||||
|
||||
function buildDouble() {
|
||||
const f = module.addFunction(prefix + "_double");
|
||||
f.addParam("p1", "i32");
|
||||
f.addParam("pr", "i32");
|
||||
|
||||
const c = f.getCodeBuilder();
|
||||
|
||||
const x = c.getLocal("p1");
|
||||
const y = c.i32_add(c.getLocal("p1"), c.i32_const(n8));
|
||||
const z = c.i32_add(c.getLocal("p1"), c.i32_const(n8*2));
|
||||
const x3 = c.getLocal("pr");
|
||||
const y3 = c.i32_add(c.getLocal("pr"), c.i32_const(n8));
|
||||
const z3 = c.i32_add(c.getLocal("pr"), c.i32_const(n8*2));
|
||||
|
||||
const A = c.i32_const(module.alloc(n8));
|
||||
const B = c.i32_const(module.alloc(n8));
|
||||
const C = c.i32_const(module.alloc(n8));
|
||||
const D = c.i32_const(module.alloc(n8));
|
||||
const E = c.i32_const(module.alloc(n8));
|
||||
const F = c.i32_const(module.alloc(n8));
|
||||
const G = c.i32_const(module.alloc(n8));
|
||||
const eightC = c.i32_const(module.alloc(n8));
|
||||
|
||||
f.addCode(
|
||||
c.if(
|
||||
c.call(prefix + "_isZero", c.getLocal("p1")),
|
||||
[
|
||||
...c.call(prefix + "_copy", c.getLocal("p1"), c.getLocal("pr")),
|
||||
...c.ret([])
|
||||
]
|
||||
),
|
||||
|
||||
c.call(prefixField + "_mul", x, x, A),
|
||||
c.call(prefixField + "_mul", y, y, B),
|
||||
c.call(prefixField + "_mul", B, B, C),
|
||||
|
||||
c.call(prefixField + "_add", x, B, D),
|
||||
c.call(prefixField + "_mul", D, D, D),
|
||||
c.call(prefixField + "_sub", D, A, D),
|
||||
c.call(prefixField + "_sub", D, C, D),
|
||||
c.call(prefixField + "_add", D, D, D),
|
||||
|
||||
c.call(prefixField + "_add", A, A, E),
|
||||
c.call(prefixField + "_add", E, A, E),
|
||||
c.call(prefixField + "_mul", E, E, F),
|
||||
|
||||
c.call(prefixField + "_mul", y, z, G),
|
||||
|
||||
c.call(prefixField + "_add", D, D, x3),
|
||||
c.call(prefixField + "_sub", F, x3, x3),
|
||||
|
||||
c.call(prefixField + "_add", C, C, eightC),
|
||||
c.call(prefixField + "_add", eightC, eightC, eightC),
|
||||
c.call(prefixField + "_add", eightC, eightC, eightC),
|
||||
|
||||
c.call(prefixField + "_sub", D, x3, y3),
|
||||
c.call(prefixField + "_mul", y3, E, y3),
|
||||
c.call(prefixField + "_sub", y3, eightC, y3),
|
||||
|
||||
c.call(prefixField + "_add", G, G, z3),
|
||||
);
|
||||
}
|
||||
|
||||
function buildToMontgomery() {
|
||||
const f = module.addFunction(prefix + "_toMontgomery");
|
||||
f.addParam("p1", "i32");
|
||||
f.addParam("pr", "i32");
|
||||
|
||||
const c = f.getCodeBuilder();
|
||||
|
||||
f.addCode(c.call(
|
||||
prefixField + "_toMontgomery",
|
||||
c.getLocal("p1"),
|
||||
c.getLocal("pr")
|
||||
));
|
||||
for (let i=1; i<3; i++) {
|
||||
f.addCode(c.call(
|
||||
prefixField + "_toMontgomery",
|
||||
c.i32_add(c.getLocal("p1"), c.i32_const(i*n8)),
|
||||
c.i32_add(c.getLocal("pr"), c.i32_const(i*n8))
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
function buildFromMontgomery() {
|
||||
const f = module.addFunction(prefix + "_fromMontgomery");
|
||||
f.addParam("p1", "i32");
|
||||
f.addParam("pr", "i32");
|
||||
|
||||
const c = f.getCodeBuilder();
|
||||
|
||||
f.addCode(c.call(
|
||||
prefixField + "_fromMontgomery",
|
||||
c.getLocal("p1"),
|
||||
c.getLocal("pr")
|
||||
));
|
||||
for (let i=1; i<3; i++) {
|
||||
f.addCode(c.call(
|
||||
prefixField + "_fromMontgomery",
|
||||
c.i32_add(c.getLocal("p1"), c.i32_const(i*n8)),
|
||||
c.i32_add(c.getLocal("pr"), c.i32_const(i*n8))
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function buildAdd() {
|
||||
|
||||
const f = module.addFunction(prefix + "_add");
|
||||
f.addParam("p1", "i32");
|
||||
f.addParam("p2", "i32");
|
||||
f.addParam("pr", "i32");
|
||||
f.addLocal("z1", "i32");
|
||||
f.addLocal("z2", "i32");
|
||||
|
||||
const c = f.getCodeBuilder();
|
||||
|
||||
const x1 = c.getLocal("p1");
|
||||
const y1 = c.i32_add(c.getLocal("p1"), c.i32_const(n8));
|
||||
f.addCode(c.setLocal("z1", c.i32_add(c.getLocal("p1"), c.i32_const(n8*2))));
|
||||
const z1 = c.getLocal("z1");
|
||||
const x2 = c.getLocal("p2");
|
||||
const y2 = c.i32_add(c.getLocal("p2"), c.i32_const(n8));
|
||||
f.addCode(c.setLocal("z2", c.i32_add(c.getLocal("p2"), c.i32_const(n8*2))));
|
||||
const z2 = c.getLocal("z2");
|
||||
const x3 = c.getLocal("pr");
|
||||
const y3 = c.i32_add(c.getLocal("pr"), c.i32_const(n8));
|
||||
const z3 = c.i32_add(c.getLocal("pr"), c.i32_const(n8*2));
|
||||
|
||||
const Z1Z1 = c.i32_const(module.alloc(n8));
|
||||
const Z2Z2 = c.i32_const(module.alloc(n8));
|
||||
const U1 = c.i32_const(module.alloc(n8));
|
||||
const U2 = c.i32_const(module.alloc(n8));
|
||||
const Z1_cubed = c.i32_const(module.alloc(n8));
|
||||
const Z2_cubed = c.i32_const(module.alloc(n8));
|
||||
const S1 = c.i32_const(module.alloc(n8));
|
||||
const S2 = c.i32_const(module.alloc(n8));
|
||||
const H = c.i32_const(module.alloc(n8));
|
||||
const S2_minus_S1 = c.i32_const(module.alloc(n8));
|
||||
const I = c.i32_const(module.alloc(n8));
|
||||
const J = c.i32_const(module.alloc(n8));
|
||||
const r = c.i32_const(module.alloc(n8));
|
||||
const r2 = c.i32_const(module.alloc(n8));
|
||||
const V = c.i32_const(module.alloc(n8));
|
||||
const V2 = c.i32_const(module.alloc(n8));
|
||||
const S1_J2 = c.i32_const(module.alloc(n8));
|
||||
|
||||
f.addCode(
|
||||
c.if(
|
||||
c.call(prefix + "_isZero", c.getLocal("p1")),
|
||||
[
|
||||
...c.call(prefix + "_copy", c.getLocal("p2"), c.getLocal("pr")),
|
||||
...c.ret([])
|
||||
]
|
||||
),
|
||||
|
||||
c.if(
|
||||
c.call(prefix + "_isZero", c.getLocal("p2")),
|
||||
[
|
||||
...c.call(prefix + "_copy", c.getLocal("p1"), c.getLocal("pr")),
|
||||
...c.ret([])
|
||||
]
|
||||
),
|
||||
|
||||
c.call(prefixField + "_mul", z1, z1, Z1Z1),
|
||||
c.call(prefixField + "_mul", z2, z2, Z2Z2),
|
||||
c.call(prefixField + "_mul", x1, Z2Z2, U1),
|
||||
c.call(prefixField + "_mul", x2, Z1Z1, U2),
|
||||
c.call(prefixField + "_mul", z1, Z1Z1, Z1_cubed),
|
||||
c.call(prefixField + "_mul", z2, Z2Z2, Z2_cubed),
|
||||
c.call(prefixField + "_mul", y1, Z2_cubed, S1),
|
||||
c.call(prefixField + "_mul", y2, Z1_cubed, S2),
|
||||
|
||||
c.if(
|
||||
c.call(prefixField + "_eq", U1, U2),
|
||||
c.if(
|
||||
c.call(prefixField + "_eq", S1, S2),
|
||||
[
|
||||
...c.call(prefix + "_double", c.getLocal("p1"), c.getLocal("pr")),
|
||||
...c.ret([])
|
||||
]
|
||||
)
|
||||
),
|
||||
|
||||
c.call(prefixField + "_sub", U2, U1, H),
|
||||
c.call(prefixField + "_sub", S2, S1, S2_minus_S1),
|
||||
c.call(prefixField + "_add", H, H, I),
|
||||
c.call(prefixField + "_mul", I, I, I),
|
||||
c.call(prefixField + "_mul", H, I, J),
|
||||
c.call(prefixField + "_add", S2_minus_S1, S2_minus_S1, r),
|
||||
c.call(prefixField + "_mul", U1, I, V),
|
||||
c.call(prefixField + "_mul", r, r, r2),
|
||||
c.call(prefixField + "_add", V, V, V2),
|
||||
|
||||
c.call(prefixField + "_sub", r2, J, x3),
|
||||
c.call(prefixField + "_sub", x3, V2, x3),
|
||||
|
||||
c.call(prefixField + "_mul", S1, J, S1_J2),
|
||||
c.call(prefixField + "_add", S1_J2, S1_J2, S1_J2),
|
||||
|
||||
c.call(prefixField + "_sub", V, x3, y3),
|
||||
c.call(prefixField + "_mul", y3, r, y3),
|
||||
c.call(prefixField + "_sub", y3, S1_J2, y3),
|
||||
|
||||
c.call(prefixField + "_add", z1, z2, z3),
|
||||
c.call(prefixField + "_mul", z3, z3, z3),
|
||||
c.call(prefixField + "_sub", z3, Z1Z1, z3),
|
||||
c.call(prefixField + "_sub", z3, Z2Z2, z3),
|
||||
c.call(prefixField + "_mul", z3, H, z3),
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
function buildNeg() {
|
||||
const f = module.addFunction(prefix + "_neg");
|
||||
f.addParam("p1", "i32");
|
||||
f.addParam("pr", "i32");
|
||||
|
||||
const c = f.getCodeBuilder();
|
||||
|
||||
const x = c.getLocal("p1");
|
||||
const y = c.i32_add(c.getLocal("p1"), c.i32_const(n8));
|
||||
const z = c.i32_add(c.getLocal("p1"), c.i32_const(n8*2));
|
||||
const x3 = c.getLocal("pr");
|
||||
const y3 = c.i32_add(c.getLocal("pr"), c.i32_const(n8));
|
||||
const z3 = c.i32_add(c.getLocal("pr"), c.i32_const(n8*2));
|
||||
|
||||
f.addCode(
|
||||
c.call(prefixField + "_copy", x, x3),
|
||||
c.call(prefixField + "_neg", y, y3),
|
||||
c.call(prefixField + "_copy", z, z3)
|
||||
);
|
||||
}
|
||||
|
||||
function buildSub() {
|
||||
const f = module.addFunction(prefix + "_sub");
|
||||
f.addParam("p1", "i32");
|
||||
f.addParam("p2", "i32");
|
||||
f.addParam("pr", "i32");
|
||||
|
||||
const c = f.getCodeBuilder();
|
||||
|
||||
f.addCode(
|
||||
c.call(prefix + "_neg", c.getLocal("p2"), c.getLocal("pr")),
|
||||
c.call(prefix + "_add", c.getLocal("p1"), c.getLocal("pr"), c.getLocal("pr")),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
function buildAffine() {
|
||||
const f = module.addFunction(prefix + "_affine");
|
||||
f.addParam("p1", "i32");
|
||||
f.addParam("pr", "i32");
|
||||
|
||||
const c = f.getCodeBuilder();
|
||||
|
||||
const x = c.getLocal("p1");
|
||||
const y = c.i32_add(c.getLocal("p1"), c.i32_const(n8));
|
||||
const z = c.i32_add(c.getLocal("p1"), c.i32_const(n8*2));
|
||||
const x3 = c.getLocal("pr");
|
||||
const y3 = c.i32_add(c.getLocal("pr"), c.i32_const(n8));
|
||||
const z3 = c.i32_add(c.getLocal("pr"), c.i32_const(n8*2));
|
||||
|
||||
|
||||
const Z_inv = c.i32_const(module.alloc(n8));
|
||||
const Z2_inv = c.i32_const(module.alloc(n8));
|
||||
const Z3_inv = c.i32_const(module.alloc(n8));
|
||||
|
||||
f.addCode(
|
||||
c.if(
|
||||
c.call(prefix + "_isZero", c.getLocal("p1")),
|
||||
c.call(prefix + "_zero", c.getLocal("pr")),
|
||||
[
|
||||
...c.call(prefixField + "_inverse", z, Z_inv),
|
||||
...c.call(prefixField + "_mul", Z_inv, Z_inv, Z2_inv),
|
||||
...c.call(prefixField + "_mul", Z_inv, Z2_inv, Z3_inv),
|
||||
...c.call(prefixField + "_mul", x, Z2_inv, x3),
|
||||
...c.call(prefixField + "_mul", y, Z3_inv, y3),
|
||||
...c.call(prefixField + "_one", z3)
|
||||
]
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
buildIsZero();
|
||||
buildZero();
|
||||
buildCopy();
|
||||
buildDouble();
|
||||
buildAdd();
|
||||
buildNeg();
|
||||
buildSub();
|
||||
buildFromMontgomery();
|
||||
buildToMontgomery();
|
||||
buildAffine();
|
||||
buildTimesScalar(
|
||||
module,
|
||||
prefix + "_timesScalar",
|
||||
n8*3,
|
||||
prefix + "_add",
|
||||
prefix + "_double",
|
||||
prefix
|
||||
);
|
||||
module.exportFunction(prefix + "_isZero");
|
||||
module.exportFunction(prefix + "_copy");
|
||||
module.exportFunction(prefix + "_zero");
|
||||
module.exportFunction(prefix + "_double");
|
||||
module.exportFunction(prefix + "_add");
|
||||
module.exportFunction(prefix + "_neg");
|
||||
module.exportFunction(prefix + "_sub");
|
||||
module.exportFunction(prefix + "_fromMontgomery");
|
||||
module.exportFunction(prefix + "_toMontgomery");
|
||||
module.exportFunction(prefix + "_affine");
|
||||
module.exportFunction(prefix + "_timesScalar");
|
||||
|
||||
/*
|
||||
buildG1MulScalar(module, zq);
|
||||
module.exportFunction("g1MulScalar");
|
||||
*/
|
||||
|
||||
return prefix;
|
||||
};
|
80
src/build_f1.js
Normal file
80
src/build_f1.js
Normal file
@ -0,0 +1,80 @@
|
||||
/*
|
||||
Copyright 2019 0KIMS association.
|
||||
|
||||
This file is part of websnark (Web Assembly zkSnark Prover).
|
||||
|
||||
websnark is a free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
websnark is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with websnark. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
const bigInt = require("big-integer");
|
||||
|
||||
const buildF1m =require("./build_f1m.js");
|
||||
|
||||
module.exports = function buildF1(module, _q, _prefix, _f1mPrefix, _intPrefix) {
|
||||
|
||||
const q = bigInt(_q);
|
||||
const n64 = Math.floor((q.minus(1).bitLength() - 1)/64) +1;
|
||||
const n8 = n64*8;
|
||||
|
||||
const prefix = _prefix || "f1";
|
||||
if (module.modules[prefix]) return prefix; // already builded
|
||||
module.modules[prefix] = {
|
||||
n64: n64
|
||||
};
|
||||
|
||||
const intPrefix = _intPrefix || "int";
|
||||
const f1mPrefix = buildF1m(module, q, _f1mPrefix, intPrefix);
|
||||
|
||||
|
||||
const pR2 = module.modules[f1mPrefix].pR2;
|
||||
const pq = module.modules[f1mPrefix].pq;
|
||||
|
||||
function buildMul() {
|
||||
const pAux1 = module.alloc(n8);
|
||||
|
||||
const f = module.addFunction(prefix+ "_mul");
|
||||
f.addParam("x", "i32");
|
||||
f.addParam("y", "i32");
|
||||
f.addParam("r", "i32");
|
||||
|
||||
const c = f.getCodeBuilder();
|
||||
f.addCode(c.call(f1mPrefix + "_mul", c.getLocal("x"), c.getLocal("y"), c.i32_const(pAux1)));
|
||||
f.addCode(c.call(f1mPrefix + "_mul", c.i32_const(pAux1), c.i32_const(pR2), c.getLocal("r")));
|
||||
}
|
||||
|
||||
function buildInverse() {
|
||||
|
||||
const f = module.addFunction(prefix+ "_inverse");
|
||||
f.addParam("x", "i32");
|
||||
f.addParam("r", "i32");
|
||||
|
||||
const c = f.getCodeBuilder();
|
||||
f.addCode(c.call(intPrefix + "_inverseMod", c.getLocal("x"), c.i32_const(pq), c.getLocal("r")));
|
||||
}
|
||||
|
||||
buildMul();
|
||||
buildInverse();
|
||||
module.exportFunction(f1mPrefix + "_add", prefix + "_add");
|
||||
module.exportFunction(f1mPrefix + "_sub", prefix + "_sub");
|
||||
module.exportFunction(f1mPrefix + "_neg", prefix + "_neg");
|
||||
module.exportFunction(prefix + "_mul");
|
||||
module.exportFunction(prefix + "_inverse");
|
||||
module.exportFunction(f1mPrefix + "_copy", prefix+"_copy");
|
||||
module.exportFunction(f1mPrefix + "_zero", prefix+"_zero");
|
||||
module.exportFunction(f1mPrefix + "_one", prefix+"_one");
|
||||
module.exportFunction(f1mPrefix + "_isZero", prefix+"_isZero");
|
||||
module.exportFunction(f1mPrefix + "_eq", prefix+"_eq");
|
||||
|
||||
return prefix;
|
||||
};
|
264
src/build_f1m.js
Normal file
264
src/build_f1m.js
Normal file
@ -0,0 +1,264 @@
|
||||
/*
|
||||
Copyright 2019 0KIMS association.
|
||||
|
||||
This file is part of websnark (Web Assembly zkSnark Prover).
|
||||
|
||||
websnark is a free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
websnark is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with websnark. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
const bigInt = require("big-integer");
|
||||
const buildInt = require("./build_int.js");
|
||||
const utils = require("./utils.js");
|
||||
|
||||
module.exports = function buildF1m(module, _q, _prefix, _intPrefix) {
|
||||
const q = bigInt(_q);
|
||||
const n64 = Math.floor((q.minus(1).bitLength() - 1)/64) +1;
|
||||
const n32 = n64*2;
|
||||
const n8 = n64*8;
|
||||
|
||||
const prefix = _prefix || "f1m";
|
||||
if (module.modules[prefix]) return prefix; // already builded
|
||||
|
||||
const intPrefix = buildInt(module, n64, _intPrefix);
|
||||
const pq = module.alloc(n8, utils.bigInt2BytesLE(q, n8));
|
||||
|
||||
const pR2 = module.alloc(utils.bigInt2BytesLE(bigInt.one.shiftLeft(n64*64).square().mod(q), n8));
|
||||
const pOne = module.alloc(utils.bigInt2BytesLE(bigInt.one.shiftLeft(n64*64).mod(q), n8));
|
||||
const pZero = module.alloc(utils.bigInt2BytesLE(bigInt.zero, n8));
|
||||
module.modules[prefix] = {
|
||||
pq: pq,
|
||||
pR2: pR2,
|
||||
n64: n64,
|
||||
q: q,
|
||||
pOne: pOne,
|
||||
pZero: pZero
|
||||
};
|
||||
|
||||
function buildOne() {
|
||||
const f = module.addFunction(prefix+"_one");
|
||||
f.addParam("pr", "i32");
|
||||
|
||||
const c = f.getCodeBuilder();
|
||||
|
||||
f.addCode(c.call(prefix + "_copy", c.i32_const(pOne), c.getLocal("pr")));
|
||||
}
|
||||
|
||||
function buildAdd() {
|
||||
const f = module.addFunction(prefix+"_add");
|
||||
f.addParam("x", "i32");
|
||||
f.addParam("y", "i32");
|
||||
f.addParam("r", "i32");
|
||||
|
||||
const c = f.getCodeBuilder();
|
||||
|
||||
f.addCode(
|
||||
c.if(
|
||||
c.call(intPrefix+"_add", c.getLocal("x"), c.getLocal("y"), c.getLocal("r")),
|
||||
c.drop(c.call(intPrefix+"_sub", c.getLocal("r"), c.i32_const(pq), c.getLocal("r"))),
|
||||
c.if(
|
||||
c.call(intPrefix+"_gte", c.getLocal("r"), c.i32_const(pq) ),
|
||||
c.drop(c.call(intPrefix+"_sub", c.getLocal("r"), c.i32_const(pq), c.getLocal("r"))),
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
function buildSub() {
|
||||
const f = module.addFunction(prefix+"_sub");
|
||||
f.addParam("x", "i32");
|
||||
f.addParam("y", "i32");
|
||||
f.addParam("r", "i32");
|
||||
|
||||
const c = f.getCodeBuilder();
|
||||
|
||||
f.addCode(
|
||||
c.if(
|
||||
c.call(intPrefix+"_sub", c.getLocal("x"), c.getLocal("y"), c.getLocal("r")),
|
||||
c.drop(c.call(intPrefix+"_add", c.getLocal("r"), c.i32_const(pq), c.getLocal("r")))
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
function buildNeg() {
|
||||
const f = module.addFunction(prefix+"_neg");
|
||||
f.addParam("x", "i32");
|
||||
f.addParam("r", "i32");
|
||||
|
||||
const c = f.getCodeBuilder();
|
||||
|
||||
f.addCode(
|
||||
c.if(
|
||||
c.i32_eqz( c.call(intPrefix + "_isZero", c.getLocal("x"))),
|
||||
c.drop(c.call(intPrefix+"_sub", c.i32_const(pq), c.getLocal("x"), c.getLocal("r"))),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
function buildMReduct() {
|
||||
const carries = module.alloc(n32*n32*8);
|
||||
|
||||
const f = module.addFunction(prefix+"_mReduct");
|
||||
f.addParam("t", "i32");
|
||||
f.addParam("r", "i32");
|
||||
f.addLocal("np32", "i64");
|
||||
f.addLocal("c", "i64");
|
||||
f.addLocal("m", "i64");
|
||||
|
||||
const c = f.getCodeBuilder();
|
||||
|
||||
const np32 = bigInt("100000000",16).minus( q.modInv(bigInt("100000000",16))).toJSNumber();
|
||||
|
||||
f.addCode(c.setLocal("np32", c.i64_const(np32)));
|
||||
|
||||
for (let i=0; i<n32; i++) {
|
||||
f.addCode(c.setLocal("c", c.i64_const(0)));
|
||||
|
||||
f.addCode(
|
||||
c.setLocal(
|
||||
"m",
|
||||
c.i64_and(
|
||||
c.i64_mul(
|
||||
c.i64_load32_u(c.getLocal("t"), i*4),
|
||||
c.getLocal("np32")
|
||||
),
|
||||
c.i64_const("0xFFFFFFFF")
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
for (let j=0; j<n32; j++) {
|
||||
|
||||
f.addCode(
|
||||
c.setLocal("c",
|
||||
c.i64_add(
|
||||
c.i64_add(
|
||||
c.i64_load32_u(c.getLocal("t"), (i+j)*4),
|
||||
c.i64_shr_u(c.getLocal("c"), c.i64_const(32))
|
||||
),
|
||||
c.i64_mul(
|
||||
c.i64_load32_u(c.i32_const(pq), j*4),
|
||||
c.getLocal("m")
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
f.addCode(
|
||||
c.i64_store32(
|
||||
c.getLocal("t"),
|
||||
(i+j)*4,
|
||||
c.getLocal("c")
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
f.addCode(
|
||||
c.i64_store32(
|
||||
c.i32_const(carries),
|
||||
i*4,
|
||||
c.i64_shr_u(c.getLocal("c"), c.i64_const(32))
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
f.addCode(
|
||||
c.call(
|
||||
prefix+"_add",
|
||||
c.i32_const(carries),
|
||||
c.i32_add(
|
||||
c.getLocal("t"),
|
||||
c.i32_const(n32*4)
|
||||
),
|
||||
c.getLocal("r")
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
function buildMul() {
|
||||
|
||||
const pAux2 = module.alloc(n8*2);
|
||||
|
||||
const f = module.addFunction(prefix+"_mul");
|
||||
f.addParam("x", "i32");
|
||||
f.addParam("y", "i32");
|
||||
f.addParam("r", "i32");
|
||||
|
||||
const c = f.getCodeBuilder();
|
||||
f.addCode(c.call(intPrefix + "_mul", c.getLocal("x"), c.getLocal("y"), c.i32_const(pAux2) ));
|
||||
f.addCode(c.call(prefix + "_mReduct", c.i32_const(pAux2), c.getLocal("r")));
|
||||
}
|
||||
|
||||
|
||||
function buildToMontgomery() {
|
||||
const f = module.addFunction(prefix+"_toMontgomery");
|
||||
f.addParam("x", "i32");
|
||||
f.addParam("r", "i32");
|
||||
|
||||
const c = f.getCodeBuilder();
|
||||
f.addCode(c.call(prefix+"_mul", c.getLocal("x"), c.i32_const(pR2), c.getLocal("r")));
|
||||
}
|
||||
|
||||
function buildFromMontgomery() {
|
||||
|
||||
const pAux2 = module.alloc(n8*2);
|
||||
|
||||
const f = module.addFunction(prefix+"_fromMontgomery");
|
||||
f.addParam("x", "i32");
|
||||
f.addParam("r", "i32");
|
||||
|
||||
const c = f.getCodeBuilder();
|
||||
f.addCode(c.call(intPrefix + "_copy", c.getLocal("x"), c.i32_const(pAux2) ));
|
||||
f.addCode(c.call(intPrefix + "_zero", c.i32_const(pAux2 + n8) ));
|
||||
f.addCode(c.call(prefix+"_mReduct", c.i32_const(pAux2), c.getLocal("r")));
|
||||
}
|
||||
|
||||
function buildInverse() {
|
||||
|
||||
const f = module.addFunction(prefix+ "_inverse");
|
||||
f.addParam("x", "i32");
|
||||
f.addParam("r", "i32");
|
||||
|
||||
const c = f.getCodeBuilder();
|
||||
f.addCode(c.call(prefix + "_fromMontgomery", c.getLocal("x"), c.getLocal("r")));
|
||||
f.addCode(c.call(intPrefix + "_inverseMod", c.getLocal("r"), c.i32_const(pq), c.getLocal("r")));
|
||||
f.addCode(c.call(prefix + "_toMontgomery", c.getLocal("r"), c.getLocal("r")));
|
||||
}
|
||||
|
||||
buildAdd();
|
||||
buildSub();
|
||||
buildNeg();
|
||||
buildMReduct();
|
||||
buildMul();
|
||||
buildToMontgomery();
|
||||
buildFromMontgomery();
|
||||
buildInverse();
|
||||
module.exportFunction(prefix + "_add");
|
||||
module.exportFunction(prefix + "_sub");
|
||||
module.exportFunction(prefix + "_neg");
|
||||
module.exportFunction(prefix + "_mReduct");
|
||||
module.exportFunction(prefix + "_mul");
|
||||
module.exportFunction(prefix + "_fromMontgomery");
|
||||
module.exportFunction(prefix + "_toMontgomery");
|
||||
module.exportFunction(prefix + "_inverse");
|
||||
module.exportFunction(intPrefix + "_copy", prefix+"_copy");
|
||||
module.exportFunction(intPrefix + "_zero", prefix+"_zero");
|
||||
module.exportFunction(intPrefix + "_isZero", prefix+"_isZero");
|
||||
module.exportFunction(intPrefix + "_eq", prefix+"_eq");
|
||||
buildOne();
|
||||
module.exportFunction(prefix + "_one");
|
||||
|
||||
return prefix;
|
||||
};
|
307
src/build_f2m.js
Normal file
307
src/build_f2m.js
Normal file
@ -0,0 +1,307 @@
|
||||
/*
|
||||
Copyright 2019 0KIMS association.
|
||||
|
||||
This file is part of websnark (Web Assembly zkSnark Prover).
|
||||
|
||||
websnark is a free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
websnark is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with websnark. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
module.exports = function buildF2m(module, pNonResidue, prefix, f1mPrefix) {
|
||||
|
||||
if (module.modules[prefix]) return prefix; // already builded
|
||||
|
||||
const f1n8 = module.modules[f1mPrefix].n64*8;
|
||||
module.modules[prefix] = {
|
||||
n64: module.modules[f1mPrefix].n64*2
|
||||
};
|
||||
|
||||
function buildAdd() {
|
||||
const f = module.addFunction(prefix+"_add");
|
||||
f.addParam("x", "i32");
|
||||
f.addParam("y", "i32");
|
||||
f.addParam("r", "i32");
|
||||
|
||||
const c = f.getCodeBuilder();
|
||||
|
||||
const x0 = c.getLocal("x");
|
||||
const x1 = c.i32_add(c.getLocal("x"), c.i32_const(f1n8));
|
||||
const y0 = c.getLocal("y");
|
||||
const y1 = c.i32_add(c.getLocal("y"), c.i32_const(f1n8));
|
||||
const r0 = c.getLocal("r");
|
||||
const r1 = c.i32_add(c.getLocal("r"), c.i32_const(f1n8));
|
||||
|
||||
f.addCode(
|
||||
c.call(f1mPrefix+"_add", x0, y0, r0),
|
||||
c.call(f1mPrefix+"_add", x1, y1, r1),
|
||||
);
|
||||
}
|
||||
|
||||
function buildSub() {
|
||||
const f = module.addFunction(prefix+"_sub");
|
||||
f.addParam("x", "i32");
|
||||
f.addParam("y", "i32");
|
||||
f.addParam("r", "i32");
|
||||
|
||||
const c = f.getCodeBuilder();
|
||||
|
||||
const x0 = c.getLocal("x");
|
||||
const x1 = c.i32_add(c.getLocal("x"), c.i32_const(f1n8));
|
||||
const y0 = c.getLocal("y");
|
||||
const y1 = c.i32_add(c.getLocal("y"), c.i32_const(f1n8));
|
||||
const r0 = c.getLocal("r");
|
||||
const r1 = c.i32_add(c.getLocal("r"), c.i32_const(f1n8));
|
||||
|
||||
f.addCode(
|
||||
c.call(f1mPrefix+"_sub", x0, y0, r0),
|
||||
c.call(f1mPrefix+"_sub", x1, y1, r1),
|
||||
);
|
||||
}
|
||||
|
||||
function buildNeg() {
|
||||
const f = module.addFunction(prefix+"_neg");
|
||||
f.addParam("x", "i32");
|
||||
f.addParam("r", "i32");
|
||||
|
||||
const c = f.getCodeBuilder();
|
||||
|
||||
const x0 = c.getLocal("x");
|
||||
const x1 = c.i32_add(c.getLocal("x"), c.i32_const(f1n8));
|
||||
const r0 = c.getLocal("r");
|
||||
const r1 = c.i32_add(c.getLocal("r"), c.i32_const(f1n8));
|
||||
|
||||
f.addCode(
|
||||
c.call(f1mPrefix+"_neg", x0, r0),
|
||||
c.call(f1mPrefix+"_neg", x1, r1),
|
||||
);
|
||||
}
|
||||
|
||||
function buildMul() {
|
||||
const f = module.addFunction(prefix+"_mul");
|
||||
f.addParam("x", "i32");
|
||||
f.addParam("y", "i32");
|
||||
f.addParam("r", "i32");
|
||||
|
||||
const c = f.getCodeBuilder();
|
||||
|
||||
const x0 = c.getLocal("x");
|
||||
const x1 = c.i32_add(c.getLocal("x"), c.i32_const(f1n8));
|
||||
const y0 = c.getLocal("y");
|
||||
const y1 = c.i32_add(c.getLocal("y"), c.i32_const(f1n8));
|
||||
const r0 = c.getLocal("r");
|
||||
const r1 = c.i32_add(c.getLocal("r"), c.i32_const(f1n8));
|
||||
|
||||
const A = c.i32_const(module.alloc(f1n8));
|
||||
const B = c.i32_const(module.alloc(f1n8));
|
||||
const C = c.i32_const(module.alloc(f1n8));
|
||||
const D = c.i32_const(module.alloc(f1n8));
|
||||
|
||||
|
||||
f.addCode(
|
||||
c.call(f1mPrefix + "_mul", x0, y0, A), // A = x0*y0
|
||||
c.call(f1mPrefix + "_mul", x1, y1, B), // B = x1*y1
|
||||
|
||||
c.call(f1mPrefix + "_add", x0, x1, C), // C = x0 + x1
|
||||
c.call(f1mPrefix + "_add", y0, y1, D), // D = y0 + y1
|
||||
c.call(f1mPrefix + "_mul", C, D, C), // C = (x0 + x1)*(y0 + y1) = x0*y0+x0*y1+x1*y0+x1*y1
|
||||
|
||||
c.call(f1mPrefix + "_mul", B, c.i32_const(pNonResidue), r0), // r0 = nr*(x1*y1)
|
||||
c.call(f1mPrefix + "_add", A, r0, r0), // r0 = x0*y0 + nr*(x1*y1)
|
||||
c.call(f1mPrefix + "_add", A, B, r1), // r1 = x0*y0+x1*y1
|
||||
c.call(f1mPrefix + "_sub", C, r1, r1) // r1 = x0*y0+x0*y1+x1*y0+x1*y1 - x0*y0+x1*y1 = x0*y1+x1*y0
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
|
||||
function buildToMontgomery() {
|
||||
const f = module.addFunction(prefix+"_toMontgomery");
|
||||
f.addParam("x", "i32");
|
||||
f.addParam("r", "i32");
|
||||
|
||||
const c = f.getCodeBuilder();
|
||||
|
||||
const x0 = c.getLocal("x");
|
||||
const x1 = c.i32_add(c.getLocal("x"), c.i32_const(f1n8));
|
||||
const r0 = c.getLocal("r");
|
||||
const r1 = c.i32_add(c.getLocal("r"), c.i32_const(f1n8));
|
||||
|
||||
f.addCode(
|
||||
c.call(f1mPrefix+"_toMontgomery", x0, r0),
|
||||
c.call(f1mPrefix+"_toMontgomery", x1, r1)
|
||||
);
|
||||
}
|
||||
|
||||
function buildFromMontgomery() {
|
||||
const f = module.addFunction(prefix+"_fromMontgomery");
|
||||
f.addParam("x", "i32");
|
||||
f.addParam("r", "i32");
|
||||
|
||||
const c = f.getCodeBuilder();
|
||||
|
||||
const x0 = c.getLocal("x");
|
||||
const x1 = c.i32_add(c.getLocal("x"), c.i32_const(f1n8));
|
||||
const r0 = c.getLocal("r");
|
||||
const r1 = c.i32_add(c.getLocal("r"), c.i32_const(f1n8));
|
||||
|
||||
f.addCode(
|
||||
c.call(f1mPrefix+"_fromMontgomery", x0, r0),
|
||||
c.call(f1mPrefix+"_fromMontgomery", x1, r1)
|
||||
);
|
||||
}
|
||||
|
||||
function buildCopy() {
|
||||
const f = module.addFunction(prefix+"_copy");
|
||||
f.addParam("x", "i32");
|
||||
f.addParam("r", "i32");
|
||||
|
||||
const c = f.getCodeBuilder();
|
||||
|
||||
const x0 = c.getLocal("x");
|
||||
const x1 = c.i32_add(c.getLocal("x"), c.i32_const(f1n8));
|
||||
const r0 = c.getLocal("r");
|
||||
const r1 = c.i32_add(c.getLocal("r"), c.i32_const(f1n8));
|
||||
|
||||
f.addCode(
|
||||
c.call(f1mPrefix+"_copy", x0, r0),
|
||||
c.call(f1mPrefix+"_copy", x1, r1)
|
||||
);
|
||||
}
|
||||
|
||||
function buildZero() {
|
||||
const f = module.addFunction(prefix+"_zero");
|
||||
f.addParam("x", "i32");
|
||||
|
||||
const c = f.getCodeBuilder();
|
||||
|
||||
const x0 = c.getLocal("x");
|
||||
const x1 = c.i32_add(c.getLocal("x"), c.i32_const(f1n8));
|
||||
|
||||
f.addCode(
|
||||
c.call(f1mPrefix+"_zero", x0),
|
||||
c.call(f1mPrefix+"_zero", x1)
|
||||
);
|
||||
}
|
||||
|
||||
function buildOne() {
|
||||
const f = module.addFunction(prefix+"_one");
|
||||
f.addParam("x", "i32");
|
||||
|
||||
const c = f.getCodeBuilder();
|
||||
|
||||
const x0 = c.getLocal("x");
|
||||
const x1 = c.i32_add(c.getLocal("x"), c.i32_const(f1n8));
|
||||
|
||||
f.addCode(
|
||||
c.call(f1mPrefix+"_one", x0),
|
||||
c.call(f1mPrefix+"_zero", x1)
|
||||
);
|
||||
}
|
||||
|
||||
function buildEq() {
|
||||
const f = module.addFunction(prefix+"_eq");
|
||||
f.addParam("x", "i32");
|
||||
f.addParam("y", "i32");
|
||||
f.setReturnType("i32");
|
||||
|
||||
const c = f.getCodeBuilder();
|
||||
|
||||
const x0 = c.getLocal("x");
|
||||
const x1 = c.i32_add(c.getLocal("x"), c.i32_const(f1n8));
|
||||
const y0 = c.getLocal("y");
|
||||
const y1 = c.i32_add(c.getLocal("y"), c.i32_const(f1n8));
|
||||
|
||||
f.addCode(
|
||||
c.i32_and(
|
||||
c.call(f1mPrefix+"_eq", x0, y0),
|
||||
c.call(f1mPrefix+"_eq", x1, y1)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
function buildIsZero() {
|
||||
const f = module.addFunction(prefix+"_isZero");
|
||||
f.addParam("x", "i32");
|
||||
f.setReturnType("i32");
|
||||
|
||||
const c = f.getCodeBuilder();
|
||||
|
||||
const x0 = c.getLocal("x");
|
||||
const x1 = c.i32_add(c.getLocal("x"), c.i32_const(f1n8));
|
||||
|
||||
f.addCode(
|
||||
c.i32_and(
|
||||
c.call(f1mPrefix+"_isZero", x0),
|
||||
c.call(f1mPrefix+"_isZero", x1)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
function buildInverse() {
|
||||
const f = module.addFunction(prefix+"_inverse");
|
||||
f.addParam("x", "i32");
|
||||
f.addParam("r", "i32");
|
||||
|
||||
const c = f.getCodeBuilder();
|
||||
|
||||
const x0 = c.getLocal("x");
|
||||
const x1 = c.i32_add(c.getLocal("x"), c.i32_const(f1n8));
|
||||
const r0 = c.getLocal("r");
|
||||
const r1 = c.i32_add(c.getLocal("r"), c.i32_const(f1n8));
|
||||
|
||||
const t0 = c.i32_const(module.alloc(f1n8));
|
||||
const t1 = c.i32_const(module.alloc(f1n8));
|
||||
const t2 = c.i32_const(module.alloc(f1n8));
|
||||
const t3 = c.i32_const(module.alloc(f1n8));
|
||||
|
||||
f.addCode(
|
||||
c.call(f1mPrefix+"_mul", x0, x0, t0),
|
||||
c.call(f1mPrefix+"_mul", x1, x1, t1),
|
||||
c.call(f1mPrefix+"_mul", t1, c.i32_const(pNonResidue), t2),
|
||||
c.call(f1mPrefix+"_sub", t0, t2, t2),
|
||||
c.call(f1mPrefix+"_inverse", t2, t3),
|
||||
|
||||
c.call(f1mPrefix+"_mul", x0, t3, r0),
|
||||
c.call(f1mPrefix+"_mul", x1, t3, r1),
|
||||
c.call(f1mPrefix+"_neg", r1, r1),
|
||||
);
|
||||
}
|
||||
|
||||
buildIsZero();
|
||||
buildZero();
|
||||
buildOne();
|
||||
buildCopy();
|
||||
buildMul();
|
||||
buildAdd();
|
||||
buildSub();
|
||||
buildNeg();
|
||||
buildToMontgomery();
|
||||
buildFromMontgomery();
|
||||
buildEq();
|
||||
buildInverse();
|
||||
|
||||
module.exportFunction(prefix + "_isZero");
|
||||
module.exportFunction(prefix + "_zero");
|
||||
module.exportFunction(prefix + "_one");
|
||||
module.exportFunction(prefix + "_copy");
|
||||
module.exportFunction(prefix + "_mul");
|
||||
module.exportFunction(prefix + "_add");
|
||||
module.exportFunction(prefix + "_sub");
|
||||
module.exportFunction(prefix + "_neg");
|
||||
module.exportFunction(prefix + "_fromMontgomery");
|
||||
module.exportFunction(prefix + "_toMontgomery");
|
||||
module.exportFunction(prefix + "_eq");
|
||||
module.exportFunction(prefix + "_inverse");
|
||||
|
||||
return prefix;
|
||||
};
|
808
src/build_fft.js
Normal file
808
src/build_fft.js
Normal file
@ -0,0 +1,808 @@
|
||||
/*
|
||||
Copyright 2019 0KIMS association.
|
||||
|
||||
This file is part of websnark (Web Assembly zkSnark Prover).
|
||||
|
||||
websnark is a free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
websnark is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with websnark. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
const bigInt = require("big-integer");
|
||||
const utils = require("./utils.js");
|
||||
|
||||
module.exports = function buildFFT(module, prefix, f1mPrefix) {
|
||||
|
||||
const n64 = module.modules[f1mPrefix].n64;
|
||||
const n8 = n64*8;
|
||||
const q = module.modules[f1mPrefix].q;
|
||||
|
||||
let rem = q.minus(bigInt(1));
|
||||
let maxBits = 0;
|
||||
while (!rem.isOdd()) {
|
||||
maxBits ++;
|
||||
rem = rem.shiftRight(1);
|
||||
}
|
||||
|
||||
let nr = bigInt(2);
|
||||
|
||||
while ( nr.modPow(q.shiftRight(1), q).equals(1) ) nr = nr.add(1);
|
||||
|
||||
const w = new Array(maxBits+1);
|
||||
w[maxBits] = nr.modPow(rem, q);
|
||||
|
||||
let n=maxBits-1;
|
||||
while (n>=0) {
|
||||
w[n] = w[n+1].modPow(2, q);
|
||||
n--;
|
||||
}
|
||||
|
||||
const bytes = [];
|
||||
const R = bigInt(1).shiftLeft(n8*8).mod(q);
|
||||
|
||||
for (let i=0; i<w.length; i++) {
|
||||
const m = w[i].times(R).mod(q);
|
||||
bytes.push(...utils.bigInt2BytesLE(m, n8));
|
||||
}
|
||||
|
||||
const ROOTs = module.alloc(bytes);
|
||||
|
||||
const i2 = new Array(maxBits+1);
|
||||
i2[0] = bigInt(1);
|
||||
|
||||
for (let i=1; i<=maxBits; i++) {
|
||||
i2[i] = i2[i-1].times(2);
|
||||
}
|
||||
|
||||
const bytesi2 =[];
|
||||
for (let i=0; i<=maxBits; i++) {
|
||||
const m = i2[i].modInv(q).times(R).mod(q);
|
||||
bytesi2.push(...utils.bigInt2BytesLE(m, n8));
|
||||
}
|
||||
|
||||
const INV2 = module.alloc(bytesi2);
|
||||
|
||||
function rev(x) {
|
||||
let r=0;
|
||||
for (let i=0; i<8; i++) {
|
||||
if (x & (1 << i)) {
|
||||
r = r | (0x80 >> i);
|
||||
}
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
const rtable = Array(256);
|
||||
for (let i=0; i<256; i++) {
|
||||
rtable[i] = rev(i);
|
||||
}
|
||||
|
||||
const REVTABLE = module.alloc(rtable);
|
||||
|
||||
|
||||
function buildLog2() {
|
||||
const f = module.addFunction(prefix+"__log2");
|
||||
f.addParam("n", "i32");
|
||||
f.setReturnType("i32");
|
||||
f.addLocal("bits", "i32");
|
||||
f.addLocal("aux", "i32");
|
||||
|
||||
const c = f.getCodeBuilder();
|
||||
|
||||
f.addCode(
|
||||
c.setLocal(
|
||||
"aux",
|
||||
c.i32_shr_u(
|
||||
c.getLocal("n"),
|
||||
c.i32_const(1)
|
||||
)
|
||||
)
|
||||
);
|
||||
f.addCode(c.setLocal("bits", c.i32_const(0)));
|
||||
|
||||
f.addCode(c.block(c.loop(
|
||||
c.br_if(
|
||||
1,
|
||||
c.i32_eqz(c.getLocal("aux"))
|
||||
),
|
||||
|
||||
c.setLocal(
|
||||
"aux",
|
||||
c.i32_shr_u(
|
||||
c.getLocal("aux"),
|
||||
c.i32_const(1)
|
||||
)
|
||||
),
|
||||
|
||||
c.setLocal(
|
||||
"bits",
|
||||
c.i32_add(
|
||||
c.getLocal("bits"),
|
||||
c.i32_const(1)
|
||||
)
|
||||
),
|
||||
|
||||
c.br(0)
|
||||
)));
|
||||
|
||||
f.addCode(c.if(
|
||||
c.i32_ne(
|
||||
c.getLocal("n"),
|
||||
c.i32_shl(
|
||||
c.i32_const(1),
|
||||
c.getLocal("bits")
|
||||
)
|
||||
),
|
||||
c.unreachable()
|
||||
));
|
||||
|
||||
f.addCode(c.if(
|
||||
c.i32_gt_u(
|
||||
c.getLocal("bits"),
|
||||
c.i32_const(maxBits)
|
||||
),
|
||||
c.unreachable()
|
||||
));
|
||||
|
||||
f.addCode(c.getLocal("bits"));
|
||||
}
|
||||
|
||||
function buildFFT() {
|
||||
const f = module.addFunction(prefix+"_fft");
|
||||
f.addParam("px", "i32");
|
||||
f.addParam("n", "i32");
|
||||
f.addParam("odd", "i32");
|
||||
|
||||
f.addLocal("bits", "i32");
|
||||
|
||||
const c = f.getCodeBuilder();
|
||||
|
||||
f.addCode(
|
||||
c.setLocal(
|
||||
"bits",
|
||||
c.call(
|
||||
prefix + "__log2",
|
||||
c.getLocal("n")
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
f.addCode(c.call(
|
||||
prefix+"__rawfft",
|
||||
c.getLocal("px"),
|
||||
c.getLocal("bits"),
|
||||
c.getLocal("odd"),
|
||||
));
|
||||
|
||||
}
|
||||
|
||||
function buildIFFT() {
|
||||
const f = module.addFunction(prefix+"_ifft");
|
||||
f.addParam("px", "i32");
|
||||
f.addParam("n", "i32");
|
||||
f.addParam("odd", "i32");
|
||||
f.addLocal("bits", "i32");
|
||||
|
||||
const c = f.getCodeBuilder();
|
||||
|
||||
f.addCode(
|
||||
c.setLocal(
|
||||
"bits",
|
||||
c.call(
|
||||
prefix + "__log2",
|
||||
c.getLocal("n")
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
f.addCode(c.call(
|
||||
prefix+"__rawfft",
|
||||
c.getLocal("px"),
|
||||
c.getLocal("bits"),
|
||||
c.getLocal("odd")
|
||||
));
|
||||
|
||||
f.addCode(c.call(
|
||||
prefix+"__finalInverse",
|
||||
c.getLocal("px"),
|
||||
c.getLocal("bits"),
|
||||
));
|
||||
|
||||
}
|
||||
|
||||
function buildRawFFT() {
|
||||
const f = module.addFunction(prefix+"__rawfft");
|
||||
f.addParam("px", "i32");
|
||||
f.addParam("bits", "i32");
|
||||
f.addParam("odd", "i32");
|
||||
f.addLocal("s", "i32");
|
||||
f.addLocal("k", "i32");
|
||||
f.addLocal("j", "i32");
|
||||
f.addLocal("m", "i32");
|
||||
f.addLocal("mdiv2", "i32");
|
||||
f.addLocal("n", "i32");
|
||||
f.addLocal("pwm", "i32");
|
||||
f.addLocal("idx1", "i32");
|
||||
f.addLocal("idx2", "i32");
|
||||
|
||||
const c = f.getCodeBuilder();
|
||||
|
||||
const W = c.i32_const(module.alloc(n8));
|
||||
const T = c.i32_const(module.alloc(n8));
|
||||
const U = c.i32_const(module.alloc(n8));
|
||||
|
||||
f.addCode(
|
||||
c.call(prefix + "__reversePermutation", c.getLocal("px"), c.getLocal("bits")),
|
||||
c.setLocal("n", c.i32_shl(c.i32_const(1), c.getLocal("bits"))),
|
||||
c.setLocal("s", c.i32_const(1)),
|
||||
c.block(c.loop(
|
||||
c.br_if(
|
||||
1,
|
||||
c.i32_gt_u(
|
||||
c.getLocal("s"),
|
||||
c.getLocal("bits")
|
||||
)
|
||||
),
|
||||
c.setLocal("m", c.i32_shl(c.i32_const(1), c.getLocal("s"))),
|
||||
c.setLocal("pwm",
|
||||
c.i32_add(
|
||||
c.i32_const(ROOTs),
|
||||
c.i32_mul(
|
||||
c.getLocal("s"),
|
||||
c.i32_const(n8)
|
||||
)
|
||||
)
|
||||
),
|
||||
c.setLocal("k", c.i32_const(0)),
|
||||
c.block(c.loop(
|
||||
c.br_if(
|
||||
1,
|
||||
c.i32_ge_u(
|
||||
c.getLocal("k"),
|
||||
c.getLocal("n")
|
||||
)
|
||||
),
|
||||
|
||||
c.if(
|
||||
c.getLocal("odd"),
|
||||
c.call(
|
||||
f1mPrefix + "_copy",
|
||||
c.i32_add(
|
||||
c.getLocal("pwm"),
|
||||
c.i32_const(n8)
|
||||
),
|
||||
W
|
||||
),
|
||||
c.call(f1mPrefix + "_one", W)
|
||||
),
|
||||
|
||||
|
||||
c.setLocal("mdiv2", c.i32_shr_u(c.getLocal("m"), c.i32_const(1)) ),
|
||||
c.setLocal("j", c.i32_const(0)),
|
||||
c.block(c.loop(
|
||||
c.br_if(
|
||||
1,
|
||||
c.i32_ge_u(
|
||||
c.getLocal("j"),
|
||||
c.getLocal("mdiv2")
|
||||
)
|
||||
),
|
||||
|
||||
c.setLocal(
|
||||
"idx1",
|
||||
c.i32_add(
|
||||
c.getLocal("px"),
|
||||
c.i32_mul(
|
||||
c.i32_add(
|
||||
c.getLocal("k"),
|
||||
c.getLocal("j")
|
||||
),
|
||||
c.i32_const(n8)
|
||||
)
|
||||
)
|
||||
),
|
||||
|
||||
c.setLocal(
|
||||
"idx2",
|
||||
c.i32_add(
|
||||
c.getLocal("idx1"),
|
||||
c.i32_mul(
|
||||
c.getLocal("mdiv2"),
|
||||
c.i32_const(n8)
|
||||
)
|
||||
)
|
||||
),
|
||||
|
||||
c.call(
|
||||
f1mPrefix + "_mul",
|
||||
W,
|
||||
c.getLocal("idx2"),
|
||||
T
|
||||
),
|
||||
|
||||
c.call(
|
||||
f1mPrefix + "_copy",
|
||||
c.getLocal("idx1"),
|
||||
U
|
||||
),
|
||||
|
||||
c.call(
|
||||
f1mPrefix + "_add",
|
||||
U,
|
||||
T,
|
||||
c.getLocal("idx1"),
|
||||
),
|
||||
|
||||
c.call(
|
||||
f1mPrefix + "_sub",
|
||||
U,
|
||||
T,
|
||||
c.getLocal("idx2"),
|
||||
),
|
||||
|
||||
c.call(
|
||||
f1mPrefix + "_mul",
|
||||
W,
|
||||
c.getLocal("pwm"),
|
||||
W,
|
||||
),
|
||||
|
||||
c.setLocal("j", c.i32_add(c.getLocal("j"), c.i32_const(1))),
|
||||
c.br(0)
|
||||
)),
|
||||
|
||||
c.setLocal("k", c.i32_add(c.getLocal("k"), c.getLocal("m"))),
|
||||
c.br(0)
|
||||
)),
|
||||
|
||||
c.setLocal("s", c.i32_add(c.getLocal("s"), c.i32_const(1))),
|
||||
c.br(0)
|
||||
))
|
||||
);
|
||||
}
|
||||
|
||||
function buildCopyInterleaved() {
|
||||
const f = module.addFunction(prefix+"_copyNInterleaved");
|
||||
f.addParam("ps", "i32");
|
||||
f.addParam("pd", "i32");
|
||||
f.addParam("n", "i32");
|
||||
f.addLocal("pi", "i32");
|
||||
f.addLocal("po", "i32");
|
||||
f.addLocal("pn", "i32");
|
||||
|
||||
const c = f.getCodeBuilder();
|
||||
|
||||
f.addCode(
|
||||
c.setLocal("pi", c.getLocal("ps")),
|
||||
c.setLocal("po", c.getLocal("pd")),
|
||||
c.setLocal(
|
||||
"pn",
|
||||
c.i32_add(
|
||||
c.getLocal("ps"),
|
||||
c.i32_mul(
|
||||
c.getLocal("n"),
|
||||
c.i32_const(n8)
|
||||
)
|
||||
)
|
||||
),
|
||||
c.block(c.loop(
|
||||
c.br_if(
|
||||
1,
|
||||
c.i32_eq(
|
||||
c.getLocal("pi"),
|
||||
c.getLocal("pn")
|
||||
)
|
||||
),
|
||||
|
||||
c.call(f1mPrefix + "_copy", c.getLocal("pi"), c.getLocal("po")),
|
||||
|
||||
c.setLocal("pi", c.i32_add(c.getLocal("pi"), c.i32_const(n8))),
|
||||
c.setLocal("po", c.i32_add(c.getLocal("po"), c.i32_const(n8*2))),
|
||||
c.br(0)
|
||||
))
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
function buildToMontgomery() {
|
||||
const f = module.addFunction(prefix+"_toMontgomeryN");
|
||||
f.addParam("ps", "i32");
|
||||
f.addParam("pd", "i32");
|
||||
f.addParam("n", "i32");
|
||||
f.addLocal("pi", "i32");
|
||||
f.addLocal("po", "i32");
|
||||
f.addLocal("pn", "i32");
|
||||
|
||||
const c = f.getCodeBuilder();
|
||||
|
||||
f.addCode(
|
||||
c.setLocal("pi", c.getLocal("ps")),
|
||||
c.setLocal("po", c.getLocal("pd")),
|
||||
c.setLocal(
|
||||
"pn",
|
||||
c.i32_add(
|
||||
c.getLocal("ps"),
|
||||
c.i32_mul(
|
||||
c.getLocal("n"),
|
||||
c.i32_const(n8)
|
||||
)
|
||||
)
|
||||
),
|
||||
c.block(c.loop(
|
||||
c.br_if(
|
||||
1,
|
||||
c.i32_eq(
|
||||
c.getLocal("pi"),
|
||||
c.getLocal("pn")
|
||||
)
|
||||
),
|
||||
|
||||
c.call(f1mPrefix + "_toMontgomery", c.getLocal("pi"), c.getLocal("po")),
|
||||
|
||||
c.setLocal("pi", c.i32_add(c.getLocal("pi"), c.i32_const(n8))),
|
||||
c.setLocal("po", c.i32_add(c.getLocal("po"), c.i32_const(n8))),
|
||||
c.br(0)
|
||||
))
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
function buildMulN() {
|
||||
const f = module.addFunction(prefix+"_mulN");
|
||||
f.addParam("px", "i32");
|
||||
f.addParam("py", "i32");
|
||||
f.addParam("n", "i32");
|
||||
f.addParam("pd", "i32");
|
||||
f.addLocal("pix", "i32");
|
||||
f.addLocal("piy", "i32");
|
||||
f.addLocal("po", "i32");
|
||||
f.addLocal("lastpix", "i32");
|
||||
|
||||
const c = f.getCodeBuilder();
|
||||
|
||||
f.addCode(
|
||||
c.setLocal("pix", c.getLocal("px")),
|
||||
c.setLocal("piy", c.getLocal("py")),
|
||||
c.setLocal("po", c.getLocal("pd")),
|
||||
c.setLocal(
|
||||
"lastpix",
|
||||
c.i32_add(
|
||||
c.getLocal("px"),
|
||||
c.i32_mul(
|
||||
c.getLocal("n"),
|
||||
c.i32_const(n8)
|
||||
)
|
||||
)
|
||||
),
|
||||
c.block(c.loop(
|
||||
c.br_if(
|
||||
1,
|
||||
c.i32_eq(
|
||||
c.getLocal("pix"),
|
||||
c.getLocal("lastpix")
|
||||
)
|
||||
),
|
||||
|
||||
c.call(f1mPrefix + "_mul", c.getLocal("pix"), c.getLocal("piy"), c.getLocal("po")),
|
||||
|
||||
c.setLocal("pix", c.i32_add(c.getLocal("pix"), c.i32_const(n8))),
|
||||
c.setLocal("piy", c.i32_add(c.getLocal("piy"), c.i32_const(n8))),
|
||||
c.setLocal("po", c.i32_add(c.getLocal("po"), c.i32_const(n8))),
|
||||
c.br(0)
|
||||
))
|
||||
);
|
||||
}
|
||||
|
||||
function buildFromMontgomery() {
|
||||
const f = module.addFunction(prefix+"_fromMontgomeryN");
|
||||
f.addParam("ps", "i32");
|
||||
f.addParam("pd", "i32");
|
||||
f.addParam("n", "i32");
|
||||
f.addLocal("pi", "i32");
|
||||
f.addLocal("po", "i32");
|
||||
f.addLocal("pn", "i32");
|
||||
|
||||
const c = f.getCodeBuilder();
|
||||
|
||||
f.addCode(
|
||||
c.setLocal("pi", c.getLocal("ps")),
|
||||
c.setLocal("po", c.getLocal("pd")),
|
||||
c.setLocal(
|
||||
"pn",
|
||||
c.i32_add(
|
||||
c.getLocal("ps"),
|
||||
c.i32_mul(
|
||||
c.getLocal("n"),
|
||||
c.i32_const(n8)
|
||||
)
|
||||
)
|
||||
),
|
||||
c.block(c.loop(
|
||||
c.br_if(
|
||||
1,
|
||||
c.i32_eq(
|
||||
c.getLocal("pi"),
|
||||
c.getLocal("pn")
|
||||
)
|
||||
),
|
||||
|
||||
c.call(f1mPrefix + "_fromMontgomery", c.getLocal("pi"), c.getLocal("po")),
|
||||
|
||||
c.setLocal("pi", c.i32_add(c.getLocal("pi"), c.i32_const(n8))),
|
||||
c.setLocal("po", c.i32_add(c.getLocal("po"), c.i32_const(n8))),
|
||||
c.br(0)
|
||||
))
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
function buildFinalInverse() {
|
||||
const f = module.addFunction(prefix+"__finalInverse");
|
||||
f.addParam("px", "i32");
|
||||
f.addParam("bits", "i32");
|
||||
f.addLocal("n", "i32");
|
||||
f.addLocal("ndiv2", "i32");
|
||||
f.addLocal("pInv2", "i32");
|
||||
f.addLocal("i", "i32");
|
||||
f.addLocal("mask", "i32");
|
||||
f.addLocal("idx1", "i32");
|
||||
f.addLocal("idx2", "i32");
|
||||
|
||||
const c = f.getCodeBuilder();
|
||||
|
||||
const T = c.i32_const(module.alloc(n8));
|
||||
|
||||
f.addCode(
|
||||
c.setLocal("n", c.i32_shl( c.i32_const(1), c.getLocal("bits"))),
|
||||
|
||||
c.setLocal(
|
||||
"pInv2",
|
||||
c.i32_add(
|
||||
c.i32_const(INV2),
|
||||
c.i32_mul(
|
||||
c.getLocal("bits"),
|
||||
c.i32_const(n8)
|
||||
)
|
||||
)
|
||||
),
|
||||
|
||||
c.setLocal("mask", c.i32_sub( c.getLocal("n") , c.i32_const(1))),
|
||||
c.setLocal("i", c.i32_const(1)),
|
||||
c.setLocal(
|
||||
"ndiv2",
|
||||
c.i32_shr_u(
|
||||
c.getLocal("n"),
|
||||
c.i32_const(1)
|
||||
)
|
||||
),
|
||||
c.block(c.loop(
|
||||
c.br_if(
|
||||
1,
|
||||
c.i32_eq(
|
||||
c.getLocal("i"),
|
||||
c.getLocal("ndiv2")
|
||||
)
|
||||
),
|
||||
|
||||
c.setLocal("idx1",
|
||||
c.i32_add(
|
||||
c.getLocal("px"),
|
||||
c.i32_mul(
|
||||
c.getLocal("i"),
|
||||
c.i32_const(n8)
|
||||
)
|
||||
)
|
||||
),
|
||||
|
||||
c.setLocal("idx2",
|
||||
c.i32_add(
|
||||
c.getLocal("px"),
|
||||
c.i32_mul(
|
||||
c.i32_sub(
|
||||
c.getLocal("n"),
|
||||
c.getLocal("i")
|
||||
),
|
||||
c.i32_const(n8)
|
||||
)
|
||||
)
|
||||
),
|
||||
|
||||
c.call(f1mPrefix + "_copy", c.getLocal("idx1"), T),
|
||||
c.call(f1mPrefix + "_mul", c.getLocal("idx2") , c.getLocal("pInv2"), c.getLocal("idx1") ),
|
||||
c.call(f1mPrefix + "_mul", T , c.getLocal("pInv2"), c.getLocal("idx2")),
|
||||
|
||||
// c.call(f1mPrefix + "_mul", c.getLocal("idx1") , c.getLocal("pInv2"), c.getLocal("idx1") ),
|
||||
// c.call(f1mPrefix + "_mul", c.getLocal("idx2") , c.getLocal("pInv2"), c.getLocal("idx1") ),
|
||||
|
||||
c.setLocal("i", c.i32_add(c.getLocal("i"), c.i32_const(1))),
|
||||
|
||||
c.br(0)
|
||||
)),
|
||||
|
||||
c.call(f1mPrefix + "_mul", c.getLocal("px") , c.getLocal("pInv2"), c.getLocal("px")),
|
||||
|
||||
c.setLocal("idx2",
|
||||
c.i32_add(
|
||||
c.getLocal("px"),
|
||||
c.i32_mul(
|
||||
c.getLocal("ndiv2"),
|
||||
c.i32_const(n8)
|
||||
)
|
||||
)
|
||||
),
|
||||
|
||||
c.call(f1mPrefix + "_mul", c.getLocal("idx2"),c.getLocal("pInv2"), c.getLocal("idx2"))
|
||||
|
||||
);
|
||||
}
|
||||
|
||||
function buildReversePermutation() {
|
||||
const f = module.addFunction(prefix+"__reversePermutation");
|
||||
f.addParam("px", "i32");
|
||||
f.addParam("bits", "i32");
|
||||
f.addLocal("n", "i32");
|
||||
f.addLocal("i", "i32");
|
||||
f.addLocal("ri", "i32");
|
||||
f.addLocal("idx1", "i32");
|
||||
f.addLocal("idx2", "i32");
|
||||
|
||||
const c = f.getCodeBuilder();
|
||||
|
||||
const T = c.i32_const(module.alloc(n8));
|
||||
|
||||
f.addCode(
|
||||
c.setLocal("n", c.i32_shl( c.i32_const(1), c.getLocal("bits"))),
|
||||
c.setLocal("i", c.i32_const(0)),
|
||||
c.block(c.loop(
|
||||
c.br_if(
|
||||
1,
|
||||
c.i32_eq(
|
||||
c.getLocal("i"),
|
||||
c.getLocal("n")
|
||||
)
|
||||
),
|
||||
|
||||
c.setLocal("idx1",
|
||||
c.i32_add(
|
||||
c.getLocal("px"),
|
||||
c.i32_mul(
|
||||
c.getLocal("i"),
|
||||
c.i32_const(n8)
|
||||
)
|
||||
)
|
||||
),
|
||||
|
||||
c.setLocal("ri", c.call(prefix + "__rev", c.getLocal("i"), c.getLocal("bits"))),
|
||||
|
||||
c.setLocal("idx2",
|
||||
c.i32_add(
|
||||
c.getLocal("px"),
|
||||
c.i32_mul(
|
||||
c.getLocal("ri"),
|
||||
c.i32_const(n8)
|
||||
)
|
||||
)
|
||||
),
|
||||
|
||||
c.if(
|
||||
c.i32_lt_u(
|
||||
c.getLocal("i"),
|
||||
c.getLocal("ri")
|
||||
),
|
||||
[
|
||||
...c.call(f1mPrefix + "_copy", c.getLocal("idx1"), T),
|
||||
...c.call(f1mPrefix + "_copy", c.getLocal("idx2") , c.getLocal("idx1")),
|
||||
...c.call(f1mPrefix + "_copy", T , c.getLocal("idx2"))
|
||||
]
|
||||
),
|
||||
|
||||
c.setLocal("i", c.i32_add(c.getLocal("i"), c.i32_const(1))),
|
||||
|
||||
c.br(0)
|
||||
))
|
||||
);
|
||||
}
|
||||
|
||||
function buildRev() {
|
||||
const f = module.addFunction(prefix+"__rev");
|
||||
f.addParam("x", "i32");
|
||||
f.addParam("bits", "i32");
|
||||
f.setReturnType("i32");
|
||||
|
||||
const c = f.getCodeBuilder();
|
||||
|
||||
f.addCode(
|
||||
c.i32_rotl(
|
||||
c.i32_add(
|
||||
c.i32_add(
|
||||
c.i32_shl(
|
||||
c.i32_load8_u(
|
||||
c.i32_and(
|
||||
c.getLocal("x"),
|
||||
c.i32_const(0xFF)
|
||||
),
|
||||
REVTABLE,
|
||||
0
|
||||
),
|
||||
c.i32_const(24)
|
||||
),
|
||||
c.i32_shl(
|
||||
c.i32_load8_u(
|
||||
c.i32_and(
|
||||
c.i32_shr_u(
|
||||
c.getLocal("x"),
|
||||
c.i32_const(8)
|
||||
),
|
||||
c.i32_const(0xFF)
|
||||
),
|
||||
REVTABLE,
|
||||
0
|
||||
),
|
||||
c.i32_const(16)
|
||||
),
|
||||
),
|
||||
c.i32_add(
|
||||
c.i32_shl(
|
||||
c.i32_load8_u(
|
||||
c.i32_and(
|
||||
c.i32_shr_u(
|
||||
c.getLocal("x"),
|
||||
c.i32_const(16)
|
||||
),
|
||||
c.i32_const(0xFF)
|
||||
),
|
||||
REVTABLE,
|
||||
0
|
||||
),
|
||||
c.i32_const(8)
|
||||
),
|
||||
c.i32_load8_u(
|
||||
c.i32_and(
|
||||
c.i32_shr_u(
|
||||
c.getLocal("x"),
|
||||
c.i32_const(24)
|
||||
),
|
||||
c.i32_const(0xFF)
|
||||
),
|
||||
REVTABLE,
|
||||
0
|
||||
),
|
||||
)
|
||||
),
|
||||
c.getLocal("bits")
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
buildRev();
|
||||
buildReversePermutation();
|
||||
buildRawFFT();
|
||||
buildCopyInterleaved();
|
||||
buildFromMontgomery();
|
||||
buildToMontgomery();
|
||||
buildFinalInverse();
|
||||
buildLog2();
|
||||
buildFFT();
|
||||
buildIFFT();
|
||||
buildMulN();
|
||||
|
||||
module.exportFunction(prefix+"_fft");
|
||||
module.exportFunction(prefix+"_ifft");
|
||||
module.exportFunction(prefix+"_toMontgomeryN");
|
||||
module.exportFunction(prefix+"_fromMontgomeryN");
|
||||
module.exportFunction(prefix+"_copyNInterleaved");
|
||||
module.exportFunction(prefix+"_mulN");
|
||||
|
||||
};
|
861
src/build_int.js
Normal file
861
src/build_int.js
Normal file
@ -0,0 +1,861 @@
|
||||
/*
|
||||
Copyright 2019 0KIMS association.
|
||||
|
||||
This file is part of websnark (Web Assembly zkSnark Prover).
|
||||
|
||||
websnark is a free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
websnark is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with websnark. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
const utils = require("./utils.js");
|
||||
|
||||
module.exports = function buildInt(module, n64, _prefix) {
|
||||
|
||||
const prefix = _prefix || "int";
|
||||
if (module.modules[prefix]) return prefix; // already builded
|
||||
module.modules[prefix] = {};
|
||||
|
||||
const n32 = n64*2;
|
||||
const n8 = n64*8;
|
||||
|
||||
const one = module.alloc(n8, utils.bigInt2BytesLE(1, n8));
|
||||
|
||||
function buildCopy() {
|
||||
const f = module.addFunction(prefix+"_copy");
|
||||
f.addParam("px", "i32");
|
||||
f.addParam("pr", "i32");
|
||||
|
||||
const c = f.getCodeBuilder();
|
||||
|
||||
for (let i=0; i<n64; i++) {
|
||||
f.addCode(
|
||||
c.i64_store(
|
||||
c.getLocal("pr"),
|
||||
i*8,
|
||||
c.i64_load(
|
||||
c.getLocal("px"),
|
||||
i*8
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function buildZero() {
|
||||
const f = module.addFunction(prefix+"_zero");
|
||||
f.addParam("pr", "i32");
|
||||
|
||||
const c = f.getCodeBuilder();
|
||||
|
||||
for (let i=0; i<n64; i++) {
|
||||
f.addCode(
|
||||
c.i64_store(
|
||||
c.getLocal("pr"),
|
||||
i*8,
|
||||
c.i64_const(0)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function buildOne() {
|
||||
const f = module.addFunction(prefix+"_one");
|
||||
f.addParam("pr", "i32");
|
||||
|
||||
const c = f.getCodeBuilder();
|
||||
|
||||
f.addCode(
|
||||
c.i64_store(
|
||||
c.getLocal("pr"),
|
||||
0,
|
||||
c.i64_const(1)
|
||||
)
|
||||
);
|
||||
for (let i=1; i<n64; i++) {
|
||||
f.addCode(
|
||||
c.i64_store(
|
||||
c.getLocal("pr"),
|
||||
i*8,
|
||||
c.i64_const(0)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function buildIsZero() {
|
||||
const f = module.addFunction(prefix+"_isZero");
|
||||
f.addParam("px", "i32");
|
||||
f.setReturnType("i32");
|
||||
|
||||
const c = f.getCodeBuilder();
|
||||
|
||||
function getCompCode(n) {
|
||||
if (n==0) {
|
||||
return c.ret(c.i64_eqz(
|
||||
c.i64_load(c.getLocal("px"))
|
||||
));
|
||||
}
|
||||
return c.if(
|
||||
c.i64_eqz(
|
||||
c.i64_load(c.getLocal("px"), n*8 )
|
||||
),
|
||||
getCompCode(n-1),
|
||||
c.ret(c.i32_const(0))
|
||||
);
|
||||
}
|
||||
|
||||
f.addCode(getCompCode(n64-1));
|
||||
f.addCode(c.ret(c.i32_const(0)));
|
||||
}
|
||||
|
||||
function buildEq() {
|
||||
const f = module.addFunction(prefix+"_eq");
|
||||
f.addParam("px", "i32");
|
||||
f.addParam("py", "i32");
|
||||
f.setReturnType("i32");
|
||||
|
||||
const c = f.getCodeBuilder();
|
||||
|
||||
function getCompCode(n) {
|
||||
if (n==0) {
|
||||
return c.ret(c.i64_eq(
|
||||
c.i64_load(c.getLocal("px")),
|
||||
c.i64_load(c.getLocal("py"))
|
||||
));
|
||||
}
|
||||
return c.if(
|
||||
c.i64_eq(
|
||||
c.i64_load(c.getLocal("px"), n*8 ),
|
||||
c.i64_load(c.getLocal("py"), n*8 )
|
||||
),
|
||||
getCompCode(n-1),
|
||||
c.ret(c.i32_const(0))
|
||||
);
|
||||
}
|
||||
|
||||
f.addCode(getCompCode(n64-1));
|
||||
f.addCode(c.ret(c.i32_const(0)));
|
||||
}
|
||||
|
||||
|
||||
|
||||
function buildGte() {
|
||||
const f = module.addFunction(prefix+"_gte");
|
||||
f.addParam("px", "i32");
|
||||
f.addParam("py", "i32");
|
||||
f.setReturnType("i32");
|
||||
|
||||
const c = f.getCodeBuilder();
|
||||
|
||||
function getCompCode(n) {
|
||||
if (n==0) {
|
||||
return c.ret(c.i64_ge_u(
|
||||
c.i64_load(c.getLocal("px")),
|
||||
c.i64_load(c.getLocal("py"))
|
||||
));
|
||||
}
|
||||
return c.if(
|
||||
c.i64_lt_u(
|
||||
c.i64_load(c.getLocal("px"), n*8 ),
|
||||
c.i64_load(c.getLocal("py"), n*8 )
|
||||
),
|
||||
c.ret(c.i32_const(0)),
|
||||
c.if(
|
||||
c.i64_gt_u(
|
||||
c.i64_load(c.getLocal("px"), n*8 ),
|
||||
c.i64_load(c.getLocal("py"), n*8 )
|
||||
),
|
||||
c.ret(c.i32_const(1)),
|
||||
getCompCode(n-1)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
f.addCode(getCompCode(n64-1));
|
||||
f.addCode(c.ret(c.i32_const(0)));
|
||||
}
|
||||
|
||||
|
||||
|
||||
function buildAdd() {
|
||||
|
||||
const f = module.addFunction(prefix+"_add");
|
||||
f.addParam("x", "i32");
|
||||
f.addParam("y", "i32");
|
||||
f.addParam("r", "i32");
|
||||
f.setReturnType("i32");
|
||||
f.addLocal("c", "i64");
|
||||
|
||||
const c = f.getCodeBuilder();
|
||||
|
||||
f.addCode(c.setLocal(
|
||||
"c",
|
||||
c.i64_add(
|
||||
c.i64_load32_u(c.getLocal("x")),
|
||||
c.i64_load32_u(c.getLocal("y"))
|
||||
)
|
||||
));
|
||||
|
||||
f.addCode(c.i64_store32(
|
||||
c.getLocal("r"),
|
||||
c.getLocal("c"),
|
||||
));
|
||||
|
||||
for (let i=1; i<n32; i++) {
|
||||
f.addCode(c.setLocal( "c",
|
||||
c.i64_add(
|
||||
c.i64_add(
|
||||
c.i64_load32_u(c.getLocal("x"), 4*i),
|
||||
c.i64_load32_u(c.getLocal("y"), 4*i)
|
||||
),
|
||||
c.i64_shr_u (c.getLocal("c"), c.i64_const(32))
|
||||
)
|
||||
));
|
||||
|
||||
f.addCode(c.i64_store32(
|
||||
c.getLocal("r"),
|
||||
i*4,
|
||||
c.getLocal("c")
|
||||
));
|
||||
}
|
||||
|
||||
f.addCode(c.i32_wrap_i64(c.i64_shr_u (c.getLocal("c"), c.i64_const(32))));
|
||||
}
|
||||
|
||||
|
||||
function buildSub() {
|
||||
|
||||
const f = module.addFunction(prefix+"_sub");
|
||||
f.addParam("x", "i32");
|
||||
f.addParam("y", "i32");
|
||||
f.addParam("r", "i32");
|
||||
f.setReturnType("i32");
|
||||
f.addLocal("c", "i64");
|
||||
|
||||
const c = f.getCodeBuilder();
|
||||
|
||||
f.addCode(c.setLocal(
|
||||
"c",
|
||||
c.i64_sub(
|
||||
c.i64_load32_u(c.getLocal("x")),
|
||||
c.i64_load32_u(c.getLocal("y"))
|
||||
)
|
||||
));
|
||||
|
||||
f.addCode(c.i64_store32(
|
||||
c.getLocal("r"),
|
||||
c.i64_and(
|
||||
c.getLocal("c"),
|
||||
c.i64_const("0xFFFFFFFF")
|
||||
)
|
||||
));
|
||||
|
||||
for (let i=1; i<n32; i++) {
|
||||
f.addCode(c.setLocal( "c",
|
||||
c.i64_add(
|
||||
c.i64_sub(
|
||||
c.i64_load32_u(c.getLocal("x"), 4*i),
|
||||
c.i64_load32_u(c.getLocal("y"), 4*i)
|
||||
),
|
||||
c.i64_shr_s (c.getLocal("c"), c.i64_const(32))
|
||||
)
|
||||
));
|
||||
|
||||
f.addCode(c.i64_store32(
|
||||
c.getLocal("r"),
|
||||
i*4,
|
||||
c.i64_and( c.getLocal("c"), c.i64_const("0xFFFFFFFF"))
|
||||
));
|
||||
}
|
||||
|
||||
f.addCode(c.i32_wrap_i64 ( c.i64_shr_s (c.getLocal("c"), c.i64_const(32))));
|
||||
}
|
||||
|
||||
|
||||
function buildMul() {
|
||||
|
||||
const mulBuff = module.alloc(n32*n32*8);
|
||||
|
||||
const f = module.addFunction(prefix+"_mul");
|
||||
f.addParam("x", "i32");
|
||||
f.addParam("y", "i32");
|
||||
f.addParam("r", "i32");
|
||||
f.addLocal("c", "i64");
|
||||
|
||||
const c = f.getCodeBuilder();
|
||||
|
||||
for (let i=0; i<n32; i++) {
|
||||
for (let j=0; j<n32; j++) {
|
||||
f.addCode(c.i64_store(
|
||||
c.i32_const(mulBuff),
|
||||
(i*n32+j)*8,
|
||||
c.i64_mul(
|
||||
c.i64_load32_u( c.getLocal("x"), i*4),
|
||||
c.i64_load32_u( c.getLocal("y"), j*4)
|
||||
)
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
for (let i=0; i<n32; i++) {
|
||||
f.addCode(c.i64_shr_u(c.getLocal("c"), c.i64_const(32)));
|
||||
for (let j=0; j<i; j++) {
|
||||
f.addCode(c.i64_add(
|
||||
[],
|
||||
c.i64_load32_u(
|
||||
c.i32_const(mulBuff),
|
||||
j*(n32*8) + i*8-4 - j*8
|
||||
)
|
||||
));
|
||||
}
|
||||
for (let j=0; j<i+1; j++) {
|
||||
f.addCode(c.i64_add(
|
||||
[],
|
||||
c.i64_load32_u(
|
||||
c.i32_const(mulBuff),
|
||||
j*(n32*8) + i*8 - j*8
|
||||
)
|
||||
));
|
||||
}
|
||||
f.addCode(c.setLocal("c", []));
|
||||
f.addCode(
|
||||
c.i64_store32(
|
||||
c.getLocal("r"),
|
||||
i*4,
|
||||
c.getLocal("c")
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
for (let i=0; i<n32; i++) {
|
||||
f.addCode(c.i64_shr_u(c.getLocal("c"), c.i64_const(32)));
|
||||
for (let j=i; j<n32; j++) {
|
||||
f.addCode(c.i64_add(
|
||||
[],
|
||||
c.i64_load32_u(
|
||||
c.i32_const(mulBuff),
|
||||
j*(n32*8) + n32*8-4 + i*8- j*8
|
||||
)
|
||||
));
|
||||
}
|
||||
for (let j=i+1; j<n32; j++) {
|
||||
f.addCode(c.i64_add(
|
||||
[],
|
||||
c.i64_load32_u(
|
||||
c.i32_const(mulBuff),
|
||||
j*(n32*8) + n32*8 + i*8 - j*8
|
||||
)
|
||||
));
|
||||
}
|
||||
f.addCode(c.setLocal("c", []));
|
||||
f.addCode(
|
||||
c.i64_store32(
|
||||
c.getLocal("r"),
|
||||
i*4 + n32*4,
|
||||
c.getLocal("c")
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function _buildMul1() {
|
||||
const f = module.addFunction(prefix+"__mul1");
|
||||
f.addParam("px", "i32");
|
||||
f.addParam("y", "i64");
|
||||
f.addParam("pr", "i32");
|
||||
f.addLocal("c", "i64");
|
||||
|
||||
const c = f.getCodeBuilder();
|
||||
|
||||
f.addCode(c.setLocal(
|
||||
"c",
|
||||
c.i64_mul(
|
||||
c.i64_load32_u(c.getLocal("px"), 0, 0),
|
||||
c.getLocal("y")
|
||||
)
|
||||
));
|
||||
|
||||
f.addCode(c.i64_store32(
|
||||
c.getLocal("pr"),
|
||||
0,
|
||||
0,
|
||||
c.getLocal("c"),
|
||||
));
|
||||
|
||||
for (let i=1; i<n32; i++) {
|
||||
f.addCode(c.setLocal( "c",
|
||||
c.i64_add(
|
||||
c.i64_mul(
|
||||
c.i64_load32_u(c.getLocal("px"), 4*i, 0),
|
||||
c.getLocal("y")
|
||||
),
|
||||
c.i64_shr_u (c.getLocal("c"), c.i64_const(32))
|
||||
)
|
||||
));
|
||||
|
||||
f.addCode(c.i64_store32(
|
||||
c.getLocal("pr"),
|
||||
i*4,
|
||||
0,
|
||||
c.getLocal("c")
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
function _buildAdd1() {
|
||||
const f = module.addFunction(prefix+"__add1");
|
||||
f.addParam("x", "i32");
|
||||
f.addParam("y", "i64");
|
||||
f.addLocal("c", "i64");
|
||||
f.addLocal("px", "i32");
|
||||
|
||||
const c = f.getCodeBuilder();
|
||||
|
||||
f.addCode(c.setLocal("px", c.getLocal("x")));
|
||||
|
||||
f.addCode(c.setLocal(
|
||||
"c",
|
||||
c.i64_add(
|
||||
c.i64_load32_u(c.getLocal("px"), 0, 0),
|
||||
c.getLocal("y")
|
||||
)
|
||||
));
|
||||
|
||||
f.addCode(c.i64_store32(
|
||||
c.getLocal("px"),
|
||||
0,
|
||||
0,
|
||||
c.getLocal("c"),
|
||||
));
|
||||
|
||||
f.addCode(c.setLocal(
|
||||
"c",
|
||||
c.i64_shr_u(
|
||||
c.getLocal("c"),
|
||||
c.i64_const(32)
|
||||
)
|
||||
));
|
||||
|
||||
f.addCode(c.block(c.loop(
|
||||
c.br_if(
|
||||
1,
|
||||
c.i64_eqz(c.getLocal("c"))
|
||||
),
|
||||
c.setLocal(
|
||||
"px",
|
||||
c.i32_add(
|
||||
c.getLocal("px"),
|
||||
c.i32_const(4)
|
||||
)
|
||||
),
|
||||
|
||||
c.setLocal(
|
||||
"c",
|
||||
c.i64_add(
|
||||
c.i64_load32_u(c.getLocal("px"), 0, 0),
|
||||
c.getLocal("c")
|
||||
)
|
||||
),
|
||||
|
||||
c.i64_store32(
|
||||
c.getLocal("px"),
|
||||
0,
|
||||
0,
|
||||
c.getLocal("c"),
|
||||
),
|
||||
|
||||
c.setLocal(
|
||||
"c",
|
||||
c.i64_shr_u(
|
||||
c.getLocal("c"),
|
||||
c.i64_const(32)
|
||||
)
|
||||
),
|
||||
|
||||
c.br(0)
|
||||
)));
|
||||
}
|
||||
|
||||
|
||||
function buildDiv() {
|
||||
_buildMul1();
|
||||
_buildAdd1();
|
||||
|
||||
const f = module.addFunction(prefix+"_div");
|
||||
f.addParam("x", "i32");
|
||||
f.addParam("y", "i32");
|
||||
f.addParam("c", "i32");
|
||||
f.addParam("r", "i32");
|
||||
f.addLocal("rr", "i32");
|
||||
f.addLocal("cc", "i32");
|
||||
f.addLocal("eX", "i32");
|
||||
f.addLocal("eY", "i32");
|
||||
f.addLocal("sy", "i64");
|
||||
f.addLocal("sx", "i64");
|
||||
f.addLocal("ec", "i32");
|
||||
|
||||
const c = f.getCodeBuilder();
|
||||
|
||||
const Y = c.i32_const(module.alloc(n8));
|
||||
const Caux = c.i32_const(module.alloc(n8));
|
||||
const Raux = c.i32_const(module.alloc(n8));
|
||||
const C = c.getLocal("cc");
|
||||
const R = c.getLocal("rr");
|
||||
const pr1 = module.alloc(n8*2);
|
||||
const R1 = c.i32_const(pr1);
|
||||
const R2 = c.i32_const(pr1+n8);
|
||||
|
||||
// Ic c is 0 then store it in an auxiliary buffer
|
||||
f.addCode(c.if(
|
||||
c.getLocal("c"),
|
||||
c.setLocal("cc", c.getLocal("c")),
|
||||
c.setLocal("cc", Caux)
|
||||
));
|
||||
|
||||
// Ic r is 0 then store it in an auxiliary buffer
|
||||
f.addCode(c.if(
|
||||
c.getLocal("r"),
|
||||
c.setLocal("rr", c.getLocal("r")),
|
||||
c.setLocal("rr", Raux)
|
||||
));
|
||||
|
||||
// Copy
|
||||
f.addCode(c.call(prefix + "_copy", c.getLocal("x"), R));
|
||||
f.addCode(c.call(prefix + "_copy", c.getLocal("y"), Y));
|
||||
f.addCode(c.call(prefix + "_zero", C));
|
||||
f.addCode(c.call(prefix + "_zero", R1));
|
||||
|
||||
|
||||
f.addCode(c.setLocal("eX", c.i32_const(n8-1)));
|
||||
f.addCode(c.setLocal("eY", c.i32_const(n8-1)));
|
||||
|
||||
// while (eY>3)&&(Y[eY]==0) ey--;
|
||||
f.addCode(c.block(c.loop(
|
||||
c.br_if(
|
||||
1,
|
||||
c.i32_or(
|
||||
c.i32_load8_u(
|
||||
c.i32_add(Y , c.getLocal("eY")),
|
||||
0,
|
||||
0
|
||||
),
|
||||
c.i32_eq(
|
||||
c.getLocal("eY"),
|
||||
c.i32_const(3)
|
||||
)
|
||||
)
|
||||
),
|
||||
c.setLocal("eY", c.i32_sub(c.getLocal("eY"), c.i32_const(1))),
|
||||
c.br(0)
|
||||
)));
|
||||
|
||||
f.addCode(
|
||||
c.setLocal(
|
||||
"sy",
|
||||
c.i64_add(
|
||||
c.i64_load32_u(
|
||||
c.i32_sub(
|
||||
c.i32_add( Y, c.getLocal("eY")),
|
||||
c.i32_const(3)
|
||||
),
|
||||
0,
|
||||
0
|
||||
),
|
||||
c.i64_const(1)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
// Force a divide by 0 if quotien is 0
|
||||
f.addCode(
|
||||
c.if(
|
||||
c.i64_eq(
|
||||
c.getLocal("sy"),
|
||||
c.i64_const(1)
|
||||
),
|
||||
c.drop(c.i64_div_u(c.i64_const(0), c.i64_const(0)))
|
||||
)
|
||||
);
|
||||
|
||||
f.addCode(c.block(c.loop(
|
||||
|
||||
// while (eX>7)&&(Y[eX]==0) ex--;
|
||||
c.block(c.loop(
|
||||
c.br_if(
|
||||
1,
|
||||
c.i32_or(
|
||||
c.i32_load8_u(
|
||||
c.i32_add(R , c.getLocal("eX")),
|
||||
0,
|
||||
0
|
||||
),
|
||||
c.i32_eq(
|
||||
c.getLocal("eX"),
|
||||
c.i32_const(7)
|
||||
)
|
||||
)
|
||||
),
|
||||
c.setLocal("eX", c.i32_sub(c.getLocal("eX"), c.i32_const(1))),
|
||||
c.br(0)
|
||||
)),
|
||||
|
||||
c.setLocal(
|
||||
"sx",
|
||||
c.i64_load(
|
||||
c.i32_sub(
|
||||
c.i32_add( R, c.getLocal("eX")),
|
||||
c.i32_const(7)
|
||||
),
|
||||
0,
|
||||
0
|
||||
)
|
||||
),
|
||||
|
||||
c.setLocal(
|
||||
"sx",
|
||||
c.i64_div_u(
|
||||
c.getLocal("sx"),
|
||||
c.getLocal("sy")
|
||||
)
|
||||
),
|
||||
c.setLocal(
|
||||
"ec",
|
||||
c.i32_sub(
|
||||
c.i32_sub(
|
||||
c.getLocal("eX"),
|
||||
c.getLocal("eY")
|
||||
),
|
||||
c.i32_const(4)
|
||||
)
|
||||
),
|
||||
|
||||
// While greater than 32 bits or ec is neg, shr and inc exp
|
||||
c.block(c.loop(
|
||||
c.br_if(
|
||||
1,
|
||||
c.i32_and(
|
||||
c.i64_eqz(
|
||||
c.i64_and(
|
||||
c.getLocal("sx"),
|
||||
c.i64_const("0xFFFFFFFF00000000")
|
||||
)
|
||||
),
|
||||
c.i32_ge_s(
|
||||
c.getLocal("ec"),
|
||||
c.i32_const(0)
|
||||
)
|
||||
)
|
||||
),
|
||||
|
||||
c.setLocal(
|
||||
"sx",
|
||||
c.i64_shr_u(
|
||||
c.getLocal("sx"),
|
||||
c.i64_const(8)
|
||||
)
|
||||
),
|
||||
|
||||
c.setLocal(
|
||||
"ec",
|
||||
c.i32_add(
|
||||
c.getLocal("ec"),
|
||||
c.i32_const(1)
|
||||
)
|
||||
),
|
||||
c.br(0)
|
||||
)),
|
||||
|
||||
c.if(
|
||||
c.i64_eqz(c.getLocal("sx")),
|
||||
[
|
||||
...c.br_if(
|
||||
2,
|
||||
c.i32_eqz(c.call(prefix + "_gte", R, Y))
|
||||
),
|
||||
...c.setLocal("sx", c.i64_const(1)),
|
||||
...c.setLocal("ec", c.i32_const(0))
|
||||
]
|
||||
),
|
||||
|
||||
c.call(prefix + "__mul1", Y, c.getLocal("sx"), R2),
|
||||
c.drop(c.call(
|
||||
prefix + "_sub",
|
||||
R,
|
||||
c.i32_sub(R2, c.getLocal("ec")),
|
||||
R
|
||||
)),
|
||||
c.call(
|
||||
prefix + "__add1",
|
||||
c.i32_add(C, c.getLocal("ec")),
|
||||
c.getLocal("sx")
|
||||
),
|
||||
c.br(0)
|
||||
)));
|
||||
}
|
||||
|
||||
function buildInverseMod() {
|
||||
|
||||
const f = module.addFunction(prefix+"_inverseMod");
|
||||
f.addParam("px", "i32");
|
||||
f.addParam("pm", "i32");
|
||||
f.addParam("pr", "i32");
|
||||
f.addLocal("t", "i32");
|
||||
f.addLocal("newt", "i32");
|
||||
f.addLocal("r", "i32");
|
||||
f.addLocal("qq", "i32");
|
||||
f.addLocal("qr", "i32");
|
||||
f.addLocal("newr", "i32");
|
||||
f.addLocal("swp", "i32");
|
||||
f.addLocal("x", "i32");
|
||||
f.addLocal("signt", "i32");
|
||||
f.addLocal("signnewt", "i32");
|
||||
f.addLocal("signx", "i32");
|
||||
|
||||
const c = f.getCodeBuilder();
|
||||
|
||||
const aux1 = c.i32_const(module.alloc(n8));
|
||||
const aux2 = c.i32_const(module.alloc(n8));
|
||||
const aux3 = c.i32_const(module.alloc(n8));
|
||||
const aux4 = c.i32_const(module.alloc(n8));
|
||||
const aux5 = c.i32_const(module.alloc(n8));
|
||||
const aux6 = c.i32_const(module.alloc(n8));
|
||||
const mulBuff = c.i32_const(module.alloc(n8*2));
|
||||
const aux7 = c.i32_const(module.alloc(n8));
|
||||
|
||||
f.addCode(
|
||||
c.setLocal("t", aux1),
|
||||
c.call(prefix + "_zero", aux1),
|
||||
c.setLocal("signt", c.i32_const(0)),
|
||||
);
|
||||
|
||||
f.addCode(
|
||||
c.setLocal("r", aux2),
|
||||
c.call(prefix + "_copy", c.getLocal("pm"), aux2)
|
||||
);
|
||||
|
||||
f.addCode(
|
||||
c.setLocal("newt", aux3),
|
||||
c.call(prefix + "_one", aux3),
|
||||
c.setLocal("signnewt", c.i32_const(0)),
|
||||
);
|
||||
|
||||
f.addCode(
|
||||
c.setLocal("newr", aux4),
|
||||
c.call(prefix + "_copy", c.getLocal("px"), aux4)
|
||||
);
|
||||
|
||||
|
||||
|
||||
|
||||
f.addCode(c.setLocal("qq", aux5));
|
||||
f.addCode(c.setLocal("qr", aux6));
|
||||
f.addCode(c.setLocal("x", aux7));
|
||||
|
||||
f.addCode(c.block(c.loop(
|
||||
c.br_if(
|
||||
1,
|
||||
c.call(prefix + "_isZero", c.getLocal("newr") )
|
||||
),
|
||||
c.call(prefix + "_div", c.getLocal("r"), c.getLocal("newr"), c.getLocal("qq"), c.getLocal("qr")),
|
||||
|
||||
c.call(prefix + "_mul", c.getLocal("qq"), c.getLocal("newt"), mulBuff),
|
||||
|
||||
c.if(
|
||||
c.getLocal("signt"),
|
||||
c.if(
|
||||
c.getLocal("signnewt"),
|
||||
c.if (
|
||||
c.call(prefix + "_gte", mulBuff, c.getLocal("t")),
|
||||
[
|
||||
...c.drop(c.call(prefix + "_sub", mulBuff, c.getLocal("t"), c.getLocal("x"))),
|
||||
...c.setLocal("signx", c.i32_const(0))
|
||||
],
|
||||
[
|
||||
...c.drop(c.call(prefix + "_sub", c.getLocal("t"), mulBuff, c.getLocal("x"))),
|
||||
...c.setLocal("signx", c.i32_const(1))
|
||||
],
|
||||
),
|
||||
[
|
||||
...c.drop(c.call(prefix + "_add", mulBuff, c.getLocal("t"), c.getLocal("x"))),
|
||||
...c.setLocal("signx", c.i32_const(1))
|
||||
]
|
||||
),
|
||||
c.if(
|
||||
c.getLocal("signnewt"),
|
||||
[
|
||||
...c.drop(c.call(prefix + "_add", mulBuff, c.getLocal("t"), c.getLocal("x"))),
|
||||
...c.setLocal("signx", c.i32_const(0))
|
||||
],
|
||||
c.if (
|
||||
c.call(prefix + "_gte", c.getLocal("t"), mulBuff),
|
||||
[
|
||||
...c.drop(c.call(prefix + "_sub", c.getLocal("t"), mulBuff, c.getLocal("x"))),
|
||||
...c.setLocal("signx", c.i32_const(0))
|
||||
],
|
||||
[
|
||||
...c.drop(c.call(prefix + "_sub", mulBuff, c.getLocal("t"), c.getLocal("x"))),
|
||||
...c.setLocal("signx", c.i32_const(1))
|
||||
]
|
||||
)
|
||||
)
|
||||
),
|
||||
|
||||
c.setLocal("swp", c.getLocal("t")),
|
||||
c.setLocal("t", c.getLocal("newt")),
|
||||
c.setLocal("newt", c.getLocal("x")),
|
||||
c.setLocal("x", c.getLocal("swp")),
|
||||
|
||||
c.setLocal("signt", c.getLocal("signnewt")),
|
||||
c.setLocal("signnewt", c.getLocal("signx")),
|
||||
|
||||
c.setLocal("swp", c.getLocal("r")),
|
||||
c.setLocal("r", c.getLocal("newr")),
|
||||
c.setLocal("newr", c.getLocal("qr")),
|
||||
c.setLocal("qr", c.getLocal("swp")),
|
||||
|
||||
c.br(0)
|
||||
)));
|
||||
|
||||
f.addCode(c.if(
|
||||
c.getLocal("signt"),
|
||||
c.drop(c.call(prefix + "_sub", c.getLocal("pm"), c.getLocal("t"), c.getLocal("pr"))),
|
||||
c.call(prefix + "_copy", c.getLocal("t"), c.getLocal("pr"))
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
buildCopy();
|
||||
buildZero();
|
||||
buildIsZero();
|
||||
buildOne();
|
||||
buildEq();
|
||||
buildGte();
|
||||
buildAdd();
|
||||
buildSub();
|
||||
buildMul();
|
||||
buildDiv();
|
||||
buildInverseMod();
|
||||
module.exportFunction(prefix+"_copy");
|
||||
module.exportFunction(prefix+"_zero");
|
||||
module.exportFunction(prefix+"_one");
|
||||
module.exportFunction(prefix+"_isZero");
|
||||
module.exportFunction(prefix+"_eq");
|
||||
module.exportFunction(prefix+"_gte");
|
||||
module.exportFunction(prefix+"_add");
|
||||
module.exportFunction(prefix+"_sub");
|
||||
module.exportFunction(prefix+"_mul");
|
||||
module.exportFunction(prefix+"_div");
|
||||
module.exportFunction(prefix+"_inverseMod");
|
||||
|
||||
return prefix;
|
||||
};
|
127
src/build_mem.js
Normal file
127
src/build_mem.js
Normal file
@ -0,0 +1,127 @@
|
||||
/*
|
||||
Copyright 2019 0KIMS association.
|
||||
|
||||
This file is part of websnark (Web Assembly zkSnark Prover).
|
||||
|
||||
websnark is a free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
websnark is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with websnark. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
module.exports = function buildMem(module, prefix, prefixField) {
|
||||
|
||||
function buildCopy() {
|
||||
const f = module.addFunction(prefix+"copy");
|
||||
f.addParam("s", "i32");
|
||||
f.addParam("d", "i32");
|
||||
f.addParam("n", "i32");
|
||||
f.addLocal("bytesAfter", "i32");
|
||||
f.addLocal("sp", "i32");
|
||||
|
||||
const c = f.getCodeBuilder();
|
||||
|
||||
f.addCode(
|
||||
c.setLocal(
|
||||
"n64",
|
||||
c.i32_shl(
|
||||
c.getLocal("n"),
|
||||
c.i32_const(3)
|
||||
)
|
||||
),
|
||||
c.setLocal(
|
||||
"bytesAfter",
|
||||
c.i32_and(
|
||||
c.getLocal("n"),
|
||||
c.i32_const(0x7)
|
||||
)
|
||||
),
|
||||
c.setLocal("sp", c.getLocal("s")),
|
||||
c.setLocal("dp", c.getLocal("d")),
|
||||
c.setLocal("lastsp",
|
||||
c.add(
|
||||
c.getLocal("s"),
|
||||
c.i32_and(
|
||||
c.getLocal("n"),
|
||||
c.i32_const(0xFFFFFFF8)
|
||||
)
|
||||
)
|
||||
),
|
||||
|
||||
|
||||
c.block(c.loop(
|
||||
c.br_if(
|
||||
1,
|
||||
c.i32_eq(
|
||||
c.getLocal("sp"),
|
||||
c.getLocal("lastsp")
|
||||
)
|
||||
),
|
||||
c.i64_store(
|
||||
c.getLocal("dp"),
|
||||
c.i64_load(
|
||||
c.getLocal("sp")
|
||||
)
|
||||
),
|
||||
c.setLocal("sp", c.i32_add(c.getLocal("sp"), c.i32_const(8))),
|
||||
c.setLocal("dp", c.i32_add(c.getLocal("dp"), c.i32_const(8))),
|
||||
c.br(0)
|
||||
)),
|
||||
|
||||
c.if(
|
||||
c.getLocal("bytesAfter"),
|
||||
[
|
||||
...c.if(
|
||||
c.i32_and(c.getLocal("bytesAfter"), c.i32_const(0x4)),
|
||||
[
|
||||
...c.i32_store(
|
||||
c.getLocal("dp"),
|
||||
c.i32_load(
|
||||
c.getLocal("sp")
|
||||
)
|
||||
),
|
||||
...c.setLocal("sp", c.i32_add(c.getLocal("sp"), c.i32_const(4))),
|
||||
...c.setLocal("dp", c.i32_add(c.getLocal("dp"), c.i32_const(4))),
|
||||
]
|
||||
),
|
||||
...c.if(
|
||||
c.i32_and(c.getLocal("bytesAfter"), c.i32_const(0x2)),
|
||||
[
|
||||
...c.i32_store16(
|
||||
c.getLocal("dp"),
|
||||
c.i32_load16(
|
||||
c.getLocal("sp")
|
||||
)
|
||||
),
|
||||
...c.setLocal("sp", c.i32_add(c.getLocal("sp"), c.i32_const(2))),
|
||||
...c.setLocal("dp", c.i32_add(c.getLocal("dp"), c.i32_const(2))),
|
||||
]
|
||||
),
|
||||
...c.if(
|
||||
c.i32_and(c.getLocal("bytesAfter"), c.i32_const(0x1)),
|
||||
c.i32_store8(
|
||||
c.getLocal("dp"),
|
||||
c.i32_load8(
|
||||
c.getLocal("sp")
|
||||
)
|
||||
)
|
||||
)
|
||||
]
|
||||
)
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
buildCopy();
|
||||
module.exportFunction(prefix+"_copy");
|
||||
|
||||
return prefix;
|
||||
};
|
205
src/build_mulacc.js
Normal file
205
src/build_mulacc.js
Normal file
@ -0,0 +1,205 @@
|
||||
/*
|
||||
Copyright 2019 0KIMS association.
|
||||
|
||||
This file is part of websnark (Web Assembly zkSnark Prover).
|
||||
|
||||
websnark is a free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
websnark is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with websnark. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
module.exports = function buildMulAcc(windowSize, prefix, curvePrefix, scalarPrefix) {
|
||||
const pointN64 = module.modules[curvePrefix].n64;
|
||||
const pointN8 = pointN64*8;
|
||||
const scalarN64 = module.modules[scalarPrefix].n64;
|
||||
const scalarN8 = scalarN64*8;
|
||||
|
||||
function buildMultiMul64() {
|
||||
const f = module.addFunction(prefix+"__multimul");
|
||||
f.addParam("pscalars", "i32");
|
||||
f.addParam("ppoints", "i32");
|
||||
f.addParam("pr", "i32");
|
||||
f.addLocal("sel");
|
||||
f.addLocal("ppminusone");
|
||||
|
||||
const c = f.getCodeBuilder();
|
||||
|
||||
f.addCode(c.setLocal("sel", c.i32_const(0)));
|
||||
f.addCode(c.setLocal(
|
||||
"ppminusone",
|
||||
c.sub(
|
||||
c.getLocal("ppoints"),
|
||||
c.i32_const(pointN8)
|
||||
)
|
||||
));
|
||||
|
||||
for (let i=0; i<64; i++) {
|
||||
for (let s=0; s<windowSize; s++) {
|
||||
f.addCode(c.setLocal(
|
||||
"sel",
|
||||
c.i32_or(
|
||||
c.getLocal("sel"),
|
||||
c.i32_and(
|
||||
c.i32_wrap_i64(
|
||||
c.i64_rotl(
|
||||
c.i64_load(
|
||||
c.getLocal("pscalars"),
|
||||
i*scalarN64
|
||||
),
|
||||
c.i64_const(i+s+1)
|
||||
)
|
||||
),
|
||||
c.i32_const(1<<s)
|
||||
)
|
||||
)
|
||||
));
|
||||
|
||||
f.addCode(c.if(
|
||||
c.getLocal("sel"),
|
||||
c.call(
|
||||
curvePrefix + "_add",
|
||||
c.i32_add(
|
||||
c.getLocal("ppminusone"),
|
||||
c.i32_mul(
|
||||
c.getLocal("sel"),
|
||||
c.i32_const(pointN8)
|
||||
)
|
||||
)
|
||||
)
|
||||
));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
function buildMultiMul() {
|
||||
buildMultiMul64();
|
||||
const f = module.addFunction(prefix+"__multimul");
|
||||
f.addParam("pscalars", "i32");
|
||||
f.addParam("ppoints", "i32");
|
||||
f.addParam("pr", "i32");
|
||||
|
||||
const c = f.getCodeBuilder();
|
||||
|
||||
f.addCode(c.call(prefix + "_zero", c.getLocal("pr")));
|
||||
|
||||
for (let i=0; i<scalarN64; i++) {
|
||||
if (i>0) f.addCode(c.call(curvePrefix + "_double"), c.getLocal("pr"));
|
||||
f.addCode(c.call(
|
||||
prefix + "__multimul64",
|
||||
c.i32_add(c.getLocal("pscalars"), c.const(i*8)),
|
||||
c.getLocal("ppoints")
|
||||
));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function buildMulAcc() {
|
||||
buildMultiMul();
|
||||
const f = module.addFunction(prefix+"_mulacc");
|
||||
f.addParam("pscalars", "i32");
|
||||
f.addParam("ppoints", "i32");
|
||||
f.addParam("n", "i32");
|
||||
f.addParam("pr", "i32");
|
||||
f.addLocal("inc", "i32");
|
||||
f.addLocal("pp", "i32");
|
||||
f.addLocal("ps", "i32");
|
||||
f.addLocal("last", "i32");
|
||||
|
||||
const c = f.getCodeBuilder();
|
||||
|
||||
const aux = c.i32_const(module.alloc(pointN8));
|
||||
|
||||
// Check n is windowSize multiple
|
||||
f.addCode(c.if(
|
||||
c.eqz(
|
||||
c.i32_mod(
|
||||
c.getLocal("n"),
|
||||
c.i32_const(windowSize)
|
||||
)
|
||||
),
|
||||
c.unreachable()
|
||||
));
|
||||
|
||||
// Set zero the output
|
||||
f.addCode(c.call(prefix + "_zero", c.getLocal("pr")));
|
||||
|
||||
// Calculate the increment
|
||||
f.addCode(c.setLocal(
|
||||
"incPoint",
|
||||
c.i32_const(((1 << windowSize)-1) *pointN8 )
|
||||
));
|
||||
|
||||
f.addCode(c.setLocal(
|
||||
"incScalar",
|
||||
c.i32_const(windowSize *scalarN8 )
|
||||
));
|
||||
|
||||
// Calculate Initial
|
||||
f.addCode(c.setLocal(
|
||||
"pp",
|
||||
c.getLocal("ppoints")
|
||||
));
|
||||
|
||||
f.addCode(c.setLocal(
|
||||
"ps",
|
||||
c.getLocal("pscalars")
|
||||
));
|
||||
|
||||
// Calculate Last
|
||||
f.addCode(c.setLocal(
|
||||
"last",
|
||||
c.i32_mul(
|
||||
c.getLocal("incPoint"),
|
||||
c.getLocal("n")
|
||||
)
|
||||
));
|
||||
|
||||
f.addCode(c.block(c.loop(
|
||||
c.br_if(
|
||||
1,
|
||||
c.i32_eq(
|
||||
c.getLocal("pp"),
|
||||
c.getLocal("last")
|
||||
)
|
||||
),
|
||||
|
||||
c.call(prefix + "__multimul", c.getLocal("ps"), c.getLocal("pp"), aux),
|
||||
c.call(curvePrefix + "_add", aux, c.getLocal("pr"), c.getLocal("pr")),
|
||||
|
||||
c.setLocal(
|
||||
"pp",
|
||||
c.add(
|
||||
c.getLocal("pp"),
|
||||
c.getLocal("incPoint")
|
||||
)
|
||||
),
|
||||
c.setLocal(
|
||||
"ps",
|
||||
c.add(
|
||||
c.getLocal("ps"),
|
||||
c.getLocal("incScalar")
|
||||
)
|
||||
),
|
||||
c.br(0)
|
||||
)));
|
||||
|
||||
}
|
||||
|
||||
buildMulAcc();
|
||||
module.exportFunction(prefix+"_mulacc");
|
||||
|
||||
|
||||
};
|
591
src/build_multiexp.js
Normal file
591
src/build_multiexp.js
Normal file
@ -0,0 +1,591 @@
|
||||
/*
|
||||
Copyright 2019 0KIMS association.
|
||||
|
||||
This file is part of websnark (Web Assembly zkSnark Prover).
|
||||
|
||||
websnark is a free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
websnark is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with websnark. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
module.exports = function buildMultiexp(module, prefix, curvePrefix, pointFieldPrefix, scalarPrefix) {
|
||||
|
||||
const pointFieldN64 = module.modules[pointFieldPrefix].n64;
|
||||
const pointFieldN8 = pointFieldN64*8;
|
||||
const pointN64 = module.modules[curvePrefix].n64;
|
||||
const pointN8 = pointN64*8;
|
||||
const scalarN64 = module.modules[scalarPrefix].n64;
|
||||
const scalarN8 = scalarN64*8;
|
||||
|
||||
|
||||
function buildPackBits() {
|
||||
const f = module.addFunction(prefix+"__packbits");
|
||||
f.addParam("pscalars", "i32");
|
||||
f.addParam("w", "i32"); // 8 max
|
||||
f.addParam("pr", "i32"); // P to result scalarN8*8 bytes
|
||||
f.addLocal("i", "i32");
|
||||
f.addLocal("j", "i32");
|
||||
f.addLocal("w1", "i64");
|
||||
f.addLocal("w2", "i64");
|
||||
|
||||
const c = f.getCodeBuilder();
|
||||
|
||||
f.addCode(c.setLocal("i", c.i32_const(0)));
|
||||
f.addCode(c.block(c.loop(
|
||||
c.br_if(
|
||||
1,
|
||||
c.i32_eq(
|
||||
c.getLocal("i"),
|
||||
c.i32_const(scalarN8)
|
||||
)
|
||||
),
|
||||
|
||||
c.setLocal("w2", c.i64_const(0)),
|
||||
|
||||
c.setLocal("j", c.i32_const(0)),
|
||||
|
||||
c.block(c.loop(
|
||||
c.br_if(
|
||||
1,
|
||||
c.i32_eq(
|
||||
c.getLocal("j"),
|
||||
c.getLocal("w")
|
||||
)
|
||||
),
|
||||
|
||||
c.setLocal(
|
||||
"w1",
|
||||
c.i64_load8_u(
|
||||
c.i32_add(
|
||||
c.getLocal("pscalars"),
|
||||
c.i32_add(
|
||||
c.i32_mul(
|
||||
c.getLocal("j"),
|
||||
c.i32_const(scalarN8)
|
||||
),
|
||||
c.getLocal("i")
|
||||
)
|
||||
)
|
||||
)
|
||||
),
|
||||
|
||||
c.setLocal(
|
||||
"w1",
|
||||
c.i64_and(
|
||||
c.i64_or(
|
||||
c.getLocal("w1"),
|
||||
c.i64_shl(
|
||||
c.getLocal("w1"),
|
||||
c.i64_const(28)
|
||||
)
|
||||
),
|
||||
c.i64_const("0x0000000F0000000F")
|
||||
)
|
||||
),
|
||||
|
||||
c.setLocal(
|
||||
"w1",
|
||||
c.i64_and(
|
||||
c.i64_or(
|
||||
c.getLocal("w1"),
|
||||
c.i64_shl(
|
||||
c.getLocal("w1"),
|
||||
c.i64_const(14)
|
||||
)
|
||||
),
|
||||
c.i64_const("0x0003000300030003")
|
||||
)
|
||||
),
|
||||
|
||||
c.setLocal(
|
||||
"w1",
|
||||
c.i64_and(
|
||||
c.i64_or(
|
||||
c.getLocal("w1"),
|
||||
c.i64_shl(
|
||||
c.getLocal("w1"),
|
||||
c.i64_const(7)
|
||||
)
|
||||
),
|
||||
c.i64_const("0x0101010101010101")
|
||||
)
|
||||
),
|
||||
|
||||
c.setLocal(
|
||||
"w2",
|
||||
c.i64_or(
|
||||
c.getLocal("w2"),
|
||||
c.i64_shl(
|
||||
c.getLocal("w1"),
|
||||
c.i64_extend_i32_u(c.getLocal("j"))
|
||||
)
|
||||
)
|
||||
),
|
||||
|
||||
|
||||
c.setLocal("j", c.i32_add(c.getLocal("j"), c.i32_const(1))),
|
||||
c.br(0)
|
||||
)),
|
||||
|
||||
c.i64_store(
|
||||
c.i32_add(
|
||||
c.getLocal("pr"),
|
||||
c.i32_mul(
|
||||
c.getLocal("i"),
|
||||
c.i32_const(8)
|
||||
)
|
||||
),
|
||||
c.getLocal("w2")
|
||||
),
|
||||
|
||||
c.setLocal("i", c.i32_add(c.getLocal("i"), c.i32_const(1))),
|
||||
c.br(0)
|
||||
)));
|
||||
|
||||
|
||||
}
|
||||
|
||||
const c1 = [];
|
||||
const c2 = [];
|
||||
|
||||
function nbits(_b) {
|
||||
let c=0;
|
||||
let r=_b;
|
||||
while(r) {
|
||||
if (r&1) c++;
|
||||
r = r>>1;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
function split(_b) {
|
||||
const nb1 = nbits(_b) >> 1;
|
||||
let r = _b;
|
||||
let c = 0;
|
||||
if (nb1 == 0) return null;
|
||||
let mask = 0xFFFFFFFF;
|
||||
while (c<nb1) {
|
||||
if (r&1) c++;
|
||||
mask = mask << 1;
|
||||
r = r>>1;
|
||||
}
|
||||
return [(_b & mask), (_b & (~mask))];
|
||||
}
|
||||
|
||||
for (let i=0; i<256; i++) {
|
||||
const a = split(i);
|
||||
if (a) {
|
||||
c1[i] = a[0];
|
||||
c2[i] = a[1];
|
||||
} else {
|
||||
c1[i] = 0;
|
||||
c2[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
const ptable = module.alloc(pointN8*256);
|
||||
const pset = module.alloc(32);
|
||||
const composite1 = module.alloc(256, c1);
|
||||
const composite2 = module.alloc(256, c2);
|
||||
|
||||
|
||||
function buildSetSet() {
|
||||
const f = module.addFunction(prefix+"__set_set");
|
||||
f.addParam("idx", "i32");
|
||||
f.addLocal("word", "i32");
|
||||
f.addLocal("mask", "i32");
|
||||
|
||||
const c = f.getCodeBuilder();
|
||||
|
||||
f.addCode(
|
||||
c.setLocal(
|
||||
"word",
|
||||
c.i32_shl(
|
||||
c.i32_shr_u(
|
||||
c.getLocal("idx"),
|
||||
c.i32_const(5)
|
||||
),
|
||||
c.i32_const(2)
|
||||
)
|
||||
)
|
||||
);
|
||||
f.addCode(
|
||||
c.setLocal(
|
||||
"mask",
|
||||
c.i32_shl(
|
||||
c.i32_const(1),
|
||||
c.i32_and(
|
||||
c.getLocal("idx"),
|
||||
c.i32_const("0x1F")
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
f.addCode(
|
||||
c.i32_store(
|
||||
c.getLocal("word"),
|
||||
pset,
|
||||
c.i32_or(
|
||||
c.i32_load(
|
||||
c.getLocal("word"),
|
||||
pset
|
||||
),
|
||||
c.getLocal("mask")
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
function buildSetIsSet() {
|
||||
const f = module.addFunction(prefix+"__set_isSet");
|
||||
f.addParam("idx", "i32");
|
||||
f.setReturnType("i32");
|
||||
f.addLocal("word", "i32");
|
||||
f.addLocal("mask", "i32");
|
||||
|
||||
const c = f.getCodeBuilder();
|
||||
|
||||
|
||||
f.addCode(
|
||||
c.setLocal(
|
||||
"word",
|
||||
c.i32_shl(
|
||||
c.i32_shr_u(
|
||||
c.getLocal("idx"),
|
||||
c.i32_const(5)
|
||||
),
|
||||
c.i32_const(2)
|
||||
)
|
||||
)
|
||||
);
|
||||
f.addCode(
|
||||
c.setLocal(
|
||||
"mask",
|
||||
c.i32_shl(
|
||||
c.i32_const(1),
|
||||
c.i32_and(
|
||||
c.getLocal("idx"),
|
||||
c.i32_const("0x1F")
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
f.addCode(
|
||||
c.i32_and(
|
||||
c.i32_load(
|
||||
c.getLocal("word"),
|
||||
pset
|
||||
),
|
||||
c.getLocal("mask")
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
function buildPTableReset() {
|
||||
const f = module.addFunction(prefix+"__ptable_reset");
|
||||
f.addParam("ppoints", "i32");
|
||||
f.addParam("w", "i32"); // Window size Max 8
|
||||
f.addLocal("ps", "i32");
|
||||
f.addLocal("pd", "i32");
|
||||
f.addLocal("i", "i32");
|
||||
f.addLocal("isZero", "i32");
|
||||
|
||||
const c = f.getCodeBuilder();
|
||||
|
||||
f.addCode(c.setLocal("ps", c.getLocal("ppoints")));
|
||||
|
||||
f.addCode(c.call( curvePrefix + "_zero", c.i32_const(ptable) ));
|
||||
|
||||
f.addCode(c.setLocal("i", c.i32_const(0)));
|
||||
f.addCode(c.block(c.loop(
|
||||
c.br_if(
|
||||
1,
|
||||
c.i32_eq(
|
||||
c.getLocal("i"),
|
||||
c.getLocal("w")
|
||||
)
|
||||
),
|
||||
|
||||
c.setLocal(
|
||||
"pd",
|
||||
c.i32_add(
|
||||
c.i32_const(ptable),
|
||||
c.i32_mul(
|
||||
c.i32_shl(
|
||||
c.i32_const(1),
|
||||
c.getLocal("i")
|
||||
),
|
||||
c.i32_const(pointN8)
|
||||
)
|
||||
)
|
||||
),
|
||||
|
||||
|
||||
c.setLocal("isZero", c.call(pointFieldPrefix + "_isZero", c.getLocal("ps"))),
|
||||
|
||||
c.call( pointFieldPrefix + "_copy", c.getLocal("ps"), c.getLocal("pd")),
|
||||
c.setLocal("ps", c.i32_add(c.getLocal("ps"), c.i32_const(pointFieldN8))),
|
||||
c.setLocal("pd", c.i32_add(c.getLocal("pd"), c.i32_const(pointFieldN8))),
|
||||
|
||||
c.call( pointFieldPrefix + "_copy", c.getLocal("ps"), c.getLocal("pd")),
|
||||
c.setLocal("ps", c.i32_add(c.getLocal("ps"), c.i32_const(pointFieldN8))),
|
||||
c.setLocal("pd", c.i32_add(c.getLocal("pd"), c.i32_const(pointFieldN8))),
|
||||
|
||||
c.if(
|
||||
c.getLocal("isZero"),
|
||||
c.call( pointFieldPrefix + "_zero", c.getLocal("pd")),
|
||||
c.call( pointFieldPrefix + "_one", c.getLocal("pd")),
|
||||
),
|
||||
|
||||
c.setLocal("i", c.i32_add(c.getLocal("i"), c.i32_const(1))),
|
||||
c.br(0)
|
||||
)));
|
||||
|
||||
// Reset the set
|
||||
f.addCode(c.i64_store( c.i32_const(pset ),c.i64_const("0x0000000100010117")));
|
||||
f.addCode(c.i64_store( c.i32_const(pset+ 8),c.i64_const("0x0000000000000001")));
|
||||
f.addCode(c.i64_store( c.i32_const(pset+16),c.i64_const("0x0000000000000001")));
|
||||
f.addCode(c.i64_store( c.i32_const(pset+24),c.i64_const("0x0000000000000000")));
|
||||
|
||||
|
||||
}
|
||||
|
||||
function buildPTableGet() {
|
||||
const f = module.addFunction(prefix+"__ptable_get");
|
||||
f.addParam("idx", "i32");
|
||||
f.setReturnType("i32");
|
||||
f.addLocal("pr", "i32");
|
||||
f.addLocal("p1", "i32");
|
||||
f.addLocal("p2", "i32");
|
||||
|
||||
const c = f.getCodeBuilder();
|
||||
|
||||
f.addCode(
|
||||
c.setLocal(
|
||||
"pr",
|
||||
c.i32_add(
|
||||
c.i32_const(ptable),
|
||||
c.i32_mul(
|
||||
c.getLocal("idx"),
|
||||
c.i32_const(pointN8)
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
f.addCode(c.if(
|
||||
c.i32_eqz(
|
||||
c.call(
|
||||
prefix + "__set_isSet",
|
||||
c.getLocal("idx")
|
||||
),
|
||||
),
|
||||
[
|
||||
...c.setLocal(
|
||||
"p1",
|
||||
c.call(
|
||||
prefix + "__ptable_get",
|
||||
c.i32_load8_u(
|
||||
c.getLocal("idx"),
|
||||
composite1
|
||||
)
|
||||
)
|
||||
),
|
||||
...c.setLocal(
|
||||
"p2",
|
||||
c.call(
|
||||
prefix + "__ptable_get",
|
||||
c.i32_load8_u(
|
||||
c.getLocal("idx"),
|
||||
composite2
|
||||
)
|
||||
)
|
||||
),
|
||||
...c.call(
|
||||
curvePrefix + "_add",
|
||||
c.getLocal("p1"),
|
||||
c.getLocal("p2"),
|
||||
c.getLocal("pr")
|
||||
),
|
||||
...c.call(
|
||||
prefix + "__set_set",
|
||||
c.getLocal("idx")
|
||||
)
|
||||
]
|
||||
));
|
||||
|
||||
f.addCode(c.getLocal("pr"));
|
||||
}
|
||||
|
||||
function buildMulw() {
|
||||
const f = module.addFunction(prefix+"__mulw");
|
||||
f.addParam("pscalars", "i32");
|
||||
f.addParam("ppoints", "i32");
|
||||
f.addParam("w", "i32"); // Window size Max 8
|
||||
f.addParam("pr", "i32");
|
||||
f.addLocal("i", "i32");
|
||||
|
||||
const c = f.getCodeBuilder();
|
||||
|
||||
const psels = module.alloc(scalarN8 * 8);
|
||||
|
||||
f.addCode(c.call(
|
||||
prefix + "__packbits",
|
||||
c.getLocal("pscalars"),
|
||||
c.getLocal("w"),
|
||||
c.i32_const(psels)
|
||||
));
|
||||
|
||||
f.addCode(c.call(
|
||||
curvePrefix + "_zero",
|
||||
c.getLocal("pr"),
|
||||
));
|
||||
|
||||
f.addCode(c.call(
|
||||
prefix + "__ptable_reset",
|
||||
c.getLocal("ppoints"),
|
||||
c.getLocal("w")
|
||||
));
|
||||
|
||||
|
||||
f.addCode(c.setLocal("i", c.i32_const(0)));
|
||||
f.addCode(c.block(c.loop(
|
||||
c.br_if(
|
||||
1,
|
||||
c.i32_eq(
|
||||
c.getLocal("i"),
|
||||
c.i32_const(scalarN8 * 8)
|
||||
)
|
||||
),
|
||||
|
||||
c.call(curvePrefix + "_double",
|
||||
c.getLocal("pr"),
|
||||
c.getLocal("pr"),
|
||||
),
|
||||
c.call(curvePrefix + "_add",
|
||||
c.getLocal("pr"),
|
||||
c.call(
|
||||
prefix + "__ptable_get",
|
||||
c.i32_load8_u(
|
||||
c.i32_sub(
|
||||
c.i32_const(psels + scalarN8 * 8 -1),
|
||||
c.getLocal("i")
|
||||
)
|
||||
)
|
||||
),
|
||||
c.getLocal("pr"),
|
||||
),
|
||||
|
||||
c.setLocal("i", c.i32_add(c.getLocal("i"), c.i32_const(1))),
|
||||
c.br(0)
|
||||
)));
|
||||
|
||||
}
|
||||
|
||||
|
||||
function buildMultiexp() {
|
||||
const f = module.addFunction(prefix+"_multiexp");
|
||||
f.addParam("pscalars", "i32");
|
||||
f.addParam("ppoints", "i32");
|
||||
f.addParam("n", "i32"); // Number of points
|
||||
f.addParam("w", "i32"); // Window size Max 8
|
||||
f.addParam("pr", "i32");
|
||||
f.addLocal("ps", "i32");
|
||||
f.addLocal("pp", "i32");
|
||||
f.addLocal("wf", "i32");
|
||||
f.addLocal("lastps", "i32");
|
||||
|
||||
const c = f.getCodeBuilder();
|
||||
|
||||
const aux = c.i32_const(module.alloc(pointN8));
|
||||
|
||||
f.addCode(c.setLocal("ps", c.getLocal("pscalars")));
|
||||
f.addCode(c.setLocal("pp", c.getLocal("ppoints")));
|
||||
|
||||
f.addCode(c.setLocal(
|
||||
"lastps",
|
||||
c.i32_add(
|
||||
c.getLocal("ps"),
|
||||
c.i32_mul(
|
||||
c.i32_mul(
|
||||
c.i32_div_u(
|
||||
c.getLocal("n"),
|
||||
c.getLocal("w")
|
||||
),
|
||||
c.getLocal("w")
|
||||
),
|
||||
c.i32_const(scalarN8)
|
||||
)
|
||||
)
|
||||
));
|
||||
|
||||
f.addCode(c.block(c.loop(
|
||||
c.br_if(
|
||||
1,
|
||||
c.i32_eq(
|
||||
c.getLocal("ps"),
|
||||
c.getLocal("lastps")
|
||||
)
|
||||
),
|
||||
|
||||
c.call(prefix + "__mulw", c.getLocal("ps"), c.getLocal("pp"), c.getLocal("w"), aux),
|
||||
c.call(curvePrefix + "_add", aux, c.getLocal("pr"), c.getLocal("pr")),
|
||||
|
||||
c.setLocal(
|
||||
"ps",
|
||||
c.i32_add(
|
||||
c.getLocal("ps"),
|
||||
c.i32_mul(
|
||||
c.i32_const(scalarN8),
|
||||
c.getLocal("w")
|
||||
)
|
||||
)
|
||||
),
|
||||
|
||||
c.setLocal(
|
||||
"pp",
|
||||
c.i32_add(
|
||||
c.getLocal("pp"),
|
||||
c.i32_mul(
|
||||
c.i32_const(pointFieldN8*2),
|
||||
c.getLocal("w")
|
||||
)
|
||||
)
|
||||
),
|
||||
|
||||
c.br(0)
|
||||
)));
|
||||
|
||||
f.addCode(c.setLocal("wf", c.i32_rem_u(c.getLocal("n"), c.getLocal("w"))));
|
||||
|
||||
f.addCode(c.if(
|
||||
c.getLocal("wf"),
|
||||
[
|
||||
...c.call(prefix + "__mulw", c.getLocal("ps"), c.getLocal("pp"), c.getLocal("wf"), aux),
|
||||
...c.call(curvePrefix + "_add", aux, c.getLocal("pr"), c.getLocal("pr")),
|
||||
]
|
||||
));
|
||||
}
|
||||
|
||||
buildSetSet();
|
||||
buildSetIsSet();
|
||||
buildPTableReset();
|
||||
buildPTableGet();
|
||||
buildPackBits();
|
||||
buildMulw();
|
||||
buildMultiexp();
|
||||
module.exportFunction(prefix+"_multiexp");
|
||||
|
||||
|
||||
};
|
158
src/build_pol.js
Normal file
158
src/build_pol.js
Normal file
@ -0,0 +1,158 @@
|
||||
/*
|
||||
Copyright 2019 0KIMS association.
|
||||
|
||||
This file is part of websnark (Web Assembly zkSnark Prover).
|
||||
|
||||
websnark is a free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
websnark is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with websnark. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
module.exports = function buildPol(module, prefix, prefixField) {
|
||||
|
||||
const n64 = module.modules[prefixField].n64;
|
||||
const n8 = n64*8;
|
||||
|
||||
|
||||
function buildZero() {
|
||||
const f = module.addFunction(prefix+"_zero");
|
||||
f.addParam("px", "i32");
|
||||
f.addParam("n", "i32");
|
||||
f.addLocal("lastp", "i32");
|
||||
f.addLocal("p", "i32");
|
||||
|
||||
const c = f.getCodeBuilder();
|
||||
|
||||
f.addCode(
|
||||
c.setLocal("p", c.getLocal("px")),
|
||||
c.setLocal(
|
||||
"lastp",
|
||||
c.i32_add(
|
||||
c.getLocal("px"),
|
||||
c.i32_mul(
|
||||
c.getLocal("n"),
|
||||
c.i32_const(n8)
|
||||
)
|
||||
)
|
||||
),
|
||||
c.block(c.loop(
|
||||
c.br_if(
|
||||
1,
|
||||
c.i32_eq(
|
||||
c.getLocal("p"),
|
||||
c.getLocal("lastp")
|
||||
)
|
||||
),
|
||||
c.call(prefixField + "_zero", c.getLocal("p")),
|
||||
c.setLocal("p", c.i32_add(c.getLocal("p"), c.i32_const(n8))),
|
||||
c.br(0)
|
||||
))
|
||||
);
|
||||
}
|
||||
|
||||
function buildConstructLC() {
|
||||
const f = module.addFunction(prefix+"_constructLC");
|
||||
f.addParam("ppolynomials", "i32");
|
||||
f.addParam("psignals", "i32");
|
||||
f.addParam("nSignals", "i32");
|
||||
f.addParam("pres", "i32");
|
||||
f.addLocal("i", "i32");
|
||||
f.addLocal("j", "i32");
|
||||
f.addLocal("pp", "i32");
|
||||
f.addLocal("ps", "i32");
|
||||
f.addLocal("pd", "i32");
|
||||
f.addLocal("ncoefs", "i32");
|
||||
|
||||
const c = f.getCodeBuilder();
|
||||
|
||||
const aux = c.i32_const(module.alloc(n8));
|
||||
|
||||
f.addCode(
|
||||
c.setLocal("i", c.i32_const(0)),
|
||||
c.setLocal("pp", c.getLocal("ppolynomials")),
|
||||
c.setLocal("ps", c.getLocal("psignals")),
|
||||
c.block(c.loop(
|
||||
c.br_if(
|
||||
1,
|
||||
c.i32_eq(
|
||||
c.getLocal("i"),
|
||||
c.getLocal("nSignals")
|
||||
)
|
||||
),
|
||||
|
||||
c.setLocal("ncoefs", c.i32_load(c.getLocal("pp"))),
|
||||
c.setLocal("pp", c.i32_add(c.getLocal("pp"), c.i32_const(4))),
|
||||
|
||||
c.setLocal("j", c.i32_const(0)),
|
||||
c.block(c.loop(
|
||||
c.br_if(
|
||||
1,
|
||||
c.i32_eq(
|
||||
c.getLocal("j"),
|
||||
c.getLocal("ncoefs")
|
||||
)
|
||||
),
|
||||
|
||||
c.setLocal(
|
||||
"pd",
|
||||
c.i32_add(
|
||||
c.getLocal("pres"),
|
||||
c.i32_mul(
|
||||
c.i32_load(c.getLocal("pp")),
|
||||
c.i32_const(n8)
|
||||
)
|
||||
)
|
||||
),
|
||||
|
||||
c.setLocal("pp", c.i32_add(c.getLocal("pp"), c.i32_const(4))),
|
||||
|
||||
|
||||
c.call(
|
||||
prefixField + "_mul",
|
||||
c.getLocal("ps"),
|
||||
c.getLocal("pp"),
|
||||
aux
|
||||
),
|
||||
|
||||
c.call(
|
||||
prefixField + "_add",
|
||||
aux,
|
||||
c.getLocal("pd"),
|
||||
c.getLocal("pd")
|
||||
),
|
||||
|
||||
c.setLocal("pp", c.i32_add(c.getLocal("pp"), c.i32_const(n8))),
|
||||
c.setLocal("j", c.i32_add(c.getLocal("j"), c.i32_const(1))),
|
||||
c.br(0)
|
||||
)),
|
||||
|
||||
c.setLocal("ps", c.i32_add(c.getLocal("ps"), c.i32_const(n8))),
|
||||
c.setLocal("i", c.i32_add(c.getLocal("i"), c.i32_const(1))),
|
||||
c.br(0)
|
||||
))
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
buildZero();
|
||||
buildConstructLC();
|
||||
|
||||
|
||||
module.exportFunction(prefix + "_zero");
|
||||
module.exportFunction(prefix + "_constructLC");
|
||||
|
||||
return prefix;
|
||||
|
||||
|
||||
|
||||
|
||||
};
|
55
src/build_testf1.js
Normal file
55
src/build_testf1.js
Normal file
@ -0,0 +1,55 @@
|
||||
/*
|
||||
Copyright 2019 0KIMS association.
|
||||
|
||||
This file is part of websnark (Web Assembly zkSnark Prover).
|
||||
|
||||
websnark is a free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
websnark is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with websnark. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
const bigInt = require("big-integer");
|
||||
const utils = require("./utils.js");
|
||||
|
||||
module.exports = function buildTestF1(module) {
|
||||
|
||||
const q = bigInt("21888242871839275222246405745257275088696311157297823662689037894645226208583");
|
||||
|
||||
const pR2 = module.modules.f1m.pR2;
|
||||
const n8 = module.modules.f1m.n64*8;
|
||||
|
||||
const pR3 = module.alloc(utils.bigInt2BytesLE(bigInt.one.shiftLeft(256).square().mod(q).shiftRight(128), n8));
|
||||
|
||||
|
||||
function buildTestF1() {
|
||||
const f = module.addFunction("testF1");
|
||||
f.addParam("n", "i32");
|
||||
f.addLocal("i", "i32");
|
||||
|
||||
const c = f.getCodeBuilder();
|
||||
|
||||
const pAux1 = module.alloc(n8);
|
||||
|
||||
f.addCode(c.setLocal("i", c.getLocal("n")));
|
||||
f.addCode(c.block(c.loop(
|
||||
// c.call("f1m_add", c.i32_const(pR2), c.i32_const(pR2), c.i32_const(pAux1)),
|
||||
c.call("f1m_mul", c.i32_const(pR2), c.i32_const(pR2), c.i32_const(pAux1)),
|
||||
// c.call("int_div", c.i32_const(pR2), c.i32_const(pR3), c.i32_const(pAux1), c.i32_const(0)),
|
||||
c.setLocal("i", c.i32_sub(c.getLocal("i"), c.i32_const(1))),
|
||||
c.br_if(1, c.i32_eqz ( c.getLocal("i") )),
|
||||
c.br(0)
|
||||
)));
|
||||
}
|
||||
|
||||
buildTestF1();
|
||||
module.exportFunction("testF1");
|
||||
};
|
47
src/build_testg1.js
Normal file
47
src/build_testg1.js
Normal file
@ -0,0 +1,47 @@
|
||||
/*
|
||||
Copyright 2019 0KIMS association.
|
||||
|
||||
This file is part of websnark (Web Assembly zkSnark Prover).
|
||||
|
||||
websnark is a free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
websnark is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with websnark. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
const bigInt = require("big-integer");
|
||||
|
||||
module.exports = function buildTestAddG1(module) {
|
||||
|
||||
function buildTestAddG1() {
|
||||
const f = module.addFunction("testAddG1");
|
||||
f.addParam("n", "i32");
|
||||
f.addParam("pP", "i32");
|
||||
f.addParam("pR", "i32");
|
||||
f.addLocal("i", "i32");
|
||||
|
||||
const c = f.getCodeBuilder();
|
||||
|
||||
f.addCode(c.call("g1_zero", c.getLocal("pR")));
|
||||
|
||||
f.addCode(c.setLocal("i", c.getLocal("n")));
|
||||
f.addCode(c.block(c.loop(
|
||||
c.call("g1_add", c.getLocal("pP"), c.getLocal("pR"), c.getLocal("pR")),
|
||||
c.setLocal("i", c.i32_sub(c.getLocal("i"), c.i32_const(1))),
|
||||
c.br_if(1, c.i32_eqz ( c.getLocal("i") )),
|
||||
c.br(0)
|
||||
)));
|
||||
}
|
||||
|
||||
buildTestAddG1();
|
||||
module.exportFunction("testAddG1");
|
||||
};
|
||||
|
80
src/build_timesscalar.js
Normal file
80
src/build_timesscalar.js
Normal file
@ -0,0 +1,80 @@
|
||||
/*
|
||||
Copyright 2019 0KIMS association.
|
||||
|
||||
This file is part of websnark (Web Assembly zkSnark Prover).
|
||||
|
||||
websnark is a free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
websnark is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with websnark. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
module.exports = function buildTimesScalar(module, fnName, elementLen, opAB, opAA, fPrefix) {
|
||||
|
||||
const f = module.addFunction(fnName);
|
||||
f.addParam("base", "i32");
|
||||
f.addParam("scalar", "i32");
|
||||
f.addParam("scalarLength", "i32");
|
||||
f.addParam("r", "i32");
|
||||
f.addLocal("i", "i32");
|
||||
f.addLocal("b", "i32");
|
||||
|
||||
const c = f.getCodeBuilder();
|
||||
|
||||
const aux = c.i32_const(module.alloc(elementLen));
|
||||
|
||||
f.addCode(c.call(fPrefix + "_copy", c.getLocal("base"), aux));
|
||||
|
||||
f.addCode(c.call(fPrefix + "_zero", c.getLocal("r")));
|
||||
|
||||
f.addCode(c.setLocal("i", c.getLocal("scalarLength")));
|
||||
f.addCode(c.block(c.loop(
|
||||
c.setLocal("i", c.i32_sub(c.getLocal("i"), c.i32_const(1))),
|
||||
|
||||
c.setLocal(
|
||||
"b",
|
||||
c.i32_load8_u(
|
||||
c.i32_add(
|
||||
c.getLocal("scalar"),
|
||||
c.getLocal("i")
|
||||
)
|
||||
)
|
||||
),
|
||||
...innerLoop(),
|
||||
c.br_if(1, c.i32_eqz ( c.getLocal("i") )),
|
||||
c.br(0)
|
||||
)));
|
||||
|
||||
|
||||
function innerLoop() {
|
||||
const code = [];
|
||||
for (let i=0; i<8; i++) {
|
||||
code.push(
|
||||
...c.call(opAA, c.getLocal("r"), c.getLocal("r")),
|
||||
...c.if(
|
||||
c.i32_ge_u( c.getLocal("b"), c.i32_const(0x80 >> i)),
|
||||
[
|
||||
...c.setLocal(
|
||||
"b",
|
||||
c.i32_sub(
|
||||
c.getLocal("b"),
|
||||
c.i32_const(0x80 >> i)
|
||||
)
|
||||
),
|
||||
...c.call(opAB, aux, c.getLocal("r"), c.getLocal("r"))
|
||||
]
|
||||
)
|
||||
);
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
||||
};
|
153
src/f1.js
Normal file
153
src/f1.js
Normal file
@ -0,0 +1,153 @@
|
||||
/*
|
||||
Copyright 2019 0KIMS association.
|
||||
|
||||
This file is part of websnark (Web Assembly zkSnark Prover).
|
||||
|
||||
websnark is a free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
websnark is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with websnark. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* globals WebAssembly */
|
||||
const bigInt = require("big-integer");
|
||||
const ModuleBuilder = require("wasmbuilder");
|
||||
const buildF1 = require("./build_f1.js");
|
||||
const buildTestF1 = require("./build_testf1.js");
|
||||
|
||||
async function build(q) {
|
||||
const f1 = new F1(q);
|
||||
|
||||
f1.q = bigInt(q);
|
||||
f1.n64 = Math.floor((f1.q.minus(1).bitLength() - 1)/64) +1;
|
||||
f1.n32 = f1.n64*2;
|
||||
f1.n8 = f1.n64*8;
|
||||
|
||||
f1.memory = new WebAssembly.Memory({initial:1});
|
||||
f1.i32 = new Uint32Array(f1.memory.buffer);
|
||||
|
||||
const moduleBuilder = new ModuleBuilder();
|
||||
buildF1(moduleBuilder, f1.q);
|
||||
buildTestF1(moduleBuilder);
|
||||
|
||||
const code = moduleBuilder.build();
|
||||
|
||||
const wasmModule = await WebAssembly.compile(code);
|
||||
|
||||
f1.instance = await WebAssembly.instantiate(wasmModule, {
|
||||
env: {
|
||||
"memory": f1.memory
|
||||
}
|
||||
});
|
||||
|
||||
Object.assign(f1, f1.instance.exports);
|
||||
|
||||
return f1;
|
||||
}
|
||||
|
||||
class F1 {
|
||||
|
||||
constructor() {
|
||||
|
||||
}
|
||||
|
||||
alloc(length) {
|
||||
const res = this.i32[0];
|
||||
this.i32[0] += length;
|
||||
return res;
|
||||
}
|
||||
|
||||
putInt(pos, _a) {
|
||||
const a = bigInt(_a);
|
||||
if (pos & 0x7) throw new Error("Pointer must be aligned");
|
||||
if (a.bitLength > this.n64*64) {
|
||||
return this.putInt(a.mod(this.q));
|
||||
}
|
||||
for (let i=0; i<this.n32; i++) {
|
||||
this.i32[(pos>>2)+i] = a.shiftRight(i*32).and(0xFFFFFFFF).toJSNumber();
|
||||
}
|
||||
}
|
||||
|
||||
allocInt(_a) {
|
||||
const p = this.alloc(this.n8);
|
||||
if (_a) this.putInt(p, _a);
|
||||
return p;
|
||||
}
|
||||
|
||||
putInt2(pos, _a) {
|
||||
const a = bigInt(_a);
|
||||
if (pos & 0x7) throw new Error("Pointer must be aligned");
|
||||
if (a.bitLength > this.n64*64*2) {
|
||||
return this.putInt(a.mod(this.q));
|
||||
}
|
||||
for (let i=0; i<this.n32*2; i++) {
|
||||
this.i32[(pos>>2)+i] = a.shiftRight(i*32).and(0xFFFFFFFF).toJSNumber();
|
||||
}
|
||||
}
|
||||
|
||||
getInt(pos) {
|
||||
if (pos & 0x7) throw new Error("Pointer must be aligned");
|
||||
let acc = bigInt(this.i32[(pos>>2)+this.n32-1]);
|
||||
for (let i=this.n32-2; i>=0; i--) {
|
||||
acc = acc.shiftLeft(32);
|
||||
acc = acc.add(this.i32[(pos>>2)+i]);
|
||||
}
|
||||
return acc;
|
||||
}
|
||||
|
||||
getInt2(pos) {
|
||||
if (pos & 0x7) throw new Error("Pointer must be aligned");
|
||||
const last = this.n32*2-1;
|
||||
let acc = bigInt(this.i32[(pos>>2)+last]);
|
||||
for (let i=last; i>=0; i--) {
|
||||
acc = acc.shiftLeft(32);
|
||||
acc = acc.add(this.i32[(pos>>2)+i]);
|
||||
}
|
||||
return acc;
|
||||
}
|
||||
|
||||
allocInt2(_a) {
|
||||
const p = this.alloc(this.n8*2);
|
||||
if (_a) this.putInt2(p, _a);
|
||||
return p;
|
||||
}
|
||||
|
||||
test_F1(n) {
|
||||
const start = new Date().getTime();
|
||||
|
||||
this.instance.exports.testF1(n);
|
||||
|
||||
const end = new Date().getTime();
|
||||
const time = end - start;
|
||||
|
||||
return time;
|
||||
}
|
||||
/*
|
||||
function test(n) {
|
||||
|
||||
const q = 21888242871839275222246405745257275088696311157297823662689037894645226208583n;
|
||||
let a = (1n << 512n)%q ;
|
||||
let b = a >> 128n;
|
||||
|
||||
let c;
|
||||
|
||||
const start = new Date().getTime();
|
||||
for (let i=0; i<n; i++) c = a+b;
|
||||
|
||||
const end = new Date().getTime();
|
||||
const time = end - start;
|
||||
|
||||
console.log(time);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
module.exports = build;
|
593
src/groth16.js
Normal file
593
src/groth16.js
Normal file
@ -0,0 +1,593 @@
|
||||
/*
|
||||
Copyright 2019 0KIMS association.
|
||||
|
||||
This file is part of websnark (Web Assembly zkSnark Prover).
|
||||
|
||||
websnark is a free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
websnark is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with websnark. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* globals WebAssembly, Blob, Worker, navigator, Promise, window */
|
||||
const bigInt = require("big-integer");
|
||||
const groth16_wasm = require("../build/groth16_wasm.js");
|
||||
const assert = require("assert");
|
||||
|
||||
const inBrowser = (typeof window !== "undefined");
|
||||
let NodeWorker;
|
||||
let NodeCrypto;
|
||||
if (!inBrowser) {
|
||||
NodeWorker = require("worker_threads").Worker;
|
||||
NodeCrypto = require("crypto");
|
||||
}
|
||||
|
||||
|
||||
class Deferred {
|
||||
constructor() {
|
||||
this.promise = new Promise((resolve, reject)=> {
|
||||
this.reject = reject;
|
||||
this.resolve = resolve;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
function delay(ms) {
|
||||
return new Promise(resolve => setTimeout(resolve, ms));
|
||||
}
|
||||
*/
|
||||
|
||||
function thread(self) {
|
||||
let instance;
|
||||
let memory;
|
||||
let i32;
|
||||
|
||||
async function init(data) {
|
||||
const code = new Uint8Array(data.code);
|
||||
const wasmModule = await WebAssembly.compile(code);
|
||||
memory = new WebAssembly.Memory({initial:data.init});
|
||||
i32 = new Uint32Array(memory.buffer);
|
||||
|
||||
instance = await WebAssembly.instantiate(wasmModule, {
|
||||
env: {
|
||||
"memory": memory
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function alloc(length) {
|
||||
while (i32[0] & 3) i32[0]++; // Return always aligned pointers
|
||||
const res = i32[0];
|
||||
i32[0] += length;
|
||||
return res;
|
||||
}
|
||||
|
||||
function putBin(b) {
|
||||
const p = alloc(b.byteLength);
|
||||
const s32 = new Uint32Array(b);
|
||||
i32.set(s32, p/4);
|
||||
return p;
|
||||
}
|
||||
|
||||
function getBin(p, l) {
|
||||
return memory.buffer.slice(p, p+l);
|
||||
}
|
||||
|
||||
self.onmessage = function(e) {
|
||||
let data;
|
||||
if (e.data) {
|
||||
data = e.data;
|
||||
} else {
|
||||
data = e;
|
||||
}
|
||||
|
||||
if (data.command == "INIT") {
|
||||
init(data).then(function() {
|
||||
self.postMessage(data.result);
|
||||
});
|
||||
} else if (data.command == "G1_MULTIEXP") {
|
||||
|
||||
const oldAlloc = i32[0];
|
||||
const pScalars = putBin(data.scalars);
|
||||
const pPoints = putBin(data.points);
|
||||
const pRes = alloc(96);
|
||||
instance.exports.g1_zero(pRes);
|
||||
instance.exports.g1_multiexp(pScalars, pPoints, data.n, 5, pRes);
|
||||
|
||||
data.result = getBin(pRes, 96);
|
||||
i32[0] = oldAlloc;
|
||||
self.postMessage(data.result, [data.result]);
|
||||
} else if (data.command == "G2_MULTIEXP") {
|
||||
|
||||
const oldAlloc = i32[0];
|
||||
const pScalars = putBin(data.scalars);
|
||||
const pPoints = putBin(data.points);
|
||||
const pRes = alloc(192);
|
||||
instance.exports.g2_zero(pRes);
|
||||
instance.exports.g2_multiexp(pScalars, pPoints, data.n, 5, pRes);
|
||||
|
||||
data.result = getBin(pRes, 192);
|
||||
i32[0] = oldAlloc;
|
||||
self.postMessage(data.result, [data.result]);
|
||||
} else if (data.command == "CALC_H") {
|
||||
const oldAlloc = i32[0];
|
||||
const pSignals = putBin(data.signals);
|
||||
const pPolsA = putBin(data.polsA);
|
||||
const pPolsB = putBin(data.polsB);
|
||||
const nSignals = data.nSignals;
|
||||
const domainSize = data.domainSize;
|
||||
const pSignalsM = alloc(nSignals*32);
|
||||
const pPolA = alloc(domainSize*32);
|
||||
const pPolB = alloc(domainSize*32);
|
||||
const pPolA2 = alloc(domainSize*32*2);
|
||||
const pPolB2 = alloc(domainSize*32*2);
|
||||
|
||||
instance.exports.fft_toMontgomeryN(pSignals, pSignalsM, nSignals);
|
||||
|
||||
instance.exports.pol_zero(pPolA, domainSize);
|
||||
instance.exports.pol_zero(pPolB, domainSize);
|
||||
|
||||
instance.exports.pol_constructLC(pPolsA, pSignalsM, nSignals, pPolA);
|
||||
instance.exports.pol_constructLC(pPolsB, pSignalsM, nSignals, pPolB);
|
||||
|
||||
instance.exports.fft_copyNInterleaved(pPolA, pPolA2, domainSize);
|
||||
instance.exports.fft_copyNInterleaved(pPolB, pPolB2, domainSize);
|
||||
|
||||
instance.exports.fft_ifft(pPolA, domainSize, 0);
|
||||
instance.exports.fft_ifft(pPolB, domainSize, 0);
|
||||
instance.exports.fft_fft(pPolA, domainSize, 1);
|
||||
instance.exports.fft_fft(pPolB, domainSize, 1);
|
||||
|
||||
instance.exports.fft_copyNInterleaved(pPolA, pPolA2+32, domainSize);
|
||||
instance.exports.fft_copyNInterleaved(pPolB, pPolB2+32, domainSize);
|
||||
|
||||
instance.exports.fft_mulN(pPolA2, pPolB2, domainSize*2, pPolA2);
|
||||
|
||||
instance.exports.fft_ifft(pPolA2, domainSize*2, 0);
|
||||
|
||||
instance.exports.fft_fromMontgomeryN(pPolA2+domainSize*32, pPolA2+domainSize*32, nSignals);
|
||||
|
||||
data.result = getBin(pPolA2+domainSize*32, domainSize*32);
|
||||
i32[0] = oldAlloc;
|
||||
self.postMessage(data.result, [data.result]);
|
||||
} else if (data.command == "TERMINATE") {
|
||||
process.exit();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
async function build() {
|
||||
|
||||
const groth16 = new Groth16();
|
||||
|
||||
groth16.q = bigInt("21888242871839275222246405745257275088696311157297823662689037894645226208583");
|
||||
groth16.r = bigInt("21888242871839275222246405745257275088548364400416034343698204186575808495617");
|
||||
groth16.n64 = Math.floor((groth16.q.minus(1).bitLength() - 1)/64) +1;
|
||||
groth16.n32 = groth16.n64*2;
|
||||
groth16.n8 = groth16.n64*8;
|
||||
|
||||
groth16.memory = new WebAssembly.Memory({initial:1000});
|
||||
groth16.i32 = new Uint32Array(groth16.memory.buffer);
|
||||
|
||||
const wasmModule = await WebAssembly.compile(groth16_wasm.code);
|
||||
|
||||
groth16.instance = await WebAssembly.instantiate(wasmModule, {
|
||||
env: {
|
||||
"memory": groth16.memory
|
||||
}
|
||||
});
|
||||
|
||||
groth16.pq = groth16_wasm.pq;
|
||||
groth16.pr = groth16_wasm.pr;
|
||||
|
||||
groth16.pr0 = groth16.alloc(192);
|
||||
groth16.pr1 = groth16.alloc(192);
|
||||
|
||||
groth16.workers = [];
|
||||
groth16.pendingDeferreds = [];
|
||||
groth16.working = [];
|
||||
|
||||
let concurrency;
|
||||
|
||||
if ((typeof(navigator) === "object") && navigator.hardwareConcurrency) {
|
||||
concurrency = navigator.hardwareConcurrency;
|
||||
} else {
|
||||
concurrency = 8;
|
||||
}
|
||||
|
||||
function getOnMsg(i) {
|
||||
return function(e) {
|
||||
let data;
|
||||
if ((e)&&(e.data)) {
|
||||
data = e.data;
|
||||
} else {
|
||||
data = e;
|
||||
}
|
||||
|
||||
groth16.working[i]=false;
|
||||
groth16.pendingDeferreds[i].resolve(data);
|
||||
groth16.processWorks();
|
||||
};
|
||||
}
|
||||
|
||||
for (let i = 0; i<concurrency; i++) {
|
||||
|
||||
if (inBrowser) {
|
||||
const blob = new Blob(["(", thread.toString(), ")(self);"], { type: "text/javascript" });
|
||||
const url = URL.createObjectURL(blob);
|
||||
|
||||
groth16.workers[i] = new Worker(url);
|
||||
|
||||
groth16.workers[i].onmessage = getOnMsg(i);
|
||||
|
||||
} else {
|
||||
groth16.workers[i] = new NodeWorker("(" + thread.toString()+ ")(require('worker_threads').parentPort);", {eval: true});
|
||||
|
||||
groth16.workers[i].on("message", getOnMsg(i));
|
||||
}
|
||||
|
||||
groth16.working[i]=false;
|
||||
}
|
||||
|
||||
const initPromises = [];
|
||||
for (let i=0; i<groth16.workers.length;i++) {
|
||||
const copyCode = groth16_wasm.code.buffer.slice(0);
|
||||
initPromises.push(groth16.postAction(i, {
|
||||
command: "INIT",
|
||||
init: 1000,
|
||||
code: copyCode
|
||||
|
||||
}, [copyCode]));
|
||||
}
|
||||
|
||||
await Promise.all(initPromises);
|
||||
|
||||
return groth16;
|
||||
}
|
||||
|
||||
class Groth16 {
|
||||
constructor() {
|
||||
this.actionQueue = [];
|
||||
}
|
||||
|
||||
postAction(workerId, e, transfers, _deferred) {
|
||||
assert(this.working[workerId] == false);
|
||||
this.working[workerId] = true;
|
||||
|
||||
this.pendingDeferreds[workerId] = _deferred ? _deferred : new Deferred();
|
||||
this.workers[workerId].postMessage(e, transfers);
|
||||
|
||||
return this.pendingDeferreds[workerId].promise;
|
||||
}
|
||||
|
||||
processWorks() {
|
||||
for (let i=0; (i<this.workers.length)&&(this.actionQueue.length > 0); i++) {
|
||||
if (this.working[i] == false) {
|
||||
const work = this.actionQueue.shift();
|
||||
this.postAction(i, work.data, work.transfers, work.deferred);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
queueAction(actionData, transfers) {
|
||||
const d = new Deferred();
|
||||
this.actionQueue.push({
|
||||
data: actionData,
|
||||
transfers: transfers,
|
||||
deferred: d
|
||||
});
|
||||
this.processWorks();
|
||||
return d.promise;
|
||||
}
|
||||
|
||||
alloc(length) {
|
||||
while (this.i32[0] & 3) this.i32[0]++; // Return always aligned pointers
|
||||
const res = this.i32[0];
|
||||
this.i32[0] += length;
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
putBin(p, b) {
|
||||
const s32 = new Uint32Array(b);
|
||||
this.i32.set(s32, p/4);
|
||||
}
|
||||
|
||||
getBin(p, l) {
|
||||
return this.memory.buffer.slice(p, p+l);
|
||||
}
|
||||
|
||||
bin2int(b) {
|
||||
const i32 = new Uint32Array(b);
|
||||
let acc = bigInt(i32[7]);
|
||||
for (let i=6; i>=0; i--) {
|
||||
acc = acc.shiftLeft(32);
|
||||
acc = acc.add(i32[i]);
|
||||
}
|
||||
return acc.toString();
|
||||
}
|
||||
|
||||
bin2g1(b) {
|
||||
return [
|
||||
this.bin2int(b.slice(0,32)),
|
||||
this.bin2int(b.slice(32,64)),
|
||||
this.bin2int(b.slice(64,96)),
|
||||
];
|
||||
}
|
||||
bin2g2(b) {
|
||||
return [
|
||||
[
|
||||
this.bin2int(b.slice(0,32)),
|
||||
this.bin2int(b.slice(32,64))
|
||||
],
|
||||
[
|
||||
this.bin2int(b.slice(64,96)),
|
||||
this.bin2int(b.slice(96,128))
|
||||
],
|
||||
[
|
||||
this.bin2int(b.slice(128,160)),
|
||||
this.bin2int(b.slice(160,192))
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
async g1_multiexp(scalars, points) {
|
||||
const nPoints = scalars.byteLength /32;
|
||||
const nPointsPerThread = Math.floor(nPoints / this.workers.length);
|
||||
const opPromises = [];
|
||||
for (let i=0; i<this.workers.length; i++) {
|
||||
const th_nPoints =
|
||||
i < this.workers.length -1 ?
|
||||
nPointsPerThread :
|
||||
nPoints - (nPointsPerThread * (this.workers.length -1));
|
||||
const scalars_th = scalars.slice(i*nPointsPerThread*32, i*nPointsPerThread*32 + th_nPoints*32);
|
||||
const points_th = points.slice(i*nPointsPerThread*64, i*nPointsPerThread*64 + th_nPoints*64);
|
||||
opPromises.push(
|
||||
this.queueAction({
|
||||
command: "G1_MULTIEXP",
|
||||
scalars: scalars_th,
|
||||
points: points_th,
|
||||
n: th_nPoints
|
||||
}, [scalars_th, points_th])
|
||||
);
|
||||
}
|
||||
|
||||
const results = await Promise.all(opPromises);
|
||||
|
||||
this.instance.exports.g1_zero(this.pr0);
|
||||
for (let i=0; i<results.length; i++) {
|
||||
this.putBin(this.pr1, results[i]);
|
||||
this.instance.exports.g1_add(this.pr0, this.pr1, this.pr0);
|
||||
}
|
||||
|
||||
return this.getBin(this.pr0, 96);
|
||||
}
|
||||
|
||||
async g2_multiexp(scalars, points) {
|
||||
const nPoints = scalars.byteLength /32;
|
||||
const nPointsPerThread = Math.floor(nPoints / this.workers.length);
|
||||
const opPromises = [];
|
||||
for (let i=0; i<this.workers.length; i++) {
|
||||
const th_nPoints =
|
||||
i < this.workers.length -1 ?
|
||||
nPointsPerThread :
|
||||
nPoints - (nPointsPerThread * (this.workers.length -1));
|
||||
const scalars_th = scalars.slice(i*nPointsPerThread*32, i*nPointsPerThread*32 + th_nPoints*32);
|
||||
const points_th = points.slice(i*nPointsPerThread*128, i*nPointsPerThread*128 + th_nPoints*128);
|
||||
opPromises.push(
|
||||
this.queueAction({
|
||||
command: "G2_MULTIEXP",
|
||||
scalars: scalars_th,
|
||||
points: points_th,
|
||||
n: th_nPoints
|
||||
}, [scalars_th, points_th])
|
||||
);
|
||||
}
|
||||
|
||||
const results = await Promise.all(opPromises);
|
||||
|
||||
this.instance.exports.g2_zero(this.pr0);
|
||||
for (let i=0; i<results.length; i++) {
|
||||
this.putBin(this.pr1, results[i]);
|
||||
this.instance.exports.g2_add(this.pr0, this.pr1, this.pr0);
|
||||
}
|
||||
|
||||
return this.getBin(this.pr0, 192);
|
||||
}
|
||||
|
||||
g1_affine(p) {
|
||||
this.putBin(this.pr0, p);
|
||||
this.instance.exports.g1_affine(this.pr0, this.pr0);
|
||||
return this.getBin(this.pr0, 96);
|
||||
}
|
||||
|
||||
g2_affine(p) {
|
||||
this.putBin(this.pr0, p);
|
||||
this.instance.exports.g2_affine(this.pr0, this.pr0);
|
||||
return this.getBin(this.pr0, 192);
|
||||
}
|
||||
|
||||
g1_fromMontgomery(p) {
|
||||
this.putBin(this.pr0, p);
|
||||
this.instance.exports.g1_fromMontgomery(this.pr0, this.pr0);
|
||||
return this.getBin(this.pr0, 96);
|
||||
}
|
||||
|
||||
g2_fromMontgomery(p) {
|
||||
this.putBin(this.pr0, p);
|
||||
this.instance.exports.g2_fromMontgomery(this.pr0, this.pr0);
|
||||
return this.getBin(this.pr0, 192);
|
||||
}
|
||||
|
||||
loadPoint1(b) {
|
||||
const p = this.alloc(96);
|
||||
this.putBin(p, b);
|
||||
this.instance.exports.f1m_one(p+64);
|
||||
return p;
|
||||
}
|
||||
|
||||
loadPoint2(b) {
|
||||
const p = this.alloc(192);
|
||||
this.putBin(p, b);
|
||||
this.instance.exports.f2m_one(p+128);
|
||||
return p;
|
||||
}
|
||||
|
||||
terminate() {
|
||||
for (let i=0; i<this.workers.length; i++) {
|
||||
this.workers[i].postMessage({command: "TERMINATE"});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
async calcH(signals, polsA, polsB, nSignals, domainSize) {
|
||||
return this.queueAction({
|
||||
command: "CALC_H",
|
||||
signals: signals,
|
||||
polsA: polsA,
|
||||
polsB: polsB,
|
||||
nSignals: nSignals,
|
||||
domainSize: domainSize
|
||||
}, [signals, polsA, polsB]);
|
||||
}
|
||||
|
||||
async proof(signals, pkey) {
|
||||
const pkey32 = new Uint32Array(pkey);
|
||||
const nSignals = pkey32[0];
|
||||
const nPublic = pkey32[1];
|
||||
const domainSize = pkey32[2];
|
||||
const pPolsA = pkey32[3];
|
||||
const pPolsB = pkey32[4];
|
||||
const pPointsA = pkey32[5];
|
||||
const pPointsB1 = pkey32[6];
|
||||
const pPointsB2 = pkey32[7];
|
||||
const pPointsC = pkey32[8];
|
||||
const pHExps = pkey32[9];
|
||||
const polsA = pkey.slice(pPolsA, pPolsA + pPolsB);
|
||||
const polsB = pkey.slice(pPolsB, pPolsB + pPointsA);
|
||||
const pointsA = pkey.slice(pPointsA, pPointsA + nSignals*64);
|
||||
const pointsB1 = pkey.slice(pPointsB1, pPointsB1 + nSignals*64);
|
||||
const pointsB2 = pkey.slice(pPointsB2, pPointsB2 + nSignals*128);
|
||||
const pointsC = pkey.slice(pPointsC, pPointsC + (nSignals-nPublic-1)*64);
|
||||
const pointsHExps = pkey.slice(pHExps, pHExps + domainSize*64);
|
||||
|
||||
const alfa1 = pkey.slice(10*4, 10*4 + 64);
|
||||
const beta1 = pkey.slice(10*4 + 64, 10*4 + 128);
|
||||
const delta1 = pkey.slice(10*4 + 128, 10*4 + 192);
|
||||
const beta2 = pkey.slice(10*4 + 192, 10*4 + 320);
|
||||
const delta2 = pkey.slice(10*4 + 320, 10*4 + 448);
|
||||
|
||||
|
||||
const pH = this.calcH(signals.slice(0), polsA, polsB, nSignals, domainSize).then( (h) => {
|
||||
return this.g1_multiexp(h, pointsHExps);
|
||||
});
|
||||
|
||||
const pA = this.g1_multiexp(signals.slice(0), pointsA);
|
||||
const pB1 = this.g1_multiexp(signals.slice(0), pointsB1);
|
||||
const pB2 = this.g2_multiexp(signals.slice(0), pointsB2);
|
||||
const pC = this.g1_multiexp(signals.slice((nPublic+1)*32), pointsC);
|
||||
|
||||
const res = await Promise.all([pA, pB1, pB2, pC, pH]);
|
||||
|
||||
const pi_a = this.alloc(96);
|
||||
const pi_b = this.alloc(192);
|
||||
const pi_c = this.alloc(96);
|
||||
const pib1 = this.alloc(96);
|
||||
|
||||
|
||||
this.putBin(pi_a, res[0]);
|
||||
this.putBin(pib1, res[1]);
|
||||
this.putBin(pi_b, res[2]);
|
||||
this.putBin(pi_c, res[3]);
|
||||
|
||||
const pAlfa1 = this.loadPoint1(alfa1);
|
||||
const pBeta1 = this.loadPoint1(beta1);
|
||||
const pDelta1 = this.loadPoint1(delta1);
|
||||
const pBeta2 = this.loadPoint2(beta2);
|
||||
const pDelta2 = this.loadPoint2(delta2);
|
||||
|
||||
|
||||
let rnd = new Uint32Array(8);
|
||||
|
||||
const aux1 = this.alloc(96);
|
||||
const aux2 = this.alloc(192);
|
||||
|
||||
const pr = this.alloc(32);
|
||||
const ps = this.alloc(32);
|
||||
|
||||
if (inBrowser) {
|
||||
window.crypto.getRandomValues(rnd);
|
||||
this.putBin(pr, rnd);
|
||||
|
||||
window.crypto.getRandomValues(rnd);
|
||||
this.putBin(ps, rnd);
|
||||
} else {
|
||||
const br = NodeCrypto.randomBytes(32);
|
||||
this.putBin(pr, br);
|
||||
const bs = NodeCrypto.randomBytes(32);
|
||||
this.putBin(ps, bs);
|
||||
}
|
||||
|
||||
// pi_a = pi_a + Alfa1 + r*Delta1
|
||||
this.instance.exports.g1_add(pAlfa1, pi_a, pi_a);
|
||||
this.instance.exports.g1_timesScalar(pDelta1, pr, 32, aux1);
|
||||
this.instance.exports.g1_add(aux1, pi_a, pi_a);
|
||||
|
||||
// pi_b = pi_b + Beta2 + s*Delta2
|
||||
this.instance.exports.g2_add(pBeta2, pi_b, pi_b);
|
||||
this.instance.exports.g2_timesScalar(pDelta2, ps, 32, aux2);
|
||||
this.instance.exports.g2_add(aux2, pi_b, pi_b);
|
||||
|
||||
// pib1 = pib1 + Beta1 + s*Delta1
|
||||
this.instance.exports.g1_add(pBeta1, pib1, pib1);
|
||||
this.instance.exports.g1_timesScalar(pDelta1, ps, 32, aux1);
|
||||
this.instance.exports.g1_add(aux1, pib1, pib1);
|
||||
|
||||
|
||||
// pi_c = pi_c + pH
|
||||
this.putBin(aux1, res[4]);
|
||||
this.instance.exports.g1_add(aux1, pi_c, pi_c);
|
||||
|
||||
// pi_c = pi_c + s*pi_a
|
||||
this.instance.exports.g1_timesScalar(pi_a, ps, 32, aux1);
|
||||
this.instance.exports.g1_add(aux1, pi_c, pi_c);
|
||||
|
||||
// pi_c = pi_c + r*pib1
|
||||
this.instance.exports.g1_timesScalar(pib1, pr, 32, aux1);
|
||||
this.instance.exports.g1_add(aux1, pi_c, pi_c);
|
||||
|
||||
// pi_c = pi_c - r*s*delta1
|
||||
const prs = this.alloc(64);
|
||||
this.instance.exports.int_mul(pr, ps, prs);
|
||||
this.instance.exports.g1_timesScalar(pDelta1, prs, 64, aux1);
|
||||
this.instance.exports.g1_neg(aux1, aux1);
|
||||
this.instance.exports.g1_add(aux1, pi_c, pi_c);
|
||||
|
||||
this.instance.exports.g1_affine(pi_a, pi_a);
|
||||
this.instance.exports.g2_affine(pi_b, pi_b);
|
||||
this.instance.exports.g1_affine(pi_c, pi_c);
|
||||
|
||||
this.instance.exports.g1_fromMontgomery(pi_a, pi_a);
|
||||
this.instance.exports.g2_fromMontgomery(pi_b, pi_b);
|
||||
this.instance.exports.g1_fromMontgomery(pi_c, pi_c);
|
||||
|
||||
return {
|
||||
pi_a: this.bin2g1(this.getBin(pi_a, 96)),
|
||||
pi_b: this.bin2g2(this.getBin(pi_b, 192)),
|
||||
pi_c: this.bin2g1(this.getBin(pi_c, 96)),
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = build;
|
40
src/utils.js
Normal file
40
src/utils.js
Normal file
@ -0,0 +1,40 @@
|
||||
/*
|
||||
Copyright 2019 0KIMS association.
|
||||
|
||||
This file is part of websnark (Web Assembly zkSnark Prover).
|
||||
|
||||
websnark is a free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
websnark is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with websnark. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
const bigInt = require("big-integer");
|
||||
|
||||
exports.bigInt2BytesLE = function bigInt2BytesLE(_a, len) {
|
||||
const b = Array(len);
|
||||
let v = bigInt(_a);
|
||||
for (let i=0; i<len; i++) {
|
||||
b[i] = v.and(0xFF).toJSNumber();
|
||||
v = v.shiftRight(8);
|
||||
}
|
||||
return b;
|
||||
};
|
||||
|
||||
exports.bigInt2U32LE = function bigInt2BytesLE(_a, len) {
|
||||
const b = Array(len);
|
||||
let v = bigInt(_a);
|
||||
for (let i=0; i<len; i++) {
|
||||
b[i] = v.and(0xFFFFFFFF).toJSNumber();
|
||||
v = v.shiftRight(32);
|
||||
}
|
||||
return b;
|
||||
};
|
147
test/bn128.js
Normal file
147
test/bn128.js
Normal file
@ -0,0 +1,147 @@
|
||||
const assert = require("assert");
|
||||
const refBn128 = require("snarkjs").bn128;
|
||||
const refBigInt = require("snarkjs").bigInt;
|
||||
|
||||
const buildBn128 = require("../index.js").buildBn128;
|
||||
|
||||
describe("Basic tests for g1 in bn128", () => {
|
||||
it("It should do a basic point doubling G1", async () => {
|
||||
const bn128 = await buildBn128();
|
||||
const refD = refBn128.G1.double(refBn128.g1);
|
||||
|
||||
const p1 = bn128.g1_allocPoint(refBn128.g1);
|
||||
bn128.g1_toMontgomery(p1, p1);
|
||||
bn128.g1_double(p1, p1);
|
||||
bn128.g1_fromMontgomery(p1, p1);
|
||||
const d = bn128.g1_getPoint(p1);
|
||||
|
||||
for (let i=0; i<3; i++) {
|
||||
d[i] = refBigInt(d[i].toString());
|
||||
}
|
||||
|
||||
assert(refBn128.G1.equals(d, refD));
|
||||
});
|
||||
it("It should add two points G1", async () => {
|
||||
const bn128 = await buildBn128();
|
||||
const refD = refBn128.G1.affine(refBn128.G1.mulScalar(refBn128.g1, 3));
|
||||
|
||||
const p1 = bn128.g1_allocPoint(refBn128.g1);
|
||||
bn128.g1_toMontgomery(p1, p1);
|
||||
bn128.g1_double(p1, p1);
|
||||
const p2 = bn128.g1_allocPoint(refBn128.g1);
|
||||
bn128.g1_toMontgomery(p2, p2);
|
||||
bn128.g1_add(p1, p2, p2);
|
||||
bn128.g1_affine(p2, p2);
|
||||
bn128.g1_fromMontgomery(p2, p2);
|
||||
const d = bn128.g1_getPoint(p2);
|
||||
|
||||
d[0] = refBigInt(d[0].toString());
|
||||
d[1] = refBigInt(d[1].toString());
|
||||
d[2] = refBigInt(d[2].toString());
|
||||
|
||||
|
||||
assert(d[0].equals(refD[0]));
|
||||
assert(d[1].equals(refD[1]));
|
||||
assert(d[2].equals(1));
|
||||
|
||||
assert(refBn128.G1.equals(d, refD));
|
||||
});
|
||||
it("It should timesScalar G1", async () => {
|
||||
const bn128 = await buildBn128();
|
||||
const refD = refBn128.G1.mulScalar(refBn128.g1, 55);
|
||||
|
||||
const p1 = bn128.g1_allocPoint(refBn128.g1);
|
||||
bn128.g1_toMontgomery(p1, p1);
|
||||
|
||||
const s = bn128.allocInt(55);
|
||||
bn128.g1_timesScalar(p1, s, 32, p1);
|
||||
|
||||
bn128.g1_fromMontgomery(p1, p1);
|
||||
const d = bn128.g1_getPoint(p1);
|
||||
|
||||
for (let i=0; i<3; i++) {
|
||||
d[i] = refBigInt(d[i].toString());
|
||||
}
|
||||
|
||||
assert(refBn128.G1.equals(d, refD));
|
||||
});
|
||||
it("G1n == 0", async () => {
|
||||
const bn128 = await buildBn128();
|
||||
|
||||
const p1 = bn128.g1_allocPoint(refBn128.g1);
|
||||
bn128.g1_toMontgomery(p1, p1);
|
||||
|
||||
const s = bn128.allocInt(bn128.r);
|
||||
bn128.g1_timesScalar(p1, s, 32, p1);
|
||||
|
||||
bn128.g1_fromMontgomery(p1, p1);
|
||||
|
||||
assert(bn128.g1_isZero(p1));
|
||||
});
|
||||
it("It should do a test", async () => {
|
||||
const bn128 = await buildBn128();
|
||||
|
||||
const t = bn128.test_AddG1(100000);
|
||||
|
||||
console.log(t);
|
||||
}).timeout(10000000);
|
||||
it("It should validate the test", async () => {
|
||||
const bn128 = await buildBn128();
|
||||
const refD = refBn128.G1.mulScalar(refBn128.g1, 100000);
|
||||
|
||||
const p1 = bn128.g1_allocPoint(refBn128.g1);
|
||||
bn128.g1_toMontgomery(p1, p1);
|
||||
const p2 = bn128.g1_allocPoint();
|
||||
bn128.testAddG1(100000, p1, p2);
|
||||
bn128.g1_fromMontgomery(p2, p2);
|
||||
const d = bn128.g1_getPoint(p2);
|
||||
|
||||
for (let i=0; i<3; i++) {
|
||||
d[i] = refBigInt(d[i].toString());
|
||||
}
|
||||
|
||||
assert(refBn128.G1.equals(d, refD));
|
||||
|
||||
}).timeout(10000000);
|
||||
it("It should do a basic point doubling in G2", async () => {
|
||||
const bn128 = await buildBn128();
|
||||
const refD = refBn128.G2.double(refBn128.g2);
|
||||
|
||||
const p1 = bn128.g2_allocPoint(refBn128.g2);
|
||||
bn128.g2_toMontgomery(p1, p1);
|
||||
bn128.g2_double(p1, p1);
|
||||
bn128.g2_fromMontgomery(p1, p1);
|
||||
const d = bn128.g2_getPoint(p1);
|
||||
|
||||
for (let i=0; i<3; i++) {
|
||||
for (let j=0; j<2; j++) {
|
||||
d[i][j] = refBigInt(d[i][j].toString());
|
||||
}
|
||||
}
|
||||
|
||||
assert(refBn128.G2.equals(d, refD));
|
||||
});
|
||||
it("It should add two points in G2", async () => {
|
||||
const bn128 = await buildBn128();
|
||||
const refD = refBn128.G2.affine(refBn128.G2.mulScalar(refBn128.g2, 3));
|
||||
|
||||
const p1 = bn128.g2_allocPoint(refBn128.g2);
|
||||
bn128.g2_toMontgomery(p1, p1);
|
||||
bn128.g2_double(p1, p1);
|
||||
const p2 = bn128.g2_allocPoint(refBn128.g2);
|
||||
bn128.g2_toMontgomery(p2, p2);
|
||||
bn128.g2_add(p1, p2, p2);
|
||||
bn128.g2_affine(p2, p2);
|
||||
bn128.g2_fromMontgomery(p2, p2);
|
||||
const d = bn128.g2_getPoint(p2);
|
||||
|
||||
for (let i=0; i<3; i++) {
|
||||
for (let j=0; j<2; j++) {
|
||||
d[i][j] = refBigInt(d[i][j].toString());
|
||||
assert(d[i][j].equals(refD[i][j]));
|
||||
}
|
||||
}
|
||||
|
||||
assert(refBn128.G2.equals(d, refD));
|
||||
});
|
||||
});
|
BIN
test/data/proving_key.bin
Normal file
BIN
test/data/proving_key.bin
Normal file
Binary file not shown.
60
test/data/public.json
Normal file
60
test/data/public.json
Normal file
@ -0,0 +1,60 @@
|
||||
[
|
||||
"12195095808573067990042857686504557510035235683154016308243419405358680169250",
|
||||
"7149014917815960042505969439971619119991011354574443484106856202048948095881",
|
||||
"9164435831827345487378393454304824441756195871900421654673163382659437536500",
|
||||
"1234",
|
||||
"0",
|
||||
"16374068974774336469776493892198386626211184005839336945221081336304141111920",
|
||||
"1",
|
||||
"2610057752638682202795145288373380503107623443963127956230801721756904484787",
|
||||
"16617171478497210597712478520507818259149717466230047843969353176573634386897",
|
||||
"1790107960388390971897835168022684452552187545968846840523968533783427112708",
|
||||
"13303187477790464289185372704934741905530397009889514067884373165312221183226",
|
||||
"20934614636390406120326149903842640726858112697509676494085990398714931055996",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"11968552468543593335149856751038426364722479921732335754114707699811978359681",
|
||||
"9614565467070354290860829491102892458030262142650662112245199748688182033133",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"3900887248494684663431642341114683844061898198331562653906267847513911890751",
|
||||
"17279342286447729775991865155392847976865724336068569228942936646576478041635",
|
||||
"0"
|
||||
]
|
378
test/data/verification_key.json
Normal file
378
test/data/verification_key.json
Normal file
@ -0,0 +1,378 @@
|
||||
{
|
||||
"protocol": "groth",
|
||||
"nPublic": 58,
|
||||
"IC": [
|
||||
[
|
||||
"19526011409366579990588025301030213951715906703577073975290871624466881592401",
|
||||
"19704225241808120619466308438935447262963873917264064669080753233318969572957",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"7218481415766897306762916767110075847697992625643495798846732092896344771677",
|
||||
"1810734562057506037864970683351135446505342561419524855305385566525430554608",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"1640189422982581804826644035748296239719141803014116052080598186211151031797",
|
||||
"7781696247496343071100255748895449136227964112761638882773761539066568268925",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"1019783362851718589135884871584846731091007700702318392055072177004648561589",
|
||||
"18812499958741900484687753662765966120897029726834689506634674431261159346840",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"15561759052567336872552966722770915260975101273887034098005539514081530527925",
|
||||
"11730428660167585547193351712992338394459044787769016092386316685070099352472",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"1024450630178286178450853989597618731194658350885429138953206234739921258345",
|
||||
"7948069502311904001229660361963340784026126140723442378626252475516635024822",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"8134630773713074896857037173371019670883865326581932178449629660512993310425",
|
||||
"6162538535380093935174079566719686610557565288806461488942825301577983962127",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"8713144302139572077210052963377568333718037671811574593525902475107121219071",
|
||||
"13618940145565575426081729012812756247313835929620966248623806311505567102432",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"2208161957288886407409949471646360867727094427710349204075749603229409811551",
|
||||
"19165194795626512061280419859788136098199019550268978813401285308580039446381",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"1481335695502173099248239238900758768801091349137030249276629661318408132871",
|
||||
"5156686038021439018308366275250160506883007416398589471786874665591845100113",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"20337511777673950886185756823107347060969023608337968294278846656718023200150",
|
||||
"3997644781553846440387918107564571745476924483850609244466307282628877247562",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"10588095668159724333142658097242748201084821311539505166654240692525635653949",
|
||||
"1183100960889281823631938371556943968916169482989513163517955652814147785270",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"14899200894902404684338252010495693209614589615201102355683265977943244426004",
|
||||
"6733181143166489149612223364873851869451680106085133952329639843716177370522",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"1683537073912953978091278971997049690818520143499563010072565648446561661056",
|
||||
"19419929908654053003650694876848111465754667348310947518133436565700017002483",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"14657090907982846377445922373510406393589381865954917955559100596313207100861",
|
||||
"13642650140642299314216565478747411703974469867765487295597972222030646618581",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"16529622819344543978903257968152672100303712811187008674706734962518660200534",
|
||||
"9047308189580806381060024072651025924757275727793326189939157176373582276423",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"3080248660073481279234987580633467131838554544589313213304320336447912874502",
|
||||
"12178549914181501174961289691127530013023904264051503031309740303517490947766",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"15487788123318013174142216619036794699452999597075149645621900875574186695610",
|
||||
"1626752354094836838615855864490581912181205603023556119206923761362325487488",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"1666930804642622665542570167075210228582250288184353798587314779395900191926",
|
||||
"19705035825701732447104451708888835197574105722528610005429830999713513944135",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"6864231653145100847184101019813757441375546934931929553137150578511457821468",
|
||||
"11030717897717091434566238005756773466216938437645365639326676041449665933687",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"17708960029000737859399187469088839058910680034659542429747423649838721586318",
|
||||
"17966398620544733014948000033194587396780241478697380962648049866838729264654",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"13757192009142934986497800326740625614298535990393743419508862715438850214278",
|
||||
"21608544818365956429804089572501400134306590793845664759121305528719014468539",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"2387150367018947723453720841613212674042625869787597370012597855542196564772",
|
||||
"11695602459063663755646871470499162454273937998667584326916784819522675676030",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"3969932184785511719481056173532036069678557655561039720091342741570026295152",
|
||||
"17993913767992706963197080864583362193024219058878156591482644926890948868797",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"9423946557684255938323840651123017285324730158168043839780806631003806918939",
|
||||
"20601140822008955908584760520762447153677611366925313301286794723328845538334",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"12962476762153853692961359313770195651287320370991012193410923729342519400410",
|
||||
"16790095546018287000758153406357558316483550179182040426959851702714662233350",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"11513038453371099732062533711296648120504101464641839310671168933784980314882",
|
||||
"19906375207605336857368669180394946464921182728087574346715161382734582996091",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"2121497929168641193320430463750735744335423634358969475213438628839145775097",
|
||||
"14279619451032406093176776946256910631214549125624592712768709224713246159330",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"11226191782273968706267268899222700962751661296528346044234995849296626637818",
|
||||
"13010144704231455483130550798892383439128876102102878476813890284532924199082",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"11110550860460015317490388108081233932145530993142470924675507899413835184448",
|
||||
"16564127121244024114702603123214129039853156994745132309985985728814892932482",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"16778941937031321722070777716071699346818608459977560423095851882699057661238",
|
||||
"4697439800149822368300068885116892100711854565071104448591753229703512600800",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"15872083856166627537790395064677676672858055702693032209281782235450963069960",
|
||||
"10359824654894233948940829295414182326916813602184261612555323269593953713959",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"15247415861798118260310199809217153579347967502938862593203253520242564857778",
|
||||
"17943608471215894498734622964827265729455290707752355804444644415538765187171",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"19910646054904277798554639079332859903830938020106054338361835817749036204289",
|
||||
"14251173391661908313942511660900252216342610385205017933107964019360045794603",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"15617270263010441782314109350958570541215852291212818016021084008333418208875",
|
||||
"21881089065537370063139940701535262435555591536651612422900371838614353113281",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"6421115626779256473944138173048502514066702768381496596650324103983916504835",
|
||||
"3477316365965567489844246613122076671753354745444827471590577962440540253825",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"16473272305165140318293304721756072118952895979824993476741656445985532109687",
|
||||
"11966737459889574739163354519745663782810240444604837406970095410044504857114",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"5372377827028613665959777806978819222622231879950628237059135069445403406617",
|
||||
"10754772058946143812874307806006613255761709338906946759757401504859407645417",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"14186175579895909616185878057026760618866356046925560400399807036820346884046",
|
||||
"4815071274998802335087493250322971182140859271153573841178680570745042169758",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"18587428576009373156679145442597168345936336951096103073893982856175630643693",
|
||||
"16551515971501720092878042838225840381462545412649977468782450446861560095079",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"20092704064518140906336001291719220397791993391927049447238747943557979137332",
|
||||
"14309044514703625249681667739033504979034764749598333744088213698477089190167",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"18094211252427269277727737867758525438768651774457808013501513791100524400111",
|
||||
"1953616651202224570087320348179078176455230140050934991264156573541656440177",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"8306150994125890187737385803981541016404020628778896850769772941676552580695",
|
||||
"9692340394713555790690111046383485596714503094426824962694563185658648842716",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"2310757642461495319988919139078520159193510139788049016019877513576089825606",
|
||||
"8889867579822094460826499233108459267599315072851707155589562022968565836877",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"18308698969834252376687927943697318806874330259437519073367865794809196122421",
|
||||
"14739033668305736376862695711443548284923118719280017423642214528572384515934",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"21281456929816658128965712205802466600645879143675783709584584463978062814070",
|
||||
"11318407702446502058218573109267233739777220569151759825244543584735350643466",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"7520703426805357030477495741143669754535245601456768825659455316560615971189",
|
||||
"11716692431794868904945130966329488889062393077100622718344498934379412336473",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"12755699673150967843636678152611549820209710341861685811272938968227849444490",
|
||||
"8041405236201023920708302321965742245298279037603394500679202870952036944455",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"4767324308822656869298992811825434492721876454715254600244690065028848020971",
|
||||
"7698254074025215726826011606321771959580174521108656914865701606041868015929",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"5069108519819643877425272525791845153259463918796090785858826854873469677567",
|
||||
"19441624293073788344676145862916585919555281266024685026467295031220552700054",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"19615829997657139098357071858533416653704257439734430213792369647973566826347",
|
||||
"20354691099796661979686973753889173391948033275751613338970065504168017804337",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"11027190822371723497281530686863090859613245206871440157541315964572815271179",
|
||||
"10675136011261330036038351905981966853190049667679786632322902689639273096714",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"6073908302198369305254211170927314788182979554648782100497505455266731015204",
|
||||
"230783342774856919928214058753287925592697137855334446779967352493825837423",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"8065349080015031289241881658385531453814503979517539346801510330252327420241",
|
||||
"14735126201189209265547932564409552262152445686850481557202138107408115327464",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"6452037663171386579712621793513191966255625190206245575651250486849182460440",
|
||||
"7209242914697571385995884156916495284148841850843926922191745144563603631497",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"10593401732655136290887720645830905766352213200230343334980873391309958939320",
|
||||
"666955912278201937315337912832661869841839611440234361211929441370598456858",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"3479342154509588972525995110657563238207085236375361439444008581380409197198",
|
||||
"2842082156517941562270865475681450943187927072014071620218399830230257691351",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"692434019399694517146046655769177702432905351223416354821366078192182076820",
|
||||
"3395628146877374571895195099601711702304342467654447561346689703803124051395",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"897877668313362010234827860073421630587020756077760567259587493004095744184",
|
||||
"7566955279869906474734064013485588345675973359196540621993138844162613375198",
|
||||
"1"
|
||||
]
|
||||
],
|
||||
"vk_alfa_1": [
|
||||
"8354125022402491146096524632602954406606496454803779043544940201207527912027",
|
||||
"719066282644331645717102069170608708195162774370272260015202086661089311234",
|
||||
"1"
|
||||
],
|
||||
"vk_beta_2": [
|
||||
[
|
||||
"15819609270299917787101227421057497064555252095398692710896314899171935449228",
|
||||
"12410557311433316645833461472858428751547879560031808599488331029313135860054"
|
||||
],
|
||||
[
|
||||
"5915247915713704640408458318654604569396223348462269801166279014325877172920",
|
||||
"3151765353208434115856893997427239125947497909307782934497369635848305207349"
|
||||
],
|
||||
[
|
||||
"1",
|
||||
"0"
|
||||
]
|
||||
],
|
||||
"vk_gamma_2": [
|
||||
[
|
||||
"20998635465704765944234729848213271190298703821739579245252166965359275379567",
|
||||
"18569698049261699868049342823691041461765011065833511061731150982712719058931"
|
||||
],
|
||||
[
|
||||
"19643309731014428269860044007048729642835975708160558919248553748448226867008",
|
||||
"4057552944219884903616160090555822269203226833340888130271232201855723185188"
|
||||
],
|
||||
[
|
||||
"1",
|
||||
"0"
|
||||
]
|
||||
],
|
||||
"vk_delta_2": [
|
||||
[
|
||||
"1699455723545013724352264641481223849638169293269636387255739145105164643572",
|
||||
"10951443100057856372062056768155654835091940387457226546452206121970064287769"
|
||||
],
|
||||
[
|
||||
"18091804447302921360663814931698141642678950451776128240905512956330370630584",
|
||||
"11051171602925343050692043383444760908270199727214620699742880132687007451610"
|
||||
],
|
||||
[
|
||||
"1",
|
||||
"0"
|
||||
]
|
||||
],
|
||||
"vk_alfabeta_12": [
|
||||
[
|
||||
[
|
||||
"18723835367546013216669396584879552615309554640417855595864851968454850794686",
|
||||
"2751734539677780406895433411352652269903002350864560518448916000577298711044"
|
||||
],
|
||||
[
|
||||
"6091631998457053869677482825687515224140938572474416320681319181954212930660",
|
||||
"14750817718913847167640471421588191103071235885472070890891565424818957616506"
|
||||
],
|
||||
[
|
||||
"1503045325833070525242109471593215150873992909765587341806427485400509901763",
|
||||
"19595263023959996895029566929430291188201738108321510303592033282761719078927"
|
||||
]
|
||||
],
|
||||
[
|
||||
[
|
||||
"14243067455511068097745434183222546746125426041491764346913202956845188552019",
|
||||
"17462170864881388598981702392557723387786493323913878401432726985509236575485"
|
||||
],
|
||||
[
|
||||
"15670136540447067653418982806709348681767811130611329178707663135867906047157",
|
||||
"8632459998104744185409696090239906876607793844814496641442049837459287937900"
|
||||
],
|
||||
[
|
||||
"1147927280145543088837981995583243716796018112475088793287724642814036528129",
|
||||
"15939953021942181393804832630429756290981160876828402349069996652097158880389"
|
||||
]
|
||||
]
|
||||
]
|
||||
}
|
BIN
test/data/witness.bin
Normal file
BIN
test/data/witness.bin
Normal file
Binary file not shown.
485
test/f1.js
Normal file
485
test/f1.js
Normal file
@ -0,0 +1,485 @@
|
||||
const assert = require("assert");
|
||||
const bigInt = require("big-integer");
|
||||
|
||||
const buildF1 = require("../index.js").buildF1;
|
||||
|
||||
describe("Basic tests for Zq", () => {
|
||||
it("It should do a basic addition", async () => {
|
||||
const f1 = await buildF1(101);
|
||||
|
||||
const pA = f1.allocInt(3);
|
||||
const pB = f1.allocInt(4);
|
||||
const pC = f1.allocInt();
|
||||
f1.f1_add(pA, pB, pC);
|
||||
|
||||
const c = f1.getInt(pC);
|
||||
assert.equal(c, 7);
|
||||
});
|
||||
it("Should add with 2 chunks", async () => {
|
||||
const f1 = await buildF1(bigInt("100000000000000000001", 16));
|
||||
|
||||
const pA = f1.allocInt(bigInt("FFFFFFFFFFFFFFFF", 16));
|
||||
const pB = f1.allocInt(1);
|
||||
const pC = f1.allocInt();
|
||||
|
||||
f1.f1_add(pA, pB, pC);
|
||||
const c = f1.getInt(pC);
|
||||
|
||||
assert(c.equals(bigInt("10000000000000000", 16)));
|
||||
});
|
||||
it("Should add with 2 chunks overflow", async () => {
|
||||
const q = bigInt("10000000000000001", 16);
|
||||
const f1 = await buildF1(q);
|
||||
|
||||
const pA = f1.allocInt(bigInt("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 16).mod(q));
|
||||
const pB = f1.allocInt(1);
|
||||
const pC = f1.allocInt();
|
||||
|
||||
f1.f1_add(pA, pB, pC);
|
||||
const c = f1.getInt(pC);
|
||||
|
||||
assert(c.equals(1));
|
||||
});
|
||||
it("Should add with double overflow", async () => {
|
||||
const q = bigInt(1).shiftLeft(255).add(1);
|
||||
const a = bigInt(1).shiftLeft(256).minus(1).mod(q);
|
||||
const f1 = await buildF1(q);
|
||||
|
||||
const pA = f1.allocInt(a);
|
||||
const pC = f1.allocInt();
|
||||
|
||||
f1.f1_add(pA, pA, pC);
|
||||
|
||||
const c = f1.getInt(pC);
|
||||
assert(c.equals(a.add(a).mod(q)));
|
||||
});
|
||||
it("It should do a basic substraction", async () => {
|
||||
const f1 = await buildF1(101);
|
||||
|
||||
const pA = f1.allocInt(5);
|
||||
const pB = f1.allocInt(3);
|
||||
const pC = f1.allocInt();
|
||||
|
||||
f1.f1_sub(pA, pB, pC);
|
||||
const c = f1.getInt(pC);
|
||||
|
||||
assert.equal(c, 2);
|
||||
});
|
||||
it("It should do a basic substraction with negative result", async () => {
|
||||
const f1 = await buildF1(101);
|
||||
|
||||
const pA = f1.allocInt(3);
|
||||
const pB = f1.allocInt(5);
|
||||
const pC = f1.allocInt();
|
||||
|
||||
f1.f1_sub(pA, pB, pC);
|
||||
const c = f1.getInt(pC);
|
||||
|
||||
assert.equal(c.mod(101), 99);
|
||||
});
|
||||
it("Should substract with 2 chunks overflow", async () => {
|
||||
const q = bigInt("10000000000000001", 16);
|
||||
const a = bigInt("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 16).mod(q);
|
||||
const f1 = await buildF1(q);
|
||||
|
||||
const pA = f1.allocInt(1);
|
||||
const pB = f1.allocInt(a);
|
||||
const pC = f1.allocInt();
|
||||
|
||||
f1.f1_sub(pA, pB, pC);
|
||||
const c = f1.getInt(pC);
|
||||
|
||||
let d = bigInt.one.minus(a).mod(q);
|
||||
if (d.isNegative()) d = d.add(q);
|
||||
|
||||
assert(c.equals(d));
|
||||
});
|
||||
it("It should Substract a big number", async () => {
|
||||
const q = bigInt("21888242871839275222246405745257275088548364400416034343698204186575808495617");
|
||||
const f1 = await buildF1(q);
|
||||
|
||||
const a = bigInt("10000242871839275222246405745257275088548364400416034343698204186575808495617");
|
||||
const b = bigInt("10000242871839275222246405745257275088548364400416034343698204186575808234523");
|
||||
|
||||
const pA = f1.allocInt(a);
|
||||
const pB = f1.allocInt(b);
|
||||
const pC = f1.allocInt();
|
||||
|
||||
f1.f1_sub(pA, pB, pC);
|
||||
const c = f1.getInt(pC);
|
||||
|
||||
let cc = a.minus(b).mod(q);
|
||||
if (cc.isNegative()) cc = cc.add(q);
|
||||
assert(cc.equals(c.mod(q)));
|
||||
|
||||
|
||||
const pAA = f1.allocInt(b);
|
||||
const pBB = f1.allocInt(a);
|
||||
const pCC = f1.allocInt();
|
||||
|
||||
f1.f1_sub(pAA, pBB, pCC);
|
||||
const d = f1.getInt(pCC);
|
||||
|
||||
let dd = b.minus(a).mod(q);
|
||||
if (dd.isNegative()) dd = dd.add(q);
|
||||
assert(dd.equals(d.mod(q)));
|
||||
});
|
||||
|
||||
it("It should do a basic multiplication", async () => {
|
||||
const f1 = await buildF1(101);
|
||||
|
||||
const pA = f1.allocInt(3);
|
||||
const pB = f1.allocInt(4);
|
||||
const pC = f1.allocInt2();
|
||||
|
||||
f1.int_mul(pA, pB, pC);
|
||||
const c = f1.getInt2(pC);
|
||||
|
||||
assert.equal(c, 12);
|
||||
});
|
||||
|
||||
it("It should do a basic division", async () => {
|
||||
const f1 = await buildF1(101);
|
||||
|
||||
const pA = f1.allocInt(12);
|
||||
const pB = f1.allocInt(6);
|
||||
const pC = f1.allocInt();
|
||||
f1.int_div(pA, pB, pC);
|
||||
|
||||
const c = f1.getInt(pC);
|
||||
assert.equal(c, 2);
|
||||
});
|
||||
it("It should do a more complex division", async () => {
|
||||
const q = bigInt("21888242871839275222246405745257275088548364400416034343698204186575808495617");
|
||||
const f1 = await buildF1(q);
|
||||
|
||||
const pA = f1.allocInt(bigInt("FFFF00000000", 16));
|
||||
const pB = f1.allocInt(bigInt("100000000", 16));
|
||||
const pC = f1.allocInt();
|
||||
f1.int_div(pA, pB, pC);
|
||||
|
||||
const c = f1.getInt(pC);
|
||||
assert(c.equals(bigInt("FFFF", 16)));
|
||||
});
|
||||
it("It should do a division by zero", async () => {
|
||||
const q = bigInt("21888242871839275222246405745257275088548364400416034343698204186575808495617");
|
||||
const f1 = await buildF1(q);
|
||||
|
||||
const pA = f1.allocInt(bigInt("FFFF00000000", 16));
|
||||
const pB = f1.allocInt(0);
|
||||
const pC = f1.allocInt();
|
||||
try {
|
||||
f1.int_div(pA, pB, pC);
|
||||
assert(false, "Didn't throw...");
|
||||
} catch (err) {
|
||||
assert.equal(err.toString(), "RuntimeError: divide by zero");
|
||||
}
|
||||
});
|
||||
|
||||
it("It should do a various division", async () => {
|
||||
const q = bigInt("21888242871839275222246405745257275088548364400416034343698204186575808495617");
|
||||
const f1 = await buildF1(q);
|
||||
|
||||
|
||||
const v= [
|
||||
bigInt.zero,
|
||||
q.minus(1),
|
||||
q.minus(2),
|
||||
q.minus(1).shiftRight(1),
|
||||
q.minus(1).shiftRight(1).add(1),
|
||||
q.minus(1).shiftRight(1).add(2),
|
||||
q.minus(1).shiftRight(1).minus(1),
|
||||
q.minus(1).shiftRight(1).minus(2),
|
||||
bigInt(bigInt("F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0", 16)),
|
||||
bigInt(bigInt("10101010101010101010101010101010", 16)),
|
||||
bigInt(bigInt("FF00FF00FF00FF00FF00FF00FF00FF00", 16)),
|
||||
bigInt(bigInt("11001100110011001100110011001100", 16)),
|
||||
bigInt(bigInt("F0F0F0F0F0F0F0F0", 16)),
|
||||
bigInt(bigInt("1010101010101010", 16)),
|
||||
bigInt(bigInt("FF00FF00FF00FF00", 16)),
|
||||
bigInt(bigInt("1100110011001100", 16)),
|
||||
bigInt(2),
|
||||
bigInt.one,
|
||||
];
|
||||
|
||||
const pA = f1.allocInt();
|
||||
const pB = f1.allocInt();
|
||||
const pC = f1.allocInt();
|
||||
const pR = f1.allocInt();
|
||||
for (let i=0; i<v.length; i++) {
|
||||
for (let j=1; j<v.length; j++) {
|
||||
const expected_c = v[i].divide(v[j]);
|
||||
const expected_r = v[i].mod(v[j]);
|
||||
|
||||
f1.putInt(pA, v[i]);
|
||||
f1.putInt(pB, v[j]);
|
||||
|
||||
f1.int_div(pA, pB, pC, pR);
|
||||
|
||||
const c = f1.getInt(pC);
|
||||
const r = f1.getInt(pR);
|
||||
|
||||
assert(expected_r.equals(r));
|
||||
assert(expected_c.equals(c));
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
it("It should do a basic reduction 1", async () => {
|
||||
const f1 = await buildF1(bigInt("FFFFFFFFFFFFFFFF",16));
|
||||
|
||||
const pA = f1.allocInt2(bigInt(0x10000000000000000));
|
||||
const pC = f1.allocInt();
|
||||
|
||||
f1.f1m_mReduct(pA, pC);
|
||||
|
||||
const c = f1.getInt(pC);
|
||||
|
||||
assert.equal(c, 1);
|
||||
});
|
||||
it("It should do a basic reduction 2", async () => {
|
||||
const q = bigInt("21888242871839275222246405745257275088548364400416034343698204186575808495617");
|
||||
const f1 = await buildF1(q);
|
||||
|
||||
const a = bigInt("10000242871839275222246405745257275088548364400416034343698204186575808495617");
|
||||
const b = bigInt("10000242871839275222246405745257275088548364400416034343698204186575808234523");
|
||||
|
||||
const pA = f1.allocInt(a);
|
||||
const pB = f1.allocInt(b);
|
||||
const pC = f1.allocInt2();
|
||||
const pD = f1.allocInt();
|
||||
|
||||
f1.int_mul(pA, pB, pC);
|
||||
const c = f1.getInt2(pC);
|
||||
|
||||
f1.f1m_mReduct(pC, pD);
|
||||
const d = f1.getInt(pD);
|
||||
|
||||
const r = bigInt.one.shiftLeft(256).mod(q);
|
||||
const r2 = r.times(r).mod(q);
|
||||
|
||||
const pR2 = f1.allocInt(r2);
|
||||
|
||||
|
||||
const pE = f1.allocInt2();
|
||||
f1.int_mul(pD, pR2, pE);
|
||||
|
||||
const pF = f1.allocInt();
|
||||
f1.f1m_mReduct(pE, pF);
|
||||
|
||||
const f = f1.getInt2(pF);
|
||||
|
||||
assert(a.times(b).mod(q).equals(f.mod(q)));
|
||||
});
|
||||
it("It should do a basic reduction 3", async () => {
|
||||
const q = bigInt("21888242871839275222246405745257275088548364400416034343698204186575808495617");
|
||||
const f1 = await buildF1(q);
|
||||
|
||||
const a = bigInt("10000242871839275222246405745257275088548364400416034343698204186575808495617");
|
||||
const b = bigInt("10000242871839275222246405745257275088548364400416034343698204186575808234523");
|
||||
|
||||
const pA = f1.allocInt(a);
|
||||
const pB = f1.allocInt(b);
|
||||
const pC = f1.allocInt();
|
||||
|
||||
f1.f1_mul(pA, pB, pC);
|
||||
|
||||
const c = f1.getInt2(pC);
|
||||
assert(a.times(b).mod(q).equals(c.mod(q)));
|
||||
});
|
||||
it("It should do various test in zq Snarks modules", async () => {
|
||||
const q = bigInt("21888242871839275222246405745257275088696311157297823662689037894645226208583");
|
||||
const f1 = await buildF1(q);
|
||||
const v= [
|
||||
q.minus(1),
|
||||
q.minus(2),
|
||||
q.minus(1).shiftRight(1),
|
||||
q.minus(1).shiftRight(1).add(1),
|
||||
q.minus(1).shiftRight(1).add(2),
|
||||
q.minus(1).shiftRight(1).minus(1),
|
||||
q.minus(1).shiftRight(1).minus(2),
|
||||
bigInt(2),
|
||||
bigInt.one,
|
||||
bigInt.zero
|
||||
];
|
||||
|
||||
const pA = f1.allocInt();
|
||||
const pB = f1.allocInt();
|
||||
const pC = f1.allocInt();
|
||||
let c;
|
||||
|
||||
for (let i=0; i<v.length; i++) {
|
||||
for (let j=0; j<5; j++) {
|
||||
|
||||
f1.putInt(pA, v[i]);
|
||||
f1.putInt(pB, v[j]);
|
||||
|
||||
// eq
|
||||
assert.equal( f1.int_eq(pA,pB), (i==j));
|
||||
|
||||
// add
|
||||
f1.f1_add(pA, pB, pC);
|
||||
c = f1.getInt2(pC);
|
||||
assert(c.equals(v[i].add(v[j]).mod(q)));
|
||||
|
||||
// sub
|
||||
f1.f1_sub(pA, pB, pC);
|
||||
c = f1.getInt2(pC);
|
||||
|
||||
let s = v[i].minus(v[j]).mod(q);
|
||||
if (s.isNegative()) s=s.add(q);
|
||||
assert(c.equals(s));
|
||||
|
||||
// mul
|
||||
f1.f1_mul(pA, pB, pC);
|
||||
c = f1.getInt2(pC);
|
||||
assert(c.equals(v[i].times(v[j]).mod(q)));
|
||||
}
|
||||
}
|
||||
});
|
||||
it("It should do a test", async () => {
|
||||
const q = bigInt("21888242871839275222246405745257275088548364400416034343698204186575808495617");
|
||||
const f1 = await buildF1(q);
|
||||
|
||||
const t = f1.test_F1(1000000);
|
||||
|
||||
console.log(t);
|
||||
|
||||
}).timeout(10000000);
|
||||
it("Should test to montgomery", async () => {
|
||||
const q = bigInt("21888242871839275222246405745257275088548364400416034343698204186575808495617");
|
||||
const f1 = await buildF1(q);
|
||||
|
||||
const r = bigInt(11);
|
||||
|
||||
const pR = f1.allocInt(r);
|
||||
const pRes = f1.allocInt();
|
||||
const pRes2 = f1.allocInt();
|
||||
|
||||
f1.f1m_toMontgomery(pR, pRes);
|
||||
const res = f1.getInt(pRes);
|
||||
|
||||
f1.f1m_fromMontgomery(pRes, pRes2);
|
||||
const res2 = f1.getInt(pRes2);
|
||||
|
||||
assert(res.equals(r.times( bigInt.one.shiftLeft(256)).mod(q)));
|
||||
assert(res2.equals(r));
|
||||
});
|
||||
it("Should convert back and forth montgomery", async () => {
|
||||
const q = bigInt("21888242871839275222246405745257275088548364400416034343698204186575808495617");
|
||||
const v= [
|
||||
q.minus(1),
|
||||
q.minus(2),
|
||||
q.minus(1).shiftRight(1),
|
||||
q.minus(1).shiftRight(1).add(1),
|
||||
q.minus(1).shiftRight(1).add(2),
|
||||
q.minus(1).shiftRight(1).minus(1),
|
||||
q.minus(1).shiftRight(1).minus(2),
|
||||
bigInt(2),
|
||||
bigInt.one,
|
||||
bigInt.zero
|
||||
];
|
||||
const f1 = await buildF1(q);
|
||||
|
||||
const pA = f1.allocInt();
|
||||
|
||||
for (let i=0; i<v.length; i++) {
|
||||
f1.putInt(pA, v[i]);
|
||||
|
||||
f1.f1m_toMontgomery(pA, pA);
|
||||
f1.f1m_fromMontgomery(pA, pA);
|
||||
|
||||
const a = f1.getInt(pA);
|
||||
assert(v[i].equals(a));
|
||||
}
|
||||
});
|
||||
it("Should do inverse", async () => {
|
||||
const q = bigInt("21888242871839275222246405745257275088548364400416034343698204186575808495617");
|
||||
const v= [
|
||||
bigInt.one,
|
||||
q.minus(1),
|
||||
q.minus(2),
|
||||
q.minus(1).shiftRight(1),
|
||||
q.minus(1).shiftRight(1).add(1),
|
||||
q.minus(1).shiftRight(1).add(2),
|
||||
q.minus(1).shiftRight(1).minus(1),
|
||||
q.minus(1).shiftRight(1).minus(2),
|
||||
bigInt(2),
|
||||
];
|
||||
const f1 = await buildF1(q);
|
||||
|
||||
const pA = f1.allocInt();
|
||||
const pB = f1.allocInt();
|
||||
const pQ = f1.allocInt();
|
||||
|
||||
f1.putInt(pQ, q);
|
||||
|
||||
for (let i=0; i<v.length; i++) {
|
||||
f1.putInt(pA, v[i]);
|
||||
|
||||
f1.int_inverseMod(pA, pQ, pB);
|
||||
|
||||
const b = f1.getInt(pB);
|
||||
assert(b.equals(v[i].modInv(q)));
|
||||
}
|
||||
});
|
||||
it("Should do inverse in montgomery", async () => {
|
||||
const q = bigInt("21888242871839275222246405745257275088548364400416034343698204186575808495617");
|
||||
const v= [
|
||||
bigInt.one,
|
||||
q.minus(1),
|
||||
q.minus(2),
|
||||
q.minus(1).shiftRight(1),
|
||||
q.minus(1).shiftRight(1).add(1),
|
||||
q.minus(1).shiftRight(1).add(2),
|
||||
q.minus(1).shiftRight(1).minus(1),
|
||||
q.minus(1).shiftRight(1).minus(2),
|
||||
bigInt(2),
|
||||
];
|
||||
const f1 = await buildF1(q);
|
||||
|
||||
const pA = f1.allocInt();
|
||||
const pB = f1.allocInt();
|
||||
const pC = f1.allocInt();
|
||||
|
||||
for (let i=0; i<v.length; i++) {
|
||||
f1.putInt(pA, v[i]);
|
||||
|
||||
f1.f1m_toMontgomery(pA, pA);
|
||||
f1.f1m_inverse(pA, pB);
|
||||
f1.f1m_mul(pA, pB, pC);
|
||||
f1.f1m_fromMontgomery(pC, pC);
|
||||
|
||||
const c = f1.getInt(pC);
|
||||
assert(c.equals(1));
|
||||
}
|
||||
});
|
||||
it("Test Neg", async () => {
|
||||
const q = bigInt("21888242871839275222246405745257275088548364400416034343698204186575808495617");
|
||||
const v= [
|
||||
bigInt.one,
|
||||
q.minus(1),
|
||||
q.minus(2),
|
||||
q.minus(1).shiftRight(1),
|
||||
q.minus(1).shiftRight(1).add(1),
|
||||
q.minus(1).shiftRight(1).add(2),
|
||||
q.minus(1).shiftRight(1).minus(1),
|
||||
q.minus(1).shiftRight(1).minus(2),
|
||||
bigInt(2),
|
||||
];
|
||||
const f1 = await buildF1(q);
|
||||
|
||||
const pA = f1.allocInt();
|
||||
|
||||
for (let i=0; i<v.length; i++) {
|
||||
f1.putInt(pA, v[i]);
|
||||
|
||||
f1.f1m_neg(pA);
|
||||
f1.f1m_neg(pA);
|
||||
|
||||
const a = f1.getInt(pA);
|
||||
assert(a.equals(v[i]));
|
||||
}
|
||||
});
|
||||
});
|
123
test/fft.js
Normal file
123
test/fft.js
Normal file
@ -0,0 +1,123 @@
|
||||
const assert = require("assert");
|
||||
const refBn128 = require("snarkjs").bn128;
|
||||
const refBigInt = require("snarkjs").bigInt;
|
||||
|
||||
const buildBn128 = require("../index.js").buildBn128;
|
||||
|
||||
describe("FFT tests", () => {
|
||||
it("create a basic FFT", async () => {
|
||||
const bn128 = await buildBn128();
|
||||
|
||||
const N=4;
|
||||
|
||||
const p = bn128.alloc(32*N);
|
||||
for (let i=0; i<N; i++) {
|
||||
bn128.putInt(p+i*32, i);
|
||||
}
|
||||
|
||||
bn128.fft_toMontgomeryN(p, p, N);
|
||||
bn128.fft_fft(p, N);
|
||||
bn128.fft_ifft(p, N);
|
||||
bn128.fft_fromMontgomeryN(p, p, N);
|
||||
|
||||
for (let i=0; i<N; i++) {
|
||||
const a = bn128.getInt(p+i*32);
|
||||
assert.equal(a,i);
|
||||
}
|
||||
});
|
||||
|
||||
it("create a do it reverselly FFT", async () => {
|
||||
const bn128 = await buildBn128();
|
||||
|
||||
const N=1024;
|
||||
|
||||
const p = bn128.alloc(32*N);
|
||||
for (let i=0; i<N; i++) {
|
||||
bn128.putInt(p+i*32, i);
|
||||
}
|
||||
|
||||
bn128.fft_toMontgomeryN(p, p, N);
|
||||
bn128.fft_ifft(p, N, 0);
|
||||
bn128.fft_fft(p, N, 0);
|
||||
bn128.fft_fromMontgomeryN(p, p, N);
|
||||
|
||||
for (let i=0; i<N; i++) {
|
||||
const a = bn128.getInt(p+i*32);
|
||||
assert.equal(a,i);
|
||||
}
|
||||
});
|
||||
it("test with zeros", async () => {
|
||||
const bn128 = await buildBn128();
|
||||
|
||||
const N=1024;
|
||||
|
||||
const p = bn128.alloc(32*N);
|
||||
for (let i=0; i<N; i++) {
|
||||
bn128.putInt(p+i*32, (i%2 == 0)? 0 : 1);
|
||||
}
|
||||
|
||||
bn128.fft_toMontgomeryN(p, p, N);
|
||||
bn128.fft_ifft(p, N, 0);
|
||||
bn128.fft_fft(p, N, 0);
|
||||
bn128.fft_fromMontgomeryN(p, p, N);
|
||||
|
||||
for (let i=0; i<N; i++) {
|
||||
const a = bn128.getInt(p+i*32);
|
||||
assert.equal(a,(i%2 == 0)? 0 : 1);
|
||||
}
|
||||
});
|
||||
it("test interleaved", async () => {
|
||||
const bn128 = await buildBn128();
|
||||
|
||||
const N=1024;
|
||||
|
||||
const p = bn128.alloc(32*N);
|
||||
const pr1 = bn128.alloc(32*N*2);
|
||||
const pr2 = bn128.alloc(32*N*2);
|
||||
for (let i=0; i<N; i++) {
|
||||
bn128.putInt(p+i*32, i);
|
||||
}
|
||||
bn128.fft_toMontgomeryN(p, p, N);
|
||||
bn128.fft_fft(p, N, 0);
|
||||
bn128.fft_copyNInterleaved(p, pr1, N);
|
||||
|
||||
for (let i=0; i<N; i++) {
|
||||
bn128.putInt(p+i*32, i);
|
||||
}
|
||||
bn128.fft_toMontgomeryN(p, p, N);
|
||||
bn128.fft_fft(p, N, 1);
|
||||
bn128.fft_copyNInterleaved(p, pr1+32, N);
|
||||
|
||||
bn128.fft_fromMontgomeryN(pr1, pr1, N*2);
|
||||
|
||||
for (let i=0; i<N; i++) {
|
||||
bn128.putInt(pr2+i*32, i);
|
||||
}
|
||||
for (let i=N; i<N*2; i++) {
|
||||
bn128.putInt(pr2+i*32, 0);
|
||||
}
|
||||
bn128.fft_toMontgomeryN(pr2, pr2, N*2);
|
||||
bn128.fft_fft(pr2, N*2, 0);
|
||||
bn128.fft_fromMontgomeryN(pr2, pr2, N*2);
|
||||
|
||||
for (let i=0; i<N*2; i++) {
|
||||
const a = bn128.getInt(pr1+i*32, 1);
|
||||
const b = bn128.getInt(pr2+i*32, 1);
|
||||
assert(a.equals(b));
|
||||
}
|
||||
|
||||
bn128.fft_toMontgomeryN(pr1, pr1, N*2);
|
||||
bn128.fft_ifft(pr1, N*2, 0);
|
||||
bn128.fft_fromMontgomeryN(pr1, pr1, N*2);
|
||||
for (let i=0; i<N; i++) {
|
||||
const a = bn128.getInt(pr1+i*32, 1);
|
||||
assert.equal(a,i);
|
||||
}
|
||||
for (let i=N; i<N*2; i++) {
|
||||
const a = bn128.getInt(pr1+i*32, 1);
|
||||
assert.equal(a,0);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
});
|
25
test/groth16.js
Normal file
25
test/groth16.js
Normal file
@ -0,0 +1,25 @@
|
||||
|
||||
const assert = require("assert");
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
const snarkjs = require("snarkjs");
|
||||
|
||||
const buildGroth16 = require("../index.js").buildGroth16;
|
||||
|
||||
describe("Basic tests for groth16 proof generator", () => {
|
||||
it("It should do a basic point doubling G1", async () => {
|
||||
const groth16 = await buildGroth16();
|
||||
|
||||
const signals = fs.readFileSync(path.join(__dirname, "data", "witness.bin"));
|
||||
const provingKey = fs.readFileSync(path.join(__dirname, "data", "proving_key.bin"));
|
||||
const proofS = await groth16.proof(signals.buffer, provingKey.buffer);
|
||||
|
||||
const proof = snarkjs.unstringifyBigInts(proofS);
|
||||
const verifierKey = snarkjs.unstringifyBigInts(JSON.parse(fs.readFileSync(path.join(__dirname, "data", "verification_key.json"), "utf8")));
|
||||
const pub = snarkjs.unstringifyBigInts(JSON.parse(fs.readFileSync(path.join(__dirname, "data", "public.json"), "utf8")));
|
||||
|
||||
assert(snarkjs.groth.isValid(verifierKey, proof, pub));
|
||||
|
||||
groth16.terminate();
|
||||
}).timeout(10000000);
|
||||
});
|
240
tools/buildpkey.js
Normal file
240
tools/buildpkey.js
Normal file
@ -0,0 +1,240 @@
|
||||
const {unstringifyBigInts} = require("./stringifybigint.js");
|
||||
const fs = require("fs");
|
||||
const bigInt = require("big-integer");
|
||||
const assert = require("assert");
|
||||
|
||||
const version = require("../package").version;
|
||||
|
||||
const argv = require("yargs")
|
||||
.version(version)
|
||||
.usage(`node buildpkey.js -i "proving_key.json" -o "proving_key.bin"
|
||||
Default: circuit.json
|
||||
`)
|
||||
.alias("i", "input")
|
||||
.alias("o", "output")
|
||||
.help("h")
|
||||
.alias("h", "help")
|
||||
.epilogue(`Copyright (C) 2018 0kims association
|
||||
This program comes with ABSOLUTELY NO WARRANTY;
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; see the COPYING file in the official
|
||||
repo directory at https://github.com/iden3/circom `)
|
||||
.argv;
|
||||
|
||||
const inputName = (argv.input) ? argv.input : "proving_key.json";
|
||||
const outputName = (argv.output) ? argv.output : "proving_key.bin";
|
||||
|
||||
|
||||
const provingKey = unstringifyBigInts(JSON.parse(fs.readFileSync(inputName, "utf8")));
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
function writeUint32(h, val) {
|
||||
h.dataView.setUint32(h.offset, val, true);
|
||||
h.offset += 4;
|
||||
}
|
||||
|
||||
function writeUint32ToPointer(h, p, val) {
|
||||
h.dataView.setUint32(p, val, true);
|
||||
}
|
||||
|
||||
|
||||
function alloc(h, n) {
|
||||
const o = h.offset;
|
||||
h.offset += n;
|
||||
return o;
|
||||
}
|
||||
|
||||
function writeBigInt(h, bi) {
|
||||
for (let i=0; i<8; i++) {
|
||||
const v = bi.shiftRight(i*32).and(0xFFFFFFFF).toJSNumber();
|
||||
writeUint32(h, v);
|
||||
}
|
||||
}
|
||||
|
||||
function toMontgomeryQ(p) {
|
||||
const q = bigInt("21888242871839275222246405745257275088696311157297823662689037894645226208583");
|
||||
return p.times(bigInt.one.shiftLeft(256)).mod(q);
|
||||
}
|
||||
|
||||
function toMontgomeryR(p) {
|
||||
const r = bigInt("21888242871839275222246405745257275088548364400416034343698204186575808495617");
|
||||
return p.times(bigInt.one.shiftLeft(256)).mod(r);
|
||||
}
|
||||
|
||||
function writePoint(h, p) {
|
||||
writeBigInt(h, toMontgomeryQ(p[0]));
|
||||
writeBigInt(h, toMontgomeryQ(p[1]));
|
||||
}
|
||||
|
||||
function writePoint2(h, p) {
|
||||
writeBigInt(h, toMontgomeryQ(p[0][0]));
|
||||
writeBigInt(h, toMontgomeryQ(p[0][1]));
|
||||
writeBigInt(h, toMontgomeryQ(p[1][0]));
|
||||
writeBigInt(h, toMontgomeryQ(p[1][1]));
|
||||
}
|
||||
|
||||
function writeTransformedPolynomial(h, p) {
|
||||
|
||||
const keys = Object.keys(p);
|
||||
|
||||
writeUint32(h, keys.length);
|
||||
|
||||
for (let i=0; i<keys.length; i++) {
|
||||
writeUint32(h, keys[i]);
|
||||
writeBigInt(h, toMontgomeryR(p[keys[i]]));
|
||||
}
|
||||
}
|
||||
|
||||
function calculateBuffLen(provingKey) {
|
||||
function polSize(pol) {
|
||||
const l= Object.keys(pol).length;
|
||||
return 36*l + 4;
|
||||
}
|
||||
|
||||
let size = 40;
|
||||
|
||||
// alfa1, beta1, delta1
|
||||
size += 3 * (32*2);
|
||||
|
||||
// beta2, delta2
|
||||
size += 2 * (32*4);
|
||||
|
||||
for (let i=0; i<provingKey.nVars; i++) {
|
||||
size += polSize(provingKey.polsA[i]);
|
||||
size += polSize(provingKey.polsB[i]);
|
||||
}
|
||||
|
||||
size += provingKey.nVars* (32*2);
|
||||
size += provingKey.nVars* (32*2);
|
||||
size += provingKey.nVars* (32*4);
|
||||
size += (provingKey.nVars - provingKey.nPublic - 1)* (32*2);
|
||||
size += provingKey.domainSize * (32*2);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
|
||||
const buffLen = calculateBuffLen(provingKey);
|
||||
|
||||
const buff = new ArrayBuffer(buffLen);
|
||||
|
||||
const h = {
|
||||
dataView: new DataView(buff),
|
||||
offset: 0
|
||||
};
|
||||
|
||||
|
||||
writeUint32(h, provingKey.nVars);
|
||||
writeUint32(h, provingKey.nPublic);
|
||||
writeUint32(h, provingKey.domainSize);
|
||||
const pPolsA = alloc(h, 4);
|
||||
const pPolsB = alloc(h, 4);
|
||||
const pPointsA = alloc(h, 4);
|
||||
const pPointsB1 = alloc(h, 4);
|
||||
const pPointsB2 = alloc(h, 4);
|
||||
const pPointsC = alloc(h, 4);
|
||||
const pPointsHExps = alloc(h, 4);
|
||||
|
||||
writePoint(h, provingKey.vk_alfa_1);
|
||||
writePoint(h, provingKey.vk_beta_1);
|
||||
writePoint(h, provingKey.vk_delta_1);
|
||||
writePoint2(h, provingKey.vk_beta_2);
|
||||
writePoint2(h, provingKey.vk_delta_2);
|
||||
|
||||
writeUint32ToPointer(h, pPolsA, h.offset);
|
||||
for (let i=0; i<provingKey.nVars; i++) {
|
||||
writeTransformedPolynomial(h, provingKey.polsA[i]);
|
||||
}
|
||||
|
||||
writeUint32ToPointer(h, pPolsB, h.offset);
|
||||
for (let i=0; i<provingKey.nVars; i++) {
|
||||
writeTransformedPolynomial(h, provingKey.polsB[i]);
|
||||
}
|
||||
|
||||
writeUint32ToPointer(h, pPointsA, h.offset);
|
||||
for (let i=0; i<provingKey.nVars; i++) {
|
||||
writePoint(h, provingKey.A[i]);
|
||||
}
|
||||
|
||||
writeUint32ToPointer(h, pPointsB1, h.offset);
|
||||
for (let i=0; i<provingKey.nVars; i++) {
|
||||
writePoint(h, provingKey.B1[i]);
|
||||
}
|
||||
|
||||
writeUint32ToPointer(h, pPointsB2, h.offset);
|
||||
for (let i=0; i<provingKey.nVars; i++) {
|
||||
writePoint2(h, provingKey.B2[i]);
|
||||
}
|
||||
|
||||
writeUint32ToPointer(h, pPointsC, h.offset);
|
||||
for (let i=provingKey.nPublic+1; i<provingKey.nVars; i++) {
|
||||
writePoint(h, provingKey.C[i]);
|
||||
}
|
||||
|
||||
writeUint32ToPointer(h, pPointsHExps, h.offset);
|
||||
for (let i=0; i<provingKey.domainSize; i++) {
|
||||
writePoint(h, provingKey.hExps[i]);
|
||||
}
|
||||
|
||||
assert.equal(h.offset, buffLen);
|
||||
|
||||
var wstream = fs.createWriteStream(outputName);
|
||||
wstream.write(Buffer.from(buff));
|
||||
wstream.end();
|
||||
|
||||
/*
|
||||
NSignals
|
||||
NPublic
|
||||
DomainSize (2 multiple)
|
||||
pPolsA
|
||||
pPolsB
|
||||
pPointsA
|
||||
pPointsB1
|
||||
pPointsB2
|
||||
pPointsC
|
||||
pPointsHExps
|
||||
Alfa1
|
||||
Beta1
|
||||
Delta1
|
||||
Beta2
|
||||
Delta2
|
||||
PolinomialA_0
|
||||
PolinomialA_1
|
||||
PolinomialA_2
|
||||
...
|
||||
PolinomialA_NVars-1
|
||||
|
||||
PolinomialB_0
|
||||
PolinomialB_1
|
||||
PolinomialB_2
|
||||
...
|
||||
PolinomialB_NVars-1
|
||||
|
||||
PointA_0
|
||||
PointA_1
|
||||
...
|
||||
PointA_NVars-1
|
||||
|
||||
PointB1_0
|
||||
PointB1_1
|
||||
...
|
||||
PointB1_NVars-1
|
||||
|
||||
PointB2_0
|
||||
PointB2_1
|
||||
...
|
||||
PointB2_NVars-1
|
||||
|
||||
PointC_nPublics+1
|
||||
PointC_nPublics+2
|
||||
...
|
||||
PointC_nPublics+NVars
|
||||
|
||||
PointHExp_0
|
||||
PointHExp_1
|
||||
...
|
||||
PointHExp_DomainSize-1
|
||||
*/
|
54
tools/buildwasm.js
Normal file
54
tools/buildwasm.js
Normal file
@ -0,0 +1,54 @@
|
||||
const bigInt = require("big-integer");
|
||||
const ModuleBuilder = require("wasmbuilder");
|
||||
const buildF1m = require("../src/build_f1m.js");
|
||||
const buildF2m = require("../src/build_f2m.js");
|
||||
const buildF1 = require("../src/build_f1.js");
|
||||
const buildCurve = require("../src/build_curve.js");
|
||||
const buildTest = require("../src/build_testg1");
|
||||
const buildFFT = require("../src/build_fft");
|
||||
const buildMultiexp = require("../src/build_multiexp");
|
||||
const buildPol = require("../src/build_pol");
|
||||
const utils = require("../src/utils");
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
|
||||
function buildWasm() {
|
||||
|
||||
const q = bigInt("21888242871839275222246405745257275088696311157297823662689037894645226208583");
|
||||
const r = bigInt("21888242871839275222246405745257275088548364400416034343698204186575808495617");
|
||||
|
||||
const moduleBuilder = new ModuleBuilder();
|
||||
moduleBuilder.setMemory(1000);
|
||||
buildF1m(moduleBuilder, q, "f1m");
|
||||
buildF1(moduleBuilder, r, "fr", "frm");
|
||||
buildCurve(moduleBuilder, "g1", "f1m");
|
||||
buildMultiexp(moduleBuilder, "g1", "g1", "f1m", "fr");
|
||||
buildFFT(moduleBuilder, "fft", "frm");
|
||||
buildPol(moduleBuilder, "pol", "frm");
|
||||
|
||||
const pNonResidueF2 = moduleBuilder.alloc(
|
||||
utils.bigInt2BytesLE(
|
||||
bigInt("15537367993719455909907449462855742678907882278146377936676643359958227611562"), // -1 in montgomery
|
||||
32
|
||||
)
|
||||
);
|
||||
|
||||
buildF2m(moduleBuilder, pNonResidueF2, "f2m", "f1m");
|
||||
buildCurve(moduleBuilder, "g2", "f2m");
|
||||
buildMultiexp(moduleBuilder, "g2", "g2", "f2m", "fr");
|
||||
|
||||
buildTest(moduleBuilder);
|
||||
|
||||
const code = moduleBuilder.build();
|
||||
|
||||
fs.writeFileSync(
|
||||
path.join( __dirname, "..", "build", "groth16_wasm.js"),
|
||||
`
|
||||
exports.code = new Buffer("${Buffer.from(code).toString("base64")}", "base64");
|
||||
exports.pq = ${moduleBuilder.modules.f1m.pq};
|
||||
exports.pr = ${moduleBuilder.modules.frm.pq};
|
||||
`
|
||||
);
|
||||
}
|
||||
|
||||
buildWasm();
|
76
tools/buildwitness.js
Normal file
76
tools/buildwitness.js
Normal file
@ -0,0 +1,76 @@
|
||||
const {unstringifyBigInts} = require("./stringifybigint.js");
|
||||
const fs = require("fs");
|
||||
const assert = require("assert");
|
||||
|
||||
const version = require("../package").version;
|
||||
|
||||
const argv = require("yargs")
|
||||
.version(version)
|
||||
.usage(`node buildpkey.js -i "witness.json" -o "witness.bin"
|
||||
Default: circuit.json
|
||||
`)
|
||||
.alias("i", "input")
|
||||
.alias("o", "output")
|
||||
.help("h")
|
||||
.alias("h", "help")
|
||||
.epilogue(`Copyright (C) 2018 0kims association
|
||||
This program comes with ABSOLUTELY NO WARRANTY;
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; see the COPYING file in the official
|
||||
repo directory at https://github.com/iden3/circom `)
|
||||
.argv;
|
||||
|
||||
const inputName = (argv.input) ? argv.input : "witness.json";
|
||||
const outputName = (argv.output) ? argv.output : "witness.bin";
|
||||
|
||||
|
||||
const witness = unstringifyBigInts(JSON.parse(fs.readFileSync(inputName, "utf8")));
|
||||
|
||||
|
||||
function writeUint32(h, val) {
|
||||
h.dataView.setUint32(h.offset, val, true);
|
||||
h.offset += 4;
|
||||
}
|
||||
|
||||
|
||||
function writeBigInt(h, bi) {
|
||||
for (let i=0; i<8; i++) {
|
||||
const v = bi.shiftRight(i*32).and(0xFFFFFFFF).toJSNumber();
|
||||
writeUint32(h, v);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function calculateBuffLen(witness) {
|
||||
|
||||
let size = 0;
|
||||
|
||||
// beta2, delta2
|
||||
size += witness.length * 32;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
|
||||
const buffLen = calculateBuffLen(witness);
|
||||
|
||||
const buff = new ArrayBuffer(buffLen);
|
||||
|
||||
const h = {
|
||||
dataView: new DataView(buff),
|
||||
offset: 0
|
||||
};
|
||||
|
||||
|
||||
// writeUint32(h, witness.length);
|
||||
|
||||
for (let i=0; i<witness.length; i++) {
|
||||
writeBigInt(h, witness[i]);
|
||||
}
|
||||
|
||||
assert.equal(h.offset, buffLen);
|
||||
|
||||
var wstream = fs.createWriteStream(outputName);
|
||||
wstream.write(Buffer.from(buff));
|
||||
wstream.end();
|
||||
|
55
tools/stringifybigint.js
Normal file
55
tools/stringifybigint.js
Normal file
@ -0,0 +1,55 @@
|
||||
/*
|
||||
Copyright 2018 0kims association.
|
||||
|
||||
This file is part of snarkjs.
|
||||
|
||||
snarkjs is a free software: you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation, either version 3 of the License, or (at your option)
|
||||
any later version.
|
||||
|
||||
snarkjs is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
snarkjs. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
const bigInt = require("big-integer");
|
||||
|
||||
module.exports.stringifyBigInts = stringifyBigInts;
|
||||
module.exports.unstringifyBigInts = unstringifyBigInts;
|
||||
|
||||
function stringifyBigInts(o) {
|
||||
if ((typeof(o) == "bigint") || (o instanceof bigInt)) {
|
||||
return o.toString(10);
|
||||
} else if (Array.isArray(o)) {
|
||||
return o.map(stringifyBigInts);
|
||||
} else if (typeof o == "object") {
|
||||
const res = {};
|
||||
for (let k in o) {
|
||||
res[k] = stringifyBigInts(o[k]);
|
||||
}
|
||||
return res;
|
||||
} else {
|
||||
return o;
|
||||
}
|
||||
}
|
||||
|
||||
function unstringifyBigInts(o) {
|
||||
if ((typeof(o) == "string") && (/^[0-9]+$/.test(o) )) {
|
||||
return bigInt(o);
|
||||
} else if (Array.isArray(o)) {
|
||||
return o.map(unstringifyBigInts);
|
||||
} else if (typeof o == "object") {
|
||||
const res = {};
|
||||
for (let k in o) {
|
||||
res[k] = unstringifyBigInts(o[k]);
|
||||
}
|
||||
return res;
|
||||
} else {
|
||||
return o;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user