]> Cypherpunks.ru repositories - gogost.git/commitdiff
1.1 release is ready
authorSergey Matveev <stargrave@stargrave.org>
Tue, 4 Oct 2016 18:39:47 +0000 (21:39 +0300)
committerSergey Matveev <stargrave@stargrave.org>
Tue, 4 Oct 2016 18:46:53 +0000 (21:46 +0300)
43 files changed:
AUTHORS [new file with mode: 0644]
BSDmakefile [new file with mode: 0644]
COPYING [new file with mode: 0644]
GNUmakefile [new file with mode: 0644]
INSTALL [new file with mode: 0644]
NEWS [new file with mode: 0644]
PUBKEY.asc [new file with mode: 0644]
README [new file with mode: 0644]
TODO [new file with mode: 0644]
VERSION [new file with mode: 0644]
common.mk [new file with mode: 0644]
makedist.sh [new file with mode: 0755]
src/cypherpunks.ru/gogost/gogost.go [new file with mode: 0644]
src/cypherpunks.ru/gogost/gost28147/cbc_test.go [new file with mode: 0644]
src/cypherpunks.ru/gogost/gost28147/cfb.go [new file with mode: 0644]
src/cypherpunks.ru/gogost/gost28147/cfb_test.go [new file with mode: 0644]
src/cypherpunks.ru/gogost/gost28147/cipher.go [new file with mode: 0644]
src/cypherpunks.ru/gogost/gost28147/cipher_test.go [new file with mode: 0644]
src/cypherpunks.ru/gogost/gost28147/ctr.go [new file with mode: 0644]
src/cypherpunks.ru/gogost/gost28147/ctr_test.go [new file with mode: 0644]
src/cypherpunks.ru/gogost/gost28147/ecb.go [new file with mode: 0644]
src/cypherpunks.ru/gogost/gost28147/ecb_test.go [new file with mode: 0644]
src/cypherpunks.ru/gogost/gost28147/mac.go [new file with mode: 0644]
src/cypherpunks.ru/gogost/gost28147/mac_test.go [new file with mode: 0644]
src/cypherpunks.ru/gogost/gost28147/sbox.go [new file with mode: 0644]
src/cypherpunks.ru/gogost/gost3410/2001_test.go [new file with mode: 0644]
src/cypherpunks.ru/gogost/gost3410/2012_test.go [new file with mode: 0644]
src/cypherpunks.ru/gogost/gost3410/curve.go [new file with mode: 0644]
src/cypherpunks.ru/gogost/gost3410/doc.go [new file with mode: 0644]
src/cypherpunks.ru/gogost/gost3410/params.go [new file with mode: 0644]
src/cypherpunks.ru/gogost/gost3410/private.go [new file with mode: 0644]
src/cypherpunks.ru/gogost/gost3410/public.go [new file with mode: 0644]
src/cypherpunks.ru/gogost/gost3410/utils.go [new file with mode: 0644]
src/cypherpunks.ru/gogost/gost34112012/cmd/gogost-streebog/main.go [new file with mode: 0644]
src/cypherpunks.ru/gogost/gost34112012/hash.go [new file with mode: 0644]
src/cypherpunks.ru/gogost/gost34112012/hash_test.go [new file with mode: 0644]
src/cypherpunks.ru/gogost/gost341194/hash.go [new file with mode: 0644]
src/cypherpunks.ru/gogost/gost341194/hash_test.go [new file with mode: 0644]
src/cypherpunks.ru/gogost/gost3412/cipher.go [new file with mode: 0644]
src/cypherpunks.ru/gogost/gost3412/cipher_test.go [new file with mode: 0644]
src/cypherpunks.ru/gogost/gost3413/padding.go [new file with mode: 0644]
www.mk [new file with mode: 0644]
www.texi [new file with mode: 0644]

diff --git a/AUTHORS b/AUTHORS
new file mode 100644 (file)
index 0000000..f047789
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1 @@
+* Sergey Matveev <stargrave@stargrave.org>
diff --git a/BSDmakefile b/BSDmakefile
new file mode 100644 (file)
index 0000000..b57abb4
--- /dev/null
@@ -0,0 +1,4 @@
+GOPATH != pwd
+VERSION != cat VERSION
+
+include common.mk
diff --git a/COPYING b/COPYING
new file mode 100644 (file)
index 0000000..9a2708d
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,674 @@
+                   GNU GENERAL PUBLIC LICENSE
+                      Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                           Preamble
+
+  The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+  The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works.  By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.  We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors.  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+  To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights.  Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received.  You must make sure that they, too, receive
+or can get the source code.  And you must show them these terms so they
+know their rights.
+
+  Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+  For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software.  For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+  Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so.  This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software.  The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable.  Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products.  If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+  Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary.  To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                      TERMS AND CONDITIONS
+
+  0. Definitions.
+
+  "This License" refers to version 3 of the GNU General Public License.
+
+  "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+  "The Program" refers to any copyrightable work licensed under this
+License.  Each licensee is addressed as "you".  "Licensees" and
+"recipients" may be individuals or organizations.
+
+  To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy.  The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+  A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+  To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy.  Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+  To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies.  Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+  An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License.  If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+  1. Source Code.
+
+  The "source code" for a work means the preferred form of the work
+for making modifications to it.  "Object code" means any non-source
+form of a work.
+
+  A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+  The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form.  A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+  The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities.  However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work.  For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+  The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+  The Corresponding Source for a work in source code form is that
+same work.
+
+  2. Basic Permissions.
+
+  All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met.  This License explicitly affirms your unlimited
+permission to run the unmodified Program.  The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work.  This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+  You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force.  You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright.  Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+  Conveying under any other circumstances is permitted solely under
+the conditions stated below.  Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+  3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+  No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+  When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+  4. Conveying Verbatim Copies.
+
+  You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+  You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+  5. Conveying Modified Source Versions.
+
+  You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+    a) The work must carry prominent notices stating that you modified
+    it, and giving a relevant date.
+
+    b) The work must carry prominent notices stating that it is
+    released under this License and any conditions added under section
+    7.  This requirement modifies the requirement in section 4 to
+    "keep intact all notices".
+
+    c) You must license the entire work, as a whole, under this
+    License to anyone who comes into possession of a copy.  This
+    License will therefore apply, along with any applicable section 7
+    additional terms, to the whole of the work, and all its parts,
+    regardless of how they are packaged.  This License gives no
+    permission to license the work in any other way, but it does not
+    invalidate such permission if you have separately received it.
+
+    d) If the work has interactive user interfaces, each must display
+    Appropriate Legal Notices; however, if the Program has interactive
+    interfaces that do not display Appropriate Legal Notices, your
+    work need not make them do so.
+
+  A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit.  Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+  6. Conveying Non-Source Forms.
+
+  You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+    a) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by the
+    Corresponding Source fixed on a durable physical medium
+    customarily used for software interchange.
+
+    b) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by a
+    written offer, valid for at least three years and valid for as
+    long as you offer spare parts or customer support for that product
+    model, to give anyone who possesses the object code either (1) a
+    copy of the Corresponding Source for all the software in the
+    product that is covered by this License, on a durable physical
+    medium customarily used for software interchange, for a price no
+    more than your reasonable cost of physically performing this
+    conveying of source, or (2) access to copy the
+    Corresponding Source from a network server at no charge.
+
+    c) Convey individual copies of the object code with a copy of the
+    written offer to provide the Corresponding Source.  This
+    alternative is allowed only occasionally and noncommercially, and
+    only if you received the object code with such an offer, in accord
+    with subsection 6b.
+
+    d) Convey the object code by offering access from a designated
+    place (gratis or for a charge), and offer equivalent access to the
+    Corresponding Source in the same way through the same place at no
+    further charge.  You need not require recipients to copy the
+    Corresponding Source along with the object code.  If the place to
+    copy the object code is a network server, the Corresponding Source
+    may be on a different server (operated by you or a third party)
+    that supports equivalent copying facilities, provided you maintain
+    clear directions next to the object code saying where to find the
+    Corresponding Source.  Regardless of what server hosts the
+    Corresponding Source, you remain obligated to ensure that it is
+    available for as long as needed to satisfy these requirements.
+
+    e) Convey the object code using peer-to-peer transmission, provided
+    you inform other peers where the object code and Corresponding
+    Source of the work are being offered to the general public at no
+    charge under subsection 6d.
+
+  A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+  A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling.  In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage.  For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product.  A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+  "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source.  The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+  If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information.  But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+  The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed.  Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+  Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+  7. Additional Terms.
+
+  "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law.  If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+  When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it.  (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.)  You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+  Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+    a) Disclaiming warranty or limiting liability differently from the
+    terms of sections 15 and 16 of this License; or
+
+    b) Requiring preservation of specified reasonable legal notices or
+    author attributions in that material or in the Appropriate Legal
+    Notices displayed by works containing it; or
+
+    c) Prohibiting misrepresentation of the origin of that material, or
+    requiring that modified versions of such material be marked in
+    reasonable ways as different from the original version; or
+
+    d) Limiting the use for publicity purposes of names of licensors or
+    authors of the material; or
+
+    e) Declining to grant rights under trademark law for use of some
+    trade names, trademarks, or service marks; or
+
+    f) Requiring indemnification of licensors and authors of that
+    material by anyone who conveys the material (or modified versions of
+    it) with contractual assumptions of liability to the recipient, for
+    any liability that these contractual assumptions directly impose on
+    those licensors and authors.
+
+  All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10.  If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term.  If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+  If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+  Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+  8. Termination.
+
+  You may not propagate or modify a covered work except as expressly
+provided under this License.  Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+  However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+  Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+  Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License.  If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+  9. Acceptance Not Required for Having Copies.
+
+  You are not required to accept this License in order to receive or
+run a copy of the Program.  Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance.  However,
+nothing other than this License grants you permission to propagate or
+modify any covered work.  These actions infringe copyright if you do
+not accept this License.  Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+  10. Automatic Licensing of Downstream Recipients.
+
+  Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License.  You are not responsible
+for enforcing compliance by third parties with this License.
+
+  An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations.  If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+  You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License.  For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+  11. Patents.
+
+  A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based.  The
+work thus licensed is called the contributor's "contributor version".
+
+  A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version.  For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+  Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+  In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement).  To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+  If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients.  "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+  
+  If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+  A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License.  You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+  Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+  12. No Surrender of Others' Freedom.
+
+  If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all.  For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+  13. Use with the GNU Affero General Public License.
+
+  Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work.  The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+  14. Revised Versions of this License.
+
+  The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+  Each version is given a distinguishing version number.  If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation.  If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+  If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+  Later license versions may give you additional or different
+permissions.  However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+  15. Disclaimer of Warranty.
+
+  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. Limitation of Liability.
+
+  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+  17. Interpretation of Sections 15 and 16.
+
+  If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+                    END OF TERMS AND CONDITIONS
+
+           How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+  If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+    <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>.
diff --git a/GNUmakefile b/GNUmakefile
new file mode 100644 (file)
index 0000000..79efdfc
--- /dev/null
@@ -0,0 +1,4 @@
+GOPATH = $(shell pwd)
+VERSION = $(shell cat VERSION)
+
+include common.mk
diff --git a/INSTALL b/INSTALL
new file mode 100644 (file)
index 0000000..5f1d926
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,26 @@
+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
diff --git a/NEWS b/NEWS
new file mode 100644 (file)
index 0000000..046a3b9
--- /dev/null
+++ b/NEWS
@@ -0,0 +1,7 @@
+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
diff --git a/PUBKEY.asc b/PUBKEY.asc
new file mode 100644 (file)
index 0000000..9776b52
--- /dev/null
@@ -0,0 +1,20 @@
+-----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-----
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..4890f7a
--- /dev/null
+++ b/README
@@ -0,0 +1,28 @@
+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/
diff --git a/TODO b/TODO
new file mode 100644 (file)
index 0000000..0e2d7f7
--- /dev/null
+++ b/TODO
@@ -0,0 +1,3 @@
+* 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)
diff --git a/VERSION b/VERSION
new file mode 100644 (file)
index 0000000..9459d4b
--- /dev/null
+++ b/VERSION
@@ -0,0 +1 @@
+1.1
diff --git a/common.mk b/common.mk
new file mode 100644 (file)
index 0000000..5d59e85
--- /dev/null
+++ b/common.mk
@@ -0,0 +1,7 @@
+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/...
diff --git a/makedist.sh b/makedist.sh
new file mode 100755 (executable)
index 0000000..f7f1ab1
--- /dev/null
@@ -0,0 +1,64 @@
+#!/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/
diff --git a/src/cypherpunks.ru/gogost/gogost.go b/src/cypherpunks.ru/gogost/gogost.go
new file mode 100644 (file)
index 0000000..767e461
--- /dev/null
@@ -0,0 +1,6 @@
+// Pure Go GOST cryptographic functions library.
+package gogost
+
+var (
+       Version string
+)
diff --git a/src/cypherpunks.ru/gogost/gost28147/cbc_test.go b/src/cypherpunks.ru/gogost/gost28147/cbc_test.go
new file mode 100644 (file)
index 0000000..99ac058
--- /dev/null
@@ -0,0 +1,47 @@
+// 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)
+       }
+}
diff --git a/src/cypherpunks.ru/gogost/gost28147/cfb.go b/src/cypherpunks.ru/gogost/gost28147/cfb.go
new file mode 100644 (file)
index 0000000..bf2a71c
--- /dev/null
@@ -0,0 +1,71 @@
+// 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
+}
diff --git a/src/cypherpunks.ru/gogost/gost28147/cfb_test.go b/src/cypherpunks.ru/gogost/gost28147/cfb_test.go
new file mode 100644 (file)
index 0000000..95ee1d5
--- /dev/null
@@ -0,0 +1,87 @@
+// 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)
+}
diff --git a/src/cypherpunks.ru/gogost/gost28147/cipher.go b/src/cypherpunks.ru/gogost/gost28147/cipher.go
new file mode 100644 (file)
index 0000000..2405acd
--- /dev/null
@@ -0,0 +1,122 @@
+// 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)
+}
diff --git a/src/cypherpunks.ru/gogost/gost28147/cipher_test.go b/src/cypherpunks.ru/gogost/gost28147/cipher_test.go
new file mode 100644 (file)
index 0000000..34053b3
--- /dev/null
@@ -0,0 +1,41 @@
+// 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)
+       }
+}
diff --git a/src/cypherpunks.ru/gogost/gost28147/ctr.go b/src/cypherpunks.ru/gogost/gost28147/ctr.go
new file mode 100644 (file)
index 0000000..77d0950
--- /dev/null
@@ -0,0 +1,55 @@
+// 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
+}
diff --git a/src/cypherpunks.ru/gogost/gost28147/ctr_test.go b/src/cypherpunks.ru/gogost/gost28147/ctr_test.go
new file mode 100644 (file)
index 0000000..a168002
--- /dev/null
@@ -0,0 +1,201 @@
+// 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)
+       }
+}
diff --git a/src/cypherpunks.ru/gogost/gost28147/ecb.go b/src/cypherpunks.ru/gogost/gost28147/ecb.go
new file mode 100644 (file)
index 0000000..ee5cb73
--- /dev/null
@@ -0,0 +1,55 @@
+// 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()
+}
diff --git a/src/cypherpunks.ru/gogost/gost28147/ecb_test.go b/src/cypherpunks.ru/gogost/gost28147/ecb_test.go
new file mode 100644 (file)
index 0000000..b8b2aae
--- /dev/null
@@ -0,0 +1,258 @@
+// 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()
+}
diff --git a/src/cypherpunks.ru/gogost/gost28147/mac.go b/src/cypherpunks.ru/gogost/gost28147/mac.go
new file mode 100644 (file)
index 0000000..304e622
--- /dev/null
@@ -0,0 +1,100 @@
+// 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]...)
+}
diff --git a/src/cypherpunks.ru/gogost/gost28147/mac_test.go b/src/cypherpunks.ru/gogost/gost28147/mac_test.go
new file mode 100644 (file)
index 0000000..ff3ac54
--- /dev/null
@@ -0,0 +1,126 @@
+// 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)
+       }
+}
diff --git a/src/cypherpunks.ru/gogost/gost28147/sbox.go b/src/cypherpunks.ru/gogost/gost28147/sbox.go
new file mode 100644 (file)
index 0000000..f1394f3
--- /dev/null
@@ -0,0 +1,126 @@
+// 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
+}
diff --git a/src/cypherpunks.ru/gogost/gost3410/2001_test.go b/src/cypherpunks.ru/gogost/gost3410/2001_test.go
new file mode 100644 (file)
index 0000000..0bc1429
--- /dev/null
@@ -0,0 +1,163 @@
+// 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)
+       }
+}
diff --git a/src/cypherpunks.ru/gogost/gost3410/2012_test.go b/src/cypherpunks.ru/gogost/gost3410/2012_test.go
new file mode 100644 (file)
index 0000000..fc2d61a
--- /dev/null
@@ -0,0 +1,246 @@
+// 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)
+       }
+}
diff --git a/src/cypherpunks.ru/gogost/gost3410/curve.go b/src/cypherpunks.ru/gogost/gost3410/curve.go
new file mode 100644 (file)
index 0000000..70f5a66
--- /dev/null
@@ -0,0 +1,135 @@
+// 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
+}
diff --git a/src/cypherpunks.ru/gogost/gost3410/doc.go b/src/cypherpunks.ru/gogost/gost3410/doc.go
new file mode 100644 (file)
index 0000000..2c7a398
--- /dev/null
@@ -0,0 +1,2 @@
+// GOST R 34.10-2001 (RFC 5832) and 34.10-2012 (RFC 7091) signature algorithm.
+package gost3410
diff --git a/src/cypherpunks.ru/gogost/gost3410/params.go b/src/cypherpunks.ru/gogost/gost3410/params.go
new file mode 100644 (file)
index 0000000..052acc6
--- /dev/null
@@ -0,0 +1,311 @@
+// 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][:],
+       )
+}
diff --git a/src/cypherpunks.ru/gogost/gost3410/private.go b/src/cypherpunks.ru/gogost/gost3410/private.go
new file mode 100644 (file)
index 0000000..0eec619
--- /dev/null
@@ -0,0 +1,104 @@
+// 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
+}
diff --git a/src/cypherpunks.ru/gogost/gost3410/public.go b/src/cypherpunks.ru/gogost/gost3410/public.go
new file mode 100644 (file)
index 0000000..e886502
--- /dev/null
@@ -0,0 +1,105 @@
+// 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
+}
diff --git a/src/cypherpunks.ru/gogost/gost3410/utils.go b/src/cypherpunks.ru/gogost/gost3410/utils.go
new file mode 100644 (file)
index 0000000..e35760b
--- /dev/null
@@ -0,0 +1,37 @@
+// 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...)
+}
diff --git a/src/cypherpunks.ru/gogost/gost34112012/cmd/gogost-streebog/main.go b/src/cypherpunks.ru/gogost/gost34112012/cmd/gogost-streebog/main.go
new file mode 100644 (file)
index 0000000..b6b9ff4
--- /dev/null
@@ -0,0 +1,45 @@
+// 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)))
+}
diff --git a/src/cypherpunks.ru/gogost/gost34112012/hash.go b/src/cypherpunks.ru/gogost/gost34112012/hash.go
new file mode 100644 (file)
index 0000000..7289c40
--- /dev/null
@@ -0,0 +1,406 @@
+// 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
+}
diff --git a/src/cypherpunks.ru/gogost/gost34112012/hash_test.go b/src/cypherpunks.ru/gogost/gost34112012/hash_test.go
new file mode 100644 (file)
index 0000000..e22db5f
--- /dev/null
@@ -0,0 +1,175 @@
+// 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)
+       }
+}
diff --git a/src/cypherpunks.ru/gogost/gost341194/hash.go b/src/cypherpunks.ru/gogost/gost341194/hash.go
new file mode 100644 (file)
index 0000000..c20970e
--- /dev/null
@@ -0,0 +1,269 @@
+// 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[:]...)
+}
diff --git a/src/cypherpunks.ru/gogost/gost341194/hash_test.go b/src/cypherpunks.ru/gogost/gost341194/hash_test.go
new file mode 100644 (file)
index 0000000..cfc9dd7
--- /dev/null
@@ -0,0 +1,256 @@
+// 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)
+       }
+}
diff --git a/src/cypherpunks.ru/gogost/gost3412/cipher.go b/src/cypherpunks.ru/gogost/gost3412/cipher.go
new file mode 100644 (file)
index 0000000..8322727
--- /dev/null
@@ -0,0 +1,188 @@
+// 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[:])
+}
diff --git a/src/cypherpunks.ru/gogost/gost3412/cipher_test.go b/src/cypherpunks.ru/gogost/gost3412/cipher_test.go
new file mode 100644 (file)
index 0000000..88aaf91
--- /dev/null
@@ -0,0 +1,326 @@
+// 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()
+       }
+}
diff --git a/src/cypherpunks.ru/gogost/gost3413/padding.go b/src/cypherpunks.ru/gogost/gost3413/padding.go
new file mode 100644 (file)
index 0000000..4b23d08
--- /dev/null
@@ -0,0 +1,49 @@
+// 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)
+}
diff --git a/www.mk b/www.mk
new file mode 100644 (file)
index 0000000..47be472
--- /dev/null
+++ b/www.mk
@@ -0,0 +1,12 @@
+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
diff --git a/www.texi b/www.texi
new file mode 100644 (file)
index 0000000..2d06c8f
--- /dev/null
+++ b/www.texi
@@ -0,0 +1,109 @@
+\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