diff --git a/.licensesnip b/.licensesnip new file mode 100644 index 00000000..5814dadc --- /dev/null +++ b/.licensesnip @@ -0,0 +1,3 @@ +The Licensed Work is (c) 2023 ChainSafe +Code: https://github.com/ChainSafe/Spectre +SPDX-License-Identifier: LGPL-3.0-only diff --git a/LICENSE b/LICENSE index 93e4a4bd..8d71b819 100644 --- a/LICENSE +++ b/LICENSE @@ -1,13 +1,674 @@ -Copyright 2023 ChainSafe Systems +GNU GENERAL PUBLIC LICENSE +Version 3, 29 June 2007 -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at +Copyright (C) 2007 Free Software Foundation, Inc. +Everyone is permitted to copy and distribute verbatim copies +of this license document, but changing it is not allowed. - http://www.apache.org/licenses/LICENSE-2.0 + Preamble -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. +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. + + +Copyright (C) + +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 . + +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: + +Spectre Copyright (C) 2023 ChainSafe +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 +. + +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 +. diff --git a/contract-tests/src/lib.rs b/contract-tests/src/lib.rs index 88b4317f..362e563f 100644 --- a/contract-tests/src/lib.rs +++ b/contract-tests/src/lib.rs @@ -1,3 +1,7 @@ +// The Licensed Work is (c) 2023 ChainSafe +// Code: https://github.com/ChainSafe/Spectre +// SPDX-License-Identifier: LGPL-3.0-only + use ethers::{ core::utils::{Anvil, AnvilInstance}, middleware::SignerMiddleware, diff --git a/contract-tests/tests/rotation_input_encoding.rs b/contract-tests/tests/rotation_input_encoding.rs index 64688b19..7ca77e56 100644 --- a/contract-tests/tests/rotation_input_encoding.rs +++ b/contract-tests/tests/rotation_input_encoding.rs @@ -1,3 +1,7 @@ +// The Licensed Work is (c) 2023 ChainSafe +// Code: https://github.com/ChainSafe/Spectre +// SPDX-License-Identifier: LGPL-3.0-only + #![allow(incomplete_features)] #![feature(generic_const_exprs)] @@ -11,7 +15,7 @@ use itertools::Itertools; use lightclient_circuits::committee_update_circuit::CommitteeUpdateCircuit; use lightclient_circuits::halo2_proofs::halo2curves::bn256; use lightclient_circuits::poseidon::poseidon_committee_commitment_from_compressed; -use lightclient_circuits::witness::CommitteeRotationArgs; +use lightclient_circuits::witness::CommitteeUpdateArgs; use rstest::rstest; use ssz_rs::prelude::*; use ssz_rs::Merkleized; @@ -24,11 +28,11 @@ abigen!( ); // CommitteeRotationArgs type produced by abigen macro matches the solidity struct type -impl From> for RotateInput +impl From> for RotateInput where [(); Spec::SYNC_COMMITTEE_SIZE]:, { - fn from(args: CommitteeRotationArgs) -> Self { + fn from(args: CommitteeUpdateArgs) -> Self { let poseidon_commitment = poseidon_committee_commitment_from_compressed( &args.pubkeys_compressed.iter().cloned().collect_vec(), ); diff --git a/contract-tests/tests/spectre.rs b/contract-tests/tests/spectre.rs index 6104bec0..9f9a7001 100644 --- a/contract-tests/tests/spectre.rs +++ b/contract-tests/tests/spectre.rs @@ -1,3 +1,7 @@ +// The Licensed Work is (c) 2023 ChainSafe +// Code: https://github.com/ChainSafe/Spectre +// SPDX-License-Identifier: LGPL-3.0-only + /** * These are the highest level integration tests for the Spectre protocol * They treat the Spectre contract as an ethereum light-client and test against the spec diff --git a/contract-tests/tests/step_input_encoding.rs b/contract-tests/tests/step_input_encoding.rs index bac52af3..bdf53160 100644 --- a/contract-tests/tests/step_input_encoding.rs +++ b/contract-tests/tests/step_input_encoding.rs @@ -1,3 +1,7 @@ +// The Licensed Work is (c) 2023 ChainSafe +// Code: https://github.com/ChainSafe/Spectre +// SPDX-License-Identifier: LGPL-3.0-only + use std::ops::Deref; use std::path::PathBuf; diff --git a/contracts/rust-abi/lib.rs b/contracts/rust-abi/lib.rs index 42043dc9..4016baff 100644 --- a/contracts/rust-abi/lib.rs +++ b/contracts/rust-abi/lib.rs @@ -1,10 +1,14 @@ +// The Licensed Work is (c) 2023 ChainSafe +// Code: https://github.com/ChainSafe/Spectre +// SPDX-License-Identifier: LGPL-3.0-only + #![allow(incomplete_features)] #![feature(generic_const_exprs)] use ethers::{contract::abigen, types::U256}; use itertools::Itertools; use lightclient_circuits::{ poseidon::poseidon_committee_commitment_from_compressed, - witness::{CommitteeRotationArgs, SyncStepArgs}, + witness::{CommitteeUpdateArgs, SyncStepArgs}, }; use ssz_rs::{Merkleized, Vector}; use std::ops::Deref; @@ -63,11 +67,11 @@ impl SyncStepInput { } // CommitteeRotationArgs type produced by abigen macro matches the solidity struct type -impl From> for RotateInput +impl From> for RotateInput where [(); Spec::SYNC_COMMITTEE_SIZE]:, { - fn from(args: CommitteeRotationArgs) -> Self { + fn from(args: CommitteeUpdateArgs) -> Self { let sync_committee_poseidon = poseidon_committee_commitment_from_compressed( &args.pubkeys_compressed.iter().cloned().collect_vec(), ); diff --git a/contracts/script/deploy_local.sh b/contracts/script/deploy_local.sh index 6132d7ac..b8fe7263 100644 --- a/contracts/script/deploy_local.sh +++ b/contracts/script/deploy_local.sh @@ -1,3 +1,7 @@ +# The Licensed Work is (c) 2023 ChainSafe +# Code: https://github.com/ChainSafe/Spectre +# SPDX-License-Identifier: LGPL-3.0-only + #!/bin/sh cd $(git rev-parse --show-toplevel) source .env diff --git a/contracts/script/deploy_testnet.sh b/contracts/script/deploy_testnet.sh index a435ad4c..e64fcb4f 100644 --- a/contracts/script/deploy_testnet.sh +++ b/contracts/script/deploy_testnet.sh @@ -1,3 +1,7 @@ +# The Licensed Work is (c) 2023 ChainSafe +# Code: https://github.com/ChainSafe/Spectre +# SPDX-License-Identifier: LGPL-3.0-only + #!/bin/sh cd $(git rev-parse --show-toplevel) source .env diff --git a/eth-types/src/lib.rs b/eth-types/src/lib.rs index 5c3ba175..240c22e0 100644 --- a/eth-types/src/lib.rs +++ b/eth-types/src/lib.rs @@ -1,3 +1,7 @@ +// The Licensed Work is (c) 2023 ChainSafe +// Code: https://github.com/ChainSafe/Spectre +// SPDX-License-Identifier: LGPL-3.0-only + #![allow(incomplete_features)] #![feature(associated_type_bounds)] #![feature(associated_type_defaults)] @@ -11,4 +15,5 @@ pub use spec::{Mainnet, Minimal, Spec, Testnet}; pub const NUM_LIMBS: usize = 4; pub const LIMB_BITS: usize = 104; +/// The field used in circuits. pub trait Field = BigPrimeField + PrimeField; diff --git a/eth-types/src/spec.rs b/eth-types/src/spec.rs index 0f9ff786..e7a42e14 100644 --- a/eth-types/src/spec.rs +++ b/eth-types/src/spec.rs @@ -1,5 +1,10 @@ +// The Licensed Work is (c) 2023 ChainSafe +// Code: https://github.com/ChainSafe/Spectre +// SPDX-License-Identifier: LGPL-3.0-only + use core::fmt::Debug; +/// Beacon chain specification. pub trait Spec: 'static + Sized + Copy + Default + Debug { const SYNC_COMMITTEE_SIZE: usize; const SYNC_COMMITTEE_ROOT_INDEX: usize; diff --git a/lightclient-circuits/config/committee_update_18.json b/lightclient-circuits/config/committee_update_18.json deleted file mode 100644 index f4f64d68..00000000 --- a/lightclient-circuits/config/committee_update_18.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "params": { - "k": 18, - "num_advice_per_phase": [ - 12 - ], - "num_fixed": 1, - "num_lookup_advice_per_phase": [ - 1, - 0, - 0 - ], - "lookup_bits": 8, - "num_instance_columns": 1 - }, - "break_points": [ - [ - 262134, - 262132, - 262134, - 262132, - 262133, - 262132, - 262132, - 262133, - 262132, - 262134, - 262133 - ] - ] -} \ No newline at end of file diff --git a/lightclient-circuits/config/committee_update_mainnet.json b/lightclient-circuits/config/committee_update_mainnet.json deleted file mode 100644 index f4f64d68..00000000 --- a/lightclient-circuits/config/committee_update_mainnet.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "params": { - "k": 18, - "num_advice_per_phase": [ - 12 - ], - "num_fixed": 1, - "num_lookup_advice_per_phase": [ - 1, - 0, - 0 - ], - "lookup_bits": 8, - "num_instance_columns": 1 - }, - "break_points": [ - [ - 262134, - 262132, - 262134, - 262132, - 262133, - 262132, - 262132, - 262133, - 262132, - 262134, - 262133 - ] - ] -} \ No newline at end of file diff --git a/lightclient-circuits/config/committee_update_testnet.json b/lightclient-circuits/config/committee_update_testnet.json index f4f64d68..2f358bb8 100644 --- a/lightclient-circuits/config/committee_update_testnet.json +++ b/lightclient-circuits/config/committee_update_testnet.json @@ -2,7 +2,7 @@ "params": { "k": 18, "num_advice_per_phase": [ - 12 + 7 ], "num_fixed": 1, "num_lookup_advice_per_phase": [ @@ -10,22 +10,17 @@ 0, 0 ], - "lookup_bits": 8, + "lookup_bits": 17, "num_instance_columns": 1 }, "break_points": [ [ 262134, - 262132, 262134, - 262132, - 262133, - 262132, - 262132, + 262134, 262133, - 262132, 262134, - 262133 + 262134 ] ] -} \ No newline at end of file +} diff --git a/lightclient-circuits/config/committee_update_verifier_25.json b/lightclient-circuits/config/committee_update_verifier_25.json deleted file mode 100644 index 88107546..00000000 --- a/lightclient-circuits/config/committee_update_verifier_25.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "params": { - "degree": 25, - "num_advice": 1, - "num_lookup_advice": 1, - "num_fixed": 1, - "lookup_bits": 8 - }, - "break_points": [ - [] - ] -} \ No newline at end of file diff --git a/lightclient-circuits/config/committee_update_verifier_mainnet.json b/lightclient-circuits/config/committee_update_verifier_mainnet.json deleted file mode 100644 index 88107546..00000000 --- a/lightclient-circuits/config/committee_update_verifier_mainnet.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "params": { - "degree": 25, - "num_advice": 1, - "num_lookup_advice": 1, - "num_fixed": 1, - "lookup_bits": 8 - }, - "break_points": [ - [] - ] -} \ No newline at end of file diff --git a/lightclient-circuits/config/committee_update_verifier_testnet.json b/lightclient-circuits/config/committee_update_verifier_testnet.json index 88107546..6d34e366 100644 --- a/lightclient-circuits/config/committee_update_verifier_testnet.json +++ b/lightclient-circuits/config/committee_update_verifier_testnet.json @@ -9,4 +9,4 @@ "break_points": [ [] ] -} \ No newline at end of file +} diff --git a/lightclient-circuits/config/sync_step_20.json b/lightclient-circuits/config/sync_step_20.json deleted file mode 100644 index 5e5db520..00000000 --- a/lightclient-circuits/config/sync_step_20.json +++ /dev/null @@ -1,40 +0,0 @@ -{ - "params": { - "k": 20, - "num_advice_per_phase": [ - 21 - ], - "num_fixed": 1, - "num_lookup_advice_per_phase": [ - 3, - 0, - 0 - ], - "lookup_bits": 8, - "num_instance_columns": 1 - }, - "break_points": [ - [ - 1048565, - 1048564, - 1048566, - 1048565, - 1048565, - 1048566, - 1048566, - 1048566, - 1048564, - 1048565, - 1048566, - 1048564, - 1048566, - 1048566, - 1048564, - 1048564, - 1048566, - 1048564, - 1048566, - 1048566 - ] - ] -} \ No newline at end of file diff --git a/lightclient-circuits/config/sync_step_22.json b/lightclient-circuits/config/sync_step_22.json deleted file mode 100644 index 8f0ef69f..00000000 --- a/lightclient-circuits/config/sync_step_22.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "params": { - "k": 22, - "num_advice_per_phase": [ - 6 - ], - "num_fixed": 1, - "num_lookup_advice_per_phase": [ - 1, - 0, - 0 - ], - "lookup_bits": 8, - "num_instance_columns": 1 - }, - "break_points": [ - [ - 4194292, - 4194292, - 4194293, - 4194294, - 4194294 - ] - ] -} \ No newline at end of file diff --git a/lightclient-circuits/config/sync_step_mainnet.json b/lightclient-circuits/config/sync_step_mainnet.json deleted file mode 100644 index c430ae66..00000000 --- a/lightclient-circuits/config/sync_step_mainnet.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "params": { - "k": 22, - "num_advice_per_phase": [ - 6 - ], - "num_fixed": 1, - "num_lookup_advice_per_phase": [ - 1, - 0, - 0 - ], - "lookup_bits": 8, - "num_instance_columns": 1 - }, - "break_points": [ - [ - 4194292, - 4194294, - 4194292, - 4194293, - 4194293 - ] - ] -} \ No newline at end of file diff --git a/lightclient-circuits/config/sync_step_testnet.json b/lightclient-circuits/config/sync_step_testnet.json index 0c3a8dbe..216bbebe 100644 --- a/lightclient-circuits/config/sync_step_testnet.json +++ b/lightclient-circuits/config/sync_step_testnet.json @@ -1,8 +1,8 @@ { "params": { - "k": 22, + "k": 21, "num_advice_per_phase": [ - 3 + 6 ], "num_fixed": 1, "num_lookup_advice_per_phase": [ @@ -10,13 +10,16 @@ 0, 0 ], - "lookup_bits": 21, + "lookup_bits": 20, "num_instance_columns": 1 }, "break_points": [ [ - 4194294, - 4194294 + 2097142, + 2097142, + 2097140, + 2097142, + 2097142 ] ] -} \ No newline at end of file +} diff --git a/lightclient-circuits/config/sync_step_verifier_testnet.json b/lightclient-circuits/config/sync_step_verifier_testnet.json new file mode 100644 index 00000000..a20e1235 --- /dev/null +++ b/lightclient-circuits/config/sync_step_verifier_testnet.json @@ -0,0 +1,12 @@ +{ + "params": { + "degree": 23, + "num_advice": 1, + "num_lookup_advice": 1, + "num_fixed": 1, + "lookup_bits": 8 + }, + "break_points": [ + [] + ] + } diff --git a/lightclient-circuits/src/aggregation_circuit.rs b/lightclient-circuits/src/aggregation_circuit.rs index 4ce959c1..57ec4b59 100644 --- a/lightclient-circuits/src/aggregation_circuit.rs +++ b/lightclient-circuits/src/aggregation_circuit.rs @@ -1,3 +1,7 @@ +// The Licensed Work is (c) 2023 ChainSafe +// Code: https://github.com/ChainSafe/Spectre +// SPDX-License-Identifier: LGPL-3.0-only + use crate::util::{AppCircuit, Halo2ConfigPinning, PinnableCircuit}; use halo2_base::{ gates::{circuit::CircuitBuilderStage, flex_gate::MultiPhaseThreadBreakPoints}, @@ -15,6 +19,7 @@ use std::{ path::Path, }; +/// Configuration for the aggregation circuit. #[derive(Clone, Debug, Serialize, Deserialize)] pub struct AggregationConfigPinning { pub params: AggregationConfigParams, @@ -79,12 +84,12 @@ impl AppCircuit for AggregationCircuit { snark: &Self::Witness, k: u32, ) -> Result, Error> { - // let lookup_bits = k as usize - 1; + let lookup_bits = k as usize - 1; let params = gen_srs(k); let circuit_params = pinning.clone().map_or( AggregationConfigParams { degree: k, - lookup_bits: 8, + lookup_bits, ..Default::default() }, |p| p.params, @@ -97,14 +102,15 @@ impl AppCircuit for AggregationCircuit { Default::default(), ); + // We assume that `AggregationCircuit` will only be used for a single aggregation/compression layer. + circuit.expose_previous_instances(false); + match stage { CircuitBuilderStage::Prover => { - circuit.expose_previous_instances(false); circuit.set_params(circuit_params); circuit.set_break_points(pinning.map_or(vec![], |p| p.break_points)); } _ => { - circuit.expose_previous_instances(false); set_var( "AGG_CONFIG_PARAMS", serde_json::to_string(&circuit.calculate_params(Some(10))).unwrap(), diff --git a/lightclient-circuits/src/committee_update_circuit.rs b/lightclient-circuits/src/committee_update_circuit.rs index 8f201ac0..ad612c45 100644 --- a/lightclient-circuits/src/committee_update_circuit.rs +++ b/lightclient-circuits/src/committee_update_circuit.rs @@ -1,6 +1,10 @@ +// The Licensed Work is (c) 2023 ChainSafe +// Code: https://github.com/ChainSafe/Spectre +// SPDX-License-Identifier: LGPL-3.0-only + use crate::{ gadget::crypto::{HashInstructions, Sha256ChipWide, ShaBitGateManager, ShaCircuitBuilder}, - poseidon::{fq_array_poseidon, fq_array_poseidon_native}, + poseidon::{fq_array_poseidon, poseidon_hash_fq_array}, ssz_merkle::{ssz_merkleize_chunks, verify_merkle_proof}, sync_step_circuit::clear_3_bits, util::{AppCircuit, CommonGateManager, Eth2ConfigPinning, IntoWitness}, @@ -23,7 +27,14 @@ use itertools::Itertools; use ssz_rs::{Merkleized, Vector}; use std::{env::var, iter, marker::PhantomData, vec}; -#[allow(type_alias_bounds)] +/// `CommitteeUpdateCircuit` maps next sync committee SSZ root in the finalized state root to the corresponding Poseidon commitment to the public keys. +/// +/// Assumes that public keys are BLS12-381 points on G1; `sync_committee_branch` is exactly `S::SYNC_COMMITTEE_PUBKEYS_DEPTH` hashes in lenght. +/// +/// The circuit exposes two public inputs: +/// - `poseidon_commit` is a Poseidon "onion" commitment to the X coordinates of sync committee public keys. Coordinates are expressed as big-integer with two limbs of LIMB_BITS * 2 bits. +/// - `committee_root_ssz` is a Merkle SSZ root of the list of sync committee public keys. +/// - `finalized_header_root` is a Merkle SSZ root of the finalized header. #[derive(Clone, Debug, Default)] pub struct CommitteeUpdateCircuit { _f: PhantomData, @@ -34,7 +45,7 @@ impl CommitteeUpdateCircuit { fn synthesize( builder: &mut ShaCircuitBuilder>, fp_chip: &FpChip, - args: &witness::CommitteeRotationArgs, + args: &witness::CommitteeUpdateArgs, ) -> Result>, Error> { let range = fp_chip.range(); @@ -51,7 +62,7 @@ impl CommitteeUpdateCircuit { }) .collect_vec(); - // Note: This is the root of the public keys in the SyncCommittee struct + // Note: This is the root of the public keys list in the SyncCommittee struct // not the root of the SyncCommittee struct itself. let committee_root_ssz = Self::sync_committee_root_ssz(builder, &sha256_chip, compressed_encodings.clone())?; @@ -101,6 +112,9 @@ impl CommitteeUpdateCircuit { Ok(public_inputs) } + /// Decodes the pub keys bytes into and X coordinate reperesented as a big integers. + /// + /// Assumes that input bytes are in Big-Endian encoding. fn decode_pubkeys_x( ctx: &mut Context, fp_chip: &FpChip<'_, F>, @@ -156,8 +170,10 @@ impl CommitteeUpdateCircuit { ssz_merkleize_chunks(builder, hasher, pubkeys_hashes) } + // Computes public inputs to `CommitteeUpdateCircuit` matching the in-circuit logic from `synthesise` method. + // Note, this function outputes only instances of the `CommitteeUpdateCircuit` proof, not the aggregated proof which will also include 12 accumulator limbs. pub fn get_instances( - args: &witness::CommitteeRotationArgs, + args: &witness::CommitteeUpdateArgs, limb_bits: usize, ) -> Vec> where @@ -169,7 +185,7 @@ impl CommitteeUpdateCircuit { .expect("bad bls12_381::Fq encoding") }); - let poseidon_commitment = fq_array_poseidon_native::(pubkeys_x, limb_bits); + let poseidon_commitment = poseidon_hash_fq_array::(pubkeys_x, limb_bits); let mut pk_vector: Vector, { S::SYNC_COMMITTEE_SIZE }> = args .pubkeys_compressed @@ -200,12 +216,12 @@ impl CommitteeUpdateCircuit { impl AppCircuit for CommitteeUpdateCircuit { type Pinning = Eth2ConfigPinning; - type Witness = witness::CommitteeRotationArgs; + type Witness = witness::CommitteeUpdateArgs; fn create_circuit( stage: CircuitBuilderStage, pinning: Option, - witness: &witness::CommitteeRotationArgs, + witness: &witness::CommitteeUpdateArgs, k: u32, ) -> Result, Error> { let mut builder = Eth2CircuitBuilder::>::from_stage(stage) @@ -244,7 +260,7 @@ mod tests { use crate::{ aggregation_circuit::AggregationConfigPinning, util::Halo2ConfigPinning, - witness::CommitteeRotationArgs, + witness::CommitteeUpdateArgs, }; use super::*; @@ -263,7 +279,7 @@ mod tests { use snark_verifier_sdk::evm::{evm_verify, gen_evm_proof_shplonk}; use snark_verifier_sdk::{halo2::aggregation::AggregationCircuit, CircuitExt, Snark}; - fn load_circuit_args() -> CommitteeRotationArgs { + fn load_circuit_args() -> CommitteeUpdateArgs { #[derive(serde::Deserialize)] struct ArgsJson { finalized_header: BeaconBlockHeader, @@ -277,7 +293,7 @@ mod tests { finalized_header, } = serde_json::from_slice(&fs::read("../test_data/rotation_512.json").unwrap()).unwrap(); - CommitteeRotationArgs { + CommitteeUpdateArgs { pubkeys_compressed, _spec: PhantomData, finalized_header, @@ -288,7 +304,7 @@ mod tests { fn gen_application_snark( params: &ParamsKZG, pk: &ProvingKey, - witness: &CommitteeRotationArgs, + witness: &CommitteeUpdateArgs, pinning_path: &str, ) -> Snark { CommitteeUpdateCircuit::::gen_snark_shplonk( @@ -335,7 +351,7 @@ mod tests { PKEY_PATH, PINNING_PATH, false, - &CommitteeRotationArgs::::default(), + &CommitteeUpdateArgs::::default(), ); let witness = load_circuit_args(); @@ -363,7 +379,7 @@ mod tests { APP_PK_PATH, APP_PINNING_PATH, false, - &CommitteeRotationArgs::::default(), + &CommitteeUpdateArgs::::default(), ); let witness = load_circuit_args(); diff --git a/lightclient-circuits/src/gadget.rs b/lightclient-circuits/src/gadget.rs deleted file mode 100644 index 726e208d..00000000 --- a/lightclient-circuits/src/gadget.rs +++ /dev/null @@ -1,3 +0,0 @@ -mod common; -pub use common::*; -pub mod crypto; diff --git a/lightclient-circuits/src/gadget/common.rs b/lightclient-circuits/src/gadget/common.rs index b1f5dbc1..bab8fac4 100644 --- a/lightclient-circuits/src/gadget/common.rs +++ b/lightclient-circuits/src/gadget/common.rs @@ -1,8 +1,16 @@ +// The Licensed Work is (c) 2023 ChainSafe +// Code: https://github.com/ChainSafe/Spectre +// SPDX-License-Identifier: LGPL-3.0-only + //! Utility traits, functions used in the crate. use eth_types::Field; use halo2_base::{gates::GateInstructions, AssignedValue, Context, QuantumCell}; use itertools::Itertools; +/// Constraints number `a` to have a little-endian byte representation that is returned. +/// Uses a verification trick where instead of decomposing `a` into bytes in circuit, +/// we upload LE bytes and composing them back into `checksum` via inner product. +/// This relies on the fact tha inner product is significantly more efficient than decomposing into bytes that involves a lot of scalar division. pub fn to_bytes_le( a: &AssignedValue, gate: &impl GateInstructions, @@ -12,6 +20,7 @@ pub fn to_bytes_le( .map(|i| QuantumCell::Constant(gate.pow_of_two()[i * 8])) .collect_vec(); + // Compute LE bytes off-circuit. let assigned_bytes = a .value() .to_bytes_le() diff --git a/lightclient-circuits/src/gadget/crypto/builder.rs b/lightclient-circuits/src/gadget/crypto/builder.rs index 198776d1..c257c2c2 100644 --- a/lightclient-circuits/src/gadget/crypto/builder.rs +++ b/lightclient-circuits/src/gadget/crypto/builder.rs @@ -1,3 +1,7 @@ +// The Licensed Work is (c) 2023 ChainSafe +// Code: https://github.com/ChainSafe/Spectre +// SPDX-License-Identifier: LGPL-3.0-only + use std::env::set_var; use crate::util::{CommonGateManager, Eth2ConfigPinning, GateBuilderConfig, PinnableCircuit}; diff --git a/lightclient-circuits/src/gadget/crypto/ecc.rs b/lightclient-circuits/src/gadget/crypto/ecc.rs index 50b50203..5fe5eac6 100644 --- a/lightclient-circuits/src/gadget/crypto/ecc.rs +++ b/lightclient-circuits/src/gadget/crypto/ecc.rs @@ -1,3 +1,7 @@ +// The Licensed Work is (c) 2023 ChainSafe +// Code: https://github.com/ChainSafe/Spectre +// SPDX-License-Identifier: LGPL-3.0-only + use eth_types::Field; use halo2_base::Context; use halo2_ecc::{bigint::ProperCrtUint, bls12_381::FpChip, fields::FieldChip}; diff --git a/lightclient-circuits/src/gadget/crypto/mod.rs b/lightclient-circuits/src/gadget/crypto/mod.rs index 69e2f05b..61cceaeb 100644 --- a/lightclient-circuits/src/gadget/crypto/mod.rs +++ b/lightclient-circuits/src/gadget/crypto/mod.rs @@ -1,3 +1,7 @@ +// The Licensed Work is (c) 2023 ChainSafe +// Code: https://github.com/ChainSafe/Spectre +// SPDX-License-Identifier: LGPL-3.0-only + mod builder; mod ecc; diff --git a/lightclient-circuits/src/gadget/crypto/sha256_flex.rs b/lightclient-circuits/src/gadget/crypto/sha256_flex.rs index ade9643d..c33b8500 100644 --- a/lightclient-circuits/src/gadget/crypto/sha256_flex.rs +++ b/lightclient-circuits/src/gadget/crypto/sha256_flex.rs @@ -1,3 +1,11 @@ +// The Licensed Work is (c) 2023 ChainSafe +// Code: https://github.com/ChainSafe/Spectre +// SPDX-License-Identifier: LGPL-3.0-only + +// ! This file is a modified version of the original file from https://github.com/zkemail/halo2-dynamic-sha256 (MIT license) +// ! The original implementation is made to be "dynamic" in a sense that it can handle variable-length inputs. +// ! This is not needed for our use case so those "extra" contraints are removed. + mod compression; mod gate; mod spread; @@ -23,6 +31,9 @@ pub use self::spread::SpreadChip; use super::{HashInstructions, ShaCircuitBuilder}; +/// [`Sha256Chip`] provides functions to compute SHA256 hash [`SpreadConfig`] gates. +/// This is version of SHA256 chip is flexible by allowing do distribute advice cells into multiple sets of columns (`dense`, `spread`). +/// It also heavily benefits from lookup tables (bigger `num_bits_lookup` is better). #[derive(Debug, Clone)] pub struct Sha256Chip<'a, F: Field> { spread: SpreadChip<'a, F>, @@ -76,11 +87,7 @@ impl<'a, F: Field> HashInstructions for Sha256Chip<'a, F> { }; let padded_size = one_round_size * num_round; let zero_padding_byte_size = padded_size - input_byte_size_with_9; - // let remaining_byte_size = MAX_INPUT_SIZE - padded_size; - // assert_eq!( - // remaining_byte_size, - // one_round_size * (max_round - num_round) - // ); + let mut assign_byte = |byte: u8| builder.main().load_witness(F::from(byte as u64)); assigned_input_bytes.push(assign_byte(0x80)); @@ -97,9 +104,6 @@ impl<'a, F: Field> HashInstructions for Sha256Chip<'a, F> { } assert_eq!(assigned_input_bytes.len(), num_round * one_round_size); - // for _ in 0..remaining_byte_size { - // assigned_input_bytes.push(assign_byte(0u8)); - // } let assigned_num_round = builder.main().load_witness(F::from(num_round as u64)); @@ -180,6 +184,7 @@ impl<'a, F: Field> HashInstructions for Sha256Chip<'a, F> { impl<'a, F: Field> Sha256Chip<'a, F> { pub fn new(range: &'a RangeChip) -> Self { + // Spread chip requires 16 % lookup_bits == 0 so we set it to either 8 or 16 based on circuit degree. let lookup_bits = if range.lookup_bits() > 8 { 16 } else { 8 }; Self { @@ -187,91 +192,3 @@ impl<'a, F: Field> Sha256Chip<'a, F> { } } } - -#[cfg(test)] -mod test { - // use std::env::var; - // use std::vec; - // use std::{cell::RefCell, marker::PhantomData}; - - // use crate::gadget::crypto::ShaCircuitBuilder; - // use crate::util::{gen_pkey, IntoWitness}; - // use super::*; - // use ark_std::{end_timer, start_timer}; - // use eth_types::Testnet; - // use halo2_base::gates::range::RangeConfig; - // use halo2_base::halo2_proofs::{ - // circuit::{Layouter, SimpleFloorPlanner}, - // dev::MockProver, - // halo2curves::bn256::Fr, - // plonk::{Circuit, ConstraintSystem}, - // }; - // use halo2_base::utils::fs::gen_srs; - // use halo2_base::SKIP_FIRST_PASS; - // use sha2::{Digest, Sha256}; - - // fn test_circuit( - // k: usize, - // mut builder: ShaThreadBuilder, - // input_vector: &[Vec], - // ) -> Result>, Error> { - // let range = RangeChip::default(8); - // let sha256 = Sha256Chip::new(&range); - - // for input in input_vector { - // let _ = sha256.digest::<64>(&mut builder, input.as_slice().into_witness(), false)?; - // } - - // builder.config(k, None); - // Ok(ShaCircuitBuilder::mock(builder)) - // } - - // #[test] - // fn test_sha256_chip_constant_size() { - // let k = 15; - - // let test_input = vec![0u8; 64]; - - // let builder = ShaThreadBuilder::::mock(); - - // let circuit = test_circuit(k, builder, &[test_input]); - // let prover = MockProver::run(k as u32, &circuit.unwrap(), vec![]).unwrap(); - - // prover.assert_satisfied_par(); - // } - - // #[test] - // fn test_sha256_params_gen() { - // let k = 15; - // let test_input = vec![0u8; 64]; - // let builder = ShaThreadBuilder::::keygen(); - - // let circuit = test_circuit(k, builder, &[test_input]).unwrap(); - - // let params = gen_srs(k as u32); - // let pk = gen_pkey(|| "sha256_chip", ¶ms, None, &circuit).unwrap(); - // } - - // #[test] - // fn test_sha256_proof_gen() { - // let k = 15; - // let test_input = vec![0u8; 64]; - // let builder = ShaThreadBuilder::::keygen(); - - // let circuit = test_circuit(k, builder, &[test_input.clone()]).unwrap(); - - // let params = gen_srs(k as u32); - // let pk = gen_pkey(|| "sha256_chip", ¶ms, None, &circuit).unwrap(); - - // let break_points = circuit.break_points.take(); - - // let builder = ShaThreadBuilder::::prover(); - - // let circuit = test_circuit(k, builder, &[test_input]).unwrap(); - - // let proof = full_prover(¶ms, &pk, circuit, vec![]); - - // let is_valid = full_verifier(¶ms, pk.get_vk(), proof, vec![]); - // assert!(is_valid); - // } -} diff --git a/lightclient-circuits/src/gadget/crypto/sha256_flex/compression.rs b/lightclient-circuits/src/gadget/crypto/sha256_flex/compression.rs index 0d479645..75c72fb5 100644 --- a/lightclient-circuits/src/gadget/crypto/sha256_flex/compression.rs +++ b/lightclient-circuits/src/gadget/crypto/sha256_flex/compression.rs @@ -1,3 +1,9 @@ +// The Licensed Work is (c) 2023 ChainSafe +// Code: https://github.com/ChainSafe/Spectre +// SPDX-License-Identifier: LGPL-3.0-only + +// ! This file is a modified version of the original file from https://github.com/zkemail/halo2-dynamic-sha256 (MIT license) + use super::spread::SpreadChip; use super::util::{bits_le_to_fe, fe_to_bits_le}; use super::ShaFlexGateManager; diff --git a/lightclient-circuits/src/gadget/crypto/sha256_flex/gate.rs b/lightclient-circuits/src/gadget/crypto/sha256_flex/gate.rs index 6f1b902e..e5649db4 100644 --- a/lightclient-circuits/src/gadget/crypto/sha256_flex/gate.rs +++ b/lightclient-circuits/src/gadget/crypto/sha256_flex/gate.rs @@ -1,3 +1,7 @@ +// The Licensed Work is (c) 2023 ChainSafe +// Code: https://github.com/ChainSafe/Spectre +// SPDX-License-Identifier: LGPL-3.0-only + use std::any::TypeId; use eth_types::Field; @@ -21,6 +25,8 @@ pub const FIRST_PHASE: usize = 0; struct Dence; struct Spread; +/// `ShaFlexGateManager` keeps track of halo2-lib virtual cells and assigns them to the region corresponding to the `SpreadConfig`. +/// It also loads of the copy (permutation) constraints between halo2-lib and vanilla cells in Plonk table. #[derive(Clone, Debug, Default, CopyGetters)] pub struct ShaFlexGateManager { #[getset(get_copy = "pub")] @@ -73,10 +79,6 @@ impl ShaFlexGateManager { )); self.threads_spread.last_mut().unwrap() } - - // pub fn thread_count(&self) -> usize { - // self.core.thread_count() - // } } impl CommonGateManager for ShaFlexGateManager { diff --git a/lightclient-circuits/src/gadget/crypto/sha256_flex/spread.rs b/lightclient-circuits/src/gadget/crypto/sha256_flex/spread.rs index 3ef58138..91488bd4 100644 --- a/lightclient-circuits/src/gadget/crypto/sha256_flex/spread.rs +++ b/lightclient-circuits/src/gadget/crypto/sha256_flex/spread.rs @@ -1,3 +1,9 @@ +// The Licensed Work is (c) 2023 ChainSafe +// Code: https://github.com/ChainSafe/Spectre +// SPDX-License-Identifier: LGPL-3.0-only + +// ! This file is a modified version of the original file from https://github.com/zkemail/halo2-dynamic-sha256 (MIT license) + use eth_types::Field; use halo2_base::gates::circuit::BaseCircuitParams; use halo2_base::utils::{decompose, ScalarField}; diff --git a/lightclient-circuits/src/gadget/crypto/sha256_flex/util.rs b/lightclient-circuits/src/gadget/crypto/sha256_flex/util.rs index 5dd65145..381f380f 100644 --- a/lightclient-circuits/src/gadget/crypto/sha256_flex/util.rs +++ b/lightclient-circuits/src/gadget/crypto/sha256_flex/util.rs @@ -1,3 +1,9 @@ +// The Licensed Work is (c) 2023 ChainSafe +// Code: https://github.com/ChainSafe/Spectre +// SPDX-License-Identifier: LGPL-3.0-only + +// ! This file is a modified version of the original file from https://github.com/zkemail/halo2-dynamic-sha256 (MIT license) + use eth_types::Field; use halo2_base::utils::{biguint_to_fe, fe_to_biguint}; use itertools::Itertools; diff --git a/lightclient-circuits/src/gadget/crypto/sha256_wide.rs b/lightclient-circuits/src/gadget/crypto/sha256_wide.rs index 8dea7a84..afce2c51 100644 --- a/lightclient-circuits/src/gadget/crypto/sha256_wide.rs +++ b/lightclient-circuits/src/gadget/crypto/sha256_wide.rs @@ -1,3 +1,7 @@ +// The Licensed Work is (c) 2023 ChainSafe +// Code: https://github.com/ChainSafe/Spectre +// SPDX-License-Identifier: LGPL-3.0-only + mod gate; use eth_types::Field; @@ -15,6 +19,8 @@ pub use self::gate::ShaBitGateManager; use super::{HashInstructions, ShaCircuitBuilder}; use crate::gadget::common::to_bytes_le; +/// [`Sha256ChipWide`] provides functions to compute SHA256 hash [`Sha256CircuitConfig`] gates. +/// This is version of SHA256 chip is wider than is possible with [`Sha256Chip`] but it takes significantly less rows. #[derive(Debug)] pub struct Sha256ChipWide<'a, F: Field> { range: &'a RangeChip, @@ -115,79 +121,3 @@ pub fn word_to_bytes_le( .chain(to_bytes_le::<_, 16>(&word.hi(), gate, ctx)) .collect() } - -// #[cfg(test)] -// mod test { -// use std::env::var; -// use std::vec; -// use std::{cell::RefCell, marker::PhantomData}; - -// use crate::gadget::crypto::{constant_randomness, ShaCircuitBuilder}; -// use crate::util::{full_prover, full_verifier, gen_pkey, Challenges, IntoWitness}; - -// use super::*; -// use ark_std::{end_timer, start_timer}; -// use eth_types::Testnet; -// use halo2_base::gates::builder::FlexGateConfigParams; -// use halo2_base::gates::range::RangeConfig; -// use halo2_base::utils::fs::gen_srs; -// use halo2_base::SKIP_FIRST_PASS; -// use halo2_base::{ -// gates::{builder::GateThreadBuilder, range::RangeStrategy}, -// halo2_proofs::{ -// circuit::{Layouter, SimpleFloorPlanner}, -// dev::MockProver, -// halo2curves::bn256::Fr, -// plonk::{Circuit, ConstraintSystem}, -// }, -// }; -// use sha2::{Digest, Sha256}; - -// // fn test_circuit( -// // k: usize, -// // builder: &mut ShaBitThreadBuilder, -// // input_vector: &[Vec], -// // ) -> Result<(), Error> { -// // let range = RangeChip::default(8); -// // let sha256 = Sha256ChipWide::new(&range, constant_randomness()); - -// // for input in input_vector { -// // let _ = sha256.digest::<64>(builder, input.as_slice().into_witness(), false)?; -// // } - -// // builder.config(k, None); - -// // Ok(()) -// // } - -// // #[test] -// // fn test_sha256_chip_constant_size() { -// // let k = 10; - -// // let test_input = vec![0u8; 64]; - -// // let mut builder = ShaBitThreadBuilder::::mock(); - -// // test_circuit(k, &mut builder, &[test_input]).unwrap(); - -// // let circuit = ShaCircuitBuilder::mock(builder); - -// // let prover = MockProver::run(k as u32, &circuit, vec![]).unwrap(); - -// // prover.assert_satisfied_par(); -// // } - -// // #[test] -// // fn test_sha256_wide_params_gen() { -// // let k = 10; -// // let test_input = vec![1u8; 64]; -// // let mut builder = ShaBitThreadBuilder::::keygen(); - -// // test_circuit(k, &mut builder, &[test_input]).unwrap(); - -// // let circuit = ShaCircuitBuilder::keygen(builder); - -// // let params = gen_srs(k as u32); -// // let pk = gen_pkey(|| "sha256_wide_chip", ¶ms, None, &circuit).unwrap(); -// // } -// } diff --git a/lightclient-circuits/src/gadget/crypto/sha256_wide/gate.rs b/lightclient-circuits/src/gadget/crypto/sha256_wide/gate.rs index 0b76bb5b..e469cd5a 100644 --- a/lightclient-circuits/src/gadget/crypto/sha256_wide/gate.rs +++ b/lightclient-circuits/src/gadget/crypto/sha256_wide/gate.rs @@ -1,8 +1,12 @@ +// The Licensed Work is (c) 2023 ChainSafe +// Code: https://github.com/ChainSafe/Spectre +// SPDX-License-Identifier: LGPL-3.0-only + use crate::util::{CommonGateManager, GateBuilderConfig}; use eth_types::Field; use getset::CopyGetters; use halo2_base::{ - gates::circuit::{BaseCircuitParams, CircuitBuilderStage}, + gates::circuit::BaseCircuitParams, halo2_proofs::{ circuit::Region, plonk::{ConstraintSystem, Error}, @@ -24,6 +28,8 @@ use zkevm_hashes::{ util::word::Word, }; +/// `ShaBitGateManager` keeps track of halo2-lib virtual cells and assigns them to the region corresponding to the `Sha256CircuitConfig`. +/// It also loads of the copy (permutation) constraints between halo2-lib and vanilla cells in Plonk table. #[derive(Clone, Debug, CopyGetters)] pub struct ShaBitGateManager { #[getset(get_copy = "pub")] @@ -54,11 +60,6 @@ impl CommonGateManager for ShaBitGateManager { fn custom_context(&mut self) -> Self::CustomContext<'_> {} - fn from_stage(stage: CircuitBuilderStage) -> Self { - Self::new(stage == CircuitBuilderStage::Prover) - .unknown(stage == CircuitBuilderStage::Keygen) - } - fn use_copy_manager(mut self, copy_manager: SharedCopyConstraintManager) -> Self { self.set_copy_manager(copy_manager); self @@ -100,16 +101,6 @@ impl VirtualRegionManager for ShaBitGateManager { .insert(loaded_input_word.cell.unwrap(), vanilla_input_word.cell()); }); }); - - // if self.witness_gen_only() { - // config - // .assign_in_region(region, config, false, None) - // .unwrap(); - // } else { - // let mut copy_manager = self.copy_manager.lock().unwrap(); - // config.assign_sha256_rows(region, config, self.use_unknown(), Some(&mut copy_manager)) - // .unwrap(); - // } } } @@ -118,7 +109,6 @@ impl ShaBitGateManager { struct UnassignedShaTableRow { is_final: F, io: F, - // length: F, } let table_rows = virtual_rows .iter() @@ -139,7 +129,6 @@ impl ShaBitGateManager { UnassignedShaTableRow { is_final: F::from(row.is_final), io: io_value, - // length: F::from(row.length as u64), } }) // .enumerate() @@ -151,7 +140,7 @@ impl ShaBitGateManager { let loaded_blocks = table_rows .chunks_exact(SHA256_NUM_ROWS) .map(|rows| { - let last_row = rows.last().unwrap(); // rows[SHA256_NUM_ROWS - 1] + let last_row = rows.last().unwrap(); let is_final = copy_manager.mock_external_assigned(last_row.is_final); let output_lo = copy_manager.mock_external_assigned(last_row.io); let output_hi = copy_manager.mock_external_assigned(rows[SHA256_NUM_ROWS - 2].io); @@ -162,8 +151,6 @@ impl ShaBitGateManager { .collect::>() .try_into() .unwrap(); - // let length = - // copy_manager.mock_external_assigned(input_rows.last().unwrap().1.length); LoadedSha256 { is_final, hash: Word::new([output_lo, output_hi]), @@ -180,7 +167,6 @@ impl ShaBitGateManager { /// Mutates `self` to use the given copy manager everywhere, including in all threads. pub fn set_copy_manager(&mut self, copy_manager: SharedCopyConstraintManager) { self.copy_manager = copy_manager.clone(); - // TODO: set to `self.sha_contexts`. } } diff --git a/lightclient-circuits/src/gadget/mod.rs b/lightclient-circuits/src/gadget/mod.rs new file mode 100644 index 00000000..fbdff468 --- /dev/null +++ b/lightclient-circuits/src/gadget/mod.rs @@ -0,0 +1,7 @@ +// The Licensed Work is (c) 2023 ChainSafe +// Code: https://github.com/ChainSafe/Spectre +// SPDX-License-Identifier: LGPL-3.0-only + +mod common; +pub use common::*; +pub mod crypto; diff --git a/lightclient-circuits/src/lib.rs b/lightclient-circuits/src/lib.rs index 4d1b5a84..653a4c83 100644 --- a/lightclient-circuits/src/lib.rs +++ b/lightclient-circuits/src/lib.rs @@ -1,3 +1,7 @@ +// The Licensed Work is (c) 2023 ChainSafe +// Code: https://github.com/ChainSafe/Spectre +// SPDX-License-Identifier: LGPL-3.0-only + #![allow(incomplete_features)] #![feature(int_roundings)] #![feature(associated_type_bounds)] @@ -7,6 +11,7 @@ #![feature(generic_arg_infer)] #![feature(return_position_impl_trait_in_trait)] #![allow(clippy::needless_range_loop)] + pub mod gadget; pub mod util; pub mod witness; diff --git a/lightclient-circuits/src/poseidon.rs b/lightclient-circuits/src/poseidon.rs index ab6dcbb6..2826e226 100644 --- a/lightclient-circuits/src/poseidon.rs +++ b/lightclient-circuits/src/poseidon.rs @@ -1,3 +1,7 @@ +// The Licensed Work is (c) 2023 ChainSafe +// Code: https://github.com/ChainSafe/Spectre +// SPDX-License-Identifier: LGPL-3.0-only + use eth_types::{Field, LIMB_BITS}; use halo2_base::{ gates::GateInstructions, halo2_proofs::halo2curves::bn256, halo2_proofs::plonk::Error, @@ -18,11 +22,20 @@ const N_ROUNDS_PC: [usize; 16] = [ 56, 57, 56, 60, 60, 63, 64, 63, 60, 66, 60, 65, 70, 60, 64, 68, ]; +// Empirically chosen to take the least space in circuit. const POSEIDON_SIZE: usize = 11; const T: usize = POSEIDON_SIZE + 1; const R_P: usize = N_ROUNDS_PC[T - 2]; const R_F: usize = 8; +/// Generates Poseidon hash commitment to a list of BLS12-381 Fq elements. +/// +/// Fields elements are initially represented as `NUM_LIMBS` limbs of `LIMB_BITS` bits each. +/// By composing element two limbs in one, we reduce the number of inputs to Poseidon in half. +/// +/// Each Poseidon sponge absorbs `POSEIDON_SIZE`-2 elements and previos sponge output if it's not the first batch, ie. onion commitment. +/// +/// Assumes that LIMB_BITS * 2 < 254 (BN254). pub fn fq_array_poseidon<'a, F: Field>( ctx: &mut Context, fp_chip: &FpChip, @@ -60,7 +73,10 @@ pub fn fq_array_poseidon<'a, F: Field>( Ok(current_poseidon_hash.unwrap()) } -pub fn fq_array_poseidon_native(elems: impl Iterator, limb_bits: usize) -> F { +/// Generates Poseidon hash commitment to a list of BLS12-381 Fq elements. +/// +/// This is the off-circuit analog of `fq_array_poseidon`. +pub fn poseidon_hash_fq_array(elems: impl Iterator, limb_bits: usize) -> F { let limbs = elems // Converts Fq elements to Fr limbs. .flat_map(|x| { @@ -83,6 +99,7 @@ pub fn fq_array_poseidon_native(elems: impl Iterator, limb_ current_poseidon_hash.unwrap() } +/// Wrapper on `poseidon_hash_fq_array` taking pubkeys encoded as uncompressed bytes. pub fn poseidon_committee_commitment_from_uncompressed( pubkeys_uncompressed: &[Vec], ) -> bn256::Fr { @@ -97,14 +114,15 @@ pub fn poseidon_committee_commitment_from_uncompressed( }) .collect_vec(); - fq_array_poseidon_native::(pubkey_affines.iter().map(|p| p.x), LIMB_BITS) + poseidon_hash_fq_array::(pubkey_affines.iter().map(|p| p.x), LIMB_BITS) } +/// Wrapper on `poseidon_hash_fq_array` taking pubkeys encoded as compressed bytes. pub fn poseidon_committee_commitment_from_compressed(pubkeys_compressed: &[Vec]) -> bn256::Fr { let pubkeys_x = pubkeys_compressed.iter().cloned().map(|mut bytes| { bytes[0] &= 0b00011111; bls12_381::Fq::from_bytes_be(&bytes.try_into().unwrap()) .expect("bad bls12_381::Fq encoding") }); - fq_array_poseidon_native::(pubkeys_x, LIMB_BITS) + poseidon_hash_fq_array::(pubkeys_x, LIMB_BITS) } diff --git a/lightclient-circuits/src/ssz_merkle.rs b/lightclient-circuits/src/ssz_merkle.rs index 3a877ac4..94b96cea 100644 --- a/lightclient-circuits/src/ssz_merkle.rs +++ b/lightclient-circuits/src/ssz_merkle.rs @@ -1,3 +1,7 @@ +// The Licensed Work is (c) 2023 ChainSafe +// Code: https://github.com/ChainSafe/Spectre +// SPDX-License-Identifier: LGPL-3.0-only + use crate::{ gadget::crypto::HashInstructions, util::IntoConstant, @@ -10,6 +14,10 @@ use halo2_base::{ }; use itertools::Itertools; +/// Computes Merkle root of a list of SSZ chunks. +/// +/// Can work with numbers of chunks that are not a power of two, in which case the tree level is padded with zero hashes. +/// However, zero hashes are only precomputed for the first two levels. pub fn ssz_merkleize_chunks>( builder: &mut CircuitBuilder, hasher: &impl HashInstructions, @@ -44,20 +52,23 @@ pub fn ssz_merkleize_chunks>( _ => unreachable!(), }); - Ok(root.bytes) + Ok(root.to_vec()) } +/// Verifies `leaf` against the `root` using Merkle `branch`. Requires `gindex` for deterministic traversal of the tree. +/// +/// Assumes that `root` and `leaf` are 32 bytes each. pub fn verify_merkle_proof>( builder: &mut CircuitBuilder, hasher: &impl HashInstructions, - proof: impl IntoIterator>>, + branch: impl IntoIterator>>, leaf: HashInputChunk>, root: &[AssignedValue], mut gindex: usize, ) -> Result<(), Error> { let mut computed_hash = leaf; - for witness in proof.into_iter() { + for witness in branch.into_iter() { computed_hash = hasher .digest( builder, @@ -71,7 +82,7 @@ pub fn verify_merkle_proof>( gindex /= 2; } - let computed_root = computed_hash.bytes.into_iter().map(|b| match b { + let computed_root = computed_hash.into_iter().map(|b| match b { QuantumCell::Existing(av) => av, _ => unreachable!(), }); diff --git a/lightclient-circuits/src/sync_step_circuit.rs b/lightclient-circuits/src/sync_step_circuit.rs index 74b562c2..5c91008e 100644 --- a/lightclient-circuits/src/sync_step_circuit.rs +++ b/lightclient-circuits/src/sync_step_circuit.rs @@ -1,3 +1,7 @@ +// The Licensed Work is (c) 2023 ChainSafe +// Code: https://github.com/ChainSafe/Spectre +// SPDX-License-Identifier: LGPL-3.0-only + use crate::{ gadget::{ crypto::{ @@ -6,7 +10,7 @@ use crate::{ }, to_bytes_le, }, - poseidon::{fq_array_poseidon, fq_array_poseidon_native}, + poseidon::{fq_array_poseidon, poseidon_hash_fq_array}, ssz_merkle::{ssz_merkleize_chunks, verify_merkle_proof}, util::{AppCircuit, Eth2ConfigPinning, IntoWitness}, witness::{self, HashInput, HashInputChunk, SyncStepArgs}, @@ -39,7 +43,15 @@ use num_bigint::BigUint; use ssz_rs::Merkleized; use std::{env::var, marker::PhantomData, vec}; -#[allow(type_alias_bounds)] +/// `StepCircuit` verifies that Beacon chain block header is attested by a lightclient sync committee via aggregated signature, +/// and the execution (Eth1) payload via Merkle proof against the finalized block header. +/// +/// Assumes that signature is a BLS12-381 point on G2, and public keys are BLS12-381 points on G1; `finality_branch` is exactly `S::FINALIZED_HEADER_DEPTH` hashes in lenght; +/// and `execution_payload_branch` is `S::EXECUTION_PAYLOAD_DEPTH` hashes in lenght. +/// +/// The circuit exposes two public inputs: +/// - `pub_inputs_commit` is SHA256(attested_slot || inalized_slot || participation_sum || finalized_header_root || execution_payload_root) truncated to 253 bits. All committed valeus are in little endian. +/// - `poseidon_commit` is a Poseidon "onion" commitment to the X coordinates of sync committee public keys. Coordinates are expressed as big-integer with two limbs of LIMB_BITS * 2 bits. #[derive(Clone, Debug, Default)] pub struct StepCircuit { _f: PhantomData, @@ -52,10 +64,7 @@ impl StepCircuit { fp_chip: &FpChip, args: &witness::SyncStepArgs, ) -> Result>, Error> { - assert!( - !args.signature_compressed.is_empty(), - "no attestations supplied" - ); + assert!(!args.signature_compressed.is_empty(), "signature expected"); let range = fp_chip.range(); let gate = range.gate(); @@ -87,13 +96,16 @@ impl StepCircuit { &args.pariticipation_bits, &mut assigned_affines, ); + + // Commit to the pubkeys using Poseidon hash. This constraints prover to use the pubkeys of the current sync committee, + // because the same commitment is computed in `CommitteeUpdateCircuit` and stored in the contract at the begining of the period. let poseidon_commit = fq_array_poseidon( builder.main(), fp_chip, assigned_affines.iter().map(|p| &p.x), )?; - // Verify attestted header + // Compute attested header root let attested_slot_bytes: HashInputChunk<_> = args.attested_header.slot.into_witness(); let attested_header_state_root = args .attested_header @@ -114,6 +126,7 @@ impl StepCircuit { ], )?; + // Compute finalized header root let finalized_block_body_root = args .finalized_header .body_root @@ -121,7 +134,6 @@ impl StepCircuit { .iter() .map(|&b| builder.main().load_witness(F::from(b as u64))) .collect_vec(); - let finalized_slot_bytes: HashInputChunk<_> = args.finalized_header.slot.into_witness(); let finalized_header_root = ssz_merkleize_chunks( builder, @@ -139,7 +151,7 @@ impl StepCircuit { builder, HashInput::TwoToOne( attested_header_root.into(), - args.domain.to_vec().into_witness(), + args.domain.to_vec().into_witness(), // `domain` can't be a constant because will change in next fork. ), )?; @@ -154,7 +166,7 @@ impl StepCircuit { bls_chip.assert_valid_signature(builder.main(), signature, msghash, agg_pubkey); - // verify finalized block header against current beacon state merkle proof + // Verify finalized block header against current state root via the Merkle "finality" proof verify_merkle_proof( builder, &sha256_chip, @@ -166,7 +178,7 @@ impl StepCircuit { S::FINALIZED_HEADER_INDEX, )?; - // verify execution state root against finilized block body merkle proof + // Verify execution payload root against finalized block body via the Merkle "execution" proof verify_merkle_proof( builder, &sha256_chip, @@ -180,31 +192,35 @@ impl StepCircuit { // Public Input Commitment // See "Onion hashing vs. Input concatenation" in https://github.com/ChainSafe/Spectre/issues/17#issuecomment-1740965182 - let participation_sum_le = to_bytes_le::<_, 8>(&participation_sum, gate, builder.main()); - let pub_inputs_concat = itertools::chain![ - attested_slot_bytes.bytes.into_iter().take(8), - finalized_slot_bytes.bytes.into_iter().take(8), - participation_sum_le - .into_iter() - .map(|b| QuantumCell::Existing(b)), - finalized_header_root - .into_iter() - .map(|b| QuantumCell::Existing(b)), - execution_payload_root.bytes.into_iter(), - ] - .collect_vec(); + let pub_inputs_commit = { + let participation_sum_le = + to_bytes_le::<_, 8>(&participation_sum, gate, builder.main()); + let pub_inputs_concat = itertools::chain![ + attested_slot_bytes.into_iter().take(8), + finalized_slot_bytes.into_iter().take(8), + participation_sum_le + .into_iter() + .map(|b| QuantumCell::Existing(b)), + finalized_header_root + .into_iter() + .map(|b| QuantumCell::Existing(b)), + execution_payload_root.into_iter(), + ] + .collect_vec(); - let pub_inputs_bytes = sha256_chip - .digest(builder, pub_inputs_concat)? - .try_into() - .unwrap(); + let pub_inputs_bytes = sha256_chip + .digest(builder, pub_inputs_concat)? + .try_into() + .unwrap(); - let pub_inputs_commit = - truncate_sha256_into_single_elem(builder.main(), range, pub_inputs_bytes); + truncate_sha256_into_single_elem(builder.main(), range, pub_inputs_bytes) + }; Ok(vec![pub_inputs_commit, poseidon_commit]) } + // Computes public inputs to `StepCircuit` matching the in-circuit logic from `synthesise` method. + // Note, this function outputes only instances of the `StepCircuit` proof, not the aggregated proof which will also include 12 accumulator limbs. pub fn get_instances(args: &SyncStepArgs, limb_bits: usize) -> Vec> { use sha2::Digest; const INPUT_SIZE: usize = 8 * 3 + 32 * 2; @@ -252,8 +268,7 @@ impl StepCircuit { }) .collect_vec(); let poseidon_commitment = - fq_array_poseidon_native::(pubkey_affines.iter().map(|p| p.x), limb_bits); - + poseidon_hash_fq_array::(pubkey_affines.iter().map(|p| p.x), limb_bits); let mut public_input_commitment = sha2::Sha256::digest(&input).to_vec(); // Truncate to 253 bits @@ -306,6 +321,7 @@ pub fn clear_3_bits( } impl StepCircuit { + /// Decompresses siganure from bytes and assigns it to the circuit. fn assign_signature( ctx: &mut Context, g2_chip: &G2Chip, @@ -318,6 +334,7 @@ impl StepCircuit { } /// Takes a list of pubkeys and aggregates them. + /// The outputs are the aggregated pubkey, the sum of participation bits, and a list of assigned pubkeys. fn aggregate_pubkeys( ctx: &mut Context, fp_chip: &FpChip<'_, F>, @@ -440,7 +457,7 @@ mod tests { } #[test] - fn test_sync_circuit() { + fn test_step_circuit() { const K: u32 = 20; let witness = load_circuit_args(); @@ -461,7 +478,7 @@ mod tests { } #[test] - fn test_sync_proofgen() { + fn test_step_proofgen() { const K: u32 = 22; let params = gen_srs(K); @@ -485,7 +502,7 @@ mod tests { } #[test] - fn test_sync_evm_verify() { + fn test_step_evm_verify() { const K: u32 = 22; let params = gen_srs(K); diff --git a/lightclient-circuits/src/util.rs b/lightclient-circuits/src/util.rs deleted file mode 100644 index 586f98d7..00000000 --- a/lightclient-circuits/src/util.rs +++ /dev/null @@ -1,13 +0,0 @@ -//! Common utility traits and functions. - -mod common; -pub use common::*; - -mod conversion; -pub(crate) use conversion::*; - -mod proof; -pub use proof::*; - -mod circuit; -pub use circuit::*; diff --git a/lightclient-circuits/src/util/circuit.rs b/lightclient-circuits/src/util/circuit.rs index 76c8d37f..6bda314f 100644 --- a/lightclient-circuits/src/util/circuit.rs +++ b/lightclient-circuits/src/util/circuit.rs @@ -1,3 +1,7 @@ +// The Licensed Work is (c) 2023 ChainSafe +// Code: https://github.com/ChainSafe/Spectre +// SPDX-License-Identifier: LGPL-3.0-only + use std::env::{set_var, var}; use std::fs; use std::{fs::File, path::Path}; @@ -20,6 +24,7 @@ use snark_verifier_sdk::halo2::gen_proof_shplonk; use snark_verifier_sdk::{gen_pk, halo2::gen_snark_shplonk, read_pk}; use snark_verifier_sdk::{CircuitExt, Snark}; +/// Halo2 circuit configuration parameters. pub trait Halo2ConfigPinning: Serialize { type BreakPoints; /// Loads configuration parameters from a file and sets environmental variables. diff --git a/lightclient-circuits/src/util/conversion.rs b/lightclient-circuits/src/util/conversion.rs index ebab2b24..d4cd681d 100644 --- a/lightclient-circuits/src/util/conversion.rs +++ b/lightclient-circuits/src/util/conversion.rs @@ -1,3 +1,7 @@ +// The Licensed Work is (c) 2023 ChainSafe +// Code: https://github.com/ChainSafe/Spectre +// SPDX-License-Identifier: LGPL-3.0-only + pub trait WitnessFrom: Sized { fn witness_from(value: T) -> Self; } diff --git a/lightclient-circuits/src/util/common.rs b/lightclient-circuits/src/util/gates.rs similarity index 68% rename from lightclient-circuits/src/util/common.rs rename to lightclient-circuits/src/util/gates.rs index 674915e0..7a529d98 100644 --- a/lightclient-circuits/src/util/common.rs +++ b/lightclient-circuits/src/util/gates.rs @@ -1,7 +1,10 @@ -#![allow(dead_code)] +// The Licensed Work is (c) 2023 ChainSafe +// Code: https://github.com/ChainSafe/Spectre +// SPDX-License-Identifier: LGPL-3.0-only + use eth_types::*; use halo2_base::{ - gates::circuit::{BaseCircuitParams, CircuitBuilderStage}, + gates::circuit::BaseCircuitParams, halo2_proofs::{ circuit::{Layouter, Region}, plonk::{ConstraintSystem, Error}, @@ -11,6 +14,7 @@ use halo2_base::{ }, }; +/// Custom config for a custom gate builder. pub trait GateBuilderConfig: Clone + Sized { fn configure(meta: &mut ConstraintSystem, params: BaseCircuitParams) -> Self; @@ -19,6 +23,7 @@ pub trait GateBuilderConfig: Clone + Sized { fn annotate_columns_in_region(&self, region: &mut Region); } +/// Thin abstraction over a gate a `VirtualRegionManager`. pub trait CommonGateManager: VirtualRegionManager + Clone { type CustomContext<'a> where @@ -31,22 +36,5 @@ pub trait CommonGateManager: VirtualRegionManager + Clone { /// Returns `self` with a given copy manager fn use_copy_manager(self, copy_manager: SharedCopyConstraintManager) -> Self; - fn from_stage(stage: CircuitBuilderStage) -> Self { - Self::new(stage == CircuitBuilderStage::Prover) - .unknown(stage == CircuitBuilderStage::Keygen) - } - - fn mock() -> Self { - Self::new(false) - } - - fn keygen() -> Self { - Self::new(false).unknown(true) - } - - fn prover() -> Self { - Self::new(true) - } - fn unknown(self, use_unknown: bool) -> Self; } diff --git a/lightclient-circuits/src/util/mod.rs b/lightclient-circuits/src/util/mod.rs new file mode 100644 index 00000000..90d4d035 --- /dev/null +++ b/lightclient-circuits/src/util/mod.rs @@ -0,0 +1,14 @@ +// The Licensed Work is (c) 2023 ChainSafe +// Code: https://github.com/ChainSafe/Spectre +// SPDX-License-Identifier: LGPL-3.0-only + +//! Common utility traits and functions. + +mod gates; +pub use gates::*; + +mod conversion; +pub(crate) use conversion::*; + +mod circuit; +pub use circuit::*; diff --git a/lightclient-circuits/src/util/proof.rs b/lightclient-circuits/src/util/proof.rs deleted file mode 100644 index 69460a96..00000000 --- a/lightclient-circuits/src/util/proof.rs +++ /dev/null @@ -1,86 +0,0 @@ -use std::fs; -use std::{fs::File, path::Path}; - -use ark_std::{end_timer, start_timer}; -use halo2_base::halo2_proofs::{ - halo2curves::bn256::{Bn256, Fr, G1Affine}, - plonk::{keygen_pk, keygen_vk, Circuit, ProvingKey, VerifyingKey}, - poly::kzg::commitment::ParamsKZG, - SerdeFormat::RawBytesUnchecked, -}; - -pub use halo2_base::utils::fs::{gen_srs, read_or_create_srs, read_params}; - -/// Generate setup artifacts for a circuit of size `k`, where 2^k represents the number of rows in the circuit. -/// -/// If the trusted setup parameters are not found, the function performs an unsafe trusted setup to generate the necessary parameters -/// If the provided `k` value is larger than the `k` value of the loaded parameters, an error is returned, as the provided `k` is too large. -/// Otherwise, if the `k` value is smaller than the `k` value of the loaded parameters, the parameters are downsized to fit the requested `k`. -#[allow(clippy::type_complexity)] -pub fn read_vkey>( - path: &Path, - params: C::Params, -) -> Result, &'static str> { - let timer = start_timer!(|| "Loading vkey"); - - let mut file = File::open(path).map_err(|_| "failed to read file")?; - - let vk = VerifyingKey::::read::<_, C>(&mut file, RawBytesUnchecked, params) - .map_err(|_| "failed to decode vkey"); - - end_timer!(timer); - - vk -} - -/// Generate setup artifacts for a circuit of size `k`, where 2^k represents the number of rows in the circuit. -/// -/// If the trusted setup parameters are not found, the function performs an unsafe trusted setup to generate the necessary parameters -/// If the provided `k` value is larger than the `k` value of the loaded parameters, an error is returned, as the provided `k` is too large. -/// Otherwise, if the `k` value is smaller than the `k` value of the loaded parameters, the parameters are downsized to fit the requested `k`. -#[allow(clippy::type_complexity)] -pub fn gen_pkey>( - name: impl Fn() -> &'static str, - params: &ParamsKZG, - dir_path: Option<&Path>, - circuit: &C, -) -> Result, &'static str> { - if let Some(path) = &dir_path { - fs::create_dir_all(path).expect("Failed to create directory"); - } - - let (timer, vkey) = if let Some(dir) = dir_path { - let vkey_path = dir.join(format!("{}.vkey", name())); - match File::open(&vkey_path) { - Ok(mut file) => ( - start_timer!(|| "Loading vkey"), - VerifyingKey::::read::<_, C>( - &mut file, - RawBytesUnchecked, - circuit.params(), - ) - .expect("failed to read vkey"), - ), - Err(_) => { - let timer = start_timer!(|| "Creating and writting vkey"); - let vk = keygen_vk(params, circuit).expect("vk generation should not fail"); - let mut file = File::create(vkey_path).expect("couldn't create vkey file"); - vk.write(&mut file, RawBytesUnchecked) - .expect("Failed to write vkey"); - (timer, vk) - } - } - } else { - ( - start_timer!(|| "Generating vkey"), - keygen_vk(params, circuit).expect("vk generation should not fail"), - ) - }; - end_timer!(timer); - - let timer = start_timer!(|| "Generating pkey"); - let pkey = keygen_pk(params, vkey, circuit).expect("pk generation should not fail"); - end_timer!(timer); - - Ok(pkey) -} diff --git a/lightclient-circuits/src/witness.rs b/lightclient-circuits/src/witness.rs deleted file mode 100644 index dbd9d30c..00000000 --- a/lightclient-circuits/src/witness.rs +++ /dev/null @@ -1,10 +0,0 @@ -//! Witnesses for all circuits. - -mod step; -pub use step::*; - -mod rotation; -pub use rotation::*; - -mod hashing; -pub use hashing::*; diff --git a/lightclient-circuits/src/witness/hashing.rs b/lightclient-circuits/src/witness/hashing.rs index d929890a..e890a336 100644 --- a/lightclient-circuits/src/witness/hashing.rs +++ b/lightclient-circuits/src/witness/hashing.rs @@ -1,7 +1,11 @@ +// The Licensed Work is (c) 2023 ChainSafe +// Code: https://github.com/ChainSafe/Spectre +// SPDX-License-Identifier: LGPL-3.0-only + use std::hash::Hash; use eth_types::Field; -use halo2_base::{AssignedValue, Context, QuantumCell}; +use halo2_base::{AssignedValue, QuantumCell}; use itertools::Itertools; use crate::util::{ConstantFrom, IntoWitness, WitnessFrom}; @@ -13,23 +17,12 @@ pub enum HashInput { } impl HashInput { - pub fn len(&self) -> usize { - match self { - HashInput::Single(inner) => inner.bytes.len(), - HashInput::TwoToOne(left, right) => left.bytes.len() + right.bytes.len(), - } - } - - pub fn is_empty(&self) -> bool { - self.len() == 0 - } - pub fn to_vec(self) -> Vec { match self { - HashInput::Single(inner) => inner.bytes, + HashInput::Single(inner) => inner.0, HashInput::TwoToOne(left, right) => { - let mut result = left.bytes; - result.extend(right.bytes); + let mut result = left.0; + result.extend(right.0); result } } @@ -37,27 +30,15 @@ impl HashInput { pub fn map B>(self, f: F) -> HashInput { match self { - HashInput::Single(inner) => HashInput::Single(HashInputChunk { - bytes: inner.bytes.into_iter().map(f).collect(), - is_rlc: inner.is_rlc, - }), + HashInput::Single(inner) => { + HashInput::Single(HashInputChunk(inner.0.into_iter().map(f).collect())) + } HashInput::TwoToOne(left, right) => { - let left_size = left.bytes.len(); - let mut all = left - .bytes - .into_iter() - .chain(right.bytes) - .map(f) - .collect_vec(); + let left_size = left.0.len(); + let mut all = left.0.into_iter().chain(right.0).map(f).collect_vec(); let remainer = all.split_off(left_size); - let left = HashInputChunk { - bytes: all, - is_rlc: left.is_rlc, - }; - let right = HashInputChunk { - bytes: remainer, - is_rlc: right.is_rlc, - }; + let left = HashInputChunk(all); + let right = HashInputChunk(remainer); HashInput::TwoToOne(left, right) } @@ -75,28 +56,6 @@ impl IntoIterator for HashInput> { } } -impl HashInput> { - pub fn into_assigned(self, ctx: &mut Context) -> HashInput> { - self.map(|cell| match cell { - QuantumCell::Existing(v) => v, - QuantumCell::Witness(v) => ctx.load_witness(v), - QuantumCell::Constant(v) => ctx.load_constant(v), - _ => unreachable!(), - }) - } -} - -impl From>> for HashInput { - fn from(input: HashInput>) -> Self { - input.map(|cell| match cell { - QuantumCell::Existing(v) => v.value().get_lower_32() as u8, - QuantumCell::Witness(v) => v.get_lower_32() as u8, - QuantumCell::Constant(v) => v.get_lower_32() as u8, - _ => unreachable!(), - }) - } -} - impl>> From for HashInput { fn from(input: I) -> Self { HashInput::Single(input.into()) @@ -121,14 +80,13 @@ impl>> WitnessFrom for HashInput Self { let input: HashInputChunk = input.into(); - HashInput::Single(HashInputChunk { - bytes: input - .bytes + HashInput::Single(HashInputChunk( + input + .0 .into_iter() .map(|b| QuantumCell::Witness(F::from(b as u64))) .collect(), - is_rlc: input.is_rlc, - }) + )) } } @@ -141,24 +99,29 @@ impl>, IR: Into>> Witne } #[derive(Debug, Clone, Hash, PartialEq, Eq)] -pub struct HashInputChunk { - pub bytes: Vec, - pub is_rlc: bool, -} +pub struct HashInputChunk(Vec); impl HashInputChunk { pub fn new(bytes: Vec) -> Self { - Self { - is_rlc: bytes.len() >= 32, - bytes, - } + Self(bytes) } pub fn map B>(self, f: F) -> HashInputChunk { - HashInputChunk { - bytes: self.bytes.into_iter().map(f).collect(), - is_rlc: self.is_rlc, - } + HashInputChunk(self.0.into_iter().map(f).collect()) + } + + pub fn to_vec(self) -> Vec { + self.0 + } +} + +impl IntoIterator for HashInputChunk> { + type Item = QuantumCell; + + type IntoIter = std::vec::IntoIter; + + fn into_iter(self) -> Self::IntoIter { + self.0.into_iter() } } @@ -166,14 +129,13 @@ impl>> WitnessFrom for HashInputChunk Self { let input: HashInputChunk = input.into(); - HashInputChunk { - bytes: input - .bytes + HashInputChunk( + input + .0 .into_iter() .map(|b| QuantumCell::Witness(F::from(b as u64))) .collect(), - is_rlc: input.is_rlc, - } + ) } } @@ -181,51 +143,37 @@ impl>> ConstantFrom for HashInputChunk Self { let input: HashInputChunk = input.into(); - HashInputChunk { - bytes: input - .bytes + HashInputChunk( + input + .0 .into_iter() .map(|b| QuantumCell::Constant(F::from(b as u64))) .collect(), - is_rlc: input.is_rlc, - } + ) } } impl From<&[u8]> for HashInputChunk { fn from(input: &[u8]) -> Self { - HashInputChunk { - bytes: input.to_vec(), - is_rlc: input.len() >= 32, - } + HashInputChunk(input.to_vec()) } } impl From> for HashInputChunk { fn from(input: Vec) -> Self { - let is_rlc = input.len() >= 32; - HashInputChunk { - bytes: input, - is_rlc, - } + HashInputChunk(input) } } impl From for HashInputChunk { fn from(input: u64) -> Self { - HashInputChunk { - bytes: pad_to_32(&input.to_le_bytes()), - is_rlc: false, - } + HashInputChunk(pad_to_32(&input.to_le_bytes())) } } impl From for HashInputChunk { fn from(input: usize) -> Self { - HashInputChunk { - bytes: pad_to_32(&input.to_le_bytes()), - is_rlc: false, - } + HashInputChunk(pad_to_32(&input.to_le_bytes())) } } @@ -237,10 +185,7 @@ impl>> From .into_iter() .map(|av| QuantumCell::Existing(av)) .collect_vec(); - HashInputChunk { - is_rlc: bytes.len() >= 32, - bytes, - } + HashInputChunk(bytes) } } diff --git a/lightclient-circuits/src/witness/mod.rs b/lightclient-circuits/src/witness/mod.rs new file mode 100644 index 00000000..69cf38df --- /dev/null +++ b/lightclient-circuits/src/witness/mod.rs @@ -0,0 +1,14 @@ +// The Licensed Work is (c) 2023 ChainSafe +// Code: https://github.com/ChainSafe/Spectre +// SPDX-License-Identifier: LGPL-3.0-only + +//! Witnesses for all circuits. + +mod step; +pub use step::*; + +mod rotation; +pub use rotation::*; + +mod hashing; +pub use hashing::*; diff --git a/lightclient-circuits/src/witness/rotation.rs b/lightclient-circuits/src/witness/rotation.rs index 89c8d0d2..50a5018f 100644 --- a/lightclient-circuits/src/witness/rotation.rs +++ b/lightclient-circuits/src/witness/rotation.rs @@ -1,3 +1,7 @@ +// The Licensed Work is (c) 2023 ChainSafe +// Code: https://github.com/ChainSafe/Spectre +// SPDX-License-Identifier: LGPL-3.0-only + use eth_types::Spec; use ethereum_consensus_types::BeaconBlockHeader; use itertools::Itertools; @@ -5,8 +9,11 @@ use serde::{Deserialize, Serialize}; use sha2::{Digest, Sha256}; use std::{iter, marker::PhantomData}; +/// Input datum for the `CommitteeUpdateCircuit` to map next sync committee SSZ root in the finalized state root to the corresponding Poseidon commitment to the public keys. +/// +/// Assumes that public keys are BLS12-381 points on G1; `sync_committee_branch` is exactly `S::SYNC_COMMITTEE_PUBKEYS_DEPTH` hashes in lenght. #[derive(Debug, Clone, Serialize, Deserialize)] -pub struct CommitteeRotationArgs { +pub struct CommitteeUpdateArgs { pub pubkeys_compressed: Vec>, pub finalized_header: BeaconBlockHeader, @@ -17,7 +24,8 @@ pub struct CommitteeRotationArgs { pub _spec: PhantomData, } -impl Default for CommitteeRotationArgs { +// This default witness is intended for circuit setup and testing purposes only. +impl Default for CommitteeUpdateArgs { fn default() -> Self { let dummy_x_bytes = iter::once(192).pad_using(48, |_| 0).rev().collect_vec(); @@ -99,7 +107,7 @@ mod tests { #[test] fn test_committee_update_default_witness() { const K: u32 = 18; - let witness = CommitteeRotationArgs::::default(); + let witness = CommitteeUpdateArgs::::default(); let circuit = CommitteeUpdateCircuit::::create_circuit( CircuitBuilderStage::Mock, diff --git a/lightclient-circuits/src/witness/step.rs b/lightclient-circuits/src/witness/step.rs index bd1166ab..324584dd 100644 --- a/lightclient-circuits/src/witness/step.rs +++ b/lightclient-circuits/src/witness/step.rs @@ -1,3 +1,7 @@ +// The Licensed Work is (c) 2023 ChainSafe +// Code: https://github.com/ChainSafe/Spectre +// SPDX-License-Identifier: LGPL-3.0-only + use eth_types::Spec; use ethereum_consensus_types::signing::compute_signing_root; use ethereum_consensus_types::BeaconBlockHeader; @@ -13,6 +17,12 @@ use std::ops::Deref; use super::mock_root; +/// Input datum for the `StepCircuit` to verify `attested_header` singed by the lightclient sync committee, +/// and the `execution_payload_root` via Merkle `finality_branch` against the `finalized_header` root. +/// +/// Assumes that aggregated BLS signarure is represented as a compressed G2 point and the public keys are uncompressed G1 points; +/// `pariticipation_bits` vector has exactly `S::SYNC_COMMITTEE_SIZE`` bits; +/// `finality_branch` and `execution_payload_branch` are exactly `S::FINALIZED_HEADER_DEPTH` and `S::EXECUTION_STATE_ROOT_DEPTH` long respectively. #[derive(Debug, Clone, Serialize, Deserialize)] pub struct SyncStepArgs { pub signature_compressed: Vec, @@ -37,6 +47,7 @@ pub struct SyncStepArgs { pub _spec: PhantomData, } +// This default witness is intended for circuit setup and testing purposes only. impl Default for SyncStepArgs { fn default() -> Self { const DOMAIN: [u8; 32] = [ diff --git a/lightclient-circuits/tests/step.rs b/lightclient-circuits/tests/step.rs index 88d68ca5..07cd2d63 100644 --- a/lightclient-circuits/tests/step.rs +++ b/lightclient-circuits/tests/step.rs @@ -1,11 +1,15 @@ +// The Licensed Work is (c) 2023 ChainSafe +// Code: https://github.com/ChainSafe/Spectre +// SPDX-License-Identifier: LGPL-3.0-only + use ark_std::{end_timer, start_timer}; use eth_types::{Minimal, LIMB_BITS}; use halo2_base::gates::circuit::CircuitBuilderStage; use halo2_base::halo2_proofs::dev::MockProver; use halo2_base::halo2_proofs::halo2curves::bn256; +use halo2_base::utils::fs::gen_srs; use lightclient_circuits::committee_update_circuit::CommitteeUpdateCircuit; use lightclient_circuits::sync_step_circuit::StepCircuit; -use lightclient_circuits::util::gen_srs; use lightclient_circuits::util::AppCircuit; use lightclient_circuits::util::Eth2ConfigPinning; use lightclient_circuits::util::Halo2ConfigPinning; diff --git a/preprocessor/scripts/generateTestData.ts b/preprocessor/scripts/generateTestData.ts index add25bb8..3c65013f 100644 --- a/preprocessor/scripts/generateTestData.ts +++ b/preprocessor/scripts/generateTestData.ts @@ -1,3 +1,7 @@ +// The Licensed Work is (c) 2023 ChainSafe +// Code: https://github.com/ChainSafe/Spectre +// SPDX-License-Identifier: LGPL-3.0-only + import fs from "fs"; import { bls12_381 } from '@noble/curves/bls12-381' import { @@ -122,7 +126,7 @@ let finalizedBlock = { beaconState.finalizedCheckpoint.root = ssz.phase0.BeaconBlockHeader.hashTreeRoot(finalizedBlock); -const finilizedBlockJson = ssz.phase0.BeaconBlockHeader.toJson(finalizedBlock); +const finalizedBlockJson = ssz.phase0.BeaconBlockHeader.toJson(finalizedBlock); assert.deepStrictEqual(createNodeFromProof(execPayloadMerkleProof).root, beaconBlockTree.node.root) @@ -159,11 +163,11 @@ const attestedBlockJson = ssz.phase0.BeaconBlockHeader.toJson(attestedBlock); let beaconStateTree = ssz.capella.BeaconState.toView(beaconState); -let finilizedBlockRootGindex = ssz.capella.BeaconState.getPathInfo(["finalizedCheckpoint", "root"]).gindex; +let finalizedBlockRootGindex = ssz.capella.BeaconState.getPathInfo(["finalizedCheckpoint", "root"]).gindex; -let finilizedBlockMerkleProof = createProof(beaconStateTree.node, { type: ProofType.single, gindex: finilizedBlockRootGindex }) as SingleProof; +let finalizedBlockMerkleProof = createProof(beaconStateTree.node, { type: ProofType.single, gindex: finalizedBlockRootGindex }) as SingleProof; -assert.deepStrictEqual(createNodeFromProof(finilizedBlockMerkleProof).root, beaconStateTree.node.root) +assert.deepStrictEqual(createNodeFromProof(finalizedBlockMerkleProof).root, beaconStateTree.node.root) fs.writeFileSync( `../test_data/sync_step_${N_validators}.json`, @@ -172,8 +176,8 @@ fs.writeFileSync( pubkeysUncompressed: Array.from(beaconState.validators.entries()).map(([i, _]) => Array.from(g1PointToBytesLE(pubKeyPoints[i], false))), pariticipationBits: Array.from(beaconState.validators.entries()).map((_) => true), attestedHeader: attestedBlockJson, - finalizedHeader: finilizedBlockJson, - finalityBranch: finilizedBlockMerkleProof.witnesses.map((w) => Array.from(w)), + finalizedHeader: finalizedBlockJson, + finalityBranch: finalizedBlockMerkleProof.witnesses.map((w) => Array.from(w)), executionPayloadBranch: execPayloadMerkleProof.witnesses.map((w) => Array.from(w)), executionPayloadRoot: execPayloadRoot, domain: Array.from(domain), diff --git a/preprocessor/scripts/util.ts b/preprocessor/scripts/util.ts index 7d55f67f..4f024076 100644 --- a/preprocessor/scripts/util.ts +++ b/preprocessor/scripts/util.ts @@ -1,3 +1,7 @@ +// The Licensed Work is (c) 2023 ChainSafe +// Code: https://github.com/ChainSafe/Spectre +// SPDX-License-Identifier: LGPL-3.0-only + import { GindexBitstring } from "@chainsafe/persistent-merkle-tree"; import { ProjPointType } from "@noble/curves/abstract/weierstrass"; @@ -27,7 +31,7 @@ export function serialize(obj: any, replacer: (value: any) => any = (value) => v if (value instanceof Uint8Array) { return Array.from(value); } - + if (typeof value === 'bigint') { return Number(value); } @@ -212,26 +216,6 @@ export function hexToIntArray(hex: string): number[] { return array; } -function bigIntToBytesLE(value: bigint): ArrayBuffer { - // Assuming the BigInt fits in 8 bytes (change as needed) - const buffer = new ArrayBuffer(8); - const view = new DataView(buffer); - - let remainder = value; - let i = 0; - while (remainder > 0n) { - // Get the lower 8 bits of the remainder - // And store it in the buffer - view.setUint8(i, Number(remainder & 255n)); - - // Shift the remainder 8 bits to the right - remainder >>= 8n; - i++; - } - - return buffer; -} - export function chunkArray(arr: T[], chunkSize: number): T[][] { const chunks: T[][] = []; for (let i = 0; i < arr.length; i += chunkSize) { diff --git a/preprocessor/src/lib.rs b/preprocessor/src/lib.rs index 136282d3..d243711c 100644 --- a/preprocessor/src/lib.rs +++ b/preprocessor/src/lib.rs @@ -1,129 +1,25 @@ +// The Licensed Work is (c) 2023 ChainSafe +// Code: https://github.com/ChainSafe/Spectre +// SPDX-License-Identifier: LGPL-3.0-only + #![allow(incomplete_features)] #![feature(generic_const_exprs)] -mod sync; +mod rotation; +mod step; use beacon_api_client::{BlockId, Client, ClientTypes, Value, VersionedValue}; use eth_types::Spec; +use ethereum_consensus_types::bls::BlsSignature; use ethereum_consensus_types::{ - BeaconBlockHeader, ByteVector, LightClientBootstrap, LightClientFinalityUpdate, - LightClientUpdateCapella, Root, + BeaconBlockHeader, LightClientBootstrap, LightClientFinalityUpdate, LightClientUpdateCapella, + Root, }; -use itertools::Itertools; -use lightclient_circuits::witness::{CommitteeRotationArgs, SyncStepArgs}; -use serde::{Deserialize, Serialize}; -use ssz_rs::{Node, Vector}; -use std::ops::Deref; -pub use sync::*; -mod rotation; -use ethereum_consensus_types::bls::BlsPublicKey; -use ethereum_consensus_types::bls::BlsSignature; -pub use rotation::*; -pub async fn light_client_update_to_args( - update: &mut LightClientUpdateCapella< - { S::SYNC_COMMITTEE_SIZE }, - { S::SYNC_COMMITTEE_ROOT_INDEX }, - { S::SYNC_COMMITTEE_DEPTH }, - { S::FINALIZED_HEADER_INDEX }, - { S::FINALIZED_HEADER_DEPTH }, - { S::BYTES_PER_LOGS_BLOOM }, - { S::MAX_EXTRA_DATA_BYTES }, - >, - pubkeys_compressed: Vector, - domain: [u8; 32], -) -> eyre::Result<(SyncStepArgs, CommitteeRotationArgs)> -where - [(); S::SYNC_COMMITTEE_SIZE]:, - [(); S::FINALIZED_HEADER_DEPTH]:, - [(); S::BYTES_PER_LOGS_BLOOM]:, - [(); S::MAX_EXTRA_DATA_BYTES]:, - [(); S::SYNC_COMMITTEE_ROOT_INDEX]:, - [(); S::SYNC_COMMITTEE_DEPTH]:, - [(); S::FINALIZED_HEADER_INDEX]:, -{ - let finality_update = LightClientFinalityUpdate { - attested_header: update.attested_header.clone(), - finalized_header: update.finalized_header.clone(), - finality_branch: Vector::try_from( - update - .finality_branch - .iter() - .map(|v| ByteVector(Vector::try_from(v.deref().to_vec()).unwrap())) - .collect_vec(), - ) - .unwrap(), - sync_aggregate: update.sync_aggregate.clone(), - signature_slot: update.signature_slot, - }; - - let rotation_args = rotation::rotation_args_from_update(update).await?; - - let sync_args = - sync::step_args_from_finality_update(finality_update, pubkeys_compressed, domain).await?; - - Ok((sync_args, rotation_args)) -} - -pub async fn get_block_header( - client: &Client, - id: BlockId, -) -> eyre::Result { - // TODO: Once the ethereum beacon_api_client is updated, we can avoid this struct definition - #[derive(Serialize, Deserialize)] - struct BeaconHeaderSummary { - pub root: Root, - pub canonical: bool, - pub header: SignedBeaconBlockHeader, - } - #[derive(Serialize, Deserialize)] - struct SignedBeaconBlockHeader { - pub message: BeaconBlockHeader, - pub signature: BlsSignature, - } - - let route = format!("eth/v1/beacon/headers/{id}"); - let block: BeaconHeaderSummary = client.get::>(&route).await?.data; - Ok(block.header.message) -} - -pub async fn get_light_client_update_at_current_period( - client: &Client, -) -> eyre::Result< - LightClientUpdateCapella< - { S::SYNC_COMMITTEE_SIZE }, - { S::SYNC_COMMITTEE_ROOT_INDEX }, - { S::SYNC_COMMITTEE_DEPTH }, - { S::FINALIZED_HEADER_INDEX }, - { S::FINALIZED_HEADER_DEPTH }, - { S::BYTES_PER_LOGS_BLOOM }, - { S::MAX_EXTRA_DATA_BYTES }, - >, -> -where - [(); S::SYNC_COMMITTEE_SIZE]:, - [(); S::FINALIZED_HEADER_DEPTH]:, - [(); S::BYTES_PER_LOGS_BLOOM]:, - [(); S::MAX_EXTRA_DATA_BYTES]:, - [(); S::SYNC_COMMITTEE_ROOT_INDEX]:, - [(); S::SYNC_COMMITTEE_DEPTH]:, - [(); S::FINALIZED_HEADER_INDEX]:, -{ - let block = get_block_header(client, BlockId::Head).await?; - let slot = block.slot; - let period = slot / (32 * 256); - let route = format!("eth/v1/beacon/light_client/updates"); - let mut updates: Vec> = client - .http - .get(client.endpoint.join(&route)?) - .query(&[("start_period", period), ("count", 1)]) - .send() - .await? - .json() - .await?; - assert!(updates.len() == 1, "should only get one update"); - Ok(updates.pop().unwrap().data) -} +pub use rotation::*; +use serde::{Deserialize, Serialize}; +use ssz_rs::Node; +pub use step::*; pub async fn get_light_client_update_at_period( client: &Client, @@ -204,3 +100,25 @@ where .await? .data) } + +pub async fn get_block_header( + client: &Client, + id: BlockId, +) -> eyre::Result { + // TODO: Once the ethereum beacon_api_client is updated, we can avoid this struct definition + #[derive(Serialize, Deserialize)] + struct BeaconHeaderSummary { + pub root: Root, + pub canonical: bool, + pub header: SignedBeaconBlockHeader, + } + #[derive(Serialize, Deserialize)] + struct SignedBeaconBlockHeader { + pub message: BeaconBlockHeader, + pub signature: BlsSignature, + } + + let route = format!("eth/v1/beacon/headers/{id}"); + let block: BeaconHeaderSummary = client.get::>(&route).await?.data; + Ok(block.header.message) +} diff --git a/preprocessor/src/rotation.rs b/preprocessor/src/rotation.rs index 82458d3b..6330696a 100644 --- a/preprocessor/src/rotation.rs +++ b/preprocessor/src/rotation.rs @@ -1,19 +1,23 @@ +// The Licensed Work is (c) 2023 ChainSafe +// Code: https://github.com/ChainSafe/Spectre +// SPDX-License-Identifier: LGPL-3.0-only + use std::marker::PhantomData; use beacon_api_client::{BlockId, Client, ClientTypes}; use eth_types::Spec; -use ethereum_consensus_types::{BeaconBlockHeader, LightClientUpdateCapella}; +use ethereum_consensus_types::LightClientUpdateCapella; use itertools::Itertools; -use lightclient_circuits::witness::CommitteeRotationArgs; +use lightclient_circuits::witness::CommitteeUpdateArgs; use log::debug; use ssz_rs::Merkleized; -use tokio::fs; use crate::{get_block_header, get_light_client_update_at_period}; +/// Fetches LightClientUpdate from the beacon client and converts it to a [`CommitteeUpdateArgs`] witness pub async fn fetch_rotation_args( client: &Client, -) -> eyre::Result> +) -> eyre::Result> where [(); S::SYNC_COMMITTEE_SIZE]:, [(); S::FINALIZED_HEADER_DEPTH]:, @@ -35,6 +39,7 @@ where rotation_args_from_update(&mut update).await } +/// Converts a [`LightClientUpdateCapella`] to a [`CommitteeUpdateArgs`] witness. pub async fn rotation_args_from_update( update: &mut LightClientUpdateCapella< { S::SYNC_COMMITTEE_SIZE }, @@ -45,7 +50,7 @@ pub async fn rotation_args_from_update( { S::BYTES_PER_LOGS_BLOOM }, { S::MAX_EXTRA_DATA_BYTES }, >, -) -> eyre::Result> +) -> eyre::Result> where [(); S::SYNC_COMMITTEE_SIZE]:, [(); S::FINALIZED_HEADER_DEPTH]:, @@ -87,7 +92,7 @@ where "Execution payload merkle proof verification failed" ); - let args = CommitteeRotationArgs:: { + let args = CommitteeUpdateArgs:: { pubkeys_compressed, finalized_header: update.attested_header.beacon.clone(), sync_committee_branch: sync_committee_branch @@ -99,43 +104,17 @@ where Ok(args) } -pub async fn read_rotation_args(path: String) -> eyre::Result> { - #[derive(serde::Deserialize)] - struct ArgsJson { - finalized_header: BeaconBlockHeader, - committee_root_branch: Vec>, - pubkeys_compressed: Vec>, - } - - let ArgsJson { - pubkeys_compressed, - committee_root_branch, - finalized_header, - } = serde_json::from_slice( - &fs::read(path) - .await - .map_err(|e| eyre::eyre!("Error reading witness file {}", e))?, - ) - .map_err(|e| eyre::eyre!("Error decoding witness {}", e))?; - - Ok(CommitteeRotationArgs:: { - pubkeys_compressed, - finalized_header, - sync_committee_branch: committee_root_branch, - _spec: PhantomData, - }) -} - #[cfg(test)] mod tests { use super::*; use beacon_api_client::mainnet::Client as MainnetClient; use eth_types::Testnet; + use halo2_base::utils::fs::gen_srs; use lightclient_circuits::halo2_proofs::{dev::MockProver, halo2curves::bn256::Fr}; use lightclient_circuits::{ committee_update_circuit::CommitteeUpdateCircuit, halo2_base::gates::circuit::CircuitBuilderStage, - util::{gen_srs, AppCircuit, Eth2ConfigPinning, Halo2ConfigPinning}, + util::{AppCircuit, Eth2ConfigPinning, Halo2ConfigPinning}, }; use reqwest::Url; use snark_verifier_sdk::CircuitExt; @@ -144,7 +123,8 @@ mod tests { async fn test_rotation_circuit_sepolia() { const CONFIG_PATH: &str = "../lightclient-circuits/config/committee_update.json"; const K: u32 = 21; - let client = MainnetClient::new(Url::parse("http://65.109.55.120:9596").unwrap()); + let client = + MainnetClient::new(Url::parse("https://lodestar-sepolia.chainsafe.io").unwrap()); let witness = fetch_rotation_args::(&client).await.unwrap(); let pinning = Eth2ConfigPinning::from_path(CONFIG_PATH); @@ -171,9 +151,10 @@ mod tests { "../build/sync_step_21.pkey", CONFIG_PATH, false, - &CommitteeRotationArgs::::default(), + &CommitteeUpdateArgs::::default(), ); - let client = MainnetClient::new(Url::parse("http://65.109.55.120:9596").unwrap()); + let client = + MainnetClient::new(Url::parse("https://lodestar-sepolia.chainsafe.io").unwrap()); let witness = fetch_rotation_args::(&client).await.unwrap(); CommitteeUpdateCircuit::::gen_snark_shplonk( diff --git a/preprocessor/src/sync.rs b/preprocessor/src/step.rs similarity index 89% rename from preprocessor/src/sync.rs rename to preprocessor/src/step.rs index 14c67b6a..8c8fc8c3 100644 --- a/preprocessor/src/sync.rs +++ b/preprocessor/src/step.rs @@ -1,3 +1,7 @@ +// The Licensed Work is (c) 2023 ChainSafe +// Code: https://github.com/ChainSafe/Spectre +// SPDX-License-Identifier: LGPL-3.0-only + use std::marker::PhantomData; use beacon_api_client::Client; @@ -10,10 +14,10 @@ use itertools::Itertools; use lightclient_circuits::witness::SyncStepArgs; use ssz_rs::Vector; use ssz_rs::{Merkleized, Node}; -use tokio::fs; use crate::{get_light_client_bootstrap, get_light_client_finality_update}; +/// Fetches the latest `LightClientFinalityUpdate`` and the current sync committee (from LightClientBootstrap) and converts it to a [`SyncStepArgs`] witness. pub async fn fetch_step_args( client: &Client, ) -> eyre::Result> @@ -54,6 +58,7 @@ where step_args_from_finality_update(finality_update, pubkeys_compressed, domain).await } +/// Converts a [`LightClientFinalityUpdate`] to a [`SyncStepArgs`] witness. pub async fn step_args_from_finality_update( finality_update: LightClientFinalityUpdate< { S::SYNC_COMMITTEE_SIZE }, @@ -152,23 +157,14 @@ pub async fn step_args_from_finality_update( }) } -pub async fn read_step_args(path: String) -> eyre::Result> { - serde_json::from_slice( - &fs::read(path) - .await - .map_err(|e| eyre::eyre!("Error reading witness file {}", e))?, - ) - .map_err(|e| eyre::eyre!("Errror decoding witness {}", e)) -} - #[cfg(test)] mod tests { use eth_types::Testnet; + use halo2_base::utils::fs::gen_srs; use lightclient_circuits::halo2_proofs::{dev::MockProver, halo2curves::bn256::Fr}; use lightclient_circuits::{ - halo2_base::gates::circuit::CircuitBuilderStage, - sync_step_circuit::StepCircuit, - util::{gen_srs, AppCircuit}, + halo2_base::gates::circuit::CircuitBuilderStage, sync_step_circuit::StepCircuit, + util::AppCircuit, }; use snark_verifier_sdk::CircuitExt; @@ -179,7 +175,8 @@ mod tests { #[tokio::test] async fn test_sync_circuit_sepolia() { const K: u32 = 21; - let client = MainnetClient::new(Url::parse("http://65.109.55.120:9596").unwrap()); + let client = + MainnetClient::new(Url::parse("https://lodestar-sepolia.chainsafe.io").unwrap()); let witness = fetch_step_args::(&client).await.unwrap(); @@ -208,7 +205,8 @@ mod tests { false, &SyncStepArgs::::default(), ); - let client = MainnetClient::new(Url::parse("http://65.109.55.120:9596").unwrap()); + let client = + MainnetClient::new(Url::parse("https://lodestar-sepolia.chainsafe.io").unwrap()); let witness = fetch_step_args::(&client).await.unwrap(); StepCircuit::::gen_snark_shplonk( diff --git a/prover/build.rs b/prover/build.rs index 7d693320..6bfc91a2 100644 --- a/prover/build.rs +++ b/prover/build.rs @@ -1,3 +1,7 @@ +// The Licensed Work is (c) 2023 ChainSafe +// Code: https://github.com/ChainSafe/Spectre +// SPDX-License-Identifier: LGPL-3.0-only + fn main() { cli_batteries::build_rs().unwrap() } diff --git a/prover/src/args.rs b/prover/src/args.rs index c36a4415..e98cc85d 100644 --- a/prover/src/args.rs +++ b/prover/src/args.rs @@ -1,3 +1,7 @@ +// The Licensed Work is (c) 2023 ChainSafe +// Code: https://github.com/ChainSafe/Spectre +// SPDX-License-Identifier: LGPL-3.0-only + use std::path::PathBuf; use serde::{Deserialize, Serialize}; diff --git a/prover/src/cli.rs b/prover/src/cli.rs index e0d0d464..dc988865 100644 --- a/prover/src/cli.rs +++ b/prover/src/cli.rs @@ -1,11 +1,16 @@ +// The Licensed Work is (c) 2023 ChainSafe +// Code: https://github.com/ChainSafe/Spectre +// SPDX-License-Identifier: LGPL-3.0-only + use crate::args::BaseArgs; use crate::args::{OperationCmd, ProofCmd}; use ark_std::{end_timer, start_timer}; +use lightclient_circuits::halo2_base::utils::fs::gen_srs; use lightclient_circuits::{ committee_update_circuit::CommitteeUpdateCircuit, halo2_proofs::halo2curves::bn256::{Bn256, Fr}, sync_step_circuit::StepCircuit, - util::{gen_srs, AppCircuit}, + util::AppCircuit, }; use lightclient_circuits::{ halo2_base::gates::circuit::CircuitBuilderStage, halo2_proofs::poly::commitment::Params, diff --git a/prover/src/lib.rs b/prover/src/lib.rs index 82b7823c..aac547c6 100644 --- a/prover/src/lib.rs +++ b/prover/src/lib.rs @@ -1,3 +1,7 @@ +// The Licensed Work is (c) 2023 ChainSafe +// Code: https://github.com/ChainSafe/Spectre +// SPDX-License-Identifier: LGPL-3.0-only + #![allow(incomplete_features)] #![feature(generic_const_exprs)] pub mod rpc_api; diff --git a/prover/src/main.rs b/prover/src/main.rs index 242c2e90..291d2d71 100644 --- a/prover/src/main.rs +++ b/prover/src/main.rs @@ -1,3 +1,7 @@ +// The Licensed Work is (c) 2023 ChainSafe +// Code: https://github.com/ChainSafe/Spectre +// SPDX-License-Identifier: LGPL-3.0-only + #![allow(incomplete_features)] #![feature(associated_type_bounds)] #![feature(generic_const_exprs)] diff --git a/prover/src/rpc.rs b/prover/src/rpc.rs index 1a65774b..5b89570b 100644 --- a/prover/src/rpc.rs +++ b/prover/src/rpc.rs @@ -1,3 +1,7 @@ +// The Licensed Work is (c) 2023 ChainSafe +// Code: https://github.com/ChainSafe/Spectre +// SPDX-License-Identifier: LGPL-3.0-only + use super::args::Spec; use axum::{http::StatusCode, response::IntoResponse, routing::post, Router}; use ethers::prelude::*; @@ -5,11 +9,11 @@ use itertools::Itertools; use jsonrpc_v2::RequestObject as JsonRpcRequestObject; use jsonrpc_v2::{Error as JsonRpcError, Params}; use jsonrpc_v2::{MapRouter as JsonRpcMapRouter, Server as JsonRpcServer}; +use lightclient_circuits::halo2_base::utils::fs::gen_srs; use lightclient_circuits::halo2_proofs::halo2curves::bn256::Fr; use lightclient_circuits::{ - committee_update_circuit::CommitteeUpdateCircuit, - sync_step_circuit::StepCircuit, - util::{gen_srs, AppCircuit}, + committee_update_circuit::CommitteeUpdateCircuit, sync_step_circuit::StepCircuit, + util::AppCircuit, }; use preprocessor::{rotation_args_from_update, step_args_from_finality_update}; use snark_verifier_sdk::{halo2::aggregation::AggregationCircuit, Snark}; @@ -19,8 +23,9 @@ use std::sync::Arc; pub type JsonRpcServerState = Arc>; use crate::rpc_api::{ - CommitteeUpdateEvmProofResult, SyncStepCompressedEvmProofResult, - RPC_EVM_PROOF_COMMITTEE_UPDATE_CIRCUIT_COMPRESSED, RPC_EVM_PROOF_STEP_CIRCUIT_COMPRESSED, GenProofCommitteeUpdateParams, GenProofStepParams, + CommitteeUpdateEvmProofResult, GenProofCommitteeUpdateParams, GenProofStepParams, + SyncStepCompressedEvmProofResult, RPC_EVM_PROOF_COMMITTEE_UPDATE_CIRCUIT_COMPRESSED, + RPC_EVM_PROOF_STEP_CIRCUIT_COMPRESSED, }; pub(crate) fn jsonrpc_server() -> JsonRpcServer { diff --git a/prover/src/rpc_api.rs b/prover/src/rpc_api.rs index bf9ba48b..3b927720 100644 --- a/prover/src/rpc_api.rs +++ b/prover/src/rpc_api.rs @@ -1,3 +1,7 @@ +// The Licensed Work is (c) 2023 ChainSafe +// Code: https://github.com/ChainSafe/Spectre +// SPDX-License-Identifier: LGPL-3.0-only + use crate::args; use primitive_types::U256; use serde::{Deserialize, Serialize}; diff --git a/prover/src/rpc_client.rs b/prover/src/rpc_client.rs index ee6c34f2..7af5f615 100644 --- a/prover/src/rpc_client.rs +++ b/prover/src/rpc_client.rs @@ -1,3 +1,7 @@ +// The Licensed Work is (c) 2023 ChainSafe +// Code: https://github.com/ChainSafe/Spectre +// SPDX-License-Identifier: LGPL-3.0-only + pub use jsonrpc_v2; use jsonrpc_v2::{Error, Id, RequestObject, V2}; use reqwest::IntoUrl; diff --git a/prover/src/utils.rs b/prover/src/utils.rs index 768a592e..b2e747a8 100644 --- a/prover/src/utils.rs +++ b/prover/src/utils.rs @@ -1,3 +1,7 @@ +// The Licensed Work is (c) 2023 ChainSafe +// Code: https://github.com/ChainSafe/Spectre +// SPDX-License-Identifier: LGPL-3.0-only + use std::{ops::Deref, sync::Arc}; use beacon_api_client::{BlockId, VersionedValue}; @@ -50,8 +54,9 @@ pub(crate) async fn utils_cli(method: UtilsCmd) -> eyre::Result<()> { .unwrap(); println!("ssz root: {:?}", hex::encode(ssz_root.deref())); - let committee_poseidon = + let mut committee_poseidon = poseidon_committee_commitment_from_uncompressed(&pubkeys_uncompressed).to_bytes(); + committee_poseidon.reverse(); println!("poseidon commitment: {}", hex::encode(committee_poseidon)); Ok(()) diff --git a/test-utils/scripts/download_consensus_specs.sh b/test-utils/scripts/download_consensus_specs.sh old mode 100755 new mode 100644 index 8f9200b5..3d544b81 --- a/test-utils/scripts/download_consensus_specs.sh +++ b/test-utils/scripts/download_consensus_specs.sh @@ -1,3 +1,7 @@ +# The Licensed Work is (c) 2023 ChainSafe +# Code: https://github.com/ChainSafe/Spectre +# SPDX-License-Identifier: LGPL-3.0-only + #!/bin/bash TESTS_TAG=v1.3.0 REPO_NAME=consensus-spec-tests diff --git a/test-utils/src/execution_payload_header.rs b/test-utils/src/execution_payload_header.rs index 48c42d9b..aefdb50d 100644 --- a/test-utils/src/execution_payload_header.rs +++ b/test-utils/src/execution_payload_header.rs @@ -1,3 +1,7 @@ +// The Licensed Work is (c) 2023 ChainSafe +// Code: https://github.com/ChainSafe/Spectre +// SPDX-License-Identifier: LGPL-3.0-only + use crate::{ test_types::{ByteList, ByteVector, ExecutionAddress}, U256_BYTE_COUNT, diff --git a/test-utils/src/lib.rs b/test-utils/src/lib.rs index e2944dbb..c677ff7b 100644 --- a/test-utils/src/lib.rs +++ b/test-utils/src/lib.rs @@ -1,3 +1,7 @@ +// The Licensed Work is (c) 2023 ChainSafe +// Code: https://github.com/ChainSafe/Spectre +// SPDX-License-Identifier: LGPL-3.0-only + #![allow(incomplete_features)] #![feature(generic_const_exprs)] @@ -15,7 +19,7 @@ use ethereum_consensus_types::{BeaconBlockHeader, SyncCommittee}; use ethereum_consensus_types::{ForkData, Root}; use itertools::Itertools; use lightclient_circuits::poseidon::poseidon_committee_commitment_from_uncompressed; -use lightclient_circuits::witness::{CommitteeRotationArgs, SyncStepArgs}; +use lightclient_circuits::witness::{CommitteeUpdateArgs, SyncStepArgs}; use ssz_rs::prelude::*; use ssz_rs::Merkleized; use std::ops::Deref; @@ -80,7 +84,7 @@ pub fn valid_updates_from_test_path( pub fn read_test_files_and_gen_witness( path: &Path, -) -> (SyncStepArgs, CommitteeRotationArgs) { +) -> (SyncStepArgs, CommitteeUpdateArgs) { let bootstrap: LightClientBootstrap = load_snappy_ssz(path.join("bootstrap.ssz_snappy").to_str().unwrap()).unwrap(); @@ -109,7 +113,7 @@ pub fn read_test_files_and_gen_witness( sync_committee_branch.insert(0, agg_pk.hash_tree_root().unwrap().deref().to_vec()); - let rotation_wit = CommitteeRotationArgs:: { + let rotation_wit = CommitteeUpdateArgs:: { pubkeys_compressed: updates[0] .next_sync_committee .pubkeys diff --git a/test-utils/src/test_types.rs b/test-utils/src/test_types.rs index cb00f892..0fc3105b 100644 --- a/test-utils/src/test_types.rs +++ b/test-utils/src/test_types.rs @@ -1,3 +1,7 @@ +// The Licensed Work is (c) 2023 ChainSafe +// Code: https://github.com/ChainSafe/Spectre +// SPDX-License-Identifier: LGPL-3.0-only + use ssz_rs::prelude::*; #[allow(dead_code)]