--- /dev/null
+* Sergey Matveev <stargrave@stargrave.org>
--- /dev/null
+GOPATH != pwd
+VERSION != cat VERSION
+
+include common.mk
--- /dev/null
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. You must make sure that they, too, receive
+or can get the source code. And you must show them these terms so they
+know their rights.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+ <program> Copyright (C) <year> <name of author>
+ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<http://www.gnu.org/licenses/>.
+
+ The GNU General Public License does not permit incorporating your program
+into proprietary programs. If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License. But first, please read
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
--- /dev/null
+GOPATH = $(shell pwd)
+VERSION = $(shell cat VERSION)
+
+include common.mk
--- /dev/null
+Preferable way is to download tarball with the signature from official
+website and, for example, run tests with benchmarks:
+
+ % wget http://www.cypherpunks.ru/gogost/gogost-1.0.tar.xz
+ % wget http://www.cypherpunks.ru/gogost/gogost-1.0.tar.xz.sig
+ % gpg --verify gogost-1.0.tar.xz.sig gogost-1.0.tar.xz
+ % xz -d < gogost-1.0.tar.gz | tar xf -
+ % make -C gogost-1.0 bench
+
+You have to verify downloaded tarballs integrity and authenticity to be
+sure that you retrieved trusted and untampered software. GNU Privacy
+Guard is used for that purpose.
+
+For the very first time it it necessary to get signing public key and
+import it. It is provided below, but you should check alternative
+resources.
+
+ pub rsa2048/0x82343436696FC85A 2016-09-13 [SC]
+ CEBD 1282 2C46 9C02 A81A 0467 8234 3436 696F C85A
+ uid GoGOST releases <gogost at cypherpunks dot ru>
+
+ Look in PUBKEY.asc file.
+ % gpg --keyserver hkp://keys.gnupg.net/ --recv-keys 0x82343436696FC85A
+ % gpg --auto-key-locate dane --locate-keys gogost at cypherpunks dot ru
+ % gpg --auto-key-locate wkd --locate-keys gogost at cypherpunks dot ru
+ % gpg --auto-key-locate pka --locate-keys gogost at cypherpunks dot ru
--- /dev/null
+1.1:
+ * gogost-streebog is able to use either 256 or 512 bits digest size
+ * 34.13-2015 padding methods
+ * 28147-89 CBC mode of operation
+
+1.0:
+ Initial release
--- /dev/null
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+
+mQENBFfXoXsBCADKKxVI2GjDU5f3L2Y2m9oz089viCwVkD0plf3Bo8yaAnyxp/an
+EjTYQnfE2QQxbixKz2A+z/mfrFrJld3zM/rmu0WJxmEBb7J59j8uKa8DblxJuYJh
+rWWhwzm8FSC2bITzF0dFSSXSF9xcM8CoRJOBeOzpVNPopKxXW94MgHw/xlXvjASn
+cbLDKM2eFYXnWMRZsnrfVs87r8OoHxzDCWZ16/CjB5qspn5Yf7c/sXE2C5EIMJce
+biiXcLTPxKG5B5Tncmsh9HA0CquGciftm34bJxTJSPkw/0B3ROyY7yadlud7XjLI
+Ak2AP3y0AHgI4q4Q9YzPeotryG91hj6lii8jABEBAAG0J0dvR09TVCByZWxlYXNl
+cyA8Z29nb3N0QGN5cGhlcnB1bmtzLnJ1PokBQAQTAQgAKgUCV9ehewIbAwwLCgkN
+CAwHCwMEAQIHFQoJCAsDAgUWAgEDAAIeAQIXgAAKCRCCNDQ2aW/IWibQCADF59c2
+aKHVEqqm6tnyu0CFKuVWAikoss3DB8A3Vp1kLxOOoXcnSDMM1v+C6oGU7TDcobZ9
+zH2XZpnfj9MEZ5jypb2z+QlkPN7cJBOGvSJ8XpTt8E8/heyD40KS61VBNXgN3BZL
+owKBcppwthSVRntjexHzn7ha4HE8j8ysypMBtsw7x+3iKZD4roHrYdp4ddOoZT1s
+xLsNmmbUzln2ieCD/mMb8taVpFJhuAWH2o6HJTh31b/+T0AN3QL999AQcR93jF2U
+o6/MJ0m3TzXHvUTnIOXCU7xlG464+6+rRACBbRlO3wa0WSdSeQSFIy1ienYxj63W
+iXmU5IA05VS613JaiF4EEBEIAAYFAlfXoZcACgkQrhqBCeSYV+/Y1AD9Eg0+OMLb
+8ygnl+v8XUQqsf7fCcELW3oadFMu0RhcDNQA/20GNbS0omsycQkqmxYMQLkWa5wx
+4kzapQYmseDye0zy
+=sx2q
+-----END PGP PUBLIC KEY BLOCK-----
--- /dev/null
+Pure Go GOST cryptographic functions library.
+
+GOST is GOvernment STandard of Russian Federation (and Soviet Union).
+
+* GOST 28147-89 (RFC 5830) block cipher with ECB, CNT (CTR), CFB, MAC
+ CBC (RFC 4357) modes of operation
+* various 28147-89-related S-boxes included
+* GOST R 34.11-94 hash function (RFC 5831)
+* GOST R 34.11-2012 Стрибог (Streebog) hash function (RFC 6986)
+* GOST R 34.10-2001 (RFC 5832) public key signature function
+* GOST R 34.10-2012 (RFC 7091) public key signature function
+* various 34.10 curve parameters included
+* GOST R 34.12-2015 128-bit block cipher Кузнечик (Kuznechik) (RFC 7801)
+* GOST R 34.13-2015 padding methods
+
+Known problems:
+
+* intermediate calculation values are not zeroed
+* 34.10 is not time constant and slow
+
+GoGOST is free software: see the file COPYING for copying conditions.
+
+Please send questions, bug reports and patches to
+https://lists.cypherpunks.ru/mailman/listinfo/gost
+mailing list. Announcements also go to this mailing list.
+
+Development Git source code repository currently is located here:
+http://git.cypherpunks.ru/cgit.cgi/gogost.git/
--- /dev/null
+* VKO 34.10-2001 Diffie-Hellman function (RFC 4357)
+* 28147-89 and CryptoPro key wrapping (RFC 4357)
+* 28147-89 CryptoPro key meshing for CFB mode (RFC 4357)
--- /dev/null
+LDFLAGS = -X cypherpunks.ru/gogost.Version=$(VERSION)
+
+gogost-streebog:
+ GOPATH=$(GOPATH) go build -ldflags "$(LDFLAGS)" cypherpunks.ru/gogost/gost34112012/cmd/gogost-streebog
+
+bench:
+ GOPATH=$(GOPATH) go test -benchmem -bench . cypherpunks.ru/gogost/...
--- /dev/null
+#!/bin/sh -ex
+
+cur=$(pwd)
+tmp=$(mktemp -d)
+release=$1
+[ -n "$release" ]
+
+git clone . $tmp/gogost-$release
+cd $tmp/gogost-$release
+git checkout $release
+
+find . -name .git -type d | xargs rm -fr
+rm -f www* makedist* TODO
+
+cd ..
+tar cvf gogost-"$release".tar gogost-"$release"
+xz -9 gogost-"$release".tar
+gpg --detach-sign --sign --local-user 82343436696FC85A gogost-"$release".tar.xz
+
+tarball=gogost-"$release".tar.xz
+size=$(( $(wc -c < $tarball) / 1024 ))
+hash=$(gpg --print-md SHA256 < $tarball)
+hashsb=$($HOME/work/gogost/gogost-streebog < $tarball)
+
+cat <<EOF
+An entry for documentation:
+@item $release @tab $size KiB
+@tab @url{gogost-${release}.tar.xz, link} @url{gogost-${release}.tar.xz.sig, sign}
+@tab @code{$hash}
+@tab @code{$hashsb}
+EOF
+
+cat <<EOF
+Subject: GoGOST $release release announcement
+
+I am pleased to announce GoGOST $release release availability!
+
+GoGOST is free software pure Go GOST cryptographic functions library.
+GOST is GOvernment STandard of Russian Federation (and Soviet Union).
+
+------------------------ >8 ------------------------
+
+The main improvements for that release are:
+
+
+------------------------ >8 ------------------------
+
+GoGOST'es home page is: http://www.cypherpunks.ru/gogost/
+
+Source code and its signature for that version can be found here:
+
+ http://www.cypherpunks.ru/gogost/gogost-${release}.tar.xz ($size KiB)
+ http://www.cypherpunks.ru/gogost/gogost-${release}.tar.xz.sig
+
+Streebog-256 hash: $hashsb
+SHA256 hash: $hash
+GPG key ID: 0x82343436696FC85A GoGOST releases <gogost at cypherpunks dot ru>
+Fingerprint: CEBD 1282 2C46 9C02 A81A 0467 8234 3436 696F C85A
+
+Please send questions regarding the use of GoGOST, bug reports and patches
+to mailing list: https://lists.cypherpunks.ru/mailman/listinfo/gost
+EOF
+
+mv $tmp/$tarball $tmp/"$tarball".sig $cur/gogost.html/
--- /dev/null
+// Pure Go GOST cryptographic functions library.
+package gogost
+
+var (
+ Version string
+)
--- /dev/null
+// GoGOST -- Pure Go GOST cryptographic functions library
+// Copyright (C) 2015-2016 Sergey Matveev <stargrave@stargrave.org>
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+package gost28147
+
+import (
+ "bytes"
+ "crypto/cipher"
+ "crypto/rand"
+ "testing"
+ "testing/quick"
+)
+
+func TestCBCCrypter(t *testing.T) {
+ var key [KeySize]byte
+ var iv [BlockSize]byte
+ rand.Read(key[:])
+ rand.Read(iv[:])
+ c := NewCipher(key, SboxDefault)
+ f := func(pt []byte) bool {
+ for i := 0; i < BlockSize; i++ {
+ pt = append(pt, pt...)
+ }
+ ct := make([]byte, len(pt))
+ e := cipher.NewCBCEncrypter(c, iv[:])
+ e.CryptBlocks(ct, pt)
+ d := cipher.NewCBCDecrypter(c, iv[:])
+ d.CryptBlocks(ct, ct)
+ return bytes.Compare(pt, ct) == 0
+ }
+ if err := quick.Check(f, nil); err != nil {
+ t.Error(err)
+ }
+}
--- /dev/null
+// GoGOST -- Pure Go GOST cryptographic functions library
+// Copyright (C) 2015-2016 Sergey Matveev <stargrave@stargrave.org>
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+package gost28147
+
+type CFBEncrypter struct {
+ c *Cipher
+ iv []byte
+}
+
+func (c *Cipher) NewCFBEncrypter(iv [BlockSize]byte) *CFBEncrypter {
+ return &CFBEncrypter{c, iv[:]}
+}
+
+func (c *CFBEncrypter) XORKeyStream(dst, src []byte) {
+ var n int
+ i := 0
+MainLoop:
+ for {
+ c.c.Encrypt(c.iv, c.iv)
+ for n = 0; n < BlockSize; n++ {
+ if i*BlockSize+n == len(src) {
+ break MainLoop
+ }
+ c.iv[n] ^= src[i*BlockSize+n]
+ dst[i*BlockSize+n] = c.iv[n]
+ }
+ i++
+ }
+ return
+}
+
+type CFBDecrypter struct {
+ c *Cipher
+ iv []byte
+}
+
+func (c *Cipher) NewCFBDecrypter(iv [BlockSize]byte) *CFBDecrypter {
+ return &CFBDecrypter{c, iv[:]}
+}
+
+func (c *CFBDecrypter) XORKeyStream(dst, src []byte) {
+ var n int
+ i := 0
+MainLoop:
+ for {
+ c.c.Encrypt(c.iv, c.iv)
+ for n = 0; n < BlockSize; n++ {
+ if i*BlockSize+n == len(src) {
+ break MainLoop
+ }
+ dst[i*BlockSize+n] = c.iv[n] ^ src[i*BlockSize+n]
+ c.iv[n] = src[i*BlockSize+n]
+ }
+ i++
+ }
+ return
+}
--- /dev/null
+// GoGOST -- Pure Go GOST cryptographic functions library
+// Copyright (C) 2015-2016 Sergey Matveev <stargrave@stargrave.org>
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+package gost28147
+
+import (
+ "bytes"
+ "crypto/cipher"
+ "crypto/rand"
+ "testing"
+ "testing/quick"
+)
+
+func TestCFBCryptomanager(t *testing.T) {
+ key := [KeySize]byte{
+ 0x75, 0x71, 0x31, 0x34, 0xB6, 0x0F, 0xEC, 0x45,
+ 0xA6, 0x07, 0xBB, 0x83, 0xAA, 0x37, 0x46, 0xAF,
+ 0x4F, 0xF9, 0x9D, 0xA6, 0xD1, 0xB5, 0x3B, 0x5B,
+ 0x1B, 0x40, 0x2A, 0x1B, 0xAA, 0x03, 0x0D, 0x1B,
+ }
+ sbox := &GostR3411_94_TestParamSet
+ pt := []byte{
+ 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,
+ 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0x80, 0x00, 0x00,
+ }
+ ct := []byte{
+ 0x6E, 0xE8, 0x45, 0x86, 0xDD, 0x2B, 0xCA, 0x0C,
+ 0xAD, 0x36, 0x16, 0x94, 0x0E, 0x16, 0x42, 0x42,
+ }
+ c := NewCipher(key, sbox)
+ iv := [8]byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}
+ tmp := make([]byte, 16)
+ fe := c.NewCFBEncrypter(iv)
+ fe.XORKeyStream(tmp, pt)
+ if bytes.Compare(tmp, ct) != 0 {
+ t.Fail()
+ }
+ fd := c.NewCFBDecrypter(iv)
+ fd.XORKeyStream(tmp, ct)
+ if bytes.Compare(tmp, pt) != 0 {
+ t.Fail()
+ }
+}
+
+func TestCFBRandom(t *testing.T) {
+ var key [KeySize]byte
+ rand.Read(key[:])
+ c := NewCipher(key, SboxDefault)
+ f := func(ivRaw []byte, pt []byte) bool {
+ if len(pt) == 0 || len(ivRaw) < 8 {
+ return true
+ }
+ var iv [8]byte
+ copy(iv[:], ivRaw[:8])
+ ct := make([]byte, len(pt))
+ fe := c.NewCFBEncrypter(iv)
+ fe.XORKeyStream(ct, pt)
+ fd := c.NewCFBDecrypter(iv)
+ pt2 := make([]byte, len(ct))
+ fd.XORKeyStream(pt2, ct)
+ return bytes.Compare(pt2, pt) == 0
+ }
+ if err := quick.Check(f, nil); err != nil {
+ t.Error(err)
+ }
+}
+
+func TestCFBInterface(t *testing.T) {
+ var key [32]byte
+ var iv [8]byte
+ c := NewCipher(key, SboxDefault)
+ var _ cipher.Stream = c.NewCFBEncrypter(iv)
+ var _ cipher.Stream = c.NewCFBDecrypter(iv)
+}
--- /dev/null
+// GoGOST -- Pure Go GOST cryptographic functions library
+// Copyright (C) 2015-2016 Sergey Matveev <stargrave@stargrave.org>
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+// GOST 28147-89 block cipher with ECB, CFB, CTR, MAC modes of operation.
+// RFC 5830.
+package gost28147
+
+const (
+ BlockSize = 8
+ KeySize = 32
+)
+
+// All 28147 operations are going with two 32-bit halves of the whole
+// block. nv is representation of that one half.
+type nv uint32
+
+// Cyclic 11-bit shift.
+func (n nv) shift11() nv {
+ return ((n << 11) & (1<<32 - 1)) | ((n >> (32 - 11)) & (1<<32 - 1))
+}
+
+// Seq contains iteration numbers used in the encryption function
+// itself. For example 28147 encryption and decryption process differs
+// only with this sequence.
+type Seq []uint8
+
+var (
+ SeqEncrypt = Seq([]uint8{
+ 0, 1, 2, 3, 4, 5, 6, 7,
+ 0, 1, 2, 3, 4, 5, 6, 7,
+ 0, 1, 2, 3, 4, 5, 6, 7,
+ 7, 6, 5, 4, 3, 2, 1, 0,
+ })
+ SeqDecrypt = Seq([]uint8{
+ 0, 1, 2, 3, 4, 5, 6, 7,
+ 7, 6, 5, 4, 3, 2, 1, 0,
+ 7, 6, 5, 4, 3, 2, 1, 0,
+ 7, 6, 5, 4, 3, 2, 1, 0,
+ })
+)
+
+type Cipher struct {
+ key *[KeySize]byte
+ sbox *Sbox
+ x [8]nv
+}
+
+func NewCipher(key [KeySize]byte, sbox *Sbox) *Cipher {
+ c := Cipher{}
+ c.key = &key
+ c.sbox = sbox
+ c.x = [8]nv{
+ nv(key[0]) | nv(key[1])<<8 | nv(key[2])<<16 | nv(key[3])<<24,
+ nv(key[4]) | nv(key[5])<<8 | nv(key[6])<<16 | nv(key[7])<<24,
+ nv(key[8]) | nv(key[9])<<8 | nv(key[10])<<16 | nv(key[11])<<24,
+ nv(key[12]) | nv(key[13])<<8 | nv(key[14])<<16 | nv(key[15])<<24,
+ nv(key[16]) | nv(key[17])<<8 | nv(key[18])<<16 | nv(key[19])<<24,
+ nv(key[20]) | nv(key[21])<<8 | nv(key[22])<<16 | nv(key[23])<<24,
+ nv(key[24]) | nv(key[25])<<8 | nv(key[26])<<16 | nv(key[27])<<24,
+ nv(key[28]) | nv(key[29])<<8 | nv(key[30])<<16 | nv(key[31])<<24,
+ }
+ return &c
+}
+
+func (c *Cipher) BlockSize() int {
+ return BlockSize
+}
+
+// Convert binary byte block to two 32-bit internal integers.
+func block2nvs(b []byte) (n1, n2 nv) {
+ n1 = nv(b[0]) | nv(b[1])<<8 | nv(b[2])<<16 | nv(b[3])<<24
+ n2 = nv(b[4]) | nv(b[5])<<8 | nv(b[6])<<16 | nv(b[7])<<24
+ return
+}
+
+// Convert two 32-bit internal integers to binary byte block.
+func nvs2block(n1, n2 nv, b []byte) {
+ b[0] = byte((n2 >> 0) & 255)
+ b[1] = byte((n2 >> 8) & 255)
+ b[2] = byte((n2 >> 16) & 255)
+ b[3] = byte((n2 >> 24) & 255)
+ b[4] = byte((n1 >> 0) & 255)
+ b[5] = byte((n1 >> 8) & 255)
+ b[6] = byte((n1 >> 16) & 255)
+ b[7] = byte((n1 >> 24) & 255)
+}
+
+func (c *Cipher) xcrypt(seq Seq, n1, n2 nv) (nv, nv) {
+ for _, i := range seq {
+ n1, n2 = c.sbox.k(n1+c.x[i]).shift11()^n2, n1
+ }
+ return n1, n2
+}
+
+// Encrypt single block.
+// If provided slices are shorter than the block size, then it will panic.
+func (c *Cipher) Encrypt(dst, src []byte) {
+ n1, n2 := block2nvs(src)
+ n1, n2 = c.xcrypt(SeqEncrypt, n1, n2)
+ nvs2block(n1, n2, dst)
+}
+
+// Decrypt single block.
+// If provided slices are shorter than the block size, then it will panic.
+func (c *Cipher) Decrypt(dst, src []byte) {
+ n1, n2 := block2nvs(src)
+ n1, n2 = c.xcrypt(SeqDecrypt, n1, n2)
+ nvs2block(n1, n2, dst)
+}
--- /dev/null
+// GoGOST -- Pure Go GOST cryptographic functions library
+// Copyright (C) 2015-2016 Sergey Matveev <stargrave@stargrave.org>
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+package gost28147
+
+import (
+ "crypto/cipher"
+ "crypto/rand"
+ "testing"
+)
+
+func TestCipherInterface(t *testing.T) {
+ var key [32]byte
+ var _ cipher.Block = NewCipher(key, SboxDefault)
+}
+
+func BenchmarkCipher(b *testing.B) {
+ var key [KeySize]byte
+ rand.Read(key[:])
+ dst := make([]byte, BlockSize)
+ src := make([]byte, BlockSize)
+ rand.Read(src)
+ c := NewCipher(key, SboxDefault)
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ c.Encrypt(dst, src)
+ }
+}
--- /dev/null
+// GoGOST -- Pure Go GOST cryptographic functions library
+// Copyright (C) 2015-2016 Sergey Matveev <stargrave@stargrave.org>
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+package gost28147
+
+type CTR struct {
+ c *Cipher
+ n1 nv
+ n2 nv
+}
+
+func (c *Cipher) NewCTR(iv [BlockSize]byte) *CTR {
+ n1, n2 := block2nvs(iv[:])
+ n2, n1 = c.xcrypt(SeqEncrypt, n1, n2)
+ return &CTR{c, n1, n2}
+}
+
+func (c *CTR) XORKeyStream(dst, src []byte) {
+ var n1t nv
+ var n2t nv
+ block := make([]byte, BlockSize)
+ i := 0
+ var n int
+MainLoop:
+ for {
+ c.n1 += 0x01010101 // C2
+ c.n2 += 0x01010104 // C1
+ if c.n2 >= 1<<32-1 {
+ c.n2 -= 1<<32 - 1
+ }
+ n1t, n2t = c.c.xcrypt(SeqEncrypt, c.n1, c.n2)
+ nvs2block(n1t, n2t, block)
+ for n = 0; n < BlockSize; n++ {
+ if i*BlockSize+n == len(src) {
+ break MainLoop
+ }
+ dst[i*BlockSize+n] = src[i*BlockSize+n] ^ block[n]
+ }
+ i++
+ }
+ return
+}
--- /dev/null
+// GoGOST -- Pure Go GOST cryptographic functions library
+// Copyright (C) 2015-2016 Sergey Matveev <stargrave@stargrave.org>
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+package gost28147
+
+import (
+ "bytes"
+ "crypto/cipher"
+ "crypto/rand"
+ "testing"
+ "testing/quick"
+)
+
+func TestCTRGCL3Vector(t *testing.T) {
+ sbox := &Gost2814789_TestParamSet
+ key := [KeySize]byte{
+ 0x04, 0x75, 0xf6, 0xe0, 0x50, 0x38, 0xfb, 0xfa,
+ 0xd2, 0xc7, 0xc3, 0x90, 0xed, 0xb3, 0xca, 0x3d,
+ 0x15, 0x47, 0x12, 0x42, 0x91, 0xae, 0x1e, 0x8a,
+ 0x2f, 0x79, 0xcd, 0x9e, 0xd2, 0xbc, 0xef, 0xbd,
+ }
+ plaintext := []byte{
+ 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00,
+ 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
+ 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10,
+ 0x1f, 0x1e, 0x1d, 0x1c, 0x1b, 0x1a, 0x19, 0x18,
+ 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x20,
+ 0x2f, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28,
+ 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x30,
+ 0x3f, 0x3e, 0x3d, 0x3c, 0x3b, 0x3a, 0x39, 0x38,
+ 0x47, 0x46, 0x45, 0x44, 0x43, 0x42, 0x41, 0x40,
+ 0x4f, 0x4e, 0x4d, 0x4c, 0x4b, 0x4a, 0x49, 0x48,
+ 0x57, 0x56, 0x55, 0x54, 0x53, 0x52, 0x51, 0x50,
+ 0x5f, 0x5e, 0x5d, 0x5c, 0x5b, 0x5a, 0x59, 0x58,
+ 0x67, 0x66, 0x65, 0x64, 0x63, 0x62, 0x61, 0x60,
+ 0x6f, 0x6e, 0x6d, 0x6c, 0x6b, 0x6a, 0x69, 0x68,
+ 0x77, 0x76, 0x75, 0x74, 0x73, 0x72, 0x71, 0x70,
+ 0x7f, 0x7e, 0x7d, 0x7c, 0x7b, 0x7a, 0x79, 0x78,
+ 0x87, 0x86, 0x85, 0x84, 0x83, 0x82, 0x81, 0x80,
+ 0x8f, 0x8e, 0x8d, 0x8c, 0x8b, 0x8a, 0x89, 0x88,
+ 0x97, 0x96, 0x95, 0x94, 0x93, 0x92, 0x91, 0x90,
+ 0x9f, 0x9e, 0x9d, 0x9c, 0x9b, 0x9a, 0x99, 0x98,
+ 0xa7, 0xa6, 0xa5, 0xa4, 0xa3, 0xa2, 0xa1, 0xa0,
+ 0xaf, 0xae, 0xad, 0xac, 0xab, 0xaa, 0xa9, 0xa8,
+ 0xb7, 0xb6, 0xb5, 0xb4, 0xb3, 0xb2, 0xb1, 0xb0,
+ 0xbf, 0xbe, 0xbd, 0xbc, 0xbb, 0xba, 0xb9, 0xb8,
+ 0xc7, 0xc6, 0xc5, 0xc4, 0xc3, 0xc2, 0xc1, 0xc0,
+ 0xcf, 0xce, 0xcd, 0xcc, 0xcb, 0xca, 0xc9, 0xc8,
+ 0xd7, 0xd6, 0xd5, 0xd4, 0xd3, 0xd2, 0xd1, 0xd0,
+ 0xdf, 0xde, 0xdd, 0xdc, 0xdb, 0xda, 0xd9, 0xd8,
+ 0xe7, 0xe6, 0xe5, 0xe4, 0xe3, 0xe2, 0xe1, 0xe0,
+ 0xef, 0xee, 0xed, 0xec, 0xeb, 0xea, 0xe9, 0xe8,
+ 0xf7, 0xf6, 0xf5, 0xf4, 0xf3, 0xf2, 0xf1, 0xf0,
+ 0xff, 0xfe, 0xfd, 0xfc, 0xfb,
+ }
+ ciphertext := []byte{
+ 0x4a, 0x5e, 0x37, 0x6c, 0xa1, 0x12, 0xd3, 0x55,
+ 0x09, 0x13, 0x1a, 0x21, 0xac, 0xfb, 0xb2, 0x1e,
+ 0x8c, 0x24, 0x9b, 0x57, 0x20, 0x68, 0x46, 0xd5,
+ 0x23, 0x2a, 0x26, 0x35, 0x12, 0x56, 0x5c, 0x69,
+ 0x2a, 0x2f, 0xd1, 0xab, 0xbd, 0x45, 0xdc, 0x3a,
+ 0x1a, 0xa4, 0x57, 0x64, 0xd5, 0xe4, 0x69, 0x6d,
+ 0xb4, 0x8b, 0xf1, 0x54, 0x78, 0x3b, 0x10, 0x8f,
+ 0x7a, 0x4b, 0x32, 0xe0, 0xe8, 0x4c, 0xbf, 0x03,
+ 0x24, 0x37, 0x95, 0x6a, 0x55, 0xa8, 0xce, 0x6f,
+ 0x95, 0x62, 0x12, 0xf6, 0x79, 0xe6, 0xf0, 0x1b,
+ 0x86, 0xef, 0x36, 0x36, 0x05, 0xd8, 0x6f, 0x10,
+ 0xa1, 0x41, 0x05, 0x07, 0xf8, 0xfa, 0xa4, 0x0b,
+ 0x17, 0x2c, 0x71, 0xbc, 0x8b, 0xcb, 0xcf, 0x3d,
+ 0x74, 0x18, 0x32, 0x0b, 0x1c, 0xd2, 0x9e, 0x75,
+ 0xba, 0x3e, 0x61, 0xe1, 0x61, 0x96, 0xd0, 0xee,
+ 0x8f, 0xf2, 0x9a, 0x5e, 0xb7, 0x7a, 0x15, 0xaa,
+ 0x4e, 0x1e, 0x77, 0x7c, 0x99, 0xe1, 0x41, 0x13,
+ 0xf4, 0x60, 0x39, 0x46, 0x4c, 0x35, 0xde, 0x95,
+ 0xcc, 0x4f, 0xd5, 0xaf, 0xd1, 0x4d, 0x84, 0x1a,
+ 0x45, 0xc7, 0x2a, 0xf2, 0x2c, 0xc0, 0xb7, 0x94,
+ 0xa3, 0x08, 0xb9, 0x12, 0x96, 0xb5, 0x97, 0x99,
+ 0x3a, 0xb7, 0x0c, 0x14, 0x56, 0xb9, 0xcb, 0x49,
+ 0x44, 0xa9, 0x93, 0xa9, 0xfb, 0x19, 0x10, 0x8c,
+ 0x6a, 0x68, 0xe8, 0x7b, 0x06, 0x57, 0xf0, 0xef,
+ 0x88, 0x44, 0xa6, 0xd2, 0x98, 0xbe, 0xd4, 0x07,
+ 0x41, 0x37, 0x45, 0xa6, 0x71, 0x36, 0x76, 0x69,
+ 0x4b, 0x75, 0x15, 0x33, 0x90, 0x29, 0x6e, 0x33,
+ 0xcb, 0x96, 0x39, 0x78, 0x19, 0x2e, 0x96, 0xf3,
+ 0x49, 0x4c, 0x89, 0x3d, 0xa1, 0x86, 0x82, 0x00,
+ 0xce, 0xbd, 0x54, 0x29, 0x65, 0x00, 0x1d, 0x16,
+ 0x13, 0xc3, 0xfe, 0x1f, 0x8c, 0x55, 0x63, 0x09,
+ 0x1f, 0xcd, 0xd4, 0x28, 0xca,
+ }
+ iv := [8]byte{0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}
+ c := NewCipher(key, sbox)
+ ctr := c.NewCTR(iv)
+ tmp := make([]byte, len(plaintext))
+ ctr.XORKeyStream(tmp, plaintext)
+ if bytes.Compare(tmp, ciphertext) != 0 {
+ t.Fail()
+ }
+ ctr = c.NewCTR(iv)
+ ctr.XORKeyStream(tmp, tmp)
+ if bytes.Compare(tmp, plaintext) != 0 {
+ t.Fail()
+ }
+}
+
+func TestCTRGCL2Vector(t *testing.T) {
+ sbox := &Gost2814789_TestParamSet
+ key := [KeySize]byte{
+ 0xfc, 0x7a, 0xd2, 0x88, 0x6f, 0x45, 0x5b, 0x50,
+ 0xd2, 0x90, 0x08, 0xfa, 0x62, 0x2b, 0x57, 0xd5,
+ 0xc6, 0x5b, 0x3c, 0x63, 0x72, 0x02, 0x02, 0x57,
+ 0x99, 0xca, 0xdf, 0x07, 0x68, 0x51, 0x9e, 0x8a,
+ }
+ plaintext := []byte{
+ 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00,
+ 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
+ 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10,
+ 0x1f, 0x1e, 0x1d, 0x1c, 0x1b, 0x1a, 0x19, 0x18,
+ 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x20,
+ 0x2f, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28,
+ 0xff, 0xfe, 0xfd, 0xfc, 0xfb,
+ }
+ ciphertext := []byte{
+ 0xd0, 0xbe, 0x60, 0x1a, 0x2c, 0xf1, 0x90, 0x26,
+ 0x9b, 0x7b, 0x23, 0xb4, 0xd2, 0xcc, 0xe1, 0x15,
+ 0xf6, 0x05, 0x57, 0x28, 0x88, 0x75, 0xeb, 0x1e,
+ 0xd3, 0x62, 0xdc, 0xda, 0x9b, 0x62, 0xee, 0x9a,
+ 0x57, 0x87, 0x8a, 0xf1, 0x82, 0x37, 0x9c, 0x7f,
+ 0x13, 0xcc, 0x55, 0x38, 0xb5, 0x63, 0x32, 0xc5,
+ 0x23, 0xa4, 0xcb, 0x7d, 0x51,
+ }
+ var iv [8]byte
+ c := NewCipher(key, sbox)
+ ctr := c.NewCTR(iv)
+ tmp := make([]byte, len(plaintext))
+ ctr.XORKeyStream(tmp, plaintext)
+ if bytes.Compare(tmp, ciphertext) != 0 {
+ t.Fail()
+ }
+ ctr = c.NewCTR(iv)
+ ctr.XORKeyStream(tmp, tmp)
+ if bytes.Compare(tmp, plaintext) != 0 {
+ t.Fail()
+ }
+}
+
+func TestCTRRandom(t *testing.T) {
+ var key [KeySize]byte
+ rand.Read(key[:])
+ c := NewCipher(key, SboxDefault)
+ f := func(ivRaw []byte, pt []byte) bool {
+ if len(pt) == 0 || len(ivRaw) < 8 {
+ return true
+ }
+ var iv [8]byte
+ copy(iv[:], ivRaw[:8])
+ tmp := make([]byte, len(pt))
+ ctr := c.NewCTR(iv)
+ ctr.XORKeyStream(tmp, pt)
+ ctr = c.NewCTR(iv)
+ ctr.XORKeyStream(tmp, tmp)
+ return bytes.Compare(tmp, pt) == 0
+ }
+ if err := quick.Check(f, nil); err != nil {
+ t.Error(err)
+ }
+}
+func TestCTRInterface(t *testing.T) {
+ var key [32]byte
+ var iv [8]byte
+ c := NewCipher(key, SboxDefault)
+ var _ cipher.Stream = c.NewCTR(iv)
+}
+
+func BenchmarkCTR(b *testing.B) {
+ var key [KeySize]byte
+ var iv [BlockSize]byte
+ rand.Read(key[:])
+ rand.Read(iv[:])
+ dst := make([]byte, BlockSize)
+ src := make([]byte, BlockSize)
+ rand.Read(src)
+ c := NewCipher(key, SboxDefault)
+ ctr := c.NewCTR(iv)
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ ctr.XORKeyStream(dst, src)
+ }
+}
--- /dev/null
+// GoGOST -- Pure Go GOST cryptographic functions library
+// Copyright (C) 2015-2016 Sergey Matveev <stargrave@stargrave.org>
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+package gost28147
+
+type ECBEncrypter struct {
+ c *Cipher
+}
+
+func (c *Cipher) NewECBEncrypter() *ECBEncrypter {
+ e := ECBEncrypter{c}
+ return &e
+}
+
+func (e *ECBEncrypter) CryptBlocks(dst, src []byte) {
+ for i := 0; i < len(src); i += BlockSize {
+ e.c.Encrypt(dst[i:i+BlockSize], src[i:i+BlockSize])
+ }
+}
+
+func (e *ECBEncrypter) BlockSize() int {
+ return e.c.BlockSize()
+}
+
+type ECBDecrypter struct {
+ c *Cipher
+}
+
+func (c *Cipher) NewECBDecrypter() *ECBDecrypter {
+ d := ECBDecrypter{c}
+ return &d
+}
+
+func (e *ECBDecrypter) CryptBlocks(dst, src []byte) {
+ for i := 0; i < len(src); i += BlockSize {
+ e.c.Decrypt(dst[i:i+BlockSize], src[i:i+BlockSize])
+ }
+}
+
+func (e *ECBDecrypter) BlockSize() int {
+ return e.c.BlockSize()
+}
--- /dev/null
+// GoGOST -- Pure Go GOST cryptographic functions library
+// Copyright (C) 2015-2016 Sergey Matveev <stargrave@stargrave.org>
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+package gost28147
+
+import (
+ "bytes"
+ "crypto/cipher"
+ "testing"
+)
+
+func TestECBGCL3Vectors(t *testing.T) {
+ key := [KeySize]byte{
+ 0x04, 0x75, 0xf6, 0xe0, 0x50, 0x38, 0xfb, 0xfa,
+ 0xd2, 0xc7, 0xc3, 0x90, 0xed, 0xb3, 0xca, 0x3d,
+ 0x15, 0x47, 0x12, 0x42, 0x91, 0xae, 0x1e, 0x8a,
+ 0x2f, 0x79, 0xcd, 0x9e, 0xd2, 0xbc, 0xef, 0xbd,
+ }
+ c := NewCipher(key, &Gost2814789_TestParamSet)
+ plaintext := []byte{
+ 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00,
+ 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
+ 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10,
+ 0x1f, 0x1e, 0x1d, 0x1c, 0x1b, 0x1a, 0x19, 0x18,
+ 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x20,
+ 0x2f, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28,
+ 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x30,
+ 0x3f, 0x3e, 0x3d, 0x3c, 0x3b, 0x3a, 0x39, 0x38,
+ 0x47, 0x46, 0x45, 0x44, 0x43, 0x42, 0x41, 0x40,
+ 0x4f, 0x4e, 0x4d, 0x4c, 0x4b, 0x4a, 0x49, 0x48,
+ 0x57, 0x56, 0x55, 0x54, 0x53, 0x52, 0x51, 0x50,
+ 0x5f, 0x5e, 0x5d, 0x5c, 0x5b, 0x5a, 0x59, 0x58,
+ 0x67, 0x66, 0x65, 0x64, 0x63, 0x62, 0x61, 0x60,
+ 0x6f, 0x6e, 0x6d, 0x6c, 0x6b, 0x6a, 0x69, 0x68,
+ 0x77, 0x76, 0x75, 0x74, 0x73, 0x72, 0x71, 0x70,
+ 0x7f, 0x7e, 0x7d, 0x7c, 0x7b, 0x7a, 0x79, 0x78,
+ 0x87, 0x86, 0x85, 0x84, 0x83, 0x82, 0x81, 0x80,
+ 0x8f, 0x8e, 0x8d, 0x8c, 0x8b, 0x8a, 0x89, 0x88,
+ 0x97, 0x96, 0x95, 0x94, 0x93, 0x92, 0x91, 0x90,
+ 0x9f, 0x9e, 0x9d, 0x9c, 0x9b, 0x9a, 0x99, 0x98,
+ 0xa7, 0xa6, 0xa5, 0xa4, 0xa3, 0xa2, 0xa1, 0xa0,
+ 0xaf, 0xae, 0xad, 0xac, 0xab, 0xaa, 0xa9, 0xa8,
+ 0xb7, 0xb6, 0xb5, 0xb4, 0xb3, 0xb2, 0xb1, 0xb0,
+ 0xbf, 0xbe, 0xbd, 0xbc, 0xbb, 0xba, 0xb9, 0xb8,
+ 0xc7, 0xc6, 0xc5, 0xc4, 0xc3, 0xc2, 0xc1, 0xc0,
+ 0xcf, 0xce, 0xcd, 0xcc, 0xcb, 0xca, 0xc9, 0xc8,
+ 0xd7, 0xd6, 0xd5, 0xd4, 0xd3, 0xd2, 0xd1, 0xd0,
+ 0xdf, 0xde, 0xdd, 0xdc, 0xdb, 0xda, 0xd9, 0xd8,
+ 0xe7, 0xe6, 0xe5, 0xe4, 0xe3, 0xe2, 0xe1, 0xe0,
+ 0xef, 0xee, 0xed, 0xec, 0xeb, 0xea, 0xe9, 0xe8,
+ 0xf7, 0xf6, 0xf5, 0xf4, 0xf3, 0xf2, 0xf1, 0xf0,
+ 0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8,
+ }
+ ciphertext := []byte{
+ 0x4b, 0x8c, 0x4c, 0x98, 0x15, 0xf2, 0x4a, 0xea,
+ 0x1e, 0xc3, 0x57, 0x09, 0xb3, 0xbc, 0x2e, 0xd1,
+ 0xe0, 0xd1, 0xf2, 0x22, 0x65, 0x2d, 0x59, 0x18,
+ 0xf7, 0xdf, 0xfc, 0x80, 0x4b, 0xde, 0x5c, 0x68,
+ 0x46, 0x53, 0x75, 0x53, 0xa7, 0x46, 0x0d, 0xec,
+ 0x05, 0x1f, 0x1b, 0xd3, 0x0a, 0x63, 0x1a, 0xb7,
+ 0x78, 0xc4, 0x43, 0xe0, 0x5d, 0x3e, 0xa4, 0x0e,
+ 0x2d, 0x7e, 0x23, 0xa9, 0x1b, 0xc9, 0x02, 0xbc,
+ 0x21, 0x0c, 0x84, 0xcb, 0x0d, 0x0a, 0x07, 0xc8,
+ 0x7b, 0xd0, 0xfb, 0xb5, 0x1a, 0x14, 0x04, 0x5c,
+ 0xa2, 0x53, 0x97, 0x71, 0x2e, 0x5c, 0xc2, 0x8f,
+ 0x39, 0x3f, 0x6f, 0x52, 0xf2, 0x30, 0x26, 0x4e,
+ 0x8c, 0xe0, 0xd1, 0x01, 0x75, 0x6d, 0xdc, 0xd3,
+ 0x03, 0x79, 0x1e, 0xca, 0xd5, 0xc1, 0x0e, 0x12,
+ 0x53, 0x0a, 0x78, 0xe2, 0x0a, 0xb1, 0x1c, 0xea,
+ 0x3a, 0xf8, 0x55, 0xb9, 0x7c, 0xe1, 0x0b, 0xba,
+ 0xa0, 0xc8, 0x96, 0xeb, 0x50, 0x5a, 0xd3, 0x60,
+ 0x43, 0xa3, 0x0f, 0x98, 0xdb, 0xd9, 0x50, 0x6d,
+ 0x63, 0x91, 0xaf, 0x01, 0x40, 0xe9, 0x75, 0x5a,
+ 0x46, 0x5c, 0x1f, 0x19, 0x4a, 0x0b, 0x89, 0x9b,
+ 0xc4, 0xf6, 0xf8, 0xf5, 0x2f, 0x87, 0x3f, 0xfa,
+ 0x26, 0xd4, 0xf8, 0x25, 0xba, 0x1f, 0x98, 0x82,
+ 0xfc, 0x26, 0xaf, 0x2d, 0xc0, 0xf9, 0xc4, 0x58,
+ 0x49, 0xfa, 0x09, 0x80, 0x02, 0x62, 0xa4, 0x34,
+ 0x2d, 0xcb, 0x5a, 0x6b, 0xab, 0x61, 0x5d, 0x08,
+ 0xd4, 0x26, 0xe0, 0x08, 0x13, 0xd6, 0x2e, 0x02,
+ 0x2a, 0x37, 0xe8, 0xd0, 0xcf, 0x36, 0xf1, 0xc7,
+ 0xc0, 0x3f, 0x9b, 0x21, 0x60, 0xbd, 0x29, 0x2d,
+ 0x2e, 0x01, 0x48, 0x4e, 0xf8, 0x8f, 0x20, 0x16,
+ 0x8a, 0xbf, 0x82, 0xdc, 0x32, 0x7a, 0xa3, 0x18,
+ 0x69, 0xd1, 0x50, 0x59, 0x31, 0x91, 0xf2, 0x6c,
+ 0x5a, 0x5f, 0xca, 0x58, 0x9a, 0xb2, 0x2d, 0xb2,
+ }
+ e := c.NewECBEncrypter()
+ tmp := make([]byte, len(plaintext))
+ e.CryptBlocks(tmp, plaintext)
+ if bytes.Compare(tmp, ciphertext) != 0 {
+ t.Fail()
+ }
+ d := c.NewECBDecrypter()
+ d.CryptBlocks(tmp, tmp)
+ if bytes.Compare(tmp, plaintext) != 0 {
+ t.Fail()
+ }
+}
+
+// Crypto++ 5.6.2 test vectors
+func TestECBCryptoPPVectors(t *testing.T) {
+ sbox := &AppliedCryptographyParamSet
+ var key [KeySize]byte
+ var pt [BlockSize]byte
+ var ct [BlockSize]byte
+ tmp := make([]byte, BlockSize)
+ var c *Cipher
+
+ key = [KeySize]byte{
+ 0xBE, 0x5E, 0xC2, 0x00, 0x6C, 0xFF, 0x9D, 0xCF,
+ 0x52, 0x35, 0x49, 0x59, 0xF1, 0xFF, 0x0C, 0xBF,
+ 0xE9, 0x50, 0x61, 0xB5, 0xA6, 0x48, 0xC1, 0x03,
+ 0x87, 0x06, 0x9C, 0x25, 0x99, 0x7C, 0x06, 0x72,
+ }
+ pt = [BlockSize]byte{0x0D, 0xF8, 0x28, 0x02, 0xB7, 0x41, 0xA2, 0x92}
+ ct = [BlockSize]byte{0x07, 0xF9, 0x02, 0x7D, 0xF7, 0xF7, 0xDF, 0x89}
+ c = NewCipher(key, sbox)
+ c.Encrypt(tmp, pt[:])
+ if bytes.Compare(tmp, ct[:]) != 0 {
+ t.Fail()
+ }
+
+ key = [KeySize]byte{
+ 0xB3, 0x85, 0x27, 0x2A, 0xC8, 0xD7, 0x2A, 0x5A,
+ 0x8B, 0x34, 0x4B, 0xC8, 0x03, 0x63, 0xAC, 0x4D,
+ 0x09, 0xBF, 0x58, 0xF4, 0x1F, 0x54, 0x06, 0x24,
+ 0xCB, 0xCB, 0x8F, 0xDC, 0xF5, 0x53, 0x07, 0xD7,
+ }
+ pt = [BlockSize]byte{0x13, 0x54, 0xEE, 0x9C, 0x0A, 0x11, 0xCD, 0x4C}
+ ct = [BlockSize]byte{0x4F, 0xB5, 0x05, 0x36, 0xF9, 0x60, 0xA7, 0xB1}
+ c = NewCipher(key, sbox)
+ c.Encrypt(tmp, pt[:])
+ if bytes.Compare(tmp, ct[:]) != 0 {
+ t.Fail()
+ }
+
+ key = [KeySize]byte{
+ 0xAE, 0xE0, 0x2F, 0x60, 0x9A, 0x35, 0x66, 0x0E,
+ 0x40, 0x97, 0xE5, 0x46, 0xFD, 0x30, 0x26, 0xB0,
+ 0x32, 0xCD, 0x10, 0x7C, 0x7D, 0x45, 0x99, 0x77,
+ 0xAD, 0xF4, 0x89, 0xBE, 0xF2, 0x65, 0x22, 0x62,
+ }
+ pt = [BlockSize]byte{0x66, 0x93, 0xD4, 0x92, 0xC4, 0xB0, 0xCC, 0x39}
+ ct = [BlockSize]byte{0x67, 0x00, 0x34, 0xAC, 0x0F, 0xA8, 0x11, 0xB5}
+ c = NewCipher(key, sbox)
+ c.Encrypt(tmp, pt[:])
+ if bytes.Compare(tmp, ct[:]) != 0 {
+ t.Fail()
+ }
+
+ key = [KeySize]byte{
+ 0x32, 0x0E, 0x9D, 0x84, 0x22, 0x16, 0x5D, 0x58,
+ 0x91, 0x1D, 0xFC, 0x7D, 0x8B, 0xBB, 0x1F, 0x81,
+ 0xB0, 0xEC, 0xD9, 0x24, 0x02, 0x3B, 0xF9, 0x4D,
+ 0x9D, 0xF7, 0xDC, 0xF7, 0x80, 0x12, 0x40, 0xE0,
+ }
+ pt = [BlockSize]byte{0x99, 0xE2, 0xD1, 0x30, 0x80, 0x92, 0x8D, 0x79}
+ ct = [BlockSize]byte{0x81, 0x18, 0xFF, 0x9D, 0x3B, 0x3C, 0xFE, 0x7D}
+ c = NewCipher(key, sbox)
+ c.Encrypt(tmp, pt[:])
+ if bytes.Compare(tmp, ct[:]) != 0 {
+ t.Fail()
+ }
+
+ key = [KeySize]byte{
+ 0xC9, 0xF7, 0x03, 0xBB, 0xBF, 0xC6, 0x36, 0x91,
+ 0xBF, 0xA3, 0xB7, 0xB8, 0x7E, 0xA8, 0xFD, 0x5E,
+ 0x8E, 0x8E, 0xF3, 0x84, 0xEF, 0x73, 0x3F, 0x1A,
+ 0x61, 0xAE, 0xF6, 0x8C, 0x8F, 0xFA, 0x26, 0x5F,
+ }
+ pt = [BlockSize]byte{0xD1, 0xE7, 0x87, 0x74, 0x9C, 0x72, 0x81, 0x4C}
+ ct = [BlockSize]byte{0xA0, 0x83, 0x82, 0x6A, 0x79, 0x0D, 0x3E, 0x0C}
+ c = NewCipher(key, sbox)
+ c.Encrypt(tmp, pt[:])
+ if bytes.Compare(tmp, ct[:]) != 0 {
+ t.Fail()
+ }
+
+ key = [KeySize]byte{
+ 0x72, 0x8F, 0xEE, 0x32, 0xF0, 0x4B, 0x4C, 0x65,
+ 0x4A, 0xD7, 0xF6, 0x07, 0xD7, 0x1C, 0x66, 0x0C,
+ 0x2C, 0x26, 0x70, 0xD7, 0xC9, 0x99, 0x71, 0x32,
+ 0x33, 0x14, 0x9A, 0x1C, 0x0C, 0x17, 0xA1, 0xF0,
+ }
+ pt = [BlockSize]byte{0xD4, 0xC0, 0x53, 0x23, 0xA4, 0xF7, 0xA7, 0xB5}
+ ct = [BlockSize]byte{0x4D, 0x1F, 0x2E, 0x6B, 0x0D, 0x9D, 0xE2, 0xCE}
+ c = NewCipher(key, sbox)
+ c.Encrypt(tmp, pt[:])
+ if bytes.Compare(tmp, ct[:]) != 0 {
+ t.Fail()
+ }
+
+ key = [KeySize]byte{
+ 0x35, 0xFC, 0x96, 0x40, 0x22, 0x09, 0x50, 0x0F,
+ 0xCF, 0xDE, 0xF5, 0x35, 0x2D, 0x1A, 0xBB, 0x03,
+ 0x8F, 0xE3, 0x3F, 0xC0, 0xD9, 0xD5, 0x85, 0x12,
+ 0xE5, 0x63, 0x70, 0xB2, 0x2B, 0xAA, 0x13, 0x3B,
+ }
+ pt = [BlockSize]byte{0x87, 0x42, 0xD9, 0xA0, 0x5F, 0x6A, 0x3A, 0xF6}
+ ct = [BlockSize]byte{0x2F, 0x3B, 0xB8, 0x48, 0x79, 0xD1, 0x1E, 0x52}
+ c = NewCipher(key, sbox)
+ c.Encrypt(tmp, pt[:])
+ if bytes.Compare(tmp, ct[:]) != 0 {
+ t.Fail()
+ }
+
+ key = [KeySize]byte{
+ 0xD4, 0x16, 0xF6, 0x30, 0xBE, 0x65, 0xB7, 0xFE,
+ 0x15, 0x06, 0x56, 0x18, 0x33, 0x70, 0xE0, 0x70,
+ 0x18, 0x23, 0x4E, 0xE5, 0xDA, 0x3D, 0x89, 0xC4,
+ 0xCE, 0x91, 0x52, 0xA0, 0x3E, 0x5B, 0xFB, 0x77,
+ }
+ pt = [BlockSize]byte{0xF8, 0x65, 0x06, 0xDA, 0x04, 0xE4, 0x1C, 0xB8}
+ ct = [BlockSize]byte{0x96, 0xF0, 0xA5, 0xC7, 0x7A, 0x04, 0xF5, 0xCE}
+ c = NewCipher(key, sbox)
+ c.Encrypt(tmp, pt[:])
+ if bytes.Compare(tmp, ct[:]) != 0 {
+ t.Fail()
+ }
+}
+
+// http://cryptomanager.com/tv.html test vectors.
+func TestECBCryptomanager(t *testing.T) {
+ sbox := &GostR3411_94_TestParamSet
+ key := [KeySize]byte{
+ 0x75, 0x71, 0x31, 0x34, 0xB6, 0x0F, 0xEC, 0x45,
+ 0xA6, 0x07, 0xBB, 0x83, 0xAA, 0x37, 0x46, 0xAF,
+ 0x4F, 0xF9, 0x9D, 0xA6, 0xD1, 0xB5, 0x3B, 0x5B,
+ 0x1B, 0x40, 0x2A, 0x1B, 0xAA, 0x03, 0x0D, 0x1B,
+ }
+ c := NewCipher(key, sbox)
+ tmp := make([]byte, BlockSize)
+ c.Encrypt(tmp, []byte{0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88})
+ if bytes.Compare(tmp, []byte{0x03, 0x25, 0x1E, 0x14, 0xF9, 0xD2, 0x8A, 0xCB}) != 0 {
+ t.Fail()
+ }
+}
+
+func TestECBInterface(t *testing.T) {
+ var key [32]byte
+ c := NewCipher(key, SboxDefault)
+ var _ cipher.BlockMode = c.NewECBEncrypter()
+ var _ cipher.BlockMode = c.NewECBDecrypter()
+}
--- /dev/null
+// GoGOST -- Pure Go GOST cryptographic functions library
+// Copyright (C) 2015-2016 Sergey Matveev <stargrave@stargrave.org>
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+package gost28147
+
+import (
+ "errors"
+)
+
+var (
+ SeqMAC = Seq([]uint8{
+ 0, 1, 2, 3, 4, 5, 6, 7,
+ 0, 1, 2, 3, 4, 5, 6, 7,
+ })
+)
+
+type MAC struct {
+ c *Cipher
+ size int
+ iv []byte
+ prev []byte
+ buf []byte
+ n1 nv
+ n2 nv
+}
+
+// Create MAC with given tag size and initial initialization vector.
+// Size is in bytes and must be between 1 and 8. To be RFC conformant,
+// iv must be the first block of the authenticated data, second and
+// following ones are fed to Write function.
+func (c *Cipher) NewMAC(size int, iv [BlockSize]byte) (*MAC, error) {
+ if size == 0 || size > 8 {
+ return nil, errors.New("Invalid tag size")
+ }
+ m := MAC{c: c, size: size, iv: iv[:]}
+ n2, n1 := block2nvs(iv[:])
+ m.iv = make([]byte, BlockSize)
+ nvs2block(n1, n2, m.iv)
+ m.prev = make([]byte, BlockSize)
+ m.Reset()
+ return &m, nil
+}
+
+func (m *MAC) Reset() {
+ copy(m.prev, m.iv)
+ m.buf = nil
+}
+
+func (m *MAC) BlockSize() int {
+ return BlockSize
+}
+
+func (m *MAC) Size() int {
+ return m.size
+}
+
+func (m *MAC) Write(b []byte) (int, error) {
+ m.buf = append(m.buf, b...)
+ for len(m.buf) >= BlockSize {
+ for i := 0; i < BlockSize; i++ {
+ m.prev[i] ^= m.buf[i]
+ }
+ m.n1, m.n2 = block2nvs(m.prev)
+ m.n1, m.n2 = m.c.xcrypt(SeqMAC, m.n1, m.n2)
+ nvs2block(m.n2, m.n1, m.prev)
+ m.buf = m.buf[8:]
+ }
+ return len(b), nil
+}
+
+func (m *MAC) Sum(b []byte) []byte {
+ if len(m.buf) == 0 {
+ return append(b, m.prev[0:m.size]...)
+ }
+ buf := m.buf
+ var i int
+ for i = 0; i < BlockSize-len(m.buf); i++ {
+ buf = append(buf, byte(0))
+ }
+ for i = 0; i < BlockSize; i++ {
+ buf[i] ^= m.prev[i]
+ }
+ m.n1, m.n2 = block2nvs(buf)
+ m.n1, m.n2 = m.c.xcrypt(SeqMAC, m.n1, m.n2)
+ nvs2block(m.n2, m.n1, buf)
+ return append(b, buf[0:m.size]...)
+}
--- /dev/null
+// GoGOST -- Pure Go GOST cryptographic functions library
+// Copyright (C) 2015-2016 Sergey Matveev <stargrave@stargrave.org>
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+package gost28147
+
+import (
+ "bytes"
+ "crypto/rand"
+ "hash"
+ "testing"
+ "testing/quick"
+)
+
+func TestMACVectors(t *testing.T) {
+ var key [KeySize]byte
+ copy(key[:], []byte("This is message\xFF length\x0032 bytes"))
+ c := NewCipher(key, SboxDefault)
+ var iv [8]byte
+ m, err := c.NewMAC(8, iv)
+ if err != nil {
+ t.Fail()
+ }
+
+ m.Write([]byte("a"))
+ if bytes.Compare(m.Sum(nil), []byte{0xbd, 0x5d, 0x3b, 0x5b, 0x2b, 0x7b, 0x57, 0xaf}) != 0 {
+ t.Fail()
+ }
+
+ m.Reset()
+ m.Write([]byte("abc"))
+ if bytes.Compare(m.Sum(nil), []byte{0x28, 0x66, 0x1e, 0x40, 0x80, 0x5b, 0x1f, 0xf9}) != 0 {
+ t.Fail()
+ }
+
+ m.Reset()
+ for i := 0; i < 128; i++ {
+ m.Write([]byte("U"))
+ }
+ if bytes.Compare(m.Sum(nil), []byte{0x1a, 0x06, 0xd1, 0xba, 0xd7, 0x45, 0x80, 0xef}) != 0 {
+ t.Fail()
+ }
+
+ m.Reset()
+ for i := 0; i < 13; i++ {
+ m.Write([]byte("x"))
+ }
+ if bytes.Compare(m.Sum(nil), []byte{0x91, 0x7e, 0xe1, 0xf1, 0xa6, 0x68, 0xfb, 0xd3}) != 0 {
+ t.Fail()
+ }
+}
+
+func TestMACRandom(t *testing.T) {
+ var key [KeySize]byte
+ rand.Read(key[:])
+ c := NewCipher(key, SboxDefault)
+ f := func(ivRaw []byte, data []byte) bool {
+ if len(data) == 0 {
+ return true
+ }
+ var iv [8]byte
+ if len(ivRaw) >= 8 {
+ copy(iv[:], ivRaw[:8])
+ }
+ m, err := c.NewMAC(8, iv)
+ if err != nil {
+ t.Fail()
+ }
+
+ var tag1 []byte
+ var tag2 []byte
+
+ for _, b := range data {
+ m.Write([]byte{b})
+ }
+ m.Sum(tag1)
+
+ m.Reset()
+ m.Write(data)
+ m.Sum(tag2)
+
+ return bytes.Compare(tag1, tag2) == 0
+ }
+ if err := quick.Check(f, nil); err != nil {
+ t.Error(err)
+ }
+}
+
+func TestMACInterface(t *testing.T) {
+ var key [32]byte
+ var iv [8]byte
+ c := NewCipher(key, SboxDefault)
+ m, _ := c.NewMAC(8, iv)
+ var _ hash.Hash = m
+}
+
+func BenchmarkMAC(b *testing.B) {
+ var key [KeySize]byte
+ var iv [BlockSize]byte
+ rand.Read(key[:])
+ rand.Read(iv[:])
+ b1 := make([]byte, BlockSize)
+ b2 := make([]byte, BlockSize)
+ rand.Read(b1)
+ rand.Read(b2)
+ c := NewCipher(key, SboxDefault)
+ mac, _ := c.NewMAC(BlockSize, iv)
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ mac.Write(b1)
+ mac.Write(b2)
+ mac.Sum(nil)
+ }
+}
--- /dev/null
+// GoGOST -- Pure Go GOST cryptographic functions library
+// Copyright (C) 2015-2016 Sergey Matveev <stargrave@stargrave.org>
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+package gost28147
+
+// Sbox is a representation of eight substitution boxes.
+type Sbox [8][16]uint8
+
+var (
+ Gost2814789_TestParamSet = Sbox([8][16]uint8{
+ {4, 2, 15, 5, 9, 1, 0, 8, 14, 3, 11, 12, 13, 7, 10, 6},
+ {12, 9, 15, 14, 8, 1, 3, 10, 2, 7, 4, 13, 6, 0, 11, 5},
+ {13, 8, 14, 12, 7, 3, 9, 10, 1, 5, 2, 4, 6, 15, 0, 11},
+ {14, 9, 11, 2, 5, 15, 7, 1, 0, 13, 12, 6, 10, 4, 3, 8},
+ {3, 14, 5, 9, 6, 8, 0, 13, 10, 11, 7, 12, 2, 1, 15, 4},
+ {8, 15, 6, 11, 1, 9, 12, 5, 13, 3, 7, 10, 0, 14, 2, 4},
+ {9, 11, 12, 0, 3, 6, 7, 5, 4, 8, 14, 15, 1, 10, 2, 13},
+ {12, 6, 5, 2, 11, 0, 9, 13, 3, 14, 7, 10, 15, 4, 1, 8},
+ })
+ Gost28147_CryptoProParamSetA = Sbox([8][16]uint8{
+ {9, 6, 3, 2, 8, 11, 1, 7, 10, 4, 14, 15, 12, 0, 13, 5},
+ {3, 7, 14, 9, 8, 10, 15, 0, 5, 2, 6, 12, 11, 4, 13, 1},
+ {14, 4, 6, 2, 11, 3, 13, 8, 12, 15, 5, 10, 0, 7, 1, 9},
+ {14, 7, 10, 12, 13, 1, 3, 9, 0, 2, 11, 4, 15, 8, 5, 6},
+ {11, 5, 1, 9, 8, 13, 15, 0, 14, 4, 2, 3, 12, 7, 10, 6},
+ {3, 10, 13, 12, 1, 2, 0, 11, 7, 5, 9, 4, 8, 15, 14, 6},
+ {1, 13, 2, 9, 7, 10, 6, 0, 8, 12, 4, 5, 15, 3, 11, 14},
+ {11, 10, 15, 5, 0, 12, 14, 8, 6, 2, 3, 9, 1, 7, 13, 4},
+ })
+ Gost28147_CryptoProParamSetB = Sbox([8][16]uint8{
+ {8, 4, 11, 1, 3, 5, 0, 9, 2, 14, 10, 12, 13, 6, 7, 15},
+ {0, 1, 2, 10, 4, 13, 5, 12, 9, 7, 3, 15, 11, 8, 6, 14},
+ {14, 12, 0, 10, 9, 2, 13, 11, 7, 5, 8, 15, 3, 6, 1, 4},
+ {7, 5, 0, 13, 11, 6, 1, 2, 3, 10, 12, 15, 4, 14, 9, 8},
+ {2, 7, 12, 15, 9, 5, 10, 11, 1, 4, 0, 13, 6, 8, 14, 3},
+ {8, 3, 2, 6, 4, 13, 14, 11, 12, 1, 7, 15, 10, 0, 9, 5},
+ {5, 2, 10, 11, 9, 1, 12, 3, 7, 4, 13, 0, 6, 15, 8, 14},
+ {0, 4, 11, 14, 8, 3, 7, 1, 10, 2, 9, 6, 15, 13, 5, 12},
+ })
+ Gost28147_CryptoProParamSetC = Sbox([8][16]uint8{
+ {1, 11, 12, 2, 9, 13, 0, 15, 4, 5, 8, 14, 10, 7, 6, 3},
+ {0, 1, 7, 13, 11, 4, 5, 2, 8, 14, 15, 12, 9, 10, 6, 3},
+ {8, 2, 5, 0, 4, 9, 15, 10, 3, 7, 12, 13, 6, 14, 1, 11},
+ {3, 6, 0, 1, 5, 13, 10, 8, 11, 2, 9, 7, 14, 15, 12, 4},
+ {8, 13, 11, 0, 4, 5, 1, 2, 9, 3, 12, 14, 6, 15, 10, 7},
+ {12, 9, 11, 1, 8, 14, 2, 4, 7, 3, 6, 5, 10, 0, 15, 13},
+ {10, 9, 6, 8, 13, 14, 2, 0, 15, 3, 5, 11, 4, 1, 12, 7},
+ {7, 4, 0, 5, 10, 2, 15, 14, 12, 6, 1, 11, 13, 9, 3, 8},
+ })
+ Gost28147_CryptoProParamSetD = Sbox([8][16]uint8{
+ {15, 12, 2, 10, 6, 4, 5, 0, 7, 9, 14, 13, 1, 11, 8, 3},
+ {11, 6, 3, 4, 12, 15, 14, 2, 7, 13, 8, 0, 5, 10, 9, 1},
+ {1, 12, 11, 0, 15, 14, 6, 5, 10, 13, 4, 8, 9, 3, 7, 2},
+ {1, 5, 14, 12, 10, 7, 0, 13, 6, 2, 11, 4, 9, 3, 15, 8},
+ {0, 12, 8, 9, 13, 2, 10, 11, 7, 3, 6, 5, 4, 14, 15, 1},
+ {8, 0, 15, 3, 2, 5, 14, 11, 1, 10, 4, 7, 12, 9, 13, 6},
+ {3, 0, 6, 15, 1, 14, 9, 2, 13, 8, 12, 4, 11, 10, 5, 7},
+ {1, 10, 6, 8, 15, 11, 0, 4, 12, 3, 5, 9, 7, 13, 2, 14},
+ })
+ GostR3411_94_TestParamSet = Sbox([8][16]uint8{
+ {4, 10, 9, 2, 13, 8, 0, 14, 6, 11, 1, 12, 7, 15, 5, 3},
+ {14, 11, 4, 12, 6, 13, 15, 10, 2, 3, 8, 1, 0, 7, 5, 9},
+ {5, 8, 1, 13, 10, 3, 4, 2, 14, 15, 12, 7, 6, 0, 9, 11},
+ {7, 13, 10, 1, 0, 8, 9, 15, 14, 4, 6, 12, 11, 2, 5, 3},
+ {6, 12, 7, 1, 5, 15, 13, 8, 4, 10, 9, 14, 0, 3, 11, 2},
+ {4, 11, 10, 0, 7, 2, 1, 13, 3, 6, 8, 5, 9, 12, 15, 14},
+ {13, 11, 4, 1, 3, 15, 5, 9, 0, 10, 14, 7, 6, 8, 2, 12},
+ {1, 15, 13, 0, 5, 7, 10, 4, 9, 2, 3, 14, 6, 11, 8, 12},
+ })
+ GostR3411_94_CryptoProParamSet = Sbox([8][16]uint8{
+ {10, 4, 5, 6, 8, 1, 3, 7, 13, 12, 14, 0, 9, 2, 11, 15},
+ {5, 15, 4, 0, 2, 13, 11, 9, 1, 7, 6, 3, 12, 14, 10, 8},
+ {7, 15, 12, 14, 9, 4, 1, 0, 3, 11, 5, 2, 6, 10, 8, 13},
+ {4, 10, 7, 12, 0, 15, 2, 8, 14, 1, 6, 5, 13, 11, 9, 3},
+ {7, 6, 4, 11, 9, 12, 2, 10, 1, 8, 0, 14, 15, 13, 3, 5},
+ {7, 6, 2, 4, 13, 9, 15, 0, 10, 1, 5, 11, 8, 14, 12, 3},
+ {13, 14, 4, 1, 7, 0, 5, 10, 3, 12, 8, 15, 6, 2, 9, 11},
+ {1, 3, 10, 9, 5, 11, 4, 15, 8, 6, 7, 14, 13, 0, 2, 12},
+ })
+ AppliedCryptographyParamSet = Sbox([8][16]uint8{
+ {4, 10, 9, 2, 13, 8, 0, 14, 6, 11, 1, 12, 7, 15, 5, 3},
+ {14, 11, 4, 12, 6, 13, 15, 10, 2, 3, 8, 1, 0, 7, 5, 9},
+ {5, 8, 1, 13, 10, 3, 4, 2, 14, 15, 12, 7, 6, 0, 9, 11},
+ {7, 13, 10, 1, 0, 8, 9, 15, 14, 4, 6, 12, 11, 2, 5, 3},
+ {6, 12, 7, 1, 5, 15, 13, 8, 4, 10, 9, 14, 0, 3, 11, 2},
+ {4, 11, 10, 0, 7, 2, 1, 13, 3, 6, 8, 5, 9, 12, 15, 14},
+ {13, 11, 4, 1, 3, 15, 5, 9, 0, 10, 14, 7, 6, 8, 2, 12},
+ {1, 15, 13, 0, 5, 7, 10, 4, 9, 2, 3, 14, 6, 11, 8, 12},
+ })
+ Gost28147_tc26_ParamZ = Sbox([8][16]uint8{
+ {12, 4, 6, 2, 10, 5, 11, 9, 14, 8, 13, 7, 0, 3, 15, 1},
+ {6, 8, 2, 3, 9, 10, 5, 12, 1, 14, 4, 7, 11, 13, 0, 15},
+ {11, 3, 5, 8, 2, 15, 10, 13, 14, 1, 7, 4, 12, 9, 6, 0},
+ {12, 8, 2, 1, 13, 4, 15, 6, 7, 0, 10, 5, 3, 14, 9, 11},
+ {7, 15, 5, 10, 8, 1, 6, 13, 0, 9, 3, 14, 11, 4, 2, 12},
+ {5, 13, 15, 6, 9, 2, 12, 10, 11, 7, 8, 1, 4, 3, 14, 0},
+ {8, 14, 2, 5, 6, 9, 1, 12, 15, 4, 11, 0, 13, 10, 3, 7},
+ {1, 7, 14, 13, 0, 5, 8, 3, 4, 15, 10, 6, 9, 12, 11, 2},
+ })
+ SboxDefault = &Gost28147_CryptoProParamSetA
+)
+
+// Sbox substitution itself.
+func (s *Sbox) k(n nv) nv {
+ return nv(s[0][(n>>0)&0x0F])<<0 +
+ nv(s[1][(n>>4)&0x0F])<<4 +
+ nv(s[2][(n>>8)&0x0F])<<8 +
+ nv(s[3][(n>>12)&0x0F])<<12 +
+ nv(s[4][(n>>16)&0x0F])<<16 +
+ nv(s[5][(n>>20)&0x0F])<<20 +
+ nv(s[6][(n>>24)&0x0F])<<24 +
+ nv(s[7][(n>>28)&0x0F])<<28
+}
--- /dev/null
+// GoGOST -- Pure Go GOST cryptographic functions library
+// Copyright (C) 2015-2016 Sergey Matveev <stargrave@stargrave.org>
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+package gost3410
+
+import (
+ "bytes"
+ "crypto/rand"
+ "testing"
+ "testing/quick"
+)
+
+func TestRFCVectors(t *testing.T) {
+ priv := []byte{
+ 0x28, 0x3b, 0xec, 0x91, 0x98, 0xce, 0x19, 0x1d,
+ 0xee, 0x7e, 0x39, 0x49, 0x1f, 0x96, 0x60, 0x1b,
+ 0xc1, 0x72, 0x9a, 0xd3, 0x9d, 0x35, 0xed, 0x10,
+ 0xbe, 0xb9, 0x9b, 0x78, 0xde, 0x9a, 0x92, 0x7a,
+ }
+ pubX := []byte{
+ 0x0b, 0xd8, 0x6f, 0xe5, 0xd8, 0xdb, 0x89, 0x66,
+ 0x8f, 0x78, 0x9b, 0x4e, 0x1d, 0xba, 0x85, 0x85,
+ 0xc5, 0x50, 0x8b, 0x45, 0xec, 0x5b, 0x59, 0xd8,
+ 0x90, 0x6d, 0xdb, 0x70, 0xe2, 0x49, 0x2b, 0x7f,
+ }
+ pubY := []byte{
+ 0xda, 0x77, 0xff, 0x87, 0x1a, 0x10, 0xfb, 0xdf,
+ 0x27, 0x66, 0xd2, 0x93, 0xc5, 0xd1, 0x64, 0xaf,
+ 0xbb, 0x3c, 0x7b, 0x97, 0x3a, 0x41, 0xc8, 0x85,
+ 0xd1, 0x1d, 0x70, 0xd6, 0x89, 0xb4, 0xf1, 0x26,
+ }
+ digest := []byte{
+ 0x2d, 0xfb, 0xc1, 0xb3, 0x72, 0xd8, 0x9a, 0x11,
+ 0x88, 0xc0, 0x9c, 0x52, 0xe0, 0xee, 0xc6, 0x1f,
+ 0xce, 0x52, 0x03, 0x2a, 0xb1, 0x02, 0x2e, 0x8e,
+ 0x67, 0xec, 0xe6, 0x67, 0x2b, 0x04, 0x3e, 0xe5,
+ }
+ signature := []byte{
+ 0x01, 0x45, 0x6c, 0x64, 0xba, 0x46, 0x42, 0xa1,
+ 0x65, 0x3c, 0x23, 0x5a, 0x98, 0xa6, 0x02, 0x49,
+ 0xbc, 0xd6, 0xd3, 0xf7, 0x46, 0xb6, 0x31, 0xdf,
+ 0x92, 0x80, 0x14, 0xf6, 0xc5, 0xbf, 0x9c, 0x40,
+ 0x41, 0xaa, 0x28, 0xd2, 0xf1, 0xab, 0x14, 0x82,
+ 0x80, 0xcd, 0x9e, 0xd5, 0x6f, 0xed, 0xa4, 0x19,
+ 0x74, 0x05, 0x35, 0x54, 0xa4, 0x27, 0x67, 0xb8,
+ 0x3a, 0xd0, 0x43, 0xfd, 0x39, 0xdc, 0x04, 0x93,
+ }
+
+ c, err := NewCurveFromParams(CurveParamsGostR34102001Test)
+ if err != nil {
+ t.FailNow()
+ }
+ prv, err := NewPrivateKey(c, DigestSize2001, priv)
+ if err != nil {
+ t.FailNow()
+ }
+ pub, err := prv.PublicKey()
+ if err != nil {
+ t.FailNow()
+ }
+ if bytes.Compare(pub.Raw()[:32], pubX) != 0 {
+ t.FailNow()
+ }
+ if bytes.Compare(pub.Raw()[32:], pubY) != 0 {
+ t.FailNow()
+ }
+ ourSign, err := prv.SignDigest(digest, rand.Reader)
+ if err != nil {
+ t.FailNow()
+ }
+ valid, err := pub.VerifyDigest(digest, ourSign)
+ if err != nil || !valid {
+ t.FailNow()
+ }
+ valid, err = pub.VerifyDigest(digest, signature)
+ if err != nil || !valid {
+ t.FailNow()
+ }
+}
+
+func TestRandom2001(t *testing.T) {
+ c, _ := NewCurveFromParams(CurveParamsGostR34102001Test)
+ f := func(data [31]byte, digest [32]byte) bool {
+ prv, err := NewPrivateKey(
+ c,
+ DigestSize2001,
+ append([]byte{0xde}, data[:]...),
+ )
+ if err != nil {
+ return false
+ }
+ pub, err := prv.PublicKey()
+ if err != nil {
+ return false
+ }
+ pubRaw := pub.Raw()
+ pub, err = NewPublicKey(c, DigestSize2001, pubRaw)
+ if err != nil {
+ return false
+ }
+ sign, err := prv.SignDigest(digest[:], rand.Reader)
+ if err != nil {
+ return false
+ }
+ valid, err := pub.VerifyDigest(digest[:], sign)
+ if err != nil {
+ return false
+ }
+ return valid
+ }
+ if err := quick.Check(f, nil); err != nil {
+ t.Error(err)
+ }
+}
+
+func BenchmarkSign2001(b *testing.B) {
+ c, _ := NewCurveFromParams(CurveParamsGostR34102001Test)
+ prv, err := GenPrivateKey(c, DigestSize2001, rand.Reader)
+ if err != nil {
+ b.FailNow()
+ }
+ digest := make([]byte, 32)
+ rand.Read(digest)
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ prv.SignDigest(digest, rand.Reader)
+ }
+}
+
+func BenchmarkVerify2001(b *testing.B) {
+ c, _ := NewCurveFromParams(CurveParamsGostR34102001Test)
+ prv, err := GenPrivateKey(c, DigestSize2001, rand.Reader)
+ if err != nil {
+ b.FailNow()
+ }
+ digest := make([]byte, 32)
+ rand.Read(digest)
+ sign, err := prv.SignDigest(digest, rand.Reader)
+ if err != nil {
+ b.FailNow()
+ }
+ pub, err := prv.PublicKey()
+ if err != nil {
+ b.FailNow()
+ }
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ pub.VerifyDigest(digest, sign)
+ }
+}
--- /dev/null
+// GoGOST -- Pure Go GOST cryptographic functions library
+// Copyright (C) 2015-2016 Sergey Matveev <stargrave@stargrave.org>
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+package gost3410
+
+import (
+ "bytes"
+ "crypto/rand"
+ "testing"
+ "testing/quick"
+)
+
+func TestGCL3Vectors(t *testing.T) {
+ p := []byte{
+ 0x45, 0x31, 0xAC, 0xD1, 0xFE, 0x00, 0x23, 0xC7,
+ 0x55, 0x0D, 0x26, 0x7B, 0x6B, 0x2F, 0xEE, 0x80,
+ 0x92, 0x2B, 0x14, 0xB2, 0xFF, 0xB9, 0x0F, 0x04,
+ 0xD4, 0xEB, 0x7C, 0x09, 0xB5, 0xD2, 0xD1, 0x5D,
+ 0xF1, 0xD8, 0x52, 0x74, 0x1A, 0xF4, 0x70, 0x4A,
+ 0x04, 0x58, 0x04, 0x7E, 0x80, 0xE4, 0x54, 0x6D,
+ 0x35, 0xB8, 0x33, 0x6F, 0xAC, 0x22, 0x4D, 0xD8,
+ 0x16, 0x64, 0xBB, 0xF5, 0x28, 0xBE, 0x63, 0x73,
+ }
+ q := []byte{
+ 0x45, 0x31, 0xAC, 0xD1, 0xFE, 0x00, 0x23, 0xC7,
+ 0x55, 0x0D, 0x26, 0x7B, 0x6B, 0x2F, 0xEE, 0x80,
+ 0x92, 0x2B, 0x14, 0xB2, 0xFF, 0xB9, 0x0F, 0x04,
+ 0xD4, 0xEB, 0x7C, 0x09, 0xB5, 0xD2, 0xD1, 0x5D,
+ 0xA8, 0x2F, 0x2D, 0x7E, 0xCB, 0x1D, 0xBA, 0xC7,
+ 0x19, 0x90, 0x5C, 0x5E, 0xEC, 0xC4, 0x23, 0xF1,
+ 0xD8, 0x6E, 0x25, 0xED, 0xBE, 0x23, 0xC5, 0x95,
+ 0xD6, 0x44, 0xAA, 0xF1, 0x87, 0xE6, 0xE6, 0xDF,
+ }
+ a := []byte{
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07,
+ }
+ b := []byte{
+ 0x1C, 0xFF, 0x08, 0x06, 0xA3, 0x11, 0x16, 0xDA,
+ 0x29, 0xD8, 0xCF, 0xA5, 0x4E, 0x57, 0xEB, 0x74,
+ 0x8B, 0xC5, 0xF3, 0x77, 0xE4, 0x94, 0x00, 0xFD,
+ 0xD7, 0x88, 0xB6, 0x49, 0xEC, 0xA1, 0xAC, 0x43,
+ 0x61, 0x83, 0x40, 0x13, 0xB2, 0xAD, 0x73, 0x22,
+ 0x48, 0x0A, 0x89, 0xCA, 0x58, 0xE0, 0xCF, 0x74,
+ 0xBC, 0x9E, 0x54, 0x0C, 0x2A, 0xDD, 0x68, 0x97,
+ 0xFA, 0xD0, 0xA3, 0x08, 0x4F, 0x30, 0x2A, 0xDC,
+ }
+ x := []byte{
+ 0x24, 0xD1, 0x9C, 0xC6, 0x45, 0x72, 0xEE, 0x30,
+ 0xF3, 0x96, 0xBF, 0x6E, 0xBB, 0xFD, 0x7A, 0x6C,
+ 0x52, 0x13, 0xB3, 0xB3, 0xD7, 0x05, 0x7C, 0xC8,
+ 0x25, 0xF9, 0x10, 0x93, 0xA6, 0x8C, 0xD7, 0x62,
+ 0xFD, 0x60, 0x61, 0x12, 0x62, 0xCD, 0x83, 0x8D,
+ 0xC6, 0xB6, 0x0A, 0xA7, 0xEE, 0xE8, 0x04, 0xE2,
+ 0x8B, 0xC8, 0x49, 0x97, 0x7F, 0xAC, 0x33, 0xB4,
+ 0xB5, 0x30, 0xF1, 0xB1, 0x20, 0x24, 0x8A, 0x9A,
+ }
+ y := []byte{
+ 0x2B, 0xB3, 0x12, 0xA4, 0x3B, 0xD2, 0xCE, 0x6E,
+ 0x0D, 0x02, 0x06, 0x13, 0xC8, 0x57, 0xAC, 0xDD,
+ 0xCF, 0xBF, 0x06, 0x1E, 0x91, 0xE5, 0xF2, 0xC3,
+ 0xF3, 0x24, 0x47, 0xC2, 0x59, 0xF3, 0x9B, 0x2C,
+ 0x83, 0xAB, 0x15, 0x6D, 0x77, 0xF1, 0x49, 0x6B,
+ 0xF7, 0xEB, 0x33, 0x51, 0xE1, 0xEE, 0x4E, 0x43,
+ 0xDC, 0x1A, 0x18, 0xB9, 0x1B, 0x24, 0x64, 0x0B,
+ 0x6D, 0xBB, 0x92, 0xCB, 0x1A, 0xDD, 0x37, 0x1E,
+ }
+ priv := []byte{
+ 0xD4, 0x8D, 0xA1, 0x1F, 0x82, 0x67, 0x29, 0xC6,
+ 0xDF, 0xAA, 0x18, 0xFD, 0x7B, 0x6B, 0x63, 0xA2,
+ 0x14, 0x27, 0x7E, 0x82, 0xD2, 0xDA, 0x22, 0x33,
+ 0x56, 0xA0, 0x00, 0x22, 0x3B, 0x12, 0xE8, 0x72,
+ 0x20, 0x10, 0x8B, 0x50, 0x8E, 0x50, 0xE7, 0x0E,
+ 0x70, 0x69, 0x46, 0x51, 0xE8, 0xA0, 0x91, 0x30,
+ 0xC9, 0xD7, 0x56, 0x77, 0xD4, 0x36, 0x09, 0xA4,
+ 0x1B, 0x24, 0xAE, 0xAD, 0x8A, 0x04, 0xA6, 0x0B,
+ }
+ pubX := []byte{
+ 0xE1, 0xEF, 0x30, 0xD5, 0x2C, 0x61, 0x33, 0xDD,
+ 0xD9, 0x9D, 0x1D, 0x5C, 0x41, 0x45, 0x5C, 0xF7,
+ 0xDF, 0x4D, 0x8B, 0x4C, 0x92, 0x5B, 0xBC, 0x69,
+ 0xAF, 0x14, 0x33, 0xD1, 0x56, 0x58, 0x51, 0x5A,
+ 0xDD, 0x21, 0x46, 0x85, 0x0C, 0x32, 0x5C, 0x5B,
+ 0x81, 0xC1, 0x33, 0xBE, 0x65, 0x5A, 0xA8, 0xC4,
+ 0xD4, 0x40, 0xE7, 0xB9, 0x8A, 0x8D, 0x59, 0x48,
+ 0x7B, 0x0C, 0x76, 0x96, 0xBC, 0xC5, 0x5D, 0x11,
+ }
+ pubY := []byte{
+ 0xEC, 0xBE, 0x77, 0x36, 0xA9, 0xEC, 0x35, 0x7F,
+ 0xF2, 0xFD, 0x39, 0x93, 0x1F, 0x4E, 0x11, 0x4C,
+ 0xB8, 0xCD, 0xA3, 0x59, 0x27, 0x0A, 0xC7, 0xF0,
+ 0xE7, 0xFF, 0x43, 0xD9, 0x41, 0x94, 0x19, 0xEA,
+ 0x61, 0xFD, 0x2A, 0xB7, 0x7F, 0x5D, 0x9F, 0x63,
+ 0x52, 0x3D, 0x3B, 0x50, 0xA0, 0x4F, 0x63, 0xE2,
+ 0xA0, 0xCF, 0x51, 0xB7, 0xC1, 0x3A, 0xDC, 0x21,
+ 0x56, 0x0F, 0x0B, 0xD4, 0x0C, 0xC9, 0xC7, 0x37,
+ }
+ digest := []byte{
+ 0x37, 0x54, 0xF3, 0xCF, 0xAC, 0xC9, 0xE0, 0x61,
+ 0x5C, 0x4F, 0x4A, 0x7C, 0x4D, 0x8D, 0xAB, 0x53,
+ 0x1B, 0x09, 0xB6, 0xF9, 0xC1, 0x70, 0xC5, 0x33,
+ 0xA7, 0x1D, 0x14, 0x70, 0x35, 0xB0, 0xC5, 0x91,
+ 0x71, 0x84, 0xEE, 0x53, 0x65, 0x93, 0xF4, 0x41,
+ 0x43, 0x39, 0x97, 0x6C, 0x64, 0x7C, 0x5D, 0x5A,
+ 0x40, 0x7A, 0xDE, 0xDB, 0x1D, 0x56, 0x0C, 0x4F,
+ 0xC6, 0x77, 0x7D, 0x29, 0x72, 0x07, 0x5B, 0x8C,
+ }
+ signature := []byte{
+ 0x10, 0x81, 0xB3, 0x94, 0x69, 0x6F, 0xFE, 0x8E,
+ 0x65, 0x85, 0xE7, 0xA9, 0x36, 0x2D, 0x26, 0xB6,
+ 0x32, 0x5F, 0x56, 0x77, 0x8A, 0xAD, 0xBC, 0x08,
+ 0x1C, 0x0B, 0xFB, 0xE9, 0x33, 0xD5, 0x2F, 0xF5,
+ 0x82, 0x3C, 0xE2, 0x88, 0xE8, 0xC4, 0xF3, 0x62,
+ 0x52, 0x60, 0x80, 0xDF, 0x7F, 0x70, 0xCE, 0x40,
+ 0x6A, 0x6E, 0xEB, 0x1F, 0x56, 0x91, 0x9C, 0xB9,
+ 0x2A, 0x98, 0x53, 0xBD, 0xE7, 0x3E, 0x5B, 0x4A,
+ 0x2F, 0x86, 0xFA, 0x60, 0xA0, 0x81, 0x09, 0x1A,
+ 0x23, 0xDD, 0x79, 0x5E, 0x1E, 0x3C, 0x68, 0x9E,
+ 0xE5, 0x12, 0xA3, 0xC8, 0x2E, 0xE0, 0xDC, 0xC2,
+ 0x64, 0x3C, 0x78, 0xEE, 0xA8, 0xFC, 0xAC, 0xD3,
+ 0x54, 0x92, 0x55, 0x84, 0x86, 0xB2, 0x0F, 0x1C,
+ 0x9E, 0xC1, 0x97, 0xC9, 0x06, 0x99, 0x85, 0x02,
+ 0x60, 0xC9, 0x3B, 0xCB, 0xCD, 0x9C, 0x5C, 0x33,
+ 0x17, 0xE1, 0x93, 0x44, 0xE1, 0x73, 0xAE, 0x36,
+ }
+ c, err := NewCurve(p, q, a, b, x, y)
+ if err != nil {
+ t.FailNow()
+ }
+ prv, err := NewPrivateKey(c, DigestSize2012, priv)
+ if err != nil {
+ t.FailNow()
+ }
+ pub, err := prv.PublicKey()
+ if err != nil {
+ t.FailNow()
+ }
+ if bytes.Compare(pub.Raw()[:64], pubX) != 0 {
+ t.FailNow()
+ }
+ if bytes.Compare(pub.Raw()[64:], pubY) != 0 {
+ t.FailNow()
+ }
+ ourSign, err := prv.SignDigest(digest, rand.Reader)
+ if err != nil {
+ t.FailNow()
+ }
+ valid, err := pub.VerifyDigest(digest, ourSign)
+ if err != nil || !valid {
+ t.FailNow()
+ }
+ valid, err = pub.VerifyDigest(digest, signature)
+ if err != nil || !valid {
+ t.FailNow()
+ }
+}
+
+func TestRandom2012(t *testing.T) {
+ c, _ := NewCurveFromParams(CurveParamsGostR34102012TC26ParamSetA)
+ f := func(data [31]byte, digest [64]byte) bool {
+ prv, err := NewPrivateKey(
+ c,
+ DigestSize2012,
+ append([]byte{0xde}, data[:]...),
+ )
+ if err != nil {
+ return false
+ }
+ pub, err := prv.PublicKey()
+ if err != nil {
+ return false
+ }
+ pubRaw := pub.Raw()
+ pub, err = NewPublicKey(c, DigestSize2012, pubRaw)
+ if err != nil {
+ return false
+ }
+ sign, err := prv.SignDigest(digest[:], rand.Reader)
+ if err != nil {
+ return false
+ }
+ valid, err := pub.VerifyDigest(digest[:], sign)
+ if err != nil {
+ return false
+ }
+ return valid
+ }
+ if err := quick.Check(f, nil); err != nil {
+ t.Error(err)
+ }
+}
+
+func BenchmarkSign2012(b *testing.B) {
+ c, _ := NewCurveFromParams(CurveParamsGostR34102012TC26ParamSetA)
+ prv, err := GenPrivateKey(c, DigestSize2012, rand.Reader)
+ if err != nil {
+ b.FailNow()
+ }
+ digest := make([]byte, 64)
+ rand.Read(digest)
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ prv.SignDigest(digest, rand.Reader)
+ }
+}
+
+func BenchmarkVerify2012(b *testing.B) {
+ c, _ := NewCurveFromParams(CurveParamsGostR34102012TC26ParamSetA)
+ prv, err := GenPrivateKey(c, DigestSize2012, rand.Reader)
+ if err != nil {
+ b.FailNow()
+ }
+ digest := make([]byte, 64)
+ rand.Read(digest)
+ sign, err := prv.SignDigest(digest, rand.Reader)
+ if err != nil {
+ b.FailNow()
+ }
+ pub, err := prv.PublicKey()
+ if err != nil {
+ b.FailNow()
+ }
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ pub.VerifyDigest(digest, sign)
+ }
+}
--- /dev/null
+// GoGOST -- Pure Go GOST cryptographic functions library
+// Copyright (C) 2015-2016 Sergey Matveev <stargrave@stargrave.org>
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+package gost3410
+
+import (
+ "errors"
+ "math/big"
+)
+
+var (
+ zero *big.Int = big.NewInt(0)
+ bigInt1 *big.Int = big.NewInt(1)
+ bigInt2 *big.Int = big.NewInt(2)
+ bigInt3 *big.Int = big.NewInt(3)
+)
+
+type Curve struct {
+ P *big.Int
+ Q *big.Int
+ A *big.Int
+ B *big.Int
+
+ // Basic point X and Y coordinates
+ Bx *big.Int
+ By *big.Int
+
+ // Temporary variable for the add method
+ t *big.Int
+ tx *big.Int
+ ty *big.Int
+}
+
+func NewCurve(p, q, a, b, bx, by []byte) (*Curve, error) {
+ c := Curve{
+ P: bytes2big(p[:]),
+ Q: bytes2big(q[:]),
+ A: bytes2big(a[:]),
+ B: bytes2big(b[:]),
+ Bx: bytes2big(bx[:]),
+ By: bytes2big(by[:]),
+ t: big.NewInt(0),
+ tx: big.NewInt(0),
+ ty: big.NewInt(0),
+ }
+ r1 := big.NewInt(0)
+ r2 := big.NewInt(0)
+ r1.Mul(c.By, c.By)
+ r1.Mod(r1, c.P)
+ r2.Mul(c.Bx, c.Bx)
+ r2.Add(r2, c.A)
+ r2.Mul(r2, c.Bx)
+ r2.Add(r2, c.B)
+ r2.Mod(r2, c.P)
+ if r2.Cmp(big.NewInt(0)) == -1 {
+ r2.Add(r2, c.P)
+ }
+ if r1.Cmp(r2) != 0 {
+ return nil, errors.New("Invalid curve parameters")
+ }
+ return &c, nil
+}
+
+func (c *Curve) pos(v *big.Int) {
+ if v.Cmp(zero) < 0 {
+ v.Add(v, c.P)
+ }
+}
+
+func (c *Curve) add(p1x, p1y, p2x, p2y *big.Int) {
+ if p1x.Cmp(p2x) == 0 && p1y.Cmp(p2y) == 0 {
+ // double
+ c.t.Mul(p1x, p1x)
+ c.t.Mul(c.t, bigInt3)
+ c.t.Add(c.t, c.A)
+ c.tx.Mul(bigInt2, p1y)
+ c.tx.ModInverse(c.tx, c.P)
+ c.t.Mul(c.t, c.tx)
+ c.t.Mod(c.t, c.P)
+ } else {
+ c.tx.Sub(p2x, p1x)
+ c.tx.Mod(c.tx, c.P)
+ c.pos(c.tx)
+ c.ty.Sub(p2y, p1y)
+ c.ty.Mod(c.ty, c.P)
+ c.pos(c.ty)
+ c.t.ModInverse(c.tx, c.P)
+ c.t.Mul(c.t, c.ty)
+ c.t.Mod(c.t, c.P)
+ }
+ c.tx.Mul(c.t, c.t)
+ c.tx.Sub(c.tx, p1x)
+ c.tx.Sub(c.tx, p2x)
+ c.tx.Mod(c.tx, c.P)
+ c.pos(c.tx)
+ c.ty.Sub(p1x, c.tx)
+ c.ty.Mul(c.ty, c.t)
+ c.ty.Sub(c.ty, p1y)
+ c.ty.Mod(c.ty, c.P)
+ c.pos(c.ty)
+ p1x.Set(c.tx)
+ p1y.Set(c.ty)
+}
+
+func (c *Curve) Exp(degree, xS, yS *big.Int) (*big.Int, *big.Int, error) {
+ dg := big.NewInt(0).Sub(degree, bigInt1)
+ tx := big.NewInt(0).Set(xS)
+ ty := big.NewInt(0).Set(yS)
+ cx := big.NewInt(0).Set(xS)
+ cy := big.NewInt(0).Set(yS)
+ if dg.Cmp(zero) == 0 {
+ return nil, nil, errors.New("Bad degree value")
+ }
+ for dg.Cmp(zero) != 0 {
+ if dg.Bit(0) == 1 {
+ c.add(tx, ty, cx, cy)
+ }
+ dg.Rsh(dg, 1)
+ c.add(cx, cy, cx, cy)
+ }
+ return tx, ty, nil
+}
--- /dev/null
+// GOST R 34.10-2001 (RFC 5832) and 34.10-2012 (RFC 7091) signature algorithm.
+package gost3410
--- /dev/null
+// GoGOST -- Pure Go GOST cryptographic functions library
+// Copyright (C) 2015-2016 Sergey Matveev <stargrave@stargrave.org>
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+package gost3410
+
+type DigestSize uint8
+
+// Curve params: p, q, a, b, bx, by
+type CurveParams [6][]byte
+
+var (
+ DigestSize2001 DigestSize = 32
+ DigestSize2012 DigestSize = 64
+
+ CurveParamsGostR34102001cc CurveParams = CurveParams([6][]byte{
+ {0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xC7},
+ {0x5f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x60, 0x61, 0x17, 0xa2, 0xf4, 0xbd, 0xe4, 0x28,
+ 0xb7, 0x45, 0x8a, 0x54, 0xb6, 0xe8, 0x7b, 0x85},
+ {0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xc4},
+ {0x2d, 0x06, 0xB4, 0x26, 0x5e, 0xbc, 0x74, 0x9f,
+ 0xf7, 0xd0, 0xf1, 0xf1, 0xf8, 0x82, 0x32, 0xe8,
+ 0x16, 0x32, 0xe9, 0x08, 0x8f, 0xd4, 0x4b, 0x77,
+ 0x87, 0xd5, 0xe4, 0x07, 0xe9, 0x55, 0x08, 0x0c},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02},
+ {0xa2, 0x0e, 0x03, 0x4b, 0xf8, 0x81, 0x3e, 0xf5,
+ 0xc1, 0x8d, 0x01, 0x10, 0x5e, 0x72, 0x6a, 0x17,
+ 0xeb, 0x24, 0x8b, 0x26, 0x4a, 0xe9, 0x70, 0x6f,
+ 0x44, 0x0b, 0xed, 0xc8, 0xcc, 0xb6, 0xb2, 0x2c},
+ })
+ CurveParamsGostR34102001Test CurveParams = CurveParams([6][]byte{
+ {0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x31},
+ {0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x50, 0xFE, 0x8A, 0x18, 0x92, 0x97, 0x61, 0x54,
+ 0xC5, 0x9C, 0xFC, 0x19, 0x3A, 0xCC, 0xF5, 0xB3},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07},
+ {0x5F, 0xBF, 0xF4, 0x98, 0xAA, 0x93, 0x8C, 0xE7,
+ 0x39, 0xB8, 0xE0, 0x22, 0xFB, 0xAF, 0xEF, 0x40,
+ 0x56, 0x3F, 0x6E, 0x6A, 0x34, 0x72, 0xFC, 0x2A,
+ 0x51, 0x4C, 0x0C, 0xE9, 0xDA, 0xE2, 0x3B, 0x7E},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02},
+ {0x08, 0xE2, 0xA8, 0xA0, 0xE6, 0x51, 0x47, 0xD4,
+ 0xBD, 0x63, 0x16, 0x03, 0x0E, 0x16, 0xD1, 0x9C,
+ 0x85, 0xC9, 0x7F, 0x0A, 0x9C, 0xA2, 0x67, 0x12,
+ 0x2B, 0x96, 0xAB, 0xBC, 0xEA, 0x7E, 0x8F, 0xC8},
+ })
+ CurveParamsGostR34102001CryptoProA CurveParams = CurveParams([6][]byte{
+ {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFD, 0x97},
+ {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x6C, 0x61, 0x10, 0x70, 0x99, 0x5A, 0xD1, 0x00,
+ 0x45, 0x84, 0x1B, 0x09, 0xB7, 0x61, 0xB8, 0x93},
+ {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFD, 0x94},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa6},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01},
+ {0x8D, 0x91, 0xE4, 0x71, 0xE0, 0x98, 0x9C, 0xDA,
+ 0x27, 0xDF, 0x50, 0x5A, 0x45, 0x3F, 0x2B, 0x76,
+ 0x35, 0x29, 0x4F, 0x2D, 0xDF, 0x23, 0xE3, 0xB1,
+ 0x22, 0xAC, 0xC9, 0x9C, 0x9E, 0x9F, 0x1E, 0x14},
+ })
+ CurveParamsGostR34102001CryptoProB CurveParams = CurveParams([6][]byte{
+ {0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x99},
+ {0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x5F, 0x70, 0x0C, 0xFF, 0xF1, 0xA6, 0x24, 0xE5,
+ 0xE4, 0x97, 0x16, 0x1B, 0xCC, 0x8A, 0x19, 0x8F},
+ {0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x96},
+ {0x3E, 0x1A, 0xF4, 0x19, 0xA2, 0x69, 0xA5, 0xF8,
+ 0x66, 0xA7, 0xD3, 0xC2, 0x5C, 0x3D, 0xF8, 0x0A,
+ 0xE9, 0x79, 0x25, 0x93, 0x73, 0xFF, 0x2B, 0x18,
+ 0x2F, 0x49, 0xD4, 0xCE, 0x7E, 0x1B, 0xBC, 0x8B},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01},
+ {0x3F, 0xA8, 0x12, 0x43, 0x59, 0xF9, 0x66, 0x80,
+ 0xB8, 0x3D, 0x1C, 0x3E, 0xB2, 0xC0, 0x70, 0xE5,
+ 0xC5, 0x45, 0xC9, 0x85, 0x8D, 0x03, 0xEC, 0xFB,
+ 0x74, 0x4B, 0xF8, 0xD7, 0x17, 0x71, 0x7E, 0xFC},
+ })
+ CurveParamsGostR34102001CryptoProC CurveParams = CurveParams([6][]byte{
+ {0x9B, 0x9F, 0x60, 0x5F, 0x5A, 0x85, 0x81, 0x07,
+ 0xAB, 0x1E, 0xC8, 0x5E, 0x6B, 0x41, 0xC8, 0xAA,
+ 0xCF, 0x84, 0x6E, 0x86, 0x78, 0x90, 0x51, 0xD3,
+ 0x79, 0x98, 0xF7, 0xB9, 0x02, 0x2D, 0x75, 0x9B},
+ {0x9B, 0x9F, 0x60, 0x5F, 0x5A, 0x85, 0x81, 0x07,
+ 0xAB, 0x1E, 0xC8, 0x5E, 0x6B, 0x41, 0xC8, 0xAA,
+ 0x58, 0x2C, 0xA3, 0x51, 0x1E, 0xDD, 0xFB, 0x74,
+ 0xF0, 0x2F, 0x3A, 0x65, 0x98, 0x98, 0x0B, 0xB9},
+ {0x9B, 0x9F, 0x60, 0x5F, 0x5A, 0x85, 0x81, 0x07,
+ 0xAB, 0x1E, 0xC8, 0x5E, 0x6B, 0x41, 0xC8, 0xAA,
+ 0xCF, 0x84, 0x6E, 0x86, 0x78, 0x90, 0x51, 0xD3,
+ 0x79, 0x98, 0xF7, 0xB9, 0x02, 0x2D, 0x75, 0x98},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x5a},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x41, 0xEC, 0xE5, 0x57, 0x43, 0x71, 0x1A, 0x8C,
+ 0x3C, 0xBF, 0x37, 0x83, 0xCD, 0x08, 0xC0, 0xEE,
+ 0x4D, 0x4D, 0xC4, 0x40, 0xD4, 0x64, 0x1A, 0x8F,
+ 0x36, 0x6E, 0x55, 0x0D, 0xFD, 0xB3, 0xBB, 0x67},
+ })
+ CurveParamsGostR34102001CryptoProXchA CurveParams = CurveParams([6][]byte{
+ {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFD, 0x97},
+ {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x6C, 0x61, 0x10, 0x70, 0x99, 0x5A, 0xD1, 0x00,
+ 0x45, 0x84, 0x1B, 0x09, 0xB7, 0x61, 0xB8, 0x93},
+ {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFD, 0x94},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa6},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01},
+ {0x8D, 0x91, 0xE4, 0x71, 0xE0, 0x98, 0x9C, 0xDA,
+ 0x27, 0xDF, 0x50, 0x5A, 0x45, 0x3F, 0x2B, 0x76,
+ 0x35, 0x29, 0x4F, 0x2D, 0xDF, 0x23, 0xE3, 0xB1,
+ 0x22, 0xAC, 0xC9, 0x9C, 0x9E, 0x9F, 0x1E, 0x14},
+ })
+ CurveParamsGostR34102001CryptoProXchB CurveParams = CurveParams([6][]byte{
+ {0x9B, 0x9F, 0x60, 0x5F, 0x5A, 0x85, 0x81, 0x07,
+ 0xAB, 0x1E, 0xC8, 0x5E, 0x6B, 0x41, 0xC8, 0xAA,
+ 0xCF, 0x84, 0x6E, 0x86, 0x78, 0x90, 0x51, 0xD3,
+ 0x79, 0x98, 0xF7, 0xB9, 0x02, 0x2D, 0x75, 0x9B},
+ {0x9B, 0x9F, 0x60, 0x5F, 0x5A, 0x85, 0x81, 0x07,
+ 0xAB, 0x1E, 0xC8, 0x5E, 0x6B, 0x41, 0xC8, 0xAA,
+ 0x58, 0x2C, 0xA3, 0x51, 0x1E, 0xDD, 0xFB, 0x74,
+ 0xF0, 0x2F, 0x3A, 0x65, 0x98, 0x98, 0x0B, 0xB9},
+ {0x9B, 0x9F, 0x60, 0x5F, 0x5A, 0x85, 0x81, 0x07,
+ 0xAB, 0x1E, 0xC8, 0x5E, 0x6B, 0x41, 0xC8, 0xAA,
+ 0xCF, 0x84, 0x6E, 0x86, 0x78, 0x90, 0x51, 0xD3,
+ 0x79, 0x98, 0xF7, 0xB9, 0x02, 0x2D, 0x75, 0x98},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x5a},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x41, 0xEC, 0xE5, 0x57, 0x43, 0x71, 0x1A, 0x8C,
+ 0x3C, 0xBF, 0x37, 0x83, 0xCD, 0x08, 0xC0, 0xEE,
+ 0x4D, 0x4D, 0xC4, 0x40, 0xD4, 0x64, 0x1A, 0x8F,
+ 0x36, 0x6E, 0x55, 0x0D, 0xFD, 0xB3, 0xBB, 0x67},
+ })
+ CurveParamsGostR34102012TC26ParamSetA CurveParams = CurveParams([6][]byte{
+ {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFD, 0xC7},
+ {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0x27, 0xE6, 0x95, 0x32, 0xF4, 0x8D, 0x89, 0x11,
+ 0x6F, 0xF2, 0x2B, 0x8D, 0x4E, 0x05, 0x60, 0x60, 0x9B, 0x4B,
+ 0x38, 0xAB, 0xFA, 0xD2, 0xB8, 0x5D, 0xCA, 0xCD, 0xB1, 0x41,
+ 0x1F, 0x10, 0xB2, 0x75},
+ {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFD, 0xC4},
+ {0xE8, 0xC2, 0x50, 0x5D, 0xED, 0xFC, 0x86, 0xDD, 0xC1, 0xBD,
+ 0x0B, 0x2B, 0x66, 0x67, 0xF1, 0xDA, 0x34, 0xB8, 0x25, 0x74,
+ 0x76, 0x1C, 0xB0, 0xE8, 0x79, 0xBD, 0x08, 0x1C, 0xFD, 0x0B,
+ 0x62, 0x65, 0xEE, 0x3C, 0xB0, 0x90, 0xF3, 0x0D, 0x27, 0x61,
+ 0x4C, 0xB4, 0x57, 0x40, 0x10, 0xDA, 0x90, 0xDD, 0x86, 0x2E,
+ 0xF9, 0xD4, 0xEB, 0xEE, 0x47, 0x61, 0x50, 0x31, 0x90, 0x78,
+ 0x5A, 0x71, 0xC7, 0x60},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x03},
+ {0x75, 0x03, 0xCF, 0xE8, 0x7A, 0x83, 0x6A, 0xE3, 0xA6, 0x1B,
+ 0x88, 0x16, 0xE2, 0x54, 0x50, 0xE6, 0xCE, 0x5E, 0x1C, 0x93,
+ 0xAC, 0xF1, 0xAB, 0xC1, 0x77, 0x80, 0x64, 0xFD, 0xCB, 0xEF,
+ 0xA9, 0x21, 0xDF, 0x16, 0x26, 0xBE, 0x4F, 0xD0, 0x36, 0xE9,
+ 0x3D, 0x75, 0xE6, 0xA5, 0x0E, 0x3A, 0x41, 0xE9, 0x80, 0x28,
+ 0xFE, 0x5F, 0xC2, 0x35, 0xF5, 0xB8, 0x89, 0xA5, 0x89, 0xCB,
+ 0x52, 0x15, 0xF2, 0xA4},
+ })
+ CurveParamsGostR34102012TC26ParamSetB CurveParams = CurveParams([6][]byte{
+ {0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x6F},
+ {0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x01, 0x49, 0xA1, 0xEC, 0x14, 0x25, 0x65, 0xA5, 0x45,
+ 0xAC, 0xFD, 0xB7, 0x7B, 0xD9, 0xD4, 0x0C, 0xFA, 0x8B, 0x99,
+ 0x67, 0x12, 0x10, 0x1B, 0xEA, 0x0E, 0xC6, 0x34, 0x6C, 0x54,
+ 0x37, 0x4F, 0x25, 0xBD},
+ {0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x6C},
+ {0x68, 0x7D, 0x1B, 0x45, 0x9D, 0xC8, 0x41, 0x45, 0x7E, 0x3E,
+ 0x06, 0xCF, 0x6F, 0x5E, 0x25, 0x17, 0xB9, 0x7C, 0x7D, 0x61,
+ 0x4A, 0xF1, 0x38, 0xBC, 0xBF, 0x85, 0xDC, 0x80, 0x6C, 0x4B,
+ 0x28, 0x9F, 0x3E, 0x96, 0x5D, 0x2D, 0xB1, 0x41, 0x6D, 0x21,
+ 0x7F, 0x8B, 0x27, 0x6F, 0xAD, 0x1A, 0xB6, 0x9C, 0x50, 0xF7,
+ 0x8B, 0xEE, 0x1F, 0xA3, 0x10, 0x6E, 0xFB, 0x8C, 0xCB, 0xC7,
+ 0xC5, 0x14, 0x01, 0x16},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x02},
+ {0x1A, 0x8F, 0x7E, 0xDA, 0x38, 0x9B, 0x09, 0x4C, 0x2C, 0x07,
+ 0x1E, 0x36, 0x47, 0xA8, 0x94, 0x0F, 0x3C, 0x12, 0x3B, 0x69,
+ 0x75, 0x78, 0xC2, 0x13, 0xBE, 0x6D, 0xD9, 0xE6, 0xC8, 0xEC,
+ 0x73, 0x35, 0xDC, 0xB2, 0x28, 0xFD, 0x1E, 0xDF, 0x4A, 0x39,
+ 0x15, 0x2C, 0xBC, 0xAA, 0xF8, 0xC0, 0x39, 0x88, 0x28, 0x04,
+ 0x10, 0x55, 0xF9, 0x4C, 0xEE, 0xEC, 0x7E, 0x21, 0x34, 0x07,
+ 0x80, 0xFE, 0x41, 0xBD},
+ })
+
+ CurveParamsDefault = CurveParamsGostR34102001CryptoProA
+)
+
+func NewCurveFromParams(params CurveParams) (*Curve, error) {
+ return NewCurve(
+ params[0][:],
+ params[1][:],
+ params[2][:],
+ params[3][:],
+ params[4][:],
+ params[5][:],
+ )
+}
--- /dev/null
+// GoGOST -- Pure Go GOST cryptographic functions library
+// Copyright (C) 2015-2016 Sergey Matveev <stargrave@stargrave.org>
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+package gost3410
+
+import (
+ "errors"
+ "io"
+ "math/big"
+)
+
+type PrivateKey struct {
+ c *Curve
+ ds int
+ key *big.Int
+}
+
+func NewPrivateKey(curve *Curve, ds DigestSize, raw []byte) (*PrivateKey, error) {
+ key := make([]byte, len(raw))
+ copy(key, raw)
+ reverse(key)
+ k := bytes2big(key)
+ if k.Cmp(zero) == 0 {
+ return nil, errors.New("zero private key")
+ }
+ return &PrivateKey{curve, int(ds), k}, nil
+}
+
+func GenPrivateKey(curve *Curve, ds DigestSize, rand io.Reader) (*PrivateKey, error) {
+ raw := make([]byte, int(ds))
+ if _, err := io.ReadFull(rand, raw); err != nil {
+ return nil, err
+ }
+ return NewPrivateKey(curve, ds, raw)
+}
+
+func (pk *PrivateKey) Raw() []byte {
+ raw := pad(pk.key.Bytes(), pk.ds)
+ reverse(raw)
+ return raw
+}
+
+func (pk *PrivateKey) PublicKey() (*PublicKey, error) {
+ x, y, err := pk.c.Exp(pk.key, pk.c.Bx, pk.c.By)
+ if err != nil {
+ return nil, err
+ }
+ return &PublicKey{pk.c, pk.ds, x, y}, nil
+}
+
+func (pk *PrivateKey) SignDigest(digest []byte, rand io.Reader) ([]byte, error) {
+ if len(digest) != pk.ds {
+ return nil, errors.New("Invalid input digest length")
+ }
+ e := bytes2big(digest)
+ e.Mod(e, pk.c.Q)
+ if e.Cmp(zero) == 0 {
+ e = big.NewInt(1)
+ }
+ kRaw := make([]byte, pk.ds)
+ var err error
+ var k *big.Int
+ var r *big.Int
+ d := big.NewInt(0)
+ s := big.NewInt(0)
+Retry:
+ if _, err = io.ReadFull(rand, kRaw); err != nil {
+ return nil, err
+ }
+ k = bytes2big(kRaw)
+ k.Mod(k, pk.c.Q)
+ if k.Cmp(zero) == 0 {
+ goto Retry
+ }
+ r, _, err = pk.c.Exp(k, pk.c.Bx, pk.c.By)
+ if err != nil {
+ return nil, err
+ }
+ r.Mod(r, pk.c.Q)
+ if r.Cmp(zero) == 0 {
+ goto Retry
+ }
+ d.Mul(pk.key, r)
+ k.Mul(k, e)
+ s.Add(d, k)
+ s.Mod(s, pk.c.Q)
+ if s.Cmp(zero) == 0 {
+ goto Retry
+ }
+ return append(pad(s.Bytes(), pk.ds), pad(r.Bytes(), pk.ds)...), nil
+}
--- /dev/null
+// GoGOST -- Pure Go GOST cryptographic functions library
+// Copyright (C) 2015-2016 Sergey Matveev <stargrave@stargrave.org>
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+package gost3410
+
+import (
+ "errors"
+ "math/big"
+)
+
+type PublicKey struct {
+ c *Curve
+ ds int
+ x *big.Int
+ y *big.Int
+}
+
+func NewPublicKey(curve *Curve, ds DigestSize, raw []byte) (*PublicKey, error) {
+ if len(raw) != 2*int(ds) {
+ return nil, errors.New("Invalid public key length")
+ }
+ key := make([]byte, 2*int(ds))
+ copy(key, raw)
+ reverse(key)
+ return &PublicKey{
+ curve,
+ int(ds),
+ bytes2big(key[int(ds) : 2*int(ds)]),
+ bytes2big(key[:int(ds)]),
+ }, nil
+}
+
+func (pk *PublicKey) Raw() []byte {
+ raw := append(pad(pk.y.Bytes(), pk.ds), pad(pk.x.Bytes(), pk.ds)...)
+ reverse(raw)
+ return raw
+}
+
+func (pk *PublicKey) VerifyDigest(digest, signature []byte) (bool, error) {
+ if len(digest) != pk.ds {
+ return false, errors.New("Invalid input digest length")
+ }
+ if len(signature) != 2*pk.ds {
+ return false, errors.New("Invalid signature length")
+ }
+ s := bytes2big(signature[:pk.ds])
+ r := bytes2big(signature[pk.ds:])
+ if r.Cmp(zero) <= 0 || r.Cmp(pk.c.Q) >= 0 || s.Cmp(zero) <= 0 || s.Cmp(pk.c.Q) >= 0 {
+ return false, nil
+ }
+ e := bytes2big(digest)
+ e.Mod(e, pk.c.Q)
+ if e.Cmp(zero) == 0 {
+ e = big.NewInt(1)
+ }
+ v := big.NewInt(0)
+ v.ModInverse(e, pk.c.Q)
+ z1 := big.NewInt(0)
+ z2 := big.NewInt(0)
+ z1.Mul(s, v)
+ z1.Mod(z1, pk.c.Q)
+ z2.Mul(r, v)
+ z2.Mod(z2, pk.c.Q)
+ z2.Sub(pk.c.Q, z2)
+ p1x, p1y, err := pk.c.Exp(z1, pk.c.Bx, pk.c.By)
+ if err != nil {
+ return false, err
+ }
+ q1x, q1y, err := pk.c.Exp(z2, pk.x, pk.y)
+ if err != nil {
+ return false, err
+ }
+ lm := big.NewInt(0)
+ lm.Sub(q1x, p1x)
+ if lm.Cmp(zero) < 0 {
+ lm.Add(lm, pk.c.P)
+ }
+ lm.ModInverse(lm, pk.c.P)
+ z1.Sub(q1y, p1y)
+ lm.Mul(lm, z1)
+ lm.Mod(lm, pk.c.P)
+ lm.Mul(lm, lm)
+ lm.Mod(lm, pk.c.P)
+ lm.Sub(lm, p1x)
+ lm.Sub(lm, q1x)
+ lm.Mod(lm, pk.c.P)
+ if lm.Cmp(zero) < 0 {
+ lm.Add(lm, pk.c.P)
+ }
+ lm.Mod(lm, pk.c.Q)
+ return lm.Cmp(r) == 0, nil
+}
--- /dev/null
+// GoGOST -- Pure Go GOST cryptographic functions library
+// Copyright (C) 2015-2016 Sergey Matveev <stargrave@stargrave.org>
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+package gost3410
+
+import (
+ "math/big"
+)
+
+func bytes2big(d []byte) *big.Int {
+ n := big.NewInt(0)
+ n.SetBytes(d)
+ return n
+}
+
+func reverse(d []byte) {
+ for i, j := 0, len(d)-1; i < j; i, j = i+1, j-1 {
+ d[i], d[j] = d[j], d[i]
+ }
+}
+
+func pad(d []byte, size int) []byte {
+ return append(make([]byte, size-len(d)), d...)
+}
--- /dev/null
+// GoGOST -- Pure Go GOST cryptographic functions library
+// Copyright (C) 2015-2016 Sergey Matveev <stargrave@stargrave.org>
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+// Command-line 34.11-2012 hash function.
+package main
+
+import (
+ "encoding/hex"
+ "flag"
+ "fmt"
+ "io"
+ "os"
+
+ "cypherpunks.ru/gogost"
+ "cypherpunks.ru/gogost/gost34112012"
+)
+
+var (
+ digestSize = flag.Int("size", 256, "Digest size (either 256 or 512)")
+ version = flag.Bool("version", false, "Print version information")
+)
+
+func main() {
+ flag.Parse()
+ if *version {
+ fmt.Println(gogost.Version)
+ return
+ }
+ h := gost34112012.New(*digestSize)
+ io.Copy(h, os.Stdin)
+ fmt.Println(hex.EncodeToString(h.Sum(nil)))
+}
--- /dev/null
+// GoGOST -- Pure Go GOST cryptographic functions library
+// Copyright (C) 2015-2016 Sergey Matveev <stargrave@stargrave.org>
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+// GOST R 34.11-2012 hash function.
+// RFC 6986.
+package gost34112012
+
+import (
+ "encoding/binary"
+)
+
+const (
+ BlockSize = 64
+)
+
+var (
+ pi [256]byte = [256]byte{
+ 0xfc, 0xee, 0xdd, 0x11, 0xcf, 0x6e, 0x31, 0x16,
+ 0xfb, 0xc4, 0xfa, 0xda, 0x23, 0xc5, 0x04, 0x4d,
+ 0xe9, 0x77, 0xf0, 0xdb, 0x93, 0x2e, 0x99, 0xba,
+ 0x17, 0x36, 0xf1, 0xbb, 0x14, 0xcd, 0x5f, 0xc1,
+ 0xf9, 0x18, 0x65, 0x5a, 0xe2, 0x5c, 0xef, 0x21,
+ 0x81, 0x1c, 0x3c, 0x42, 0x8b, 0x01, 0x8e, 0x4f,
+ 0x05, 0x84, 0x02, 0xae, 0xe3, 0x6a, 0x8f, 0xa0,
+ 0x06, 0x0b, 0xed, 0x98, 0x7f, 0xd4, 0xd3, 0x1f,
+ 0xeb, 0x34, 0x2c, 0x51, 0xea, 0xc8, 0x48, 0xab,
+ 0xf2, 0x2a, 0x68, 0xa2, 0xfd, 0x3a, 0xce, 0xcc,
+ 0xb5, 0x70, 0x0e, 0x56, 0x08, 0x0c, 0x76, 0x12,
+ 0xbf, 0x72, 0x13, 0x47, 0x9c, 0xb7, 0x5d, 0x87,
+ 0x15, 0xa1, 0x96, 0x29, 0x10, 0x7b, 0x9a, 0xc7,
+ 0xf3, 0x91, 0x78, 0x6f, 0x9d, 0x9e, 0xb2, 0xb1,
+ 0x32, 0x75, 0x19, 0x3d, 0xff, 0x35, 0x8a, 0x7e,
+ 0x6d, 0x54, 0xc6, 0x80, 0xc3, 0xbd, 0x0d, 0x57,
+ 0xdf, 0xf5, 0x24, 0xa9, 0x3e, 0xa8, 0x43, 0xc9,
+ 0xd7, 0x79, 0xd6, 0xf6, 0x7c, 0x22, 0xb9, 0x03,
+ 0xe0, 0x0f, 0xec, 0xde, 0x7a, 0x94, 0xb0, 0xbc,
+ 0xdc, 0xe8, 0x28, 0x50, 0x4e, 0x33, 0x0a, 0x4a,
+ 0xa7, 0x97, 0x60, 0x73, 0x1e, 0x00, 0x62, 0x44,
+ 0x1a, 0xb8, 0x38, 0x82, 0x64, 0x9f, 0x26, 0x41,
+ 0xad, 0x45, 0x46, 0x92, 0x27, 0x5e, 0x55, 0x2f,
+ 0x8c, 0xa3, 0xa5, 0x7d, 0x69, 0xd5, 0x95, 0x3b,
+ 0x07, 0x58, 0xb3, 0x40, 0x86, 0xac, 0x1d, 0xf7,
+ 0x30, 0x37, 0x6b, 0xe4, 0x88, 0xd9, 0xe7, 0x89,
+ 0xe1, 0x1b, 0x83, 0x49, 0x4c, 0x3f, 0xf8, 0xfe,
+ 0x8d, 0x53, 0xaa, 0x90, 0xca, 0xd8, 0x85, 0x61,
+ 0x20, 0x71, 0x67, 0xa4, 0x2d, 0x2b, 0x09, 0x5b,
+ 0xcb, 0x9b, 0x25, 0xd0, 0xbe, 0xe5, 0x6c, 0x52,
+ 0x59, 0xa6, 0x74, 0xd2, 0xe6, 0xf4, 0xb4, 0xc0,
+ 0xd1, 0x66, 0xaf, 0xc2, 0x39, 0x4b, 0x63, 0xb6,
+ }
+ tau [64]int = [64]int{
+ 0x00, 0x08, 0x10, 0x18, 0x20, 0x28, 0x30, 0x38,
+ 0x01, 0x09, 0x11, 0x19, 0x21, 0x29, 0x31, 0x39,
+ 0x02, 0x0a, 0x12, 0x1a, 0x22, 0x2a, 0x32, 0x3a,
+ 0x03, 0x0b, 0x13, 0x1b, 0x23, 0x2b, 0x33, 0x3b,
+ 0x04, 0x0c, 0x14, 0x1c, 0x24, 0x2c, 0x34, 0x3c,
+ 0x05, 0x0d, 0x15, 0x1d, 0x25, 0x2d, 0x35, 0x3d,
+ 0x06, 0x0e, 0x16, 0x1e, 0x26, 0x2e, 0x36, 0x3e,
+ 0x07, 0x0f, 0x17, 0x1f, 0x27, 0x2f, 0x37, 0x3f,
+ }
+ c [12][BlockSize]byte = [12][BlockSize]byte{
+ [BlockSize]byte{
+ 0x07, 0x45, 0xa6, 0xf2, 0x59, 0x65, 0x80, 0xdd,
+ 0x23, 0x4d, 0x74, 0xcc, 0x36, 0x74, 0x76, 0x05,
+ 0x15, 0xd3, 0x60, 0xa4, 0x08, 0x2a, 0x42, 0xa2,
+ 0x01, 0x69, 0x67, 0x92, 0x91, 0xe0, 0x7c, 0x4b,
+ 0xfc, 0xc4, 0x85, 0x75, 0x8d, 0xb8, 0x4e, 0x71,
+ 0x16, 0xd0, 0x45, 0x2e, 0x43, 0x76, 0x6a, 0x2f,
+ 0x1f, 0x7c, 0x65, 0xc0, 0x81, 0x2f, 0xcb, 0xeb,
+ 0xe9, 0xda, 0xca, 0x1e, 0xda, 0x5b, 0x08, 0xb1,
+ },
+ [BlockSize]byte{
+ 0xb7, 0x9b, 0xb1, 0x21, 0x70, 0x04, 0x79, 0xe6,
+ 0x56, 0xcd, 0xcb, 0xd7, 0x1b, 0xa2, 0xdd, 0x55,
+ 0xca, 0xa7, 0x0a, 0xdb, 0xc2, 0x61, 0xb5, 0x5c,
+ 0x58, 0x99, 0xd6, 0x12, 0x6b, 0x17, 0xb5, 0x9a,
+ 0x31, 0x01, 0xb5, 0x16, 0x0f, 0x5e, 0xd5, 0x61,
+ 0x98, 0x2b, 0x23, 0x0a, 0x72, 0xea, 0xfe, 0xf3,
+ 0xd7, 0xb5, 0x70, 0x0f, 0x46, 0x9d, 0xe3, 0x4f,
+ 0x1a, 0x2f, 0x9d, 0xa9, 0x8a, 0xb5, 0xa3, 0x6f,
+ },
+ [BlockSize]byte{
+ 0xb2, 0x0a, 0xba, 0x0a, 0xf5, 0x96, 0x1e, 0x99,
+ 0x31, 0xdb, 0x7a, 0x86, 0x43, 0xf4, 0xb6, 0xc2,
+ 0x09, 0xdb, 0x62, 0x60, 0x37, 0x3a, 0xc9, 0xc1,
+ 0xb1, 0x9e, 0x35, 0x90, 0xe4, 0x0f, 0xe2, 0xd3,
+ 0x7b, 0x7b, 0x29, 0xb1, 0x14, 0x75, 0xea, 0xf2,
+ 0x8b, 0x1f, 0x9c, 0x52, 0x5f, 0x5e, 0xf1, 0x06,
+ 0x35, 0x84, 0x3d, 0x6a, 0x28, 0xfc, 0x39, 0x0a,
+ 0xc7, 0x2f, 0xce, 0x2b, 0xac, 0xdc, 0x74, 0xf5,
+ },
+ [BlockSize]byte{
+ 0x2e, 0xd1, 0xe3, 0x84, 0xbc, 0xbe, 0x0c, 0x22,
+ 0xf1, 0x37, 0xe8, 0x93, 0xa1, 0xea, 0x53, 0x34,
+ 0xbe, 0x03, 0x52, 0x93, 0x33, 0x13, 0xb7, 0xd8,
+ 0x75, 0xd6, 0x03, 0xed, 0x82, 0x2c, 0xd7, 0xa9,
+ 0x3f, 0x35, 0x5e, 0x68, 0xad, 0x1c, 0x72, 0x9d,
+ 0x7d, 0x3c, 0x5c, 0x33, 0x7e, 0x85, 0x8e, 0x48,
+ 0xdd, 0xe4, 0x71, 0x5d, 0xa0, 0xe1, 0x48, 0xf9,
+ 0xd2, 0x66, 0x15, 0xe8, 0xb3, 0xdf, 0x1f, 0xef,
+ },
+ [BlockSize]byte{
+ 0x57, 0xfe, 0x6c, 0x7c, 0xfd, 0x58, 0x17, 0x60,
+ 0xf5, 0x63, 0xea, 0xa9, 0x7e, 0xa2, 0x56, 0x7a,
+ 0x16, 0x1a, 0x27, 0x23, 0xb7, 0x00, 0xff, 0xdf,
+ 0xa3, 0xf5, 0x3a, 0x25, 0x47, 0x17, 0xcd, 0xbf,
+ 0xbd, 0xff, 0x0f, 0x80, 0xd7, 0x35, 0x9e, 0x35,
+ 0x4a, 0x10, 0x86, 0x16, 0x1f, 0x1c, 0x15, 0x7f,
+ 0x63, 0x23, 0xa9, 0x6c, 0x0c, 0x41, 0x3f, 0x9a,
+ 0x99, 0x47, 0x47, 0xad, 0xac, 0x6b, 0xea, 0x4b,
+ },
+ [BlockSize]byte{
+ 0x6e, 0x7d, 0x64, 0x46, 0x7a, 0x40, 0x68, 0xfa,
+ 0x35, 0x4f, 0x90, 0x36, 0x72, 0xc5, 0x71, 0xbf,
+ 0xb6, 0xc6, 0xbe, 0xc2, 0x66, 0x1f, 0xf2, 0x0a,
+ 0xb4, 0xb7, 0x9a, 0x1c, 0xb7, 0xa6, 0xfa, 0xcf,
+ 0xc6, 0x8e, 0xf0, 0x9a, 0xb4, 0x9a, 0x7f, 0x18,
+ 0x6c, 0xa4, 0x42, 0x51, 0xf9, 0xc4, 0x66, 0x2d,
+ 0xc0, 0x39, 0x30, 0x7a, 0x3b, 0xc3, 0xa4, 0x6f,
+ 0xd9, 0xd3, 0x3a, 0x1d, 0xae, 0xae, 0x4f, 0xae,
+ },
+ [BlockSize]byte{
+ 0x93, 0xd4, 0x14, 0x3a, 0x4d, 0x56, 0x86, 0x88,
+ 0xf3, 0x4a, 0x3c, 0xa2, 0x4c, 0x45, 0x17, 0x35,
+ 0x04, 0x05, 0x4a, 0x28, 0x83, 0x69, 0x47, 0x06,
+ 0x37, 0x2c, 0x82, 0x2d, 0xc5, 0xab, 0x92, 0x09,
+ 0xc9, 0x93, 0x7a, 0x19, 0x33, 0x3e, 0x47, 0xd3,
+ 0xc9, 0x87, 0xbf, 0xe6, 0xc7, 0xc6, 0x9e, 0x39,
+ 0x54, 0x09, 0x24, 0xbf, 0xfe, 0x86, 0xac, 0x51,
+ 0xec, 0xc5, 0xaa, 0xee, 0x16, 0x0e, 0xc7, 0xf4,
+ },
+ [BlockSize]byte{
+ 0x1e, 0xe7, 0x02, 0xbf, 0xd4, 0x0d, 0x7f, 0xa4,
+ 0xd9, 0xa8, 0x51, 0x59, 0x35, 0xc2, 0xac, 0x36,
+ 0x2f, 0xc4, 0xa5, 0xd1, 0x2b, 0x8d, 0xd1, 0x69,
+ 0x90, 0x06, 0x9b, 0x92, 0xcb, 0x2b, 0x89, 0xf4,
+ 0x9a, 0xc4, 0xdb, 0x4d, 0x3b, 0x44, 0xb4, 0x89,
+ 0x1e, 0xde, 0x36, 0x9c, 0x71, 0xf8, 0xb7, 0x4e,
+ 0x41, 0x41, 0x6e, 0x0c, 0x02, 0xaa, 0xe7, 0x03,
+ 0xa7, 0xc9, 0x93, 0x4d, 0x42, 0x5b, 0x1f, 0x9b,
+ },
+ [BlockSize]byte{
+ 0xdb, 0x5a, 0x23, 0x83, 0x51, 0x44, 0x61, 0x72,
+ 0x60, 0x2a, 0x1f, 0xcb, 0x92, 0xdc, 0x38, 0x0e,
+ 0x54, 0x9c, 0x07, 0xa6, 0x9a, 0x8a, 0x2b, 0x7b,
+ 0xb1, 0xce, 0xb2, 0xdb, 0x0b, 0x44, 0x0a, 0x80,
+ 0x84, 0x09, 0x0d, 0xe0, 0xb7, 0x55, 0xd9, 0x3c,
+ 0x24, 0x42, 0x89, 0x25, 0x1b, 0x3a, 0x7d, 0x3a,
+ 0xde, 0x5f, 0x16, 0xec, 0xd8, 0x9a, 0x4c, 0x94,
+ 0x9b, 0x22, 0x31, 0x16, 0x54, 0x5a, 0x8f, 0x37,
+ },
+ [BlockSize]byte{
+ 0xed, 0x9c, 0x45, 0x98, 0xfb, 0xc7, 0xb4, 0x74,
+ 0xc3, 0xb6, 0x3b, 0x15, 0xd1, 0xfa, 0x98, 0x36,
+ 0xf4, 0x52, 0x76, 0x3b, 0x30, 0x6c, 0x1e, 0x7a,
+ 0x4b, 0x33, 0x69, 0xaf, 0x02, 0x67, 0xe7, 0x9f,
+ 0x03, 0x61, 0x33, 0x1b, 0x8a, 0xe1, 0xff, 0x1f,
+ 0xdb, 0x78, 0x8a, 0xff, 0x1c, 0xe7, 0x41, 0x89,
+ 0xf3, 0xf3, 0xe4, 0xb2, 0x48, 0xe5, 0x2a, 0x38,
+ 0x52, 0x6f, 0x05, 0x80, 0xa6, 0xde, 0xbe, 0xab,
+ },
+ [BlockSize]byte{
+ 0x1b, 0x2d, 0xf3, 0x81, 0xcd, 0xa4, 0xca, 0x6b,
+ 0x5d, 0xd8, 0x6f, 0xc0, 0x4a, 0x59, 0xa2, 0xde,
+ 0x98, 0x6e, 0x47, 0x7d, 0x1d, 0xcd, 0xba, 0xef,
+ 0xca, 0xb9, 0x48, 0xea, 0xef, 0x71, 0x1d, 0x8a,
+ 0x79, 0x66, 0x84, 0x14, 0x21, 0x80, 0x01, 0x20,
+ 0x61, 0x07, 0xab, 0xeb, 0xbb, 0x6b, 0xfa, 0xd8,
+ 0x94, 0xfe, 0x5a, 0x63, 0xcd, 0xc6, 0x02, 0x30,
+ 0xfb, 0x89, 0xc8, 0xef, 0xd0, 0x9e, 0xcd, 0x7b,
+ },
+ [BlockSize]byte{
+ 0x20, 0xd7, 0x1b, 0xf1, 0x4a, 0x92, 0xbc, 0x48,
+ 0x99, 0x1b, 0xb2, 0xd9, 0xd5, 0x17, 0xf4, 0xfa,
+ 0x52, 0x28, 0xe1, 0x88, 0xaa, 0xa4, 0x1d, 0xe7,
+ 0x86, 0xcc, 0x91, 0x18, 0x9d, 0xef, 0x80, 0x5d,
+ 0x9b, 0x9f, 0x21, 0x30, 0xd4, 0x12, 0x20, 0xf8,
+ 0x77, 0x1d, 0xdf, 0xbc, 0x32, 0x3c, 0xa4, 0xcd,
+ 0x7a, 0xb1, 0x49, 0x04, 0xb0, 0x80, 0x13, 0xd2,
+ 0xba, 0x31, 0x16, 0xf1, 0x67, 0xe7, 0x8e, 0x37,
+ },
+ }
+ a [64]uint64 // It is filled in init()
+)
+
+func init() {
+ as := [64][]byte{
+ []byte{0x8e, 0x20, 0xfa, 0xa7, 0x2b, 0xa0, 0xb4, 0x70},
+ []byte{0x47, 0x10, 0x7d, 0xdd, 0x9b, 0x50, 0x5a, 0x38},
+ []byte{0xad, 0x08, 0xb0, 0xe0, 0xc3, 0x28, 0x2d, 0x1c},
+ []byte{0xd8, 0x04, 0x58, 0x70, 0xef, 0x14, 0x98, 0x0e},
+ []byte{0x6c, 0x02, 0x2c, 0x38, 0xf9, 0x0a, 0x4c, 0x07},
+ []byte{0x36, 0x01, 0x16, 0x1c, 0xf2, 0x05, 0x26, 0x8d},
+ []byte{0x1b, 0x8e, 0x0b, 0x0e, 0x79, 0x8c, 0x13, 0xc8},
+ []byte{0x83, 0x47, 0x8b, 0x07, 0xb2, 0x46, 0x87, 0x64},
+ []byte{0xa0, 0x11, 0xd3, 0x80, 0x81, 0x8e, 0x8f, 0x40},
+ []byte{0x50, 0x86, 0xe7, 0x40, 0xce, 0x47, 0xc9, 0x20},
+ []byte{0x28, 0x43, 0xfd, 0x20, 0x67, 0xad, 0xea, 0x10},
+ []byte{0x14, 0xaf, 0xf0, 0x10, 0xbd, 0xd8, 0x75, 0x08},
+ []byte{0x0a, 0xd9, 0x78, 0x08, 0xd0, 0x6c, 0xb4, 0x04},
+ []byte{0x05, 0xe2, 0x3c, 0x04, 0x68, 0x36, 0x5a, 0x02},
+ []byte{0x8c, 0x71, 0x1e, 0x02, 0x34, 0x1b, 0x2d, 0x01},
+ []byte{0x46, 0xb6, 0x0f, 0x01, 0x1a, 0x83, 0x98, 0x8e},
+ []byte{0x90, 0xda, 0xb5, 0x2a, 0x38, 0x7a, 0xe7, 0x6f},
+ []byte{0x48, 0x6d, 0xd4, 0x15, 0x1c, 0x3d, 0xfd, 0xb9},
+ []byte{0x24, 0xb8, 0x6a, 0x84, 0x0e, 0x90, 0xf0, 0xd2},
+ []byte{0x12, 0x5c, 0x35, 0x42, 0x07, 0x48, 0x78, 0x69},
+ []byte{0x09, 0x2e, 0x94, 0x21, 0x8d, 0x24, 0x3c, 0xba},
+ []byte{0x8a, 0x17, 0x4a, 0x9e, 0xc8, 0x12, 0x1e, 0x5d},
+ []byte{0x45, 0x85, 0x25, 0x4f, 0x64, 0x09, 0x0f, 0xa0},
+ []byte{0xac, 0xcc, 0x9c, 0xa9, 0x32, 0x8a, 0x89, 0x50},
+ []byte{0x9d, 0x4d, 0xf0, 0x5d, 0x5f, 0x66, 0x14, 0x51},
+ []byte{0xc0, 0xa8, 0x78, 0xa0, 0xa1, 0x33, 0x0a, 0xa6},
+ []byte{0x60, 0x54, 0x3c, 0x50, 0xde, 0x97, 0x05, 0x53},
+ []byte{0x30, 0x2a, 0x1e, 0x28, 0x6f, 0xc5, 0x8c, 0xa7},
+ []byte{0x18, 0x15, 0x0f, 0x14, 0xb9, 0xec, 0x46, 0xdd},
+ []byte{0x0c, 0x84, 0x89, 0x0a, 0xd2, 0x76, 0x23, 0xe0},
+ []byte{0x06, 0x42, 0xca, 0x05, 0x69, 0x3b, 0x9f, 0x70},
+ []byte{0x03, 0x21, 0x65, 0x8c, 0xba, 0x93, 0xc1, 0x38},
+ []byte{0x86, 0x27, 0x5d, 0xf0, 0x9c, 0xe8, 0xaa, 0xa8},
+ []byte{0x43, 0x9d, 0xa0, 0x78, 0x4e, 0x74, 0x55, 0x54},
+ []byte{0xaf, 0xc0, 0x50, 0x3c, 0x27, 0x3a, 0xa4, 0x2a},
+ []byte{0xd9, 0x60, 0x28, 0x1e, 0x9d, 0x1d, 0x52, 0x15},
+ []byte{0xe2, 0x30, 0x14, 0x0f, 0xc0, 0x80, 0x29, 0x84},
+ []byte{0x71, 0x18, 0x0a, 0x89, 0x60, 0x40, 0x9a, 0x42},
+ []byte{0xb6, 0x0c, 0x05, 0xca, 0x30, 0x20, 0x4d, 0x21},
+ []byte{0x5b, 0x06, 0x8c, 0x65, 0x18, 0x10, 0xa8, 0x9e},
+ []byte{0x45, 0x6c, 0x34, 0x88, 0x7a, 0x38, 0x05, 0xb9},
+ []byte{0xac, 0x36, 0x1a, 0x44, 0x3d, 0x1c, 0x8c, 0xd2},
+ []byte{0x56, 0x1b, 0x0d, 0x22, 0x90, 0x0e, 0x46, 0x69},
+ []byte{0x2b, 0x83, 0x88, 0x11, 0x48, 0x07, 0x23, 0xba},
+ []byte{0x9b, 0xcf, 0x44, 0x86, 0x24, 0x8d, 0x9f, 0x5d},
+ []byte{0xc3, 0xe9, 0x22, 0x43, 0x12, 0xc8, 0xc1, 0xa0},
+ []byte{0xef, 0xfa, 0x11, 0xaf, 0x09, 0x64, 0xee, 0x50},
+ []byte{0xf9, 0x7d, 0x86, 0xd9, 0x8a, 0x32, 0x77, 0x28},
+ []byte{0xe4, 0xfa, 0x20, 0x54, 0xa8, 0x0b, 0x32, 0x9c},
+ []byte{0x72, 0x7d, 0x10, 0x2a, 0x54, 0x8b, 0x19, 0x4e},
+ []byte{0x39, 0xb0, 0x08, 0x15, 0x2a, 0xcb, 0x82, 0x27},
+ []byte{0x92, 0x58, 0x04, 0x84, 0x15, 0xeb, 0x41, 0x9d},
+ []byte{0x49, 0x2c, 0x02, 0x42, 0x84, 0xfb, 0xae, 0xc0},
+ []byte{0xaa, 0x16, 0x01, 0x21, 0x42, 0xf3, 0x57, 0x60},
+ []byte{0x55, 0x0b, 0x8e, 0x9e, 0x21, 0xf7, 0xa5, 0x30},
+ []byte{0xa4, 0x8b, 0x47, 0x4f, 0x9e, 0xf5, 0xdc, 0x18},
+ []byte{0x70, 0xa6, 0xa5, 0x6e, 0x24, 0x40, 0x59, 0x8e},
+ []byte{0x38, 0x53, 0xdc, 0x37, 0x12, 0x20, 0xa2, 0x47},
+ []byte{0x1c, 0xa7, 0x6e, 0x95, 0x09, 0x10, 0x51, 0xad},
+ []byte{0x0e, 0xdd, 0x37, 0xc4, 0x8a, 0x08, 0xa6, 0xd8},
+ []byte{0x07, 0xe0, 0x95, 0x62, 0x45, 0x04, 0x53, 0x6c},
+ []byte{0x8d, 0x70, 0xc4, 0x31, 0xac, 0x02, 0xa7, 0x36},
+ []byte{0xc8, 0x38, 0x62, 0x96, 0x56, 0x01, 0xdd, 0x1b},
+ []byte{0x64, 0x1c, 0x31, 0x4b, 0x2b, 0x8e, 0xe0, 0x83},
+ }
+ for i := 0; i < 64; i++ {
+ a[i] = binary.BigEndian.Uint64(as[i])
+ }
+}
+
+type Hash struct {
+ size int
+ buf []byte
+ n uint64
+ hsh *[BlockSize]byte
+ chk *[BlockSize]byte
+ tmp *[BlockSize]byte
+}
+
+// Create new hash object with specified size digest size.
+// Size is either 512 or 256 (bits).
+func New(size int) *Hash {
+ if size != 256 && size != 512 {
+ panic("size must be either 256 or 512")
+ }
+ h := Hash{
+ size: size,
+ hsh: new([BlockSize]byte),
+ chk: new([BlockSize]byte),
+ tmp: new([BlockSize]byte),
+ }
+ h.Reset()
+ return &h
+}
+
+func (h *Hash) Reset() {
+ h.n = 0
+ h.buf = nil
+ for i := 0; i < BlockSize; i++ {
+ h.chk[i] = 0
+ if h.size == 256 {
+ h.hsh[i] = 1
+ } else {
+ h.hsh[i] = 0
+ }
+ }
+}
+
+func (h *Hash) BlockSize() int {
+ return BlockSize
+}
+
+func (h *Hash) Size() int {
+ return h.size / 8
+}
+
+func (h *Hash) Write(data []byte) (int, error) {
+ h.buf = append(h.buf, data...)
+ for len(h.buf) >= BlockSize {
+ copy(h.tmp[:], h.buf[:BlockSize])
+ h.hsh = g(h.n, h.hsh, h.tmp)
+ h.chk = add512bit(h.chk, h.tmp)
+ h.n += BlockSize * 8
+ h.buf = h.buf[BlockSize:]
+ }
+ return len(data), nil
+}
+
+func (h *Hash) Sum(in []byte) []byte {
+ buf := new([BlockSize]byte)
+ copy(h.tmp[:], buf[:])
+ copy(buf[:], h.buf[:])
+ buf[len(h.buf)] = 1
+ hsh := g(h.n, h.hsh, buf)
+ binary.LittleEndian.PutUint64(h.tmp[:], h.n+uint64(len(h.buf))*8)
+ hsh = g(0, hsh, h.tmp)
+ hsh = g(0, hsh, add512bit(h.chk, buf))
+ if h.size == 256 {
+ return append(in, hsh[BlockSize/2:]...)
+ }
+ return append(in, hsh[:]...)
+}
+
+func add512bit(chk, data *[BlockSize]byte) *[BlockSize]byte {
+ var ss uint16
+ r := new([BlockSize]byte)
+ for i := 0; i < BlockSize; i++ {
+ ss = uint16(chk[i]) + uint16(data[i]) + (ss >> 8)
+ r[i] = byte(0xFF & ss)
+ }
+ return r
+}
+
+func g(n uint64, hsh, data *[BlockSize]byte) *[BlockSize]byte {
+ ns := make([]byte, 8)
+ binary.LittleEndian.PutUint64(ns, n)
+ r := new([BlockSize]byte)
+ for i := 0; i < 8; i++ {
+ r[i] = hsh[i] ^ ns[i]
+ }
+ copy(r[8:], hsh[8:])
+ return blockXor(blockXor(e(l(ps(r)), data), hsh), data)
+}
+
+func e(k, msg *[BlockSize]byte) *[BlockSize]byte {
+ for i := 0; i < 12; i++ {
+ msg = l(ps(blockXor(k, msg)))
+ k = l(ps(blockXor(k, &c[i])))
+ }
+ return blockXor(k, msg)
+}
+
+func blockXor(x, y *[BlockSize]byte) *[BlockSize]byte {
+ r := new([BlockSize]byte)
+ for i := 0; i < BlockSize; i++ {
+ r[i] = x[i] ^ y[i]
+ }
+ return r
+}
+
+func ps(data *[BlockSize]byte) *[BlockSize]byte {
+ r := new([BlockSize]byte)
+ for i := 0; i < BlockSize; i++ {
+ r[tau[i]] = pi[int(data[i])]
+ }
+ return r
+}
+
+func l(data *[BlockSize]byte) *[BlockSize]byte {
+ var val uint64
+ var res64 uint64
+ var j int
+ r := new([BlockSize]byte)
+ for i := 0; i < 8; i++ {
+ val = binary.LittleEndian.Uint64(data[i*8 : i*8+8])
+ res64 = 0
+ for j = 0; j < BlockSize; j++ {
+ if val&0x8000000000000000 > 0 {
+ res64 ^= a[j]
+ }
+ val <<= 1
+ }
+ binary.LittleEndian.PutUint64(r[i*8:i*8+8], res64)
+ }
+ return r
+}
--- /dev/null
+// GoGOST -- Pure Go GOST cryptographic functions library
+// Copyright (C) 2015-2016 Sergey Matveev <stargrave@stargrave.org>
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+package gost34112012
+
+import (
+ "bytes"
+ "crypto/rand"
+ "hash"
+ "testing"
+ "testing/quick"
+)
+
+func TestHashInterface(t *testing.T) {
+ h := New(512)
+ var _ hash.Hash = h
+}
+
+func TestVectors(t *testing.T) {
+ h512 := New(512)
+ h256 := New(256)
+
+ // First vector
+ m := []byte{
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+ 0x38, 0x39, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35,
+ 0x36, 0x37, 0x38, 0x39, 0x30, 0x31, 0x32, 0x33,
+ 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30, 0x31,
+ 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+ 0x38, 0x39, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35,
+ 0x36, 0x37, 0x38, 0x39, 0x30, 0x31, 0x32,
+ }
+ h512.Write(m)
+ if bytes.Compare(h512.Sum(nil), []byte{
+ 0x1b, 0x54, 0xd0, 0x1a, 0x4a, 0xf5, 0xb9, 0xd5,
+ 0xcc, 0x3d, 0x86, 0xd6, 0x8d, 0x28, 0x54, 0x62,
+ 0xb1, 0x9a, 0xbc, 0x24, 0x75, 0x22, 0x2f, 0x35,
+ 0xc0, 0x85, 0x12, 0x2b, 0xe4, 0xba, 0x1f, 0xfa,
+ 0x00, 0xad, 0x30, 0xf8, 0x76, 0x7b, 0x3a, 0x82,
+ 0x38, 0x4c, 0x65, 0x74, 0xf0, 0x24, 0xc3, 0x11,
+ 0xe2, 0xa4, 0x81, 0x33, 0x2b, 0x08, 0xef, 0x7f,
+ 0x41, 0x79, 0x78, 0x91, 0xc1, 0x64, 0x6f, 0x48,
+ }) != 0 {
+ t.Fail()
+ }
+ h256.Write(m)
+ if bytes.Compare(h256.Sum(nil), []byte{
+ 0x9d, 0x15, 0x1e, 0xef, 0xd8, 0x59, 0x0b, 0x89,
+ 0xda, 0xa6, 0xba, 0x6c, 0xb7, 0x4a, 0xf9, 0x27,
+ 0x5d, 0xd0, 0x51, 0x02, 0x6b, 0xb1, 0x49, 0xa4,
+ 0x52, 0xfd, 0x84, 0xe5, 0xe5, 0x7b, 0x55, 0x00,
+ }) != 0 {
+ t.Fail()
+ }
+
+ // Second vector
+ h512.Reset()
+ h256.Reset()
+ m = []byte{
+ 0xd1, 0xe5, 0x20, 0xe2, 0xe5, 0xf2, 0xf0, 0xe8,
+ 0x2c, 0x20, 0xd1, 0xf2, 0xf0, 0xe8, 0xe1, 0xee,
+ 0xe6, 0xe8, 0x20, 0xe2, 0xed, 0xf3, 0xf6, 0xe8,
+ 0x2c, 0x20, 0xe2, 0xe5, 0xfe, 0xf2, 0xfa, 0x20,
+ 0xf1, 0x20, 0xec, 0xee, 0xf0, 0xff, 0x20, 0xf1,
+ 0xf2, 0xf0, 0xe5, 0xeb, 0xe0, 0xec, 0xe8, 0x20,
+ 0xed, 0xe0, 0x20, 0xf5, 0xf0, 0xe0, 0xe1, 0xf0,
+ 0xfb, 0xff, 0x20, 0xef, 0xeb, 0xfa, 0xea, 0xfb,
+ 0x20, 0xc8, 0xe3, 0xee, 0xf0, 0xe5, 0xe2, 0xfb,
+ }
+ h512.Write(m)
+ if bytes.Compare(h512.Sum(nil), []byte{
+ 0x1e, 0x88, 0xe6, 0x22, 0x26, 0xbf, 0xca, 0x6f,
+ 0x99, 0x94, 0xf1, 0xf2, 0xd5, 0x15, 0x69, 0xe0,
+ 0xda, 0xf8, 0x47, 0x5a, 0x3b, 0x0f, 0xe6, 0x1a,
+ 0x53, 0x00, 0xee, 0xe4, 0x6d, 0x96, 0x13, 0x76,
+ 0x03, 0x5f, 0xe8, 0x35, 0x49, 0xad, 0xa2, 0xb8,
+ 0x62, 0x0f, 0xcd, 0x7c, 0x49, 0x6c, 0xe5, 0xb3,
+ 0x3f, 0x0c, 0xb9, 0xdd, 0xdc, 0x2b, 0x64, 0x60,
+ 0x14, 0x3b, 0x03, 0xda, 0xba, 0xc9, 0xfb, 0x28,
+ }) != 0 {
+ t.Fail()
+ }
+ h256.Write(m)
+ if bytes.Compare(h256.Sum(nil), []byte{
+ 0x9d, 0xd2, 0xfe, 0x4e, 0x90, 0x40, 0x9e, 0x5d,
+ 0xa8, 0x7f, 0x53, 0x97, 0x6d, 0x74, 0x05, 0xb0,
+ 0xc0, 0xca, 0xc6, 0x28, 0xfc, 0x66, 0x9a, 0x74,
+ 0x1d, 0x50, 0x06, 0x3c, 0x55, 0x7e, 0x8f, 0x50,
+ }) != 0 {
+ t.Fail()
+ }
+}
+
+func TestBlocksized(t *testing.T) {
+ h := New(512)
+ m := make([]byte, BlockSize)
+ for i := 0; i < BlockSize; i++ {
+ m[i] = byte(i)
+ }
+ h.Write(m)
+ if bytes.Compare(h.Sum(nil), []byte{
+ 0x2a, 0xe5, 0x81, 0xf1, 0x8a, 0xe8, 0x5e, 0x35,
+ 0x96, 0xc9, 0x36, 0xac, 0xbe, 0xf9, 0x10, 0xf2,
+ 0xed, 0x70, 0xdc, 0xf9, 0x1e, 0xd5, 0xd2, 0x4b,
+ 0x39, 0xa5, 0xaf, 0x65, 0x7b, 0xf8, 0x23, 0x2a,
+ 0x30, 0x3d, 0x68, 0x60, 0x56, 0xc8, 0xc0, 0x0b,
+ 0xf3, 0x0d, 0x42, 0xe1, 0x6c, 0xe2, 0x55, 0x42,
+ 0x6f, 0xa8, 0xa1, 0x55, 0xdc, 0xb3, 0xeb, 0x82,
+ 0x2d, 0x92, 0x58, 0x08, 0xf7, 0xc7, 0xe3, 0x45,
+ }) != 0 {
+ t.Fail()
+ }
+}
+
+func TestBehaviour(t *testing.T) {
+ h := New(512)
+ // Sum does not change the state
+ hsh1 := h.Sum(nil)
+ if bytes.Compare(h.Sum(nil), hsh1) != 0 {
+ t.Fail()
+ }
+ // No data equals to no state changing
+ h.Write([]byte{})
+ if bytes.Compare(h.Sum(nil), hsh1) != 0 {
+ t.Fail()
+ }
+ // Just to be sure
+ h.Write([]byte{})
+ if bytes.Compare(h.Sum(nil), hsh1) != 0 {
+ t.Fail()
+ }
+}
+
+func TestRandom(t *testing.T) {
+ h := New(512)
+ f := func(data []byte) bool {
+ h.Reset()
+ h.Write(data)
+ d1 := h.Sum(nil)
+ h.Reset()
+ for _, c := range data {
+ h.Write([]byte{c})
+ }
+ d2 := h.Sum(nil)
+ return bytes.Compare(d1, d2) == 0
+ }
+ if err := quick.Check(f, nil); err != nil {
+ t.Error(err)
+ }
+}
+
+func BenchmarkHash(b *testing.B) {
+ h := New(512)
+ src := make([]byte, BlockSize+1)
+ rand.Read(src)
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ h.Write(src)
+ h.Sum(nil)
+ }
+}
--- /dev/null
+// GoGOST -- Pure Go GOST cryptographic functions library
+// Copyright (C) 2015-2016 Sergey Matveev <stargrave@stargrave.org>
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+// GOST R 34.11-94 hash function.
+// RFC 5831.
+package gost341194
+
+import (
+ "encoding/binary"
+ "math/big"
+
+ "cypherpunks.ru/gogost/gost28147"
+)
+
+const (
+ BlockSize = 32
+)
+
+var (
+ SboxDefault *gost28147.Sbox = &gost28147.GostR3411_94_TestParamSet
+
+ c2 [BlockSize]byte = [BlockSize]byte{
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ }
+ c3 [BlockSize]byte = [BlockSize]byte{
+ 0xff, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0xff, 0x00, 0xff, 0xff, 0x00,
+ 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,
+ 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
+ }
+ c4 [BlockSize]byte = [BlockSize]byte{
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ }
+
+ big256 *big.Int = big.NewInt(0).SetBit(big.NewInt(0), 256, 1)
+)
+
+type Hash struct {
+ sbox *gost28147.Sbox
+ size uint64
+ hsh [BlockSize]byte
+ chk *big.Int
+ buf []byte
+ tmp [BlockSize]byte
+}
+
+func New(sbox *gost28147.Sbox) *Hash {
+ h := Hash{sbox: sbox}
+ h.Reset()
+ return &h
+}
+
+func (h *Hash) Reset() {
+ h.size = 0
+ h.hsh = [BlockSize]byte{
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ }
+ h.chk = big.NewInt(0)
+ h.buf = nil
+}
+
+func (h *Hash) BlockSize() int {
+ return BlockSize
+}
+
+func (h *Hash) Size() int {
+ return BlockSize
+}
+
+func fA(in *[BlockSize]byte) *[BlockSize]byte {
+ out := new([BlockSize]byte)
+ out[0] = in[16+0] ^ in[24+0]
+ out[1] = in[16+1] ^ in[24+1]
+ out[2] = in[16+2] ^ in[24+2]
+ out[3] = in[16+3] ^ in[24+3]
+ out[4] = in[16+4] ^ in[24+4]
+ out[5] = in[16+5] ^ in[24+5]
+ out[6] = in[16+6] ^ in[24+6]
+ out[7] = in[16+7] ^ in[24+7]
+ copy(out[8:], in[0:24])
+ return out
+}
+
+func fP(in *[BlockSize]byte) *[BlockSize]byte {
+ return &[BlockSize]byte{
+ in[0], in[8], in[16], in[24], in[1], in[9], in[17],
+ in[25], in[2], in[10], in[18], in[26], in[3],
+ in[11], in[19], in[27], in[4], in[12], in[20],
+ in[28], in[5], in[13], in[21], in[29], in[6],
+ in[14], in[22], in[30], in[7], in[15], in[23], in[31],
+ }
+}
+
+func fChi(in *[BlockSize]byte) *[BlockSize]byte {
+ out := new([BlockSize]byte)
+ out[0] = in[32-2] ^ in[32-4] ^ in[32-6] ^ in[32-8] ^ in[32-32] ^ in[32-26]
+ out[1] = in[32-1] ^ in[32-3] ^ in[32-5] ^ in[32-7] ^ in[32-31] ^ in[32-25]
+ copy(out[2:32], in[0:30])
+ return out
+}
+
+func blockReverse(dst, src []byte) {
+ for i, j := 0, BlockSize-1; i < j; i, j = i+1, j-1 {
+ dst[i], dst[j] = src[j], src[i]
+ }
+}
+
+func blockXor(dst, a, b *[BlockSize]byte) {
+ for i := 0; i < BlockSize; i++ {
+ dst[i] = a[i] ^ b[i]
+ }
+ return
+}
+
+func (h *Hash) step(hin, m [BlockSize]byte) [BlockSize]byte {
+ out := new([BlockSize]byte)
+ u := new([BlockSize]byte)
+ v := new([BlockSize]byte)
+ k := new([BlockSize]byte)
+ (*u) = hin
+ (*v) = m
+ blockXor(k, u, v)
+ k = fP(k)
+ blockReverse(k[:], k[:])
+ kk := *k
+ c := gost28147.NewCipher(kk, h.sbox)
+ s := make([]byte, gost28147.BlockSize)
+ c.Encrypt(s, []byte{
+ hin[31], hin[30], hin[29], hin[28], hin[27], hin[26], hin[25], hin[24],
+ })
+ out[31] = s[0]
+ out[30] = s[1]
+ out[29] = s[2]
+ out[28] = s[3]
+ out[27] = s[4]
+ out[26] = s[5]
+ out[25] = s[6]
+ out[24] = s[7]
+
+ blockXor(u, fA(u), &c2)
+ v = fA(fA(v))
+ blockXor(k, u, v)
+ k = fP(k)
+ blockReverse(k[:], k[:])
+ c = gost28147.NewCipher(*k, h.sbox)
+ c.Encrypt(s, []byte{
+ hin[23], hin[22], hin[21], hin[20], hin[19], hin[18], hin[17], hin[16],
+ })
+ out[23] = s[0]
+ out[22] = s[1]
+ out[21] = s[2]
+ out[20] = s[3]
+ out[19] = s[4]
+ out[18] = s[5]
+ out[17] = s[6]
+ out[16] = s[7]
+
+ blockXor(u, fA(u), &c3)
+ v = fA(fA(v))
+ blockXor(k, u, v)
+ k = fP(k)
+ blockReverse(k[:], k[:])
+ c = gost28147.NewCipher(*k, h.sbox)
+ c.Encrypt(s, []byte{
+ hin[15], hin[14], hin[13], hin[12], hin[11], hin[10], hin[9], hin[8],
+ })
+ out[15] = s[0]
+ out[14] = s[1]
+ out[13] = s[2]
+ out[12] = s[3]
+ out[11] = s[4]
+ out[10] = s[5]
+ out[9] = s[6]
+ out[8] = s[7]
+
+ blockXor(u, fA(u), &c4)
+ v = fA(fA(v))
+ blockXor(k, u, v)
+ k = fP(k)
+ blockReverse(k[:], k[:])
+ c = gost28147.NewCipher(*k, h.sbox)
+ c.Encrypt(s, []byte{
+ hin[7], hin[6], hin[5], hin[4], hin[3], hin[2], hin[1], hin[0],
+ })
+ out[7] = s[0]
+ out[6] = s[1]
+ out[5] = s[2]
+ out[4] = s[3]
+ out[3] = s[4]
+ out[2] = s[5]
+ out[1] = s[6]
+ out[0] = s[7]
+
+ for i := 0; i < 12; i++ {
+ out = fChi(out)
+ }
+ blockXor(out, out, &m)
+ out = fChi(out)
+ blockXor(out, out, &hin)
+ for i := 0; i < 61; i++ {
+ out = fChi(out)
+ }
+ return *out
+}
+
+func (h *Hash) chkAdd(data []byte) *big.Int {
+ i := big.NewInt(0).SetBytes(data)
+ i.Add(i, h.chk)
+ if i.Cmp(big256) != -1 {
+ i.Sub(i, big256)
+ }
+ return i
+}
+
+func (h *Hash) Write(data []byte) (int, error) {
+ h.buf = append(h.buf, data...)
+ for len(h.buf) >= BlockSize {
+ h.size += BlockSize * 8
+ blockReverse(h.tmp[:], h.buf[:BlockSize])
+ h.chk = h.chkAdd(h.tmp[:])
+ h.buf = h.buf[BlockSize:]
+ h.hsh = h.step(h.hsh, h.tmp)
+ }
+ return len(data), nil
+}
+
+func (h *Hash) Sum(in []byte) []byte {
+ size := h.size
+ chk := h.chk
+ hsh := h.hsh
+ block := new([BlockSize]byte)
+ if len(h.buf) != 0 {
+ size += uint64(len(h.buf)) * 8
+ copy(block[:], h.buf)
+ blockReverse(block[:], block[:])
+ chk = h.chkAdd(block[:])
+ hsh = h.step(hsh, *block)
+ block = new([BlockSize]byte)
+ }
+ binary.BigEndian.PutUint64(block[24:], size)
+ hsh = h.step(hsh, *block)
+ block = new([BlockSize]byte)
+ chkBytes := chk.Bytes()
+ copy(block[BlockSize-len(chkBytes):], chkBytes)
+ hsh = h.step(hsh, *block)
+ return append(in, hsh[:]...)
+}
--- /dev/null
+// GoGOST -- Pure Go GOST cryptographic functions library
+// Copyright (C) 2015-2016 Sergey Matveev <stargrave@stargrave.org>
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+package gost341194
+
+import (
+ "bytes"
+ "crypto/rand"
+ "hash"
+ "testing"
+ "testing/quick"
+
+ "cypherpunks.ru/gogost/gost28147"
+)
+
+func TestHashInterface(t *testing.T) {
+ h := New(SboxDefault)
+ var _ hash.Hash = h
+}
+
+func TestVectors(t *testing.T) {
+ h := New(SboxDefault)
+
+ if bytes.Compare(h.Sum(nil), []byte{
+ 0x8d, 0x0f, 0x49, 0x49, 0x2c, 0x91, 0xf4, 0x5a,
+ 0x68, 0xff, 0x5c, 0x05, 0xd2, 0xc2, 0xb4, 0xab,
+ 0x78, 0x02, 0x7b, 0x9a, 0xab, 0x5c, 0xe3, 0xfe,
+ 0xff, 0x52, 0x67, 0xc4, 0x9c, 0xb9, 0x85, 0xce,
+ }) != 0 {
+ t.Fail()
+ }
+
+ h.Reset()
+ h.Write([]byte("a"))
+ if bytes.Compare(h.Sum(nil), []byte{
+ 0xdd, 0x14, 0xf3, 0x62, 0xce, 0xfd, 0x49, 0xf8,
+ 0x73, 0xa5, 0xc6, 0x44, 0x43, 0x1b, 0x87, 0x21,
+ 0x9c, 0x34, 0x49, 0x66, 0x1f, 0x80, 0x8a, 0xc8,
+ 0xe9, 0x66, 0x7c, 0x36, 0x9e, 0x53, 0x2c, 0xd4,
+ }) != 0 {
+ t.Fail()
+ }
+
+ h.Reset()
+ h.Write([]byte("abc"))
+ if bytes.Compare(h.Sum(nil), []byte{
+ 0x1d, 0xd5, 0xa4, 0x06, 0x7c, 0x49, 0x70, 0x3b,
+ 0x75, 0xbc, 0x75, 0xc9, 0x29, 0x0f, 0x5e, 0xcb,
+ 0xb5, 0xeb, 0x85, 0x22, 0x9e, 0x72, 0x77, 0xa2,
+ 0xb2, 0xb1, 0x4f, 0xc4, 0x48, 0x43, 0x13, 0xf3,
+ }) != 0 {
+ t.Fail()
+ }
+
+ h.Reset()
+ h.Write([]byte("message digest"))
+ if bytes.Compare(h.Sum(nil), []byte{
+ 0x4d, 0x9a, 0x88, 0xa4, 0x16, 0xde, 0x2f, 0xdb,
+ 0x72, 0xde, 0x48, 0x3f, 0x27, 0x65, 0x2b, 0x58,
+ 0x69, 0x24, 0x3d, 0xec, 0x59, 0xbe, 0x0c, 0xb6,
+ 0x99, 0x2c, 0x8f, 0xb1, 0xec, 0x34, 0x44, 0xad,
+ }) != 0 {
+ t.Fail()
+ }
+
+ h.Reset()
+ for i := 0; i < 128; i++ {
+ h.Write([]byte("U"))
+ }
+ if bytes.Compare(h.Sum(nil), []byte{
+ 0xa4, 0x33, 0x57, 0xfe, 0xe8, 0xa9, 0x26, 0xd9,
+ 0x52, 0x2a, 0x06, 0x87, 0x0a, 0x66, 0x25, 0x1c,
+ 0x55, 0x3e, 0x27, 0x74, 0xa0, 0x85, 0x1d, 0x0c,
+ 0xef, 0x0c, 0x18, 0x25, 0xed, 0xa3, 0xa3, 0x53,
+ }) != 0 {
+ t.Fail()
+ }
+
+ h.Reset()
+ h.Write([]byte("The quick brown fox jumps over the lazy dog"))
+ if bytes.Compare(h.Sum(nil), []byte{
+ 0x94, 0x42, 0x1f, 0x6d, 0x37, 0x0f, 0xa1, 0xd1,
+ 0x6b, 0xa7, 0xac, 0x5e, 0x31, 0x29, 0x65, 0x29,
+ 0xc9, 0x68, 0x04, 0x7d, 0xca, 0x9b, 0xf4, 0x25,
+ 0x8a, 0xc5, 0x9a, 0x0c, 0x41, 0xfa, 0xb7, 0x77,
+ }) != 0 {
+ t.Fail()
+ }
+
+ h.Reset()
+ h.Write([]byte("The quick brown fox jumps over the lazy cog"))
+ if bytes.Compare(h.Sum(nil), []byte{
+ 0x45, 0xc4, 0xee, 0x4e, 0xe1, 0xd2, 0x50, 0x91,
+ 0x31, 0x21, 0x35, 0x54, 0x0d, 0x67, 0x02, 0xe6,
+ 0x67, 0x7f, 0x7a, 0x73, 0xb5, 0xda, 0x31, 0xe1,
+ 0x0b, 0x8b, 0xb7, 0xaa, 0xda, 0xc4, 0xeb, 0xa3,
+ }) != 0 {
+ t.Fail()
+ }
+
+ h.Reset()
+ h.Write([]byte("This is message, length=32 bytes"))
+ if bytes.Compare(h.Sum(nil), []byte{
+ 0xfa, 0xff, 0x37, 0xa6, 0x15, 0xa8, 0x16, 0x69,
+ 0x1c, 0xff, 0x3e, 0xf8, 0xb6, 0x8c, 0xa2, 0x47,
+ 0xe0, 0x95, 0x25, 0xf3, 0x9f, 0x81, 0x19, 0x83,
+ 0x2e, 0xb8, 0x19, 0x75, 0xd3, 0x66, 0xc4, 0xb1,
+ }) != 0 {
+ t.Fail()
+ }
+
+ h.Reset()
+ h.Write([]byte("Suppose the original message has length = 50 bytes"))
+ if bytes.Compare(h.Sum(nil), []byte{
+ 0x08, 0x52, 0xf5, 0x62, 0x3b, 0x89, 0xdd, 0x57,
+ 0xae, 0xb4, 0x78, 0x1f, 0xe5, 0x4d, 0xf1, 0x4e,
+ 0xea, 0xfb, 0xc1, 0x35, 0x06, 0x13, 0x76, 0x3a,
+ 0x0d, 0x77, 0x0a, 0xa6, 0x57, 0xba, 0x1a, 0x47,
+ }) != 0 {
+ t.Fail()
+ }
+}
+
+func TestVectorsCryptoPro(t *testing.T) {
+ h := New(&gost28147.GostR3411_94_CryptoProParamSet)
+
+ if bytes.Compare(h.Sum(nil), []byte{
+ 0xc0, 0x56, 0xd6, 0x4c, 0x23, 0x83, 0xc4, 0x4a,
+ 0x58, 0x13, 0x9c, 0x9b, 0x56, 0x01, 0x11, 0xac,
+ 0x13, 0x3e, 0x43, 0xfb, 0x84, 0x0f, 0x83, 0x87,
+ 0x14, 0x84, 0x0c, 0xa3, 0x3c, 0x5f, 0x1e, 0x98,
+ }) != 0 {
+ t.Fail()
+ }
+
+ h.Reset()
+ h.Write([]byte("a"))
+ if bytes.Compare(h.Sum(nil), []byte{
+ 0x11, 0x30, 0x40, 0x2f, 0xcf, 0xaa, 0xf1, 0xef,
+ 0x3c, 0x13, 0xe3, 0x17, 0x3f, 0x10, 0x5a, 0x71,
+ 0x55, 0x80, 0xf7, 0xc9, 0x79, 0x00, 0xaf, 0x37,
+ 0xbf, 0x83, 0x21, 0x28, 0xdd, 0x52, 0x4c, 0xe7,
+ }) != 0 {
+ t.Fail()
+ }
+
+ h.Reset()
+ h.Write([]byte("abc"))
+ if bytes.Compare(h.Sum(nil), []byte{
+ 0x2c, 0xd4, 0x2f, 0xf9, 0x86, 0x29, 0x3b, 0x16,
+ 0x7e, 0x99, 0x43, 0x81, 0xed, 0x59, 0x74, 0x74,
+ 0x14, 0xdd, 0x24, 0x95, 0x36, 0x77, 0x76, 0x2d,
+ 0x39, 0xd7, 0x18, 0xbf, 0x6d, 0x05, 0x85, 0xb2,
+ }) != 0 {
+ t.Fail()
+ }
+
+ h.Reset()
+ h.Write([]byte("message digest"))
+ if bytes.Compare(h.Sum(nil), []byte{
+ 0xa0, 0x1b, 0x72, 0x29, 0x9b, 0xc3, 0x9a, 0x54,
+ 0x0f, 0xd6, 0x72, 0xa9, 0x9a, 0x72, 0xb4, 0xbd,
+ 0xfe, 0x74, 0x41, 0x73, 0x86, 0x98, 0x6e, 0xfa,
+ 0xeb, 0x01, 0xa4, 0x2a, 0xdd, 0x41, 0x60, 0xbc,
+ }) != 0 {
+ t.Fail()
+ }
+
+ h.Reset()
+ h.Write([]byte("The quick brown fox jumps over the lazy dog"))
+ if bytes.Compare(h.Sum(nil), []byte{
+ 0x76, 0x0a, 0x83, 0x65, 0xd5, 0x70, 0x47, 0x6e,
+ 0x78, 0x72, 0x54, 0x76, 0x1b, 0xe7, 0x65, 0x67,
+ 0x74, 0x02, 0x1b, 0x1f, 0x3d, 0xe5, 0x6f, 0x58,
+ 0x8c, 0x50, 0x1a, 0x36, 0x4a, 0x29, 0x04, 0x90,
+ }) != 0 {
+ t.Fail()
+ }
+
+ h.Reset()
+ h.Write([]byte("This is message, length=32 bytes"))
+ if bytes.Compare(h.Sum(nil), []byte{
+ 0xeb, 0x48, 0xde, 0x3e, 0x89, 0xe7, 0x1b, 0xcb,
+ 0x69, 0x5f, 0xc7, 0x52, 0xd6, 0x17, 0xfa, 0xe7,
+ 0x57, 0xf3, 0x4f, 0xa7, 0x7f, 0xa5, 0x8e, 0xe1,
+ 0x14, 0xc5, 0xbd, 0xb7, 0xf7, 0xc2, 0xef, 0x2c,
+ }) != 0 {
+ t.Fail()
+ }
+
+ h.Reset()
+ h.Write([]byte("Suppose the original message has length = 50 bytes"))
+ if bytes.Compare(h.Sum(nil), []byte{
+ 0x11, 0x50, 0xa6, 0x30, 0x31, 0xdc, 0x61, 0x1a,
+ 0x5f, 0x5e, 0x40, 0xd9, 0x31, 0x53, 0xf7, 0x4e,
+ 0xbd, 0xe8, 0x21, 0x6f, 0x67, 0x92, 0xc2, 0x5a,
+ 0x91, 0xcf, 0xca, 0xbc, 0x5c, 0x0c, 0x73, 0xc3,
+ }) != 0 {
+ t.Fail()
+ }
+
+ h.Reset()
+ for i := 0; i < 128; i++ {
+ h.Write([]byte{'U'})
+ }
+ if bytes.Compare(h.Sum(nil), []byte{
+ 0xe8, 0xc4, 0x49, 0xf6, 0x08, 0x10, 0x4c, 0x51,
+ 0x27, 0x10, 0xcd, 0x37, 0xfd, 0xed, 0x92, 0x0d,
+ 0xf1, 0xe8, 0x6b, 0x21, 0x16, 0x23, 0xfa, 0x27,
+ 0xf4, 0xbb, 0x91, 0x46, 0x61, 0xc7, 0x4a, 0x1c,
+ }) != 0 {
+ t.Fail()
+ }
+}
+
+func TestRandom(t *testing.T) {
+ h := New(SboxDefault)
+ f := func(data []byte) bool {
+ h.Reset()
+ h.Write(data)
+ d1 := h.Sum(nil)
+ h.Reset()
+ for _, c := range data {
+ h.Write([]byte{c})
+ }
+ d2 := h.Sum(nil)
+ return bytes.Compare(d1, d2) == 0
+ }
+ if err := quick.Check(f, nil); err != nil {
+ t.Error(err)
+ }
+}
+
+func BenchmarkHash(b *testing.B) {
+ h := New(SboxDefault)
+ src := make([]byte, BlockSize+1)
+ rand.Read(src)
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ h.Write(src)
+ h.Sum(nil)
+ }
+}
--- /dev/null
+// GoGOST -- Pure Go GOST cryptographic functions library
+// Copyright (C) 2015-2016 Sergey Matveev <stargrave@stargrave.org>
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+// GOST 34.12-2015 128-bit (Кузнечик (Kuznechik)) block cipher.
+package gost3412
+
+const (
+ BlockSize = 16
+ KeySize = 32
+)
+
+var (
+ lc [BlockSize]byte = [BlockSize]byte{
+ 148, 32, 133, 16, 194, 192, 1, 251, 1, 192, 194, 16,
+ 133, 32, 148, 1,
+ }
+ pi [256]byte = [256]byte{
+ 252, 238, 221, 17, 207, 110, 49, 22, 251, 196, 250,
+ 218, 35, 197, 4, 77, 233, 119, 240, 219, 147, 46,
+ 153, 186, 23, 54, 241, 187, 20, 205, 95, 193, 249,
+ 24, 101, 90, 226, 92, 239, 33, 129, 28, 60, 66, 139,
+ 1, 142, 79, 5, 132, 2, 174, 227, 106, 143, 160, 6,
+ 11, 237, 152, 127, 212, 211, 31, 235, 52, 44, 81,
+ 234, 200, 72, 171, 242, 42, 104, 162, 253, 58, 206,
+ 204, 181, 112, 14, 86, 8, 12, 118, 18, 191, 114, 19,
+ 71, 156, 183, 93, 135, 21, 161, 150, 41, 16, 123,
+ 154, 199, 243, 145, 120, 111, 157, 158, 178, 177,
+ 50, 117, 25, 61, 255, 53, 138, 126, 109, 84, 198,
+ 128, 195, 189, 13, 87, 223, 245, 36, 169, 62, 168,
+ 67, 201, 215, 121, 214, 246, 124, 34, 185, 3, 224,
+ 15, 236, 222, 122, 148, 176, 188, 220, 232, 40, 80,
+ 78, 51, 10, 74, 167, 151, 96, 115, 30, 0, 98, 68,
+ 26, 184, 56, 130, 100, 159, 38, 65, 173, 69, 70,
+ 146, 39, 94, 85, 47, 140, 163, 165, 125, 105, 213,
+ 149, 59, 7, 88, 179, 64, 134, 172, 29, 247, 48, 55,
+ 107, 228, 136, 217, 231, 137, 225, 27, 131, 73, 76,
+ 63, 248, 254, 141, 83, 170, 144, 202, 216, 133, 97,
+ 32, 113, 103, 164, 45, 43, 9, 91, 203, 155, 37, 208,
+ 190, 229, 108, 82, 89, 166, 116, 210, 230, 244, 180,
+ 192, 209, 102, 175, 194, 57, 75, 99, 182,
+ }
+ piInv [256]byte
+ cBlk [32]*[BlockSize]byte
+)
+
+func gf(a, b byte) (c byte) {
+ for b > 0 {
+ if b&1 > 0 {
+ c ^= a
+ }
+ if a&0x80 > 0 {
+ a = (a << 1) ^ 0xC3
+ } else {
+ a <<= 1
+ }
+ b >>= 1
+ }
+ return
+}
+
+func l(blk *[BlockSize]byte, rounds int) {
+ var t byte
+ var i int
+ for ; rounds > 0; rounds-- {
+ t = blk[15]
+ for i = 14; i >= 0; i-- {
+ blk[i+1] = blk[i]
+ t ^= gf(blk[i], lc[i])
+ }
+ blk[0] = t
+ }
+}
+
+func lInv(blk *[BlockSize]byte) {
+ var t byte
+ var i int
+ for n := 0; n < BlockSize; n++ {
+ t = blk[0]
+ for i = 0; i < 15; i++ {
+ blk[i] = blk[i+1]
+ t ^= gf(blk[i], lc[i])
+ }
+ blk[15] = t
+ }
+}
+
+func init() {
+ piInvP := new([256]byte)
+ for i := 0; i < 256; i++ {
+ piInvP[int(pi[i])] = byte(i)
+ }
+ piInv = *piInvP
+ CP := new([32]*[BlockSize]byte)
+ for i := 0; i < 32; i++ {
+ CP[i] = new([BlockSize]byte)
+ CP[i][15] = byte(i) + 1
+ l(CP[i], 16)
+ }
+ cBlk = *CP
+}
+
+func s(blk *[BlockSize]byte) {
+ for i := 0; i < BlockSize; i++ {
+ blk[i] = pi[int(blk[i])]
+ }
+}
+
+func xor(dst, src1, src2 *[BlockSize]byte) {
+ for i := 0; i < BlockSize; i++ {
+ dst[i] = src1[i] ^ src2[i]
+ }
+}
+
+type Cipher struct {
+ ks [10]*[BlockSize]byte
+}
+
+func (c *Cipher) BlockSize() int {
+ return BlockSize
+}
+
+func NewCipher(key [KeySize]byte) *Cipher {
+ ks := new([10]*[BlockSize]byte)
+ kr0 := new([BlockSize]byte)
+ kr1 := new([BlockSize]byte)
+ krt := new([BlockSize]byte)
+ copy(kr0[:], key[:BlockSize])
+ copy(kr1[:], key[BlockSize:])
+ ks[0] = new([BlockSize]byte)
+ ks[1] = new([BlockSize]byte)
+ copy(ks[0][:], kr0[:])
+ copy(ks[1][:], kr1[:])
+ for i := 0; i < 4; i++ {
+ for j := 0; j < 8; j++ {
+ xor(krt, kr0, cBlk[8*i+j])
+ s(krt)
+ l(krt, 16)
+ xor(krt, krt, kr1)
+ copy(kr1[:], kr0[:])
+ copy(kr0[:], krt[:])
+ }
+ ks[2+2*i] = new([BlockSize]byte)
+ copy(ks[2+2*i][:], kr0[:])
+ ks[2+2*i+1] = new([BlockSize]byte)
+ copy(ks[2+2*i+1][:], kr1[:])
+ }
+ return &Cipher{*ks}
+}
+
+func (c *Cipher) Encrypt(dst, src []byte) {
+ blk := new([BlockSize]byte)
+ copy(blk[:], src)
+ for i := 0; i < 9; i++ {
+ xor(blk, blk, c.ks[i])
+ s(blk)
+ l(blk, 16)
+ }
+ xor(blk, blk, c.ks[9])
+ copy(dst[:BlockSize], blk[:])
+}
+
+func (c *Cipher) Decrypt(dst, src []byte) {
+ blk := new([BlockSize]byte)
+ copy(blk[:], src)
+ var n int
+ for i := 9; i > 0; i-- {
+ xor(blk, blk, c.ks[i])
+ lInv(blk)
+ for n = 0; n < BlockSize; n++ {
+ blk[n] = piInv[int(blk[n])]
+ }
+ }
+ xor(blk, blk, c.ks[0])
+ copy(dst[:BlockSize], blk[:])
+}
--- /dev/null
+// GoGOST -- Pure Go GOST cryptographic functions library
+// Copyright (C) 2015-2016 Sergey Matveev <stargrave@stargrave.org>
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+package gost3412
+
+import (
+ "bytes"
+ "crypto/cipher"
+ "crypto/rand"
+ "io"
+ "testing"
+ "testing/quick"
+)
+
+var (
+ key [KeySize]byte = [KeySize]byte{
+ 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff,
+ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
+ 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10,
+ 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
+ }
+ pt [BlockSize]byte = [BlockSize]byte{
+ 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x00,
+ 0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88,
+ }
+ ct [BlockSize]byte = [BlockSize]byte{
+ 0x7f, 0x67, 0x9d, 0x90, 0xbe, 0xbc, 0x24, 0x30,
+ 0x5a, 0x46, 0x8d, 0x42, 0xb9, 0xd4, 0xed, 0xcd,
+ }
+)
+
+func TestCipherInterface(t *testing.T) {
+ var key [32]byte
+ var _ cipher.Block = NewCipher(key)
+}
+
+func TestRandom(t *testing.T) {
+ data := make([]byte, BlockSize)
+ f := func(key [KeySize]byte, pt [BlockSize]byte) bool {
+ io.ReadFull(rand.Reader, key[:])
+ c := NewCipher(key)
+ c.Encrypt(data, pt[:])
+ c.Decrypt(data, data)
+ return bytes.Compare(data, pt[:]) == 0
+ }
+ if err := quick.Check(f, nil); err != nil {
+ t.Error(err)
+ }
+}
+
+func BenchmarkEncrypt(b *testing.B) {
+ var key [KeySize]byte
+ io.ReadFull(rand.Reader, key[:])
+ c := NewCipher(key)
+ blk := make([]byte, BlockSize)
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ c.Encrypt(blk, blk)
+ }
+}
+
+func BenchmarkDecrypt(b *testing.B) {
+ var key [KeySize]byte
+ io.ReadFull(rand.Reader, key[:])
+ c := NewCipher(key)
+ blk := make([]byte, BlockSize)
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ c.Decrypt(blk, blk)
+ }
+}
+
+func TestS(t *testing.T) {
+ blk := [BlockSize]byte{
+ 0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88,
+ 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x00,
+ }
+ s(&blk)
+ if bytes.Compare(blk[:], []byte{
+ 0xb6, 0x6c, 0xd8, 0x88, 0x7d, 0x38, 0xe8, 0xd7,
+ 0x77, 0x65, 0xae, 0xea, 0x0c, 0x9a, 0x7e, 0xfc,
+ }) != 0 {
+ t.FailNow()
+ }
+ s(&blk)
+ if bytes.Compare(blk[:], []byte{
+ 0x55, 0x9d, 0x8d, 0xd7, 0xbd, 0x06, 0xcb, 0xfe,
+ 0x7e, 0x7b, 0x26, 0x25, 0x23, 0x28, 0x0d, 0x39,
+ }) != 0 {
+ t.FailNow()
+ }
+ s(&blk)
+ if bytes.Compare(blk[:], []byte{
+ 0x0c, 0x33, 0x22, 0xfe, 0xd5, 0x31, 0xe4, 0x63,
+ 0x0d, 0x80, 0xef, 0x5c, 0x5a, 0x81, 0xc5, 0x0b,
+ }) != 0 {
+ t.FailNow()
+ }
+ s(&blk)
+ if bytes.Compare(blk[:], []byte{
+ 0x23, 0xae, 0x65, 0x63, 0x3f, 0x84, 0x2d, 0x29,
+ 0xc5, 0xdf, 0x52, 0x9c, 0x13, 0xf5, 0xac, 0xda,
+ }) != 0 {
+ t.FailNow()
+ }
+}
+
+func R(blk *[BlockSize]byte) {
+ l(blk, 1)
+}
+
+func TestR(t *testing.T) {
+ blk := [BlockSize]byte{
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
+ }
+ R(&blk)
+ if bytes.Compare(blk[:], []byte{
+ 0x94, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ }) != 0 {
+ t.FailNow()
+ }
+ R(&blk)
+ if bytes.Compare(blk[:], []byte{
+ 0xa5, 0x94, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ }) != 0 {
+ t.FailNow()
+ }
+ R(&blk)
+ if bytes.Compare(blk[:], []byte{
+ 0x64, 0xa5, 0x94, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ }) != 0 {
+ t.FailNow()
+ }
+ R(&blk)
+ if bytes.Compare(blk[:], []byte{
+ 0x0d, 0x64, 0xa5, 0x94, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ }) != 0 {
+ t.FailNow()
+ }
+}
+
+func TestL(t *testing.T) {
+ blk := [BlockSize]byte{
+ 0x64, 0xa5, 0x94, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ }
+ l(&blk, 16)
+ if bytes.Compare(blk[:], []byte{
+ 0xd4, 0x56, 0x58, 0x4d, 0xd0, 0xe3, 0xe8, 0x4c,
+ 0xc3, 0x16, 0x6e, 0x4b, 0x7f, 0xa2, 0x89, 0x0d,
+ }) != 0 {
+ t.FailNow()
+ }
+ l(&blk, 16)
+ if bytes.Compare(blk[:], []byte{
+ 0x79, 0xd2, 0x62, 0x21, 0xb8, 0x7b, 0x58, 0x4c,
+ 0xd4, 0x2f, 0xbc, 0x4f, 0xfe, 0xa5, 0xde, 0x9a,
+ }) != 0 {
+ t.FailNow()
+ }
+ l(&blk, 16)
+ if bytes.Compare(blk[:], []byte{
+ 0x0e, 0x93, 0x69, 0x1a, 0x0c, 0xfc, 0x60, 0x40,
+ 0x8b, 0x7b, 0x68, 0xf6, 0x6b, 0x51, 0x3c, 0x13,
+ }) != 0 {
+ t.FailNow()
+ }
+ l(&blk, 16)
+ if bytes.Compare(blk[:], []byte{
+ 0xe6, 0xa8, 0x09, 0x4f, 0xee, 0x0a, 0xa2, 0x04,
+ 0xfd, 0x97, 0xbc, 0xb0, 0xb4, 0x4b, 0x85, 0x80,
+ }) != 0 {
+ t.FailNow()
+ }
+}
+
+func TestC(t *testing.T) {
+ if bytes.Compare(cBlk[0][:], []byte{
+ 0x6e, 0xa2, 0x76, 0x72, 0x6c, 0x48, 0x7a, 0xb8,
+ 0x5d, 0x27, 0xbd, 0x10, 0xdd, 0x84, 0x94, 0x01,
+ }) != 0 {
+ t.FailNow()
+ }
+ if bytes.Compare(cBlk[1][:], []byte{
+ 0xdc, 0x87, 0xec, 0xe4, 0xd8, 0x90, 0xf4, 0xb3,
+ 0xba, 0x4e, 0xb9, 0x20, 0x79, 0xcb, 0xeb, 0x02,
+ }) != 0 {
+ t.FailNow()
+ }
+ if bytes.Compare(cBlk[2][:], []byte{
+ 0xb2, 0x25, 0x9a, 0x96, 0xb4, 0xd8, 0x8e, 0x0b,
+ 0xe7, 0x69, 0x04, 0x30, 0xa4, 0x4f, 0x7f, 0x03,
+ }) != 0 {
+ t.FailNow()
+ }
+ if bytes.Compare(cBlk[3][:], []byte{
+ 0x7b, 0xcd, 0x1b, 0x0b, 0x73, 0xe3, 0x2b, 0xa5,
+ 0xb7, 0x9c, 0xb1, 0x40, 0xf2, 0x55, 0x15, 0x04,
+ }) != 0 {
+ t.FailNow()
+ }
+ if bytes.Compare(cBlk[4][:], []byte{
+ 0x15, 0x6f, 0x6d, 0x79, 0x1f, 0xab, 0x51, 0x1d,
+ 0xea, 0xbb, 0x0c, 0x50, 0x2f, 0xd1, 0x81, 0x05,
+ }) != 0 {
+ t.FailNow()
+ }
+ if bytes.Compare(cBlk[5][:], []byte{
+ 0xa7, 0x4a, 0xf7, 0xef, 0xab, 0x73, 0xdf, 0x16,
+ 0x0d, 0xd2, 0x08, 0x60, 0x8b, 0x9e, 0xfe, 0x06,
+ }) != 0 {
+ t.FailNow()
+ }
+ if bytes.Compare(cBlk[6][:], []byte{
+ 0xc9, 0xe8, 0x81, 0x9d, 0xc7, 0x3b, 0xa5, 0xae,
+ 0x50, 0xf5, 0xb5, 0x70, 0x56, 0x1a, 0x6a, 0x07,
+ }) != 0 {
+ t.FailNow()
+ }
+ if bytes.Compare(cBlk[7][:], []byte{
+ 0xf6, 0x59, 0x36, 0x16, 0xe6, 0x05, 0x56, 0x89,
+ 0xad, 0xfb, 0xa1, 0x80, 0x27, 0xaa, 0x2a, 0x08,
+ }) != 0 {
+ t.FailNow()
+ }
+}
+
+func TestRoundKeys(t *testing.T) {
+ c := NewCipher(key)
+ if bytes.Compare(c.ks[0][:], []byte{
+ 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff,
+ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
+ }) != 0 {
+ t.FailNow()
+ }
+ if bytes.Compare(c.ks[1][:], []byte{
+ 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10,
+ 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
+ }) != 0 {
+ t.FailNow()
+ }
+ if bytes.Compare(c.ks[2][:], []byte{
+ 0xdb, 0x31, 0x48, 0x53, 0x15, 0x69, 0x43, 0x43,
+ 0x22, 0x8d, 0x6a, 0xef, 0x8c, 0xc7, 0x8c, 0x44,
+ }) != 0 {
+ t.FailNow()
+ }
+ if bytes.Compare(c.ks[3][:], []byte{
+ 0x3d, 0x45, 0x53, 0xd8, 0xe9, 0xcf, 0xec, 0x68,
+ 0x15, 0xeb, 0xad, 0xc4, 0x0a, 0x9f, 0xfd, 0x04,
+ }) != 0 {
+ t.FailNow()
+ }
+ if bytes.Compare(c.ks[4][:], []byte{
+ 0x57, 0x64, 0x64, 0x68, 0xc4, 0x4a, 0x5e, 0x28,
+ 0xd3, 0xe5, 0x92, 0x46, 0xf4, 0x29, 0xf1, 0xac,
+ }) != 0 {
+ t.FailNow()
+ }
+ if bytes.Compare(c.ks[5][:], []byte{
+ 0xbd, 0x07, 0x94, 0x35, 0x16, 0x5c, 0x64, 0x32,
+ 0xb5, 0x32, 0xe8, 0x28, 0x34, 0xda, 0x58, 0x1b,
+ }) != 0 {
+ t.FailNow()
+ }
+ if bytes.Compare(c.ks[6][:], []byte{
+ 0x51, 0xe6, 0x40, 0x75, 0x7e, 0x87, 0x45, 0xde,
+ 0x70, 0x57, 0x27, 0x26, 0x5a, 0x00, 0x98, 0xb1,
+ }) != 0 {
+ t.FailNow()
+ }
+ if bytes.Compare(c.ks[7][:], []byte{
+ 0x5a, 0x79, 0x25, 0x01, 0x7b, 0x9f, 0xdd, 0x3e,
+ 0xd7, 0x2a, 0x91, 0xa2, 0x22, 0x86, 0xf9, 0x84,
+ }) != 0 {
+ t.FailNow()
+ }
+ if bytes.Compare(c.ks[8][:], []byte{
+ 0xbb, 0x44, 0xe2, 0x53, 0x78, 0xc7, 0x31, 0x23,
+ 0xa5, 0xf3, 0x2f, 0x73, 0xcd, 0xb6, 0xe5, 0x17,
+ }) != 0 {
+ t.FailNow()
+ }
+ if bytes.Compare(c.ks[9][:], []byte{
+ 0x72, 0xe9, 0xdd, 0x74, 0x16, 0xbc, 0xf4, 0x5b,
+ 0x75, 0x5d, 0xba, 0xa8, 0x8e, 0x4a, 0x40, 0x43,
+ }) != 0 {
+ t.FailNow()
+ }
+}
+
+func TestVectorEncrypt(t *testing.T) {
+ c := NewCipher(key)
+ dst := make([]byte, BlockSize)
+ c.Encrypt(dst, pt[:])
+ if bytes.Compare(dst, ct[:]) != 0 {
+ t.FailNow()
+ }
+}
+
+func TestVectorDecrypt(t *testing.T) {
+ c := NewCipher(key)
+ dst := make([]byte, BlockSize)
+ c.Decrypt(dst, ct[:])
+ if bytes.Compare(dst, pt[:]) != 0 {
+ t.FailNow()
+ }
+}
--- /dev/null
+// GoGOST -- Pure Go GOST cryptographic functions library
+// Copyright (C) 2015-2016 Sergey Matveev <stargrave@stargrave.org>
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+// GOST R 34.13-2015 padding methods.
+package gost3413
+
+func PadSize(dataSize, blockSize int) int {
+ if dataSize < blockSize {
+ return blockSize - dataSize
+ }
+ if dataSize%blockSize == 0 {
+ return 0
+ }
+ return blockSize - dataSize%blockSize
+}
+
+func Pad1(data []byte, blockSize int) []byte {
+ padSize := PadSize(len(data), blockSize)
+ if padSize == 0 {
+ return data
+ }
+ return append(data, make([]byte, padSize)...)
+}
+
+func Pad2(data []byte, blockSize int) []byte {
+ pad := make([]byte, 1+PadSize(len(data)+1, blockSize))
+ pad[0] = byte(0x80)
+ return append(data, pad...)
+}
+
+func Pad3(data []byte, blockSize int) []byte {
+ if PadSize(len(data), blockSize) == 0 {
+ return data
+ }
+ return Pad2(data, blockSize)
+}
--- /dev/null
+all: gogost.html
+
+MAKEINFO ?= makeinfo
+
+gogost.html: www.texi
+ rm -f gogost.html/*.html
+ $(MAKEINFO) --html \
+ --set-customization-variable NO_CSS=1 \
+ --set-customization-variable SHOW_TITLE=0 \
+ --set-customization-variable DATE_IN_HEADER=1 \
+ --set-customization-variable TOP_NODE_UP_URL=index.html \
+ -o gogost.html www.texi
--- /dev/null
+\input texinfo
+@documentencoding UTF-8
+@settitle GoGOST
+
+@copying
+Copyright @copyright{} 2015-2016 @email{stargrave@@stargrave.org, Sergey Matveev}
+@end copying
+
+@node Top
+@top GoGOST
+
+Pure Go GOST cryptographic functions library.
+GOST is GOvernment STandard of Russian Federation (and Soviet Union).
+It is
+@url{https://www.gnu.org/philosophy/pragmatic.html, copylefted}
+@url{https://www.gnu.org/philosophy/free-sw.html, free software}:
+licenced under @url{https://www.gnu.org/licenses/gpl-3.0.html, GPLv3+}.
+
+Currently supported algorithms are:
+
+@itemize
+@item GOST 28147-89 (@url{https://tools.ietf.org/html/rfc5830.html, RFC 5830})
+ block cipher with ECB, CNT (CTR), CFB, MAC,
+ CBC (@url{https://tools.ietf.org/html/rfc4357.html, RFC 4357})
+ modes of operation
+@item various 28147-89-related S-boxes included
+@item GOST R 34.11-94 hash function
+ (@url{https://tools.ietf.org/html/rfc5831.html, RFC 5831})
+@item GOST R 34.11-2012 Стрибог (Streebog) hash function
+ (@url{https://tools.ietf.org/html/rfc6986.html, RFC 6986})
+@item GOST R 34.10-2001
+ (@url{https://tools.ietf.org/html/rfc5832.html, RFC 5832})
+ public key signature function
+@item GOST R 34.10-2012
+ (@url{https://tools.ietf.org/html/rfc7091.html, RFC 7091})
+ public key signature function
+@item various 34.10 curve parameters included
+@item GOST R 34.12-2015 128-bit block cipher Кузнечик (Kuznechik)
+ (@url{https://tools.ietf.org/html/rfc7801.html, RFC 7801})
+@item GOST R 34.13-2015 padding methods
+@end itemize
+
+Please send questions, bug reports and patches to
+@url{https://lists.cypherpunks.ru/mailman/listinfo/gost, gost}
+mailing list. Announcements also go to this mailing list.
+
+@insertcopying
+
+@node Download
+@unnumbered Download
+
+Preferable way is to download tarball with the signature from
+website and, for example, run tests with benchmarks:
+
+@verbatim
+% wget http://www.cypherpunks.ru/gogost/gogost-1.1.tar.xz
+% wget http://www.cypherpunks.ru/gogost/gogost-1.1.tar.xz.sig
+% gpg --verify gogost-1.1.tar.xz.sig gogost-1.1.tar.xz
+% xz -d < gogost-1.1.tar.gz | tar xf -
+% make -C gogost-1.1 bench
+@end verbatim
+
+@multitable {XXXXX} {XXXX KiB} {link sign} {xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx} {xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx}
+@headitem Version @tab Size @tab Tarball @tab SHA256 checksum @tab Streebog-256 checksum
+
+@item 1.1 @tab 33 KiB
+@tab @url{gogost-1.1.tar.xz, link} @url{gogost-1.1.tar.xz.sig, sign}
+@tab @code{26D37912 6FE220C1 C0381835 DEFFDC4B BDCDC394 15D6E9C1 F8A5A302 04F9452B}
+@tab @code{313fa58c2c030dd5acd20b524842bd2d4ec7403fcfca2a4a238ddc187c3ef0df}
+
+@end multitable
+
+You @strong{have to} verify downloaded tarballs integrity and
+authenticity to be sure that you retrieved trusted and untampered
+software. @url{https://www.gnupg.org/, The GNU Privacy Guard} is used
+for that purpose.
+
+For the very first time it it necessary to get signing public key and
+import it. It is provided below, but you should check alternative
+resources.
+
+@verbatim
+pub rsa2048/0x82343436696FC85A 2016-09-13 [SC]
+ CEBD 1282 2C46 9C02 A81A 0467 8234 3436 696F C85A
+uid GoGOST releases <gogost at cypherpunks dot ru>
+@end verbatim
+
+@itemize
+
+@item @url{https://lists.cypherpunks.ru/mailman/listinfo/gost, gost} maillist
+
+@item
+@verbatim
+% gpg --keyserver hkp://keys.gnupg.net/ --recv-keys 0x82343436696FC85A
+% gpg --auto-key-locate dane --locate-keys gogost at cypherpunks dot ru
+% gpg --auto-key-locate wkd --locate-keys gogost at cypherpunks dot ru
+% gpg --auto-key-locate pka --locate-keys gogost at cypherpunks dot ru
+@end verbatim
+
+@item
+@verbatiminclude PUBKEY.asc
+
+@end itemize
+
+You can obtain development source code by cloning
+@url{http://git-scm.com/, Git}
+@url{https://git.cypherpunks.ru/cgit.cgi/gogost.git/, repository}.
+
+@bye