commit c2193d519c979f5c634a518fbfff53baa1ea22b8 Author: Mauricio Gomes Date: Tue May 29 18:21:53 2018 -0400 Initial import diff --git a/.gitignore b/.gitignore new file mode 100755 index 0000000..4e74fdf --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +*.gem +Gemfile.lock +lib/*.bundle +tmp/ diff --git a/Gemfile b/Gemfile new file mode 100755 index 0000000..851fabc --- /dev/null +++ b/Gemfile @@ -0,0 +1,2 @@ +source 'https://rubygems.org' +gemspec diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100755 index 0000000..94a9ed0 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + 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. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/README.md b/README.md new file mode 100755 index 0000000..ce3cced --- /dev/null +++ b/README.md @@ -0,0 +1,80 @@ +# BLAKE2b for Ruby + +BLAKE2 is a cryptographic hash function faster than MD5, SHA-1, SHA-2, and SHA-3, yet is at least as secure as the latest standard SHA-3. BLAKE2 has been adopted by many projects due to its high speed, security, and simplicity. + +More info at: [https://blake2.net](https://blake2.net). + +## SUMMARY + +This gem is a C-extension for using BLAKE2b in Ruby. BLAKE2b (or just BLAKE2) is optimized for 64-bit platforms—including NEON-enabled ARMs—and produces digests of any size between 1 and 64 bytes. + +The C code for this gem is taken from the [official reference C implementation](https://github.com/BLAKE2/BLAKE2) as of commit [ca4c89314abff54e3806b44e4a08164f8204f09a](https://github.com/BLAKE2/BLAKE2/tree/ca4c89314abff54e3806b44e4a08164f8204f09a). + +## INSTALL + +``` +gem install blake2b +``` + +## USAGE + +``` ruby +require 'blake2b' + +# The UTF-8 String (Required) that you want to digest. +input = 'abc' + +# The main application of keyed BLAKE2 is as a message authentication code (MAC) +# By default `Blake2::Key.none` is used. +key = Blake2b::Key.none +# key = Blake2::Key.from_string("foo bar baz") +# key = Blake2::Key.from_hex('DEADBEAF') +# key = Blake2::Key.from_bytes([222, 173, 190, 175]) + +# The output length in Bytes of the Hash, Max and Default is 32. +out_len = 32 + +# HEX OUTPUT +############ + +Blake2b.hex(input) +=> "508c5e8c327c14e2e1a72ba34eeb452f37458b209ed63a294d999b4c86675982" + +Blake2b.hex(input, key) +=> "508c5e8c327c14e2e1a72ba34eeb452f37458b209ed63a294d999b4c86675982" + +Blake2b.hex(input, key, out_len) +=> "508c5e8c327c14e2e1a72ba34eeb452f37458b209ed63a294d999b4c86675982" + +# BYTES OUTPUT +############## + +Blake2b.bytes(input) +=> [80, 140, 94, ...] + +Blake2b.bytes(input, key) +=> [80, 140, 94, ...] + +Blake2b.bytes(input, key, out_len) +=> [80, 140, 94, ...] + +``` + +## DEVELOPMENT + +After checking out the repo, run `bundle` to install dependencies. Then, +run `rake full` to build and test, or `rake test` to only run the tests. + +To install this gem onto your local machine, run `bundle exec rake install`. + +## Future + +Hopefully this gem will not be required once Ruby [issue #12802](https://bugs.ruby-lang.org/issues/12802) is resolved. Blake2 will either be included natively into MRI or available through the OpenSSL library. + +## License + +Blake2b is based heavily on [Blake2](https://github.com/franckverrot/blake2) by Franck Verrot, Copyright 2014. + +Blake2b is copyright 2018, Mauricio Gomes. + +The original work (Blake2) and the modified work (Blake2b) are licensed GPL v3.0. See LICENSE.txt for details. diff --git a/Rakefile b/Rakefile new file mode 100755 index 0000000..7f62887 --- /dev/null +++ b/Rakefile @@ -0,0 +1,46 @@ +require 'bundler/gem_tasks' +require 'rake/testtask' +require 'rake/extensiontask' + +spec = Gem::Specification.load('blake2b.gemspec') + +Rake::ExtensionTask.new('blake2b_ext', spec) do |ext| + ext.source_pattern = '*.{c,h}' +end + +Rake::TestTask.new do |t| + t.libs << 'test' + t.pattern = 'test/**/*_test.rb' + t.verbose = true + t.warning = true +end + +task default: :full + +desc 'clean, compile, and run the full test suite' +task full: %w(clean compile test) + +def gemspec + @gemspec ||= begin + file = File.expand_path('../blake2.gemspec', __FILE__) + eval(File.read(file), binding, file) + end +end + +desc "Validate the gemspec" +task :gemspec do + gemspec.validate +end + +desc "Build the gem" +task :gem => [:gemspec, :build] do + mkdir_p "pkg" + sh "gem build blake2.gemspec" + mv "#{gemspec.full_name}.gem", "pkg" + + require 'digest/sha2' + built_gem_path = "pkg/#{gemspec.full_name}.gem" + checksum = Digest::SHA512.new.hexdigest(File.read(built_gem_path)) + checksum_path = "checksums/#{gemspec.version}.sha512" + File.open(checksum_path, 'w' ) {|f| f.write(checksum) } +end diff --git a/blake2b.gemspec b/blake2b.gemspec new file mode 100755 index 0000000..acfe0bd --- /dev/null +++ b/blake2b.gemspec @@ -0,0 +1,25 @@ +# coding: utf-8 +Gem::Specification.new do |spec| + spec.name = "blake2b" + spec.version = "0.9.0" + spec.authors = ["Franck Verrot", "Mauricio Gomes"] + spec.email = ["mauricio@edge14.com"] + spec.homepage = "https://github.com/mgomes/blake2b" + spec.license = "GPL-3.0" + + spec.summary = "A cryptographic hash function faster than MD5, SHA-1, SHA-2, and SHA-3 for 64-bit systems." + spec.required_ruby_version = ">= 2.1.0" + spec.description = "A cryptographic hash function faster than MD5, SHA-1, SHA-2, and SHA-3 for 64-bit systems." + spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) } + + spec.extensions << "ext/blake2_ext/extconf.rb" + + spec.test_files = spec.files.grep(%r{^(test|spec|features)/}) + spec.require_paths = ["lib"] + + spec.add_development_dependency "rake-compiler", "~> 0.9" + spec.add_development_dependency "bundler" , "~> 1.5" + spec.add_development_dependency "rake" , "~> 11.1" + spec.add_development_dependency "minitest" , "~> 5.8" + spec.add_development_dependency "pry" , "~> 0.10" +end diff --git a/ext/blake2b_ext/blake2-impl.h b/ext/blake2b_ext/blake2-impl.h new file mode 100755 index 0000000..5dff7fc --- /dev/null +++ b/ext/blake2b_ext/blake2-impl.h @@ -0,0 +1,160 @@ +/* + BLAKE2 reference source code package - reference C implementations + + Copyright 2012, Samuel Neves . You may use this under the + terms of the CC0, the OpenSSL Licence, or the Apache Public License 2.0, at + your option. The terms of these licenses can be found at: + + - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0 + - OpenSSL license : https://www.openssl.org/source/license.html + - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0 + + More information about the BLAKE2 hash function can be found at + https://blake2.net. +*/ +#ifndef BLAKE2_IMPL_H +#define BLAKE2_IMPL_H + +#include +#include + +#if !defined(__cplusplus) && (!defined(__STDC_VERSION__) || __STDC_VERSION__ < 199901L) + #if defined(_MSC_VER) + #define BLAKE2_INLINE __inline + #elif defined(__GNUC__) + #define BLAKE2_INLINE __inline__ + #else + #define BLAKE2_INLINE + #endif +#else + #define BLAKE2_INLINE inline +#endif + +static BLAKE2_INLINE uint32_t load32( const void *src ) +{ +#if defined(NATIVE_LITTLE_ENDIAN) + uint32_t w; + memcpy(&w, src, sizeof w); + return w; +#else + const uint8_t *p = ( const uint8_t * )src; + return (( uint32_t )( p[0] ) << 0) | + (( uint32_t )( p[1] ) << 8) | + (( uint32_t )( p[2] ) << 16) | + (( uint32_t )( p[3] ) << 24) ; +#endif +} + +static BLAKE2_INLINE uint64_t load64( const void *src ) +{ +#if defined(NATIVE_LITTLE_ENDIAN) + uint64_t w; + memcpy(&w, src, sizeof w); + return w; +#else + const uint8_t *p = ( const uint8_t * )src; + return (( uint64_t )( p[0] ) << 0) | + (( uint64_t )( p[1] ) << 8) | + (( uint64_t )( p[2] ) << 16) | + (( uint64_t )( p[3] ) << 24) | + (( uint64_t )( p[4] ) << 32) | + (( uint64_t )( p[5] ) << 40) | + (( uint64_t )( p[6] ) << 48) | + (( uint64_t )( p[7] ) << 56) ; +#endif +} + +static BLAKE2_INLINE uint16_t load16( const void *src ) +{ +#if defined(NATIVE_LITTLE_ENDIAN) + uint16_t w; + memcpy(&w, src, sizeof w); + return w; +#else + const uint8_t *p = ( const uint8_t * )src; + return (( uint16_t )( p[0] ) << 0) | + (( uint16_t )( p[1] ) << 8) ; +#endif +} + +static BLAKE2_INLINE void store16( void *dst, uint16_t w ) +{ +#if defined(NATIVE_LITTLE_ENDIAN) + memcpy(dst, &w, sizeof w); +#else + uint8_t *p = ( uint8_t * )dst; + *p++ = ( uint8_t )w; w >>= 8; + *p++ = ( uint8_t )w; +#endif +} + +static BLAKE2_INLINE void store32( void *dst, uint32_t w ) +{ +#if defined(NATIVE_LITTLE_ENDIAN) + memcpy(dst, &w, sizeof w); +#else + uint8_t *p = ( uint8_t * )dst; + p[0] = (uint8_t)(w >> 0); + p[1] = (uint8_t)(w >> 8); + p[2] = (uint8_t)(w >> 16); + p[3] = (uint8_t)(w >> 24); +#endif +} + +static BLAKE2_INLINE void store64( void *dst, uint64_t w ) +{ +#if defined(NATIVE_LITTLE_ENDIAN) + memcpy(dst, &w, sizeof w); +#else + uint8_t *p = ( uint8_t * )dst; + p[0] = (uint8_t)(w >> 0); + p[1] = (uint8_t)(w >> 8); + p[2] = (uint8_t)(w >> 16); + p[3] = (uint8_t)(w >> 24); + p[4] = (uint8_t)(w >> 32); + p[5] = (uint8_t)(w >> 40); + p[6] = (uint8_t)(w >> 48); + p[7] = (uint8_t)(w >> 56); +#endif +} + +static BLAKE2_INLINE uint64_t load48( const void *src ) +{ + const uint8_t *p = ( const uint8_t * )src; + return (( uint64_t )( p[0] ) << 0) | + (( uint64_t )( p[1] ) << 8) | + (( uint64_t )( p[2] ) << 16) | + (( uint64_t )( p[3] ) << 24) | + (( uint64_t )( p[4] ) << 32) | + (( uint64_t )( p[5] ) << 40) ; +} + +static BLAKE2_INLINE void store48( void *dst, uint64_t w ) +{ + uint8_t *p = ( uint8_t * )dst; + p[0] = (uint8_t)(w >> 0); + p[1] = (uint8_t)(w >> 8); + p[2] = (uint8_t)(w >> 16); + p[3] = (uint8_t)(w >> 24); + p[4] = (uint8_t)(w >> 32); + p[5] = (uint8_t)(w >> 40); +} + +static BLAKE2_INLINE uint32_t rotr32( const uint32_t w, const unsigned c ) +{ + return ( w >> c ) | ( w << ( 32 - c ) ); +} + +static BLAKE2_INLINE uint64_t rotr64( const uint64_t w, const unsigned c ) +{ + return ( w >> c ) | ( w << ( 64 - c ) ); +} + +/* prevents compiler optimizing out memset() */ +static BLAKE2_INLINE void secure_zero_memory(void *v, size_t n) +{ + static void *(*const volatile memset_v)(void *, int, size_t) = &memset; + memset_v(v, 0, n); +} + +#endif diff --git a/ext/blake2b_ext/blake2.h b/ext/blake2b_ext/blake2.h new file mode 100755 index 0000000..ad62f26 --- /dev/null +++ b/ext/blake2b_ext/blake2.h @@ -0,0 +1,195 @@ +/* + BLAKE2 reference source code package - reference C implementations + + Copyright 2012, Samuel Neves . You may use this under the + terms of the CC0, the OpenSSL Licence, or the Apache Public License 2.0, at + your option. The terms of these licenses can be found at: + + - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0 + - OpenSSL license : https://www.openssl.org/source/license.html + - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0 + + More information about the BLAKE2 hash function can be found at + https://blake2.net. +*/ +#ifndef BLAKE2_H +#define BLAKE2_H + +#include +#include + +#if defined(_MSC_VER) +#define BLAKE2_PACKED(x) __pragma(pack(push, 1)) x __pragma(pack(pop)) +#else +#define BLAKE2_PACKED(x) x __attribute__((packed)) +#endif + +#if defined(__cplusplus) +extern "C" { +#endif + + enum blake2s_constant + { + BLAKE2S_BLOCKBYTES = 64, + BLAKE2S_OUTBYTES = 32, + BLAKE2S_KEYBYTES = 32, + BLAKE2S_SALTBYTES = 8, + BLAKE2S_PERSONALBYTES = 8 + }; + + enum blake2b_constant + { + BLAKE2B_BLOCKBYTES = 128, + BLAKE2B_OUTBYTES = 64, + BLAKE2B_KEYBYTES = 64, + BLAKE2B_SALTBYTES = 16, + BLAKE2B_PERSONALBYTES = 16 + }; + + typedef struct blake2s_state__ + { + uint32_t h[8]; + uint32_t t[2]; + uint32_t f[2]; + uint8_t buf[BLAKE2S_BLOCKBYTES]; + size_t buflen; + size_t outlen; + uint8_t last_node; + } blake2s_state; + + typedef struct blake2b_state__ + { + uint64_t h[8]; + uint64_t t[2]; + uint64_t f[2]; + uint8_t buf[BLAKE2B_BLOCKBYTES]; + size_t buflen; + size_t outlen; + uint8_t last_node; + } blake2b_state; + + typedef struct blake2sp_state__ + { + blake2s_state S[8][1]; + blake2s_state R[1]; + uint8_t buf[8 * BLAKE2S_BLOCKBYTES]; + size_t buflen; + size_t outlen; + } blake2sp_state; + + typedef struct blake2bp_state__ + { + blake2b_state S[4][1]; + blake2b_state R[1]; + uint8_t buf[4 * BLAKE2B_BLOCKBYTES]; + size_t buflen; + size_t outlen; + } blake2bp_state; + + + BLAKE2_PACKED(struct blake2s_param__ + { + uint8_t digest_length; /* 1 */ + uint8_t key_length; /* 2 */ + uint8_t fanout; /* 3 */ + uint8_t depth; /* 4 */ + uint32_t leaf_length; /* 8 */ + uint32_t node_offset; /* 12 */ + uint16_t xof_length; /* 14 */ + uint8_t node_depth; /* 15 */ + uint8_t inner_length; /* 16 */ + /* uint8_t reserved[0]; */ + uint8_t salt[BLAKE2S_SALTBYTES]; /* 24 */ + uint8_t personal[BLAKE2S_PERSONALBYTES]; /* 32 */ + }); + + typedef struct blake2s_param__ blake2s_param; + + BLAKE2_PACKED(struct blake2b_param__ + { + uint8_t digest_length; /* 1 */ + uint8_t key_length; /* 2 */ + uint8_t fanout; /* 3 */ + uint8_t depth; /* 4 */ + uint32_t leaf_length; /* 8 */ + uint32_t node_offset; /* 12 */ + uint32_t xof_length; /* 16 */ + uint8_t node_depth; /* 17 */ + uint8_t inner_length; /* 18 */ + uint8_t reserved[14]; /* 32 */ + uint8_t salt[BLAKE2B_SALTBYTES]; /* 48 */ + uint8_t personal[BLAKE2B_PERSONALBYTES]; /* 64 */ + }); + + typedef struct blake2b_param__ blake2b_param; + + typedef struct blake2xs_state__ + { + blake2s_state S[1]; + blake2s_param P[1]; + } blake2xs_state; + + typedef struct blake2xb_state__ + { + blake2b_state S[1]; + blake2b_param P[1]; + } blake2xb_state; + + /* Padded structs result in a compile-time error */ + enum { + BLAKE2_DUMMY_1 = 1/(sizeof(blake2s_param) == BLAKE2S_OUTBYTES), + BLAKE2_DUMMY_2 = 1/(sizeof(blake2b_param) == BLAKE2B_OUTBYTES) + }; + + /* Streaming API */ + int blake2s_init( blake2s_state *S, size_t outlen ); + int blake2s_init_key( blake2s_state *S, size_t outlen, const void *key, size_t keylen ); + int blake2s_init_param( blake2s_state *S, const blake2s_param *P ); + int blake2s_update( blake2s_state *S, const void *in, size_t inlen ); + int blake2s_final( blake2s_state *S, void *out, size_t outlen ); + + int blake2b_init( blake2b_state *S, size_t outlen ); + int blake2b_init_key( blake2b_state *S, size_t outlen, const void *key, size_t keylen ); + int blake2b_init_param( blake2b_state *S, const blake2b_param *P ); + int blake2b_update( blake2b_state *S, const void *in, size_t inlen ); + int blake2b_final( blake2b_state *S, void *out, size_t outlen ); + + int blake2sp_init( blake2sp_state *S, size_t outlen ); + int blake2sp_init_key( blake2sp_state *S, size_t outlen, const void *key, size_t keylen ); + int blake2sp_update( blake2sp_state *S, const void *in, size_t inlen ); + int blake2sp_final( blake2sp_state *S, void *out, size_t outlen ); + + int blake2bp_init( blake2bp_state *S, size_t outlen ); + int blake2bp_init_key( blake2bp_state *S, size_t outlen, const void *key, size_t keylen ); + int blake2bp_update( blake2bp_state *S, const void *in, size_t inlen ); + int blake2bp_final( blake2bp_state *S, void *out, size_t outlen ); + + /* Variable output length API */ + int blake2xs_init( blake2xs_state *S, const size_t outlen ); + int blake2xs_init_key( blake2xs_state *S, const size_t outlen, const void *key, size_t keylen ); + int blake2xs_update( blake2xs_state *S, const void *in, size_t inlen ); + int blake2xs_final(blake2xs_state *S, void *out, size_t outlen); + + int blake2xb_init( blake2xb_state *S, const size_t outlen ); + int blake2xb_init_key( blake2xb_state *S, const size_t outlen, const void *key, size_t keylen ); + int blake2xb_update( blake2xb_state *S, const void *in, size_t inlen ); + int blake2xb_final(blake2xb_state *S, void *out, size_t outlen); + + /* Simple API */ + int blake2s( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen ); + int blake2b( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen ); + + int blake2sp( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen ); + int blake2bp( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen ); + + int blake2xs( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen ); + int blake2xb( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen ); + + /* This is simply an alias for blake2b */ + int blake2( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen ); + +#if defined(__cplusplus) +} +#endif + +#endif diff --git a/ext/blake2b_ext/blake2b-ref.c b/ext/blake2b_ext/blake2b-ref.c new file mode 100644 index 0000000..cd38b1b --- /dev/null +++ b/ext/blake2b_ext/blake2b-ref.c @@ -0,0 +1,379 @@ +/* + BLAKE2 reference source code package - reference C implementations + + Copyright 2012, Samuel Neves . You may use this under the + terms of the CC0, the OpenSSL Licence, or the Apache Public License 2.0, at + your option. The terms of these licenses can be found at: + + - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0 + - OpenSSL license : https://www.openssl.org/source/license.html + - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0 + + More information about the BLAKE2 hash function can be found at + https://blake2.net. +*/ + +#include +#include +#include + +#include "blake2.h" +#include "blake2-impl.h" + +static const uint64_t blake2b_IV[8] = +{ + 0x6a09e667f3bcc908ULL, 0xbb67ae8584caa73bULL, + 0x3c6ef372fe94f82bULL, 0xa54ff53a5f1d36f1ULL, + 0x510e527fade682d1ULL, 0x9b05688c2b3e6c1fULL, + 0x1f83d9abfb41bd6bULL, 0x5be0cd19137e2179ULL +}; + +static const uint8_t blake2b_sigma[12][16] = +{ + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } , + { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 } , + { 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 } , + { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 } , + { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 } , + { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 } , + { 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 } , + { 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 } , + { 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 } , + { 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13 , 0 } , + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } , + { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 } +}; + + +static void blake2b_set_lastnode( blake2b_state *S ) +{ + S->f[1] = (uint64_t)-1; +} + +/* Some helper functions, not necessarily useful */ +static int blake2b_is_lastblock( const blake2b_state *S ) +{ + return S->f[0] != 0; +} + +static void blake2b_set_lastblock( blake2b_state *S ) +{ + if( S->last_node ) blake2b_set_lastnode( S ); + + S->f[0] = (uint64_t)-1; +} + +static void blake2b_increment_counter( blake2b_state *S, const uint64_t inc ) +{ + S->t[0] += inc; + S->t[1] += ( S->t[0] < inc ); +} + +static void blake2b_init0( blake2b_state *S ) +{ + size_t i; + memset( S, 0, sizeof( blake2b_state ) ); + + for( i = 0; i < 8; ++i ) S->h[i] = blake2b_IV[i]; +} + +/* init xors IV with input parameter block */ +int blake2b_init_param( blake2b_state *S, const blake2b_param *P ) +{ + const uint8_t *p = ( const uint8_t * )( P ); + size_t i; + + blake2b_init0( S ); + + /* IV XOR ParamBlock */ + for( i = 0; i < 8; ++i ) + S->h[i] ^= load64( p + sizeof( S->h[i] ) * i ); + + S->outlen = P->digest_length; + return 0; +} + + + +int blake2b_init( blake2b_state *S, size_t outlen ) +{ + blake2b_param P[1]; + + if ( ( !outlen ) || ( outlen > BLAKE2B_OUTBYTES ) ) return -1; + + P->digest_length = (uint8_t)outlen; + P->key_length = 0; + P->fanout = 1; + P->depth = 1; + store32( &P->leaf_length, 0 ); + store32( &P->node_offset, 0 ); + store32( &P->xof_length, 0 ); + P->node_depth = 0; + P->inner_length = 0; + memset( P->reserved, 0, sizeof( P->reserved ) ); + memset( P->salt, 0, sizeof( P->salt ) ); + memset( P->personal, 0, sizeof( P->personal ) ); + return blake2b_init_param( S, P ); +} + + +int blake2b_init_key( blake2b_state *S, size_t outlen, const void *key, size_t keylen ) +{ + blake2b_param P[1]; + + if ( ( !outlen ) || ( outlen > BLAKE2B_OUTBYTES ) ) return -1; + + if ( !key || !keylen || keylen > BLAKE2B_KEYBYTES ) return -1; + + P->digest_length = (uint8_t)outlen; + P->key_length = (uint8_t)keylen; + P->fanout = 1; + P->depth = 1; + store32( &P->leaf_length, 0 ); + store32( &P->node_offset, 0 ); + store32( &P->xof_length, 0 ); + P->node_depth = 0; + P->inner_length = 0; + memset( P->reserved, 0, sizeof( P->reserved ) ); + memset( P->salt, 0, sizeof( P->salt ) ); + memset( P->personal, 0, sizeof( P->personal ) ); + + if( blake2b_init_param( S, P ) < 0 ) return -1; + + { + uint8_t block[BLAKE2B_BLOCKBYTES]; + memset( block, 0, BLAKE2B_BLOCKBYTES ); + memcpy( block, key, keylen ); + blake2b_update( S, block, BLAKE2B_BLOCKBYTES ); + secure_zero_memory( block, BLAKE2B_BLOCKBYTES ); /* Burn the key from stack */ + } + return 0; +} + +#define G(r,i,a,b,c,d) \ + do { \ + a = a + b + m[blake2b_sigma[r][2*i+0]]; \ + d = rotr64(d ^ a, 32); \ + c = c + d; \ + b = rotr64(b ^ c, 24); \ + a = a + b + m[blake2b_sigma[r][2*i+1]]; \ + d = rotr64(d ^ a, 16); \ + c = c + d; \ + b = rotr64(b ^ c, 63); \ + } while(0) + +#define ROUND(r) \ + do { \ + G(r,0,v[ 0],v[ 4],v[ 8],v[12]); \ + G(r,1,v[ 1],v[ 5],v[ 9],v[13]); \ + G(r,2,v[ 2],v[ 6],v[10],v[14]); \ + G(r,3,v[ 3],v[ 7],v[11],v[15]); \ + G(r,4,v[ 0],v[ 5],v[10],v[15]); \ + G(r,5,v[ 1],v[ 6],v[11],v[12]); \ + G(r,6,v[ 2],v[ 7],v[ 8],v[13]); \ + G(r,7,v[ 3],v[ 4],v[ 9],v[14]); \ + } while(0) + +static void blake2b_compress( blake2b_state *S, const uint8_t block[BLAKE2B_BLOCKBYTES] ) +{ + uint64_t m[16]; + uint64_t v[16]; + size_t i; + + for( i = 0; i < 16; ++i ) { + m[i] = load64( block + i * sizeof( m[i] ) ); + } + + for( i = 0; i < 8; ++i ) { + v[i] = S->h[i]; + } + + v[ 8] = blake2b_IV[0]; + v[ 9] = blake2b_IV[1]; + v[10] = blake2b_IV[2]; + v[11] = blake2b_IV[3]; + v[12] = blake2b_IV[4] ^ S->t[0]; + v[13] = blake2b_IV[5] ^ S->t[1]; + v[14] = blake2b_IV[6] ^ S->f[0]; + v[15] = blake2b_IV[7] ^ S->f[1]; + + ROUND( 0 ); + ROUND( 1 ); + ROUND( 2 ); + ROUND( 3 ); + ROUND( 4 ); + ROUND( 5 ); + ROUND( 6 ); + ROUND( 7 ); + ROUND( 8 ); + ROUND( 9 ); + ROUND( 10 ); + ROUND( 11 ); + + for( i = 0; i < 8; ++i ) { + S->h[i] = S->h[i] ^ v[i] ^ v[i + 8]; + } +} + +#undef G +#undef ROUND + +int blake2b_update( blake2b_state *S, const void *pin, size_t inlen ) +{ + const unsigned char * in = (const unsigned char *)pin; + if( inlen > 0 ) + { + size_t left = S->buflen; + size_t fill = BLAKE2B_BLOCKBYTES - left; + if( inlen > fill ) + { + S->buflen = 0; + memcpy( S->buf + left, in, fill ); /* Fill buffer */ + blake2b_increment_counter( S, BLAKE2B_BLOCKBYTES ); + blake2b_compress( S, S->buf ); /* Compress */ + in += fill; inlen -= fill; + while(inlen > BLAKE2B_BLOCKBYTES) { + blake2b_increment_counter(S, BLAKE2B_BLOCKBYTES); + blake2b_compress( S, in ); + in += BLAKE2B_BLOCKBYTES; + inlen -= BLAKE2B_BLOCKBYTES; + } + } + memcpy( S->buf + S->buflen, in, inlen ); + S->buflen += inlen; + } + return 0; +} + +int blake2b_final( blake2b_state *S, void *out, size_t outlen ) +{ + uint8_t buffer[BLAKE2B_OUTBYTES] = {0}; + size_t i; + + if( out == NULL || outlen < S->outlen ) + return -1; + + if( blake2b_is_lastblock( S ) ) + return -1; + + blake2b_increment_counter( S, S->buflen ); + blake2b_set_lastblock( S ); + memset( S->buf + S->buflen, 0, BLAKE2B_BLOCKBYTES - S->buflen ); /* Padding */ + blake2b_compress( S, S->buf ); + + for( i = 0; i < 8; ++i ) /* Output full hash to temp buffer */ + store64( buffer + sizeof( S->h[i] ) * i, S->h[i] ); + + memcpy( out, buffer, S->outlen ); + secure_zero_memory(buffer, sizeof(buffer)); + return 0; +} + +/* inlen, at least, should be uint64_t. Others can be size_t. */ +int blake2b( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen ) +{ + blake2b_state S[1]; + + /* Verify parameters */ + if ( NULL == in && inlen > 0 ) return -1; + + if ( NULL == out ) return -1; + + if( NULL == key && keylen > 0 ) return -1; + + if( !outlen || outlen > BLAKE2B_OUTBYTES ) return -1; + + if( keylen > BLAKE2B_KEYBYTES ) return -1; + + if( keylen > 0 ) + { + if( blake2b_init_key( S, outlen, key, keylen ) < 0 ) return -1; + } + else + { + if( blake2b_init( S, outlen ) < 0 ) return -1; + } + + blake2b_update( S, ( const uint8_t * )in, inlen ); + blake2b_final( S, out, outlen ); + return 0; +} + +int blake2( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen ) { + return blake2b(out, outlen, in, inlen, key, keylen); +} + +#if defined(SUPERCOP) +int crypto_hash( unsigned char *out, unsigned char *in, unsigned long long inlen ) +{ + return blake2b( out, BLAKE2B_OUTBYTES, in, inlen, NULL, 0 ); +} +#endif + +#if defined(BLAKE2B_SELFTEST) +#include +#include "blake2-kat.h" +int main( void ) +{ + uint8_t key[BLAKE2B_KEYBYTES]; + uint8_t buf[BLAKE2_KAT_LENGTH]; + size_t i, step; + + for( i = 0; i < BLAKE2B_KEYBYTES; ++i ) + key[i] = ( uint8_t )i; + + for( i = 0; i < BLAKE2_KAT_LENGTH; ++i ) + buf[i] = ( uint8_t )i; + + /* Test simple API */ + for( i = 0; i < BLAKE2_KAT_LENGTH; ++i ) + { + uint8_t hash[BLAKE2B_OUTBYTES]; + blake2b( hash, BLAKE2B_OUTBYTES, buf, i, key, BLAKE2B_KEYBYTES ); + + if( 0 != memcmp( hash, blake2b_keyed_kat[i], BLAKE2B_OUTBYTES ) ) + { + goto fail; + } + } + + /* Test streaming API */ + for(step = 1; step < BLAKE2B_BLOCKBYTES; ++step) { + for (i = 0; i < BLAKE2_KAT_LENGTH; ++i) { + uint8_t hash[BLAKE2B_OUTBYTES]; + blake2b_state S; + uint8_t * p = buf; + size_t mlen = i; + int err = 0; + + if( (err = blake2b_init_key(&S, BLAKE2B_OUTBYTES, key, BLAKE2B_KEYBYTES)) < 0 ) { + goto fail; + } + + while (mlen >= step) { + if ( (err = blake2b_update(&S, p, step)) < 0 ) { + goto fail; + } + mlen -= step; + p += step; + } + if ( (err = blake2b_update(&S, p, mlen)) < 0) { + goto fail; + } + if ( (err = blake2b_final(&S, hash, BLAKE2B_OUTBYTES)) < 0) { + goto fail; + } + + if (0 != memcmp(hash, blake2b_keyed_kat[i], BLAKE2B_OUTBYTES)) { + goto fail; + } + } + } + + puts( "ok" ); + return 0; +fail: + puts("error"); + return -1; +} +#endif diff --git a/ext/blake2b_ext/blake2s-ref.c b/ext/blake2b_ext/blake2s-ref.c new file mode 100755 index 0000000..a10f7ef --- /dev/null +++ b/ext/blake2b_ext/blake2s-ref.c @@ -0,0 +1,405 @@ +/* + BLAKE2 reference source code package - reference C implementations + + Copyright 2012, Samuel Neves . You may use this under the + terms of the CC0, the OpenSSL Licence, or the Apache Public License 2.0, at + your option. The terms of these licenses can be found at: + + - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0 + - OpenSSL license : https://www.openssl.org/source/license.html + - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0 + + More information about the BLAKE2 hash function can be found at + https://blake2.net. +*/ + +#include +#include +#include + +#include "blake2.h" +#include "blake2-impl.h" + +static const uint32_t blake2s_IV[8] = +{ + 0x6A09E667UL, 0xBB67AE85UL, 0x3C6EF372UL, 0xA54FF53AUL, + 0x510E527FUL, 0x9B05688CUL, 0x1F83D9ABUL, 0x5BE0CD19UL +}; + +static const uint8_t blake2s_sigma[10][16] = +{ + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } , + { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 } , + { 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 } , + { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 } , + { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 } , + { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 } , + { 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 } , + { 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 } , + { 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 } , + { 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13 , 0 } , +}; + +static inline int blake2s_set_lastnode( blake2s_state *S ) +{ + S->f[1] = -1; + return 0; +} + +static inline int blake2s_clear_lastnode( blake2s_state *S ) +{ + S->f[1] = 0; + return 0; +} + +/* Some helper functions, not necessarily useful */ +static inline int blake2s_is_lastblock( const blake2s_state *S ) +{ + return S->f[0] != 0; +} + +static inline int blake2s_set_lastblock( blake2s_state *S ) +{ + if( S->last_node ) blake2s_set_lastnode( S ); + + S->f[0] = -1; + return 0; +} + +static inline int blake2s_clear_lastblock( blake2s_state *S ) +{ + if( S->last_node ) blake2s_clear_lastnode( S ); + + S->f[0] = 0; + return 0; +} + +static inline int blake2s_increment_counter( blake2s_state *S, const uint32_t inc ) +{ + S->t[0] += inc; + S->t[1] += ( S->t[0] < inc ); + return 0; +} + +// Parameter-related functions +static inline int blake2s_param_set_digest_length( blake2s_param *P, const uint8_t digest_length ) +{ + P->digest_length = digest_length; + return 0; +} + +static inline int blake2s_param_set_fanout( blake2s_param *P, const uint8_t fanout ) +{ + P->fanout = fanout; + return 0; +} + +static inline int blake2s_param_set_max_depth( blake2s_param *P, const uint8_t depth ) +{ + P->depth = depth; + return 0; +} + +static inline int blake2s_param_set_leaf_length( blake2s_param *P, const uint32_t leaf_length ) +{ + store32( &P->leaf_length, leaf_length ); + return 0; +} + +static inline int blake2s_param_set_node_offset( blake2s_param *P, const uint64_t node_offset ) +{ + store48( P->node_offset, node_offset ); + return 0; +} + +static inline int blake2s_param_set_node_depth( blake2s_param *P, const uint8_t node_depth ) +{ + P->node_depth = node_depth; + return 0; +} + +static inline int blake2s_param_set_inner_length( blake2s_param *P, const uint8_t inner_length ) +{ + P->inner_length = inner_length; + return 0; +} + +static inline int blake2s_param_set_salt( blake2s_param *P, const uint8_t salt[BLAKE2S_SALTBYTES] ) +{ + memcpy( P->salt, salt, BLAKE2S_SALTBYTES ); + return 0; +} + +static inline int blake2s_param_set_personal( blake2s_param *P, const uint8_t personal[BLAKE2S_PERSONALBYTES] ) +{ + memcpy( P->personal, personal, BLAKE2S_PERSONALBYTES ); + return 0; +} + +static inline int blake2s_init0( blake2s_state *S ) +{ + memset( S, 0, sizeof( blake2s_state ) ); + + for( int i = 0; i < 8; ++i ) S->h[i] = blake2s_IV[i]; + + return 0; +} + +/* init2 xors IV with input parameter block */ +int blake2s_init_param( blake2s_state *S, const blake2s_param *P ) +{ + blake2s_init0( S ); + const uint32_t *p = ( const uint32_t * )( P ); + + /* IV XOR ParamBlock */ + for( size_t i = 0; i < 8; ++i ) + S->h[i] ^= load32( &p[i] ); + + return 0; +} + + +// Sequential blake2s initialization +int blake2s_init( blake2s_state *S, const uint8_t outlen ) +{ + blake2s_param P[1]; + + /* Move interval verification here? */ + if ( ( !outlen ) || ( outlen > BLAKE2S_OUTBYTES ) ) return -1; + + P->digest_length = outlen; + P->key_length = 0; + P->fanout = 1; + P->depth = 1; + store32( &P->leaf_length, 0 ); + store48( &P->node_offset, 0 ); + P->node_depth = 0; + P->inner_length = 0; + // memset(P->reserved, 0, sizeof(P->reserved) ); + memset( P->salt, 0, sizeof( P->salt ) ); + memset( P->personal, 0, sizeof( P->personal ) ); + return blake2s_init_param( S, P ); +} + +int blake2s_init_key( blake2s_state *S, const uint8_t outlen, const void *key, const uint8_t keylen ) +{ + blake2s_param P[1]; + + if ( ( !outlen ) || ( outlen > BLAKE2S_OUTBYTES ) ) return -1; + + if ( !key || !keylen || keylen > BLAKE2S_KEYBYTES ) return -1; + + P->digest_length = outlen; + P->key_length = keylen; + P->fanout = 1; + P->depth = 1; + store32( &P->leaf_length, 0 ); + store48( &P->node_offset, 0 ); + P->node_depth = 0; + P->inner_length = 0; + // memset(P->reserved, 0, sizeof(P->reserved) ); + memset( P->salt, 0, sizeof( P->salt ) ); + memset( P->personal, 0, sizeof( P->personal ) ); + + if( blake2s_init_param( S, P ) < 0 ) return -1; + + { + uint8_t block[BLAKE2S_BLOCKBYTES]; + memset( block, 0, BLAKE2S_BLOCKBYTES ); + memcpy( block, key, keylen ); + blake2s_update( S, block, BLAKE2S_BLOCKBYTES ); + secure_zero_memory( block, BLAKE2S_BLOCKBYTES ); /* Burn the key from stack */ + } + return 0; +} + +static int blake2s_compress( blake2s_state *S, const uint8_t block[BLAKE2S_BLOCKBYTES] ) +{ + uint32_t m[16]; + uint32_t v[16]; + + for( size_t i = 0; i < 16; ++i ) + m[i] = load32( block + i * sizeof( m[i] ) ); + + for( size_t i = 0; i < 8; ++i ) + v[i] = S->h[i]; + + v[ 8] = blake2s_IV[0]; + v[ 9] = blake2s_IV[1]; + v[10] = blake2s_IV[2]; + v[11] = blake2s_IV[3]; + v[12] = S->t[0] ^ blake2s_IV[4]; + v[13] = S->t[1] ^ blake2s_IV[5]; + v[14] = S->f[0] ^ blake2s_IV[6]; + v[15] = S->f[1] ^ blake2s_IV[7]; +#define G(r,i,a,b,c,d) \ + do { \ + a = a + b + m[blake2s_sigma[r][2*i+0]]; \ + d = rotr32(d ^ a, 16); \ + c = c + d; \ + b = rotr32(b ^ c, 12); \ + a = a + b + m[blake2s_sigma[r][2*i+1]]; \ + d = rotr32(d ^ a, 8); \ + c = c + d; \ + b = rotr32(b ^ c, 7); \ + } while(0) +#define ROUND(r) \ + do { \ + G(r,0,v[ 0],v[ 4],v[ 8],v[12]); \ + G(r,1,v[ 1],v[ 5],v[ 9],v[13]); \ + G(r,2,v[ 2],v[ 6],v[10],v[14]); \ + G(r,3,v[ 3],v[ 7],v[11],v[15]); \ + G(r,4,v[ 0],v[ 5],v[10],v[15]); \ + G(r,5,v[ 1],v[ 6],v[11],v[12]); \ + G(r,6,v[ 2],v[ 7],v[ 8],v[13]); \ + G(r,7,v[ 3],v[ 4],v[ 9],v[14]); \ + } while(0) + ROUND( 0 ); + ROUND( 1 ); + ROUND( 2 ); + ROUND( 3 ); + ROUND( 4 ); + ROUND( 5 ); + ROUND( 6 ); + ROUND( 7 ); + ROUND( 8 ); + ROUND( 9 ); + + for( size_t i = 0; i < 8; ++i ) + S->h[i] = S->h[i] ^ v[i] ^ v[i + 8]; + +#undef G +#undef ROUND + return 0; +} + + +int blake2s_update( blake2s_state *S, const uint8_t *in, uint64_t inlen ) +{ + while( inlen > 0 ) + { + size_t left = S->buflen; + size_t fill = 2 * BLAKE2S_BLOCKBYTES - left; + + if( inlen > fill ) + { + memcpy( S->buf + left, in, fill ); // Fill buffer + S->buflen += fill; + blake2s_increment_counter( S, BLAKE2S_BLOCKBYTES ); + blake2s_compress( S, S->buf ); // Compress + memcpy( S->buf, S->buf + BLAKE2S_BLOCKBYTES, BLAKE2S_BLOCKBYTES ); // Shift buffer left + S->buflen -= BLAKE2S_BLOCKBYTES; + in += fill; + inlen -= fill; + } + else // inlen <= fill + { + memcpy( S->buf + left, in, inlen ); + S->buflen += inlen; // Be lazy, do not compress + in += inlen; + inlen -= inlen; + } + } + + return 0; +} + +int blake2s_final( blake2s_state *S, uint8_t *out, uint8_t outlen ) +{ + uint8_t buffer[BLAKE2S_OUTBYTES] = {0}; + + if( out == NULL || outlen == 0 || outlen > BLAKE2S_OUTBYTES ) + return -1; + + if( blake2s_is_lastblock( S ) ) + return -1; + + + if( S->buflen > BLAKE2S_BLOCKBYTES ) + { + blake2s_increment_counter( S, BLAKE2S_BLOCKBYTES ); + blake2s_compress( S, S->buf ); + S->buflen -= BLAKE2S_BLOCKBYTES; + memcpy( S->buf, S->buf + BLAKE2S_BLOCKBYTES, S->buflen ); + } + + blake2s_increment_counter( S, ( uint32_t )S->buflen ); + blake2s_set_lastblock( S ); + memset( S->buf + S->buflen, 0, 2 * BLAKE2S_BLOCKBYTES - S->buflen ); /* Padding */ + blake2s_compress( S, S->buf ); + + for( int i = 0; i < 8; ++i ) /* Output full hash to temp buffer */ + store32( buffer + sizeof( S->h[i] ) * i, S->h[i] ); + + memcpy( out, buffer, outlen ); + return 0; +} + +int blake2s( uint8_t *out, const void *in, const void *key, const uint8_t outlen, const uint64_t inlen, uint8_t keylen ) +{ + blake2s_state S[1]; + + /* Verify parameters */ + if ( NULL == in && inlen > 0 ) return -1; + + if ( NULL == out ) return -1; + + if ( NULL == key && keylen > 0) return -1; + + if( !outlen || outlen > BLAKE2S_OUTBYTES ) return -1; + + if( keylen > BLAKE2S_KEYBYTES ) return -1; + + if( keylen > 0 ) + { + if( blake2s_init_key( S, outlen, key, keylen ) < 0 ) return -1; + } + else + { + if( blake2s_init( S, outlen ) < 0 ) return -1; + } + + blake2s_update( S, ( const uint8_t * )in, inlen ); + blake2s_final( S, out, outlen ); + return 0; +} + +#if defined(SUPERCOP) +int crypto_hash( unsigned char *out, unsigned char *in, unsigned long long inlen ) +{ + return blake2s( out, in, NULL, BLAKE2S_OUTBYTES, inlen, 0 ); +} +#endif + +#if defined(BLAKE2S_SELFTEST) +#include +#include "blake2-kat.h" +int main( int argc, char **argv ) +{ + uint8_t key[BLAKE2S_KEYBYTES]; + uint8_t buf[KAT_LENGTH]; + + for( size_t i = 0; i < BLAKE2S_KEYBYTES; ++i ) + key[i] = ( uint8_t )i; + + for( size_t i = 0; i < KAT_LENGTH; ++i ) + buf[i] = ( uint8_t )i; + + for( size_t i = 0; i < KAT_LENGTH; ++i ) + { + uint8_t hash[BLAKE2S_OUTBYTES]; + blake2s( hash, buf, key, BLAKE2S_OUTBYTES, i, BLAKE2S_KEYBYTES ); + + if( 0 != memcmp( hash, blake2s_keyed_kat[i], BLAKE2S_OUTBYTES ) ) + { + puts( "error" ); + return -1; + } + } + + puts( "ok" ); + return 0; +} +#endif + + diff --git a/ext/blake2b_ext/extconf.rb b/ext/blake2b_ext/extconf.rb new file mode 100755 index 0000000..10e75d4 --- /dev/null +++ b/ext/blake2b_ext/extconf.rb @@ -0,0 +1,3 @@ +require 'mkmf' +$CFLAGS += ' -std=c99' +create_makefile 'blake2b_ext' diff --git a/ext/blake2b_ext/rbext.c b/ext/blake2b_ext/rbext.c new file mode 100755 index 0000000..a9d0b2d --- /dev/null +++ b/ext/blake2b_ext/rbext.c @@ -0,0 +1,108 @@ +#include +#include +#include "blake2.h" + +typedef struct { + uint8_t key_length; + uint8_t *key_bytes; + + uint8_t output_length; + uint8_t *output; + + VALUE to_hex; + VALUE to_bytes; +} Blake2; + +VALUE cBlake2; + +static void blake2_free(Blake2 *blake2) { + free(blake2->key_bytes); + free(blake2->output); + + rb_gc_mark(blake2->to_hex); + rb_gc_mark(blake2->to_bytes); + + ruby_xfree(blake2); +} + +static VALUE blake2_alloc(VALUE klass) { + Blake2 *blake2_obj = (Blake2 *)ruby_xmalloc(sizeof(Blake2)); + + return Data_Wrap_Struct(klass, NULL, blake2_free, blake2_obj); +} + +VALUE m_blake2_initialize(VALUE self, VALUE _len, VALUE _key) { + Blake2 *blake2; + Data_Get_Struct(self, Blake2, blake2); + int i; + + ID bytes_method = rb_intern("bytes"); + blake2->to_hex = ID2SYM(rb_intern("to_hex")); + blake2->to_bytes = ID2SYM(rb_intern("to_bytes")); + + VALUE key_bytes_ary = rb_funcall(_key, bytes_method, 0); + blake2->key_length = RARRAY_LEN(key_bytes_ary); + blake2->key_bytes = (uint8_t*)malloc(blake2->key_length * sizeof(uint8_t)); + + for(i = 0; i < blake2->key_length; i++) { + VALUE byte = rb_ary_entry(key_bytes_ary, i); + blake2->key_bytes[i] = NUM2INT(byte); + } + + blake2->output_length = NUM2INT(_len); + blake2->output = (uint8_t*)malloc(blake2->output_length * sizeof(uint8_t)); + + return Qnil; +} + + +VALUE m_blake2_digest(VALUE self, VALUE _input, VALUE _representation) { + Blake2 *blake2; + + char *input = RSTRING_PTR(_input); + int input_length = RSTRING_LEN(_input); + int i; + + Data_Get_Struct(self, Blake2, blake2); + + blake2b(blake2->output, input, blake2->key_bytes, + blake2->output_length, input_length, blake2->key_length); + + VALUE result; + + if(_representation == blake2->to_bytes) { + result = rb_ary_new2(blake2->output_length); + + for(i = 0; i < blake2->output_length; i++) { + rb_ary_push(result, INT2NUM(blake2->output[i])); + } + } else if(_representation == blake2->to_hex) { + int ary_len = blake2->output_length * sizeof(char) * 2; + char *c_str = (char*)malloc(ary_len + 1); + + for(i = 0; i < blake2->output_length; i++) { + sprintf(c_str + (i * 2), "%02x", blake2->output[i]); + } + c_str[ary_len] = 0; + + result = rb_str_new(c_str, ary_len); + + if(RSTRING_LEN(result) != ary_len) { + rb_raise(rb_eRuntimeError, "m_blake2_digest: sizes don't match. Ary: %d != %d", RSTRING_LEN(result), ary_len); + } + + free(c_str); + } else { + rb_raise(rb_eArgError, "unknown representation :%"PRIsVALUE"", _representation); + } + + return result; +} + +void Init_blake2_ext() { + cBlake2 = rb_define_class("Blake2b", rb_cObject); + rb_define_alloc_func(cBlake2, blake2_alloc); + + rb_define_private_method(cBlake2, "initialize", RUBY_METHOD_FUNC(m_blake2_initialize), 2); + rb_define_method(cBlake2, "digest", RUBY_METHOD_FUNC(m_blake2_digest), 2); +} diff --git a/lib/blake2b.rb b/lib/blake2b.rb new file mode 100755 index 0000000..907bc1a --- /dev/null +++ b/lib/blake2b.rb @@ -0,0 +1,29 @@ +require 'blake2b_ext' +require 'blake2b/key' + +class Blake2b + def self.hex(input, key = Blake2::Key.none, out_len = 32) + check_if_valid!(input, key, out_len) + Blake2b.new(out_len, key).digest(input, :to_hex) + end + + def self.bytes(input, key = Blake2::Key.none, out_len = 32) + check_if_valid!(input, key, out_len) + Blake2b.new(out_len, key).digest(input, :to_bytes) + end + + def self.check_if_valid!(input, key, out_len) + unless input.is_a?(String) + raise ArgumentError, 'input arg must be a String' + end + + unless key.is_a?(Blake2::Key) + raise ArgumentError, 'key arg must be a Blake2b::Key' + end + + unless out_len.is_a?(Integer) && out_len.between?(1, 32) + raise ArgumentError, 'out_len arg must be an Integer between 1 and 32 inclusive' + end + end + private_class_method :check_if_valid! +end diff --git a/lib/blake2b/key.rb b/lib/blake2b/key.rb new file mode 100755 index 0000000..05bb441 --- /dev/null +++ b/lib/blake2b/key.rb @@ -0,0 +1,55 @@ +class Blake2b + # Validate and normalize an HMAC key, provided in different formats, + # into an Array of Integer Bytes. + class Key + attr_reader :bytes + + def initialize(bytes) + @bytes = bytes + end + + # Create a blank Key + # + # @return [Blake2b::Key] a Blake2::Key object with a `bytes` attr + def self.none + new([]) + end + + # Create a key from an ASCII String + # + # @param str [String] an ASCII String key + # @return [Blake2b::Key] a Blake2::Key object with a `bytes` attr + def self.from_string(str) + if str.is_a?(String) && str.ascii_only? + new(str.bytes) + else + raise ArgumentError, 'key must be an ASCII String' + end + end + + # Create a key from a Hex String [a-fA-F0-9] + # + # @param str [String] a Hex String key + # @return [Blake2b::Key] a Blake2::Key object with a `bytes` attr + def self.from_hex(str) + if str.is_a?(String) && str.match(/^[a-fA-F0-9]+$/) + new([str].pack('H*').bytes) + else + raise ArgumentError, 'key must be a Hex String [a-fA-F0-9]' + end + end + + # Create a key from Array of Integer (0-255) Bytes. + # This simply validates and passes through the Array. + # + # @param str [Array] an Array of Integer (0-255) Bytes + # @return [Blake2b::Key] a Blake2b::Key object with a `bytes` attr + def self.from_bytes(bytes) + if bytes.all? { |b| b.is_a?(Integer) && b.between?(0, 255) } + new(bytes) + else + raise ArgumentError, 'key must be a Byte Array of Integers (0-255)' + end + end + end +end diff --git a/test/blake2/key_test.rb b/test/blake2/key_test.rb new file mode 100755 index 0000000..24d9446 --- /dev/null +++ b/test/blake2/key_test.rb @@ -0,0 +1,42 @@ +require 'test_helper' + +class KeyTest < MiniTest::Test + def test_none + key = Blake2::Key.none + assert_equal [], key.bytes + end + + def test_from_string + key = Blake2::Key.from_string('foo bar baz') + assert_equal [102, 111, 111, 32, 98, 97, 114, 32, 98, 97, 122], key.bytes + end + + def test_from_string_raises_on_non_ascii_string + assert_raises(ArgumentError) { Blake2::Key.from_string('💩') } + end + + def test_from_hex + key = Blake2::Key.from_hex('DEADBEAF') + assert_equal [222, 173, 190, 175], key.bytes + end + + def test_from_hex_raises_on_non_hex_string + assert_raises(ArgumentError) { Blake2::Key.from_hex('DEADBEAFZZ') } + end + + def test_from_bytes_hex + key = Blake2::Key.from_bytes([0xDE, 0xAD, 0xBE, 0xAF]) + assert_equal [222, 173, 190, 175], key.bytes + end + + def test_from_bytes_int + key = Blake2::Key.from_bytes([222, 173, 190, 175]) + assert_equal [222, 173, 190, 175], key.bytes + end + + def test_from_hex_raises_on_non_valid_byte_array + assert_raises(ArgumentError) { Blake2::Key.from_bytes([-1]) } + assert_raises(ArgumentError) { Blake2::Key.from_bytes([256]) } + assert_raises(ArgumentError) { Blake2::Key.from_bytes(['foo']) } + end +end diff --git a/test/blake2b_api_test.rb b/test/blake2b_api_test.rb new file mode 100755 index 0000000..5a62217 --- /dev/null +++ b/test/blake2b_api_test.rb @@ -0,0 +1,60 @@ +require 'test_helper' + +class Blake2bTest < MiniTest::Test + def test_hex_with_input_only + res = Blake2b.hex('abc') + assert_kind_of String, res + assert_equal '508c5e8c327c14e2e1a72ba34eeb452f37458b209ed63a294d999b4c86675982', res + end + + def test_hex_with_input_and_key + res = Blake2b.hex('abc', Blake2b::Key.none) + assert_kind_of String, res + assert_equal '508c5e8c327c14e2e1a72ba34eeb452f37458b209ed63a294d999b4c86675982', res + end + + def test_hex_with_input_key_and_length + res = Blake2b.hex('abc', Blake2b::Key.none, 32) + assert_kind_of String, res + assert_equal '508c5e8c327c14e2e1a72ba34eeb452f37458b209ed63a294d999b4c86675982', res + end + + def test_bytes_with_input_only + res = Blake2b.bytes('abc') + assert_kind_of Array, res + assert_equal [80, 140, 94, 140, 50, 124, 20, 226, 225, 167, 43, 163, 78, 235, 69, 47, 55, 69, 139, 32, 158, 214, 58, 41, 77, 153, 155, 76, 134, 103, 89, 130], res + end + + def test_bytes_with_input_and_key + res = Blake2b.bytes('abc', Blake2b::Key.none) + assert_kind_of Array, res + assert_equal [80, 140, 94, 140, 50, 124, 20, 226, 225, 167, 43, 163, 78, 235, 69, 47, 55, 69, 139, 32, 158, 214, 58, 41, 77, 153, 155, 76, 134, 103, 89, 130], res + end + + def test_bytes_with_input_key_and_length + res = Blake2b.bytes('abc', Blake2b::Key.none, 32) + assert_kind_of Array, res + assert_equal [80, 140, 94, 140, 50, 124, 20, 226, 225, 167, 43, 163, 78, 235, 69, 47, 55, 69, 139, 32, 158, 214, 58, 41, 77, 153, 155, 76, 134, 103, 89, 130], res + end + + def test_input_raises_on_non_string + assert_raises(ArgumentError) { Blake2b.hex(nil) } + assert_raises(ArgumentError) { Blake2b.bytes(nil) } + end + + def test_key_raises_on_non_key + assert_raises(ArgumentError) { Blake2b.hex('abc', []) } + assert_raises(ArgumentError) { Blake2b.bytes('abc', []) } + end + + def test_length_raises_on_invalid + assert_raises(ArgumentError) { Blake2b.hex('abc', Blake2b::Key.none, -1) } + assert_raises(ArgumentError) { Blake2b.hex('abc', Blake2b::Key.none, 0) } + assert_raises(ArgumentError) { Blake2b.hex('abc', Blake2b::Key.none, 33) } + assert_raises(ArgumentError) { Blake2b.hex('abc', Blake2b::Key.none, '32') } + assert_raises(ArgumentError) { Blake2b.bytes('abc', Blake2b::Key.none, -1) } + assert_raises(ArgumentError) { Blake2b.bytes('abc', Blake2b::Key.none, 0) } + assert_raises(ArgumentError) { Blake2b.bytes('abc', Blake2b::Key.none, 33) } + assert_raises(ArgumentError) { Blake2b.bytes('abc', Blake2b::Key.none, '32') } + end +end diff --git a/test/blake2b_test.rb b/test/blake2b_test.rb new file mode 100755 index 0000000..dfd67df --- /dev/null +++ b/test/blake2b_test.rb @@ -0,0 +1,25 @@ +require 'test_helper' + +class Blake2bTest < MiniTest::Test + def setup + out_len = 32 + key = Blake2b::Key.from_string('foo bar baz') + + @digestor = Blake2b.new(out_len, key) + + @input = 'hello world' + @expected = '95670379036532875f58bf23fbcb549675b656bd639a6124a614ccd8a980b180' + end + + def test_to_hex + res = @digestor.digest(@input, :to_hex) + assert_kind_of String, res + assert_equal @expected, res + end + + def test_to_bytes + res = @digestor.digest(@input, :to_bytes) + assert_kind_of Array, res + assert_equal [@expected].pack('H*').bytes, res + end +end diff --git a/test/blake2b_vector_test.rb b/test/blake2b_vector_test.rb new file mode 100755 index 0000000..c79c3cb --- /dev/null +++ b/test/blake2b_vector_test.rb @@ -0,0 +1,593 @@ +# rubocop:disable MethodLength, ClassLength, WordArray, LineLength +require 'test_helper' + +# These test vectors are taken from blake2s-js npm package +# https://github.com/dchest/blake2s-js/blob/master/test/test.js +# +class Blake2bVectorTest < MiniTest::Test + def setup + @golden = [ + '69217a3079908094e11121d042354a7c1f55b6482ca1a51e1b250dfd1ed0eef9', + 'e34d74dbaf4ff4c6abd871cc220451d2ea2648846c7757fbaac82fe51ad64bea', + 'ddad9ab15dac4549ba42f49d262496bef6c0bae1dd342a8808f8ea267c6e210c', + 'e8f91c6ef232a041452ab0e149070cdd7dd1769e75b3a5921be37876c45c9900', + '0cc70e00348b86ba2944d0c32038b25c55584f90df2304f55fa332af5fb01e20', + 'ec1964191087a4fe9df1c795342a02ffc191a5b251764856ae5b8b5769f0c6cd', + 'e1fa51618d7df4eb70cf0d5a9e906f806e9d19f7f4f01e3b621288e4120405d6', + '598001fafbe8f94ec66dc827d012cfcbba2228569f448e89ea2208c8bf769293', + 'c7e887b546623635e93e0495598f1726821996c2377705b93a1f636f872bfa2d', + 'c315a437dd28062a770d481967136b1b5eb88b21ee53d0329c5897126e9db02c', + 'bb473deddc055fea6228f207da575347bb00404cd349d38c18026307a224cbff', + '687e1873a8277591bb33d9adf9a13912efefe557cafc39a7952623e47255f16d', + '1ac7ba754d6e2f94e0e86c46bfb262abbb74f450ef456d6b4d97aa80ce6da767', + '012c97809614816b5d9494477d4b687d15b96eb69c0e8074a8516f31224b5c98', + '91ffd26cfa4da5134c7ea262f7889c329f61f6a657225cc212f40056d986b3f4', + 'd97c828d8182a72180a06a78268330673f7c4e0635947c04c02323fd45c0a52d', + 'efc04cdc391c7e9119bd38668a534e65fe31036d6a62112e44ebeb11f9c57080', + '992cf5c053442a5fbc4faf583e04e50bb70d2f39fbb6a503f89e56a63e18578a', + '38640e9f21983e67b539caccae5ecf615ae2764f75a09c9c59b76483c1fbc735', + '213dd34c7efe4fb27a6b35f6b4000d1fe03281af3c723e5c9f94747a5f31cd3b', + 'ec246eeeb9ced3f7ad33ed28660dd9bb0732513db4e2fa278b60cde3682a4ccd', + 'ac9b61d446648c3005d7892bf3a8719f4c8181cfdcbc2b79fef10a279b911095', + '7bf8b22959e34e3a43f7079223e83a9754617d391e213dfd808e41b9bead4ce7', + '68d4b5d4fa0e302b64ccc5af792913ac4c88ec95c07ddf40694256eb88ce9f3d', + 'b2c2420f05f9abe36315919336b37e4e0fa33ff7e76a492767006fdb5d935462', + '134f61bbd0bbb69aed5343904551a3e6c1aa7dcdd77e903e7023eb7c60320aa7', + '4693f9bff7d4f3986a7d176e6e06f72ad1490d805c99e25347b8de77b4db6d9b', + '853e26f741953b0fd5bdb424e8ab9e8b3750eaa8ef61e47902c91e554e9c73b9', + 'f7de536361abaa0e158156cf0ea4f63a99b5e4054f8fa4c9d45f6285cad55694', + '4c230608860a99ae8d7bd5c2cc17fa52096b9a61bedb17cb7617864ad29ca7a6', + 'aeb920ea87952dadb1fb759291e3388139a872865001886ed84752e93c250c2a', + 'aba4ad9b480b9df3d08ca5e87b0c2440d4e4ea21224c2eb42cbae469d089b931', + '05825607d7fdf2d82ef4c3c8c2aea961ad98d60edff7d018983e21204c0d93d1', + 'a742f8b6af82d8a6ca2357c5f1cf91defbd066267d75c048b352366585025962', + '2bcac89599000b42c95ae23835a713704ed79789c84fef149a874ff733f017a2', + 'ac1ed07d048f105a9e5b7ab85b09a492d5baff14b8bfb0e9fd789486eea2b974', + 'e48d0ecfaf497d5b27c25d99e156cb0579d440d6e31fb62473696dbf95e010e4', + '12a91fadf8b21644fd0f934f3c4a8f62ba862ffd20e8e961154c15c13884ed3d', + '7cbee96e139897dc98fbef3be81ad4d964d235cb12141fb66727e6e5df73a878', + 'ebf66abb597ae572a7297cb0871e355accafad8377b8e78bf164ce2a18de4baf', + '71b933b07e4ff7818ce059d008829e453c6ff02ec0a7db393fc2d870f37a7286', + '7cf7c51331220b8d3ebaed9c29398a16d98156e2613cb088f2b0e08a1be4cf4f', + '3e41a108e0f64ad276b979e1ce068279e16f7bc7e4aa1d211e17b81161df1602', + '886502a82ab47ba8d86710aa9de3d46ea65c47af6ee8de450cceb8b11b045f50', + 'c021bc5f0954fee94f46ea09487e10a84840d02f64810bc08d9e551f7d416814', + '2030516e8a5fe19ae79c336fce26382a749d3fd0ec91e537d4bd2358c12dfb22', + '556698dac8317fd36dfbdf25a79cb112d5425860605cbaf507f23bf7e9f42afe', + '2f867ba67773fdc3e92fced99a6409ad39d0b880fde8f109a81730c4451d0178', + '172ec218f119dfae98896dff29dd9876c94af87417f9ae4c7014bb4e4b96afc7', + '3f85814a18195f879aa962f95d26bd82a278f2b82320218f6b3bd6f7f667a6d9', + '1b618fbaa566b3d498c12e982c9ec52e4da85a8c54f38f34c090394f23c184c1', + '0c758fb5692ffd41a3575d0af00cc7fbf2cbe5905a58323a88ae4244f6e4c993', + 'a931360cad628c7f12a6c1c4b753b0f4062aef3ce65a1ae3f19369dadf3ae23d', + 'cbac7d773b1e3b3c6691d7abb7e9df045c8ba19268ded153207f5e804352ec5d', + '23a196d3802ed3c1b384019a82325840d32f71950c4580b03445e0898e14053c', + 'f4495470f226c8c214be08fdfad4bc4a2a9dbea9136a210df0d4b64929e6fc14', + 'e290dd270b467f34ab1c002d340fa016257ff19e5833fdbbf2cb401c3b2817de', + '9fc7b5ded3c15042b2a6582dc39be016d24a682d5e61ad1eff9c63309848f706', + '8cca67a36d17d5e6341cb592fd7bef9926c9e3aa1027ea11a7d8bd260b576e04', + '409392f560f86831da4373ee5e0074260595d7bc24183b60ed700d4583d3f6f0', + '2802165de090915546f3398cd849164a19f92adbc361adc99b0f20c8ea071054', + 'ad839168d9f8a4be95ba9ef9a692f07256ae43fe6f9864e290691b0256ce50a9', + '75fdaa5038c284b86d6e8affe8b2807e467b86600e79af3689fbc06328cbf894', + 'e57cb79487dd57902432b250733813bd96a84efce59f650fac26e6696aefafc3', + '56f34e8b96557e90c1f24b52d0c89d51086acf1b00f634cf1dde9233b8eaaa3e', + '1b53ee94aaf34e4b159d48de352c7f0661d0a40edff95a0b1639b4090e974472', + '05705e2a81757c14bd383ea98dda544eb10e6bc07bae435e2518dbe133525375', + 'd8b2866e8a309db53e529ec32911d82f5ca16cff76216891a9676aa31aaa6c42', + 'f5041c241270eb04c71ec2c95d4c38d803b1237b0f29fd4db3eb397669e88699', + '9a4ce077c349322f595e0ee79ed0da5fab66752cbfef8f87d0e9d0723c7530dd', + '657b09f3d0f52b5b8f2f97163a0edf0c04f075408a07bbeb3a4101a891990d62', + '1e3f7bd5a58fa533344aa8ed3ac122bb9e70d4ef50d004530821948f5fe6315a', + '80dccf3fd83dfd0d35aa28585922ab89d5313997673eaf905cea9c0b225c7b5f', + '8a0d0fbf6377d83bb08b514b4b1c43acc95d751714f8925645cb6bc856ca150a', + '9fa5b487738ad2844cc6348a901918f659a3b89e9c0dfeead30dd94bcf42ef8e', + '80832c4a1677f5ea2560f668e9354dd36997f03728cfa55e1b38337c0c9ef818', + 'ab37ddb683137e74080d026b590b96ae9bb447722f305a5ac570ec1df9b1743c', + '3ee735a694c2559b693aa68629361e15d12265ad6a3dedf488b0b00fac9754ba', + 'd6fcd23219b647e4cbd5eb2d0ad01ec8838a4b2901fc325cc3701981ca6c888b', + '0520ec2f5bf7a755dacb50c6bf233e3515434763db0139ccd9faefbb8207612d', + 'aff3b75f3f581264d7661662b92f5ad37c1d32bd45ff81a4ed8adc9ef30dd989', + 'd0dd650befd3ba63dc25102c627c921b9cbeb0b130686935b5c927cb7ccd5e3b', + 'e1149816b10a8514fb3e2cab2c08bee9f73ce76221701246a589bbb67302d8a9', + '7da3f441de9054317e72b5dbf979da01e6bceebb8478eae6a22849d90292635c', + '1230b1fc8a7d9215edc2d4a2decbdd0a6e216c924278c91fc5d10e7d60192d94', + '5750d716b4808f751febc38806ba170bf6d5199a7816be514e3f932fbe0cb871', + '6fc59b2f10feba954aa6820b3ca987ee81d5cc1da3c63ce827301c569dfb39ce', + 'c7c3fe1eebdc7b5a939326e8ddb83e8bf2b780b65678cb62f208b040abdd35e2', + '0c75c1a15cf34a314ee478f4a5ce0b8a6b36528ef7a820696c3e4246c5a15864', + '216dc12a108569a3c7cdde4aed43a6c330139dda3ccc4a108905db3861899050', + 'a57be6ae6756f28b02f59dadf7e0d7d8807f10fa15ced1ad3585521a1d995a89', + '816aef875953716cd7a581f732f53dd435dab66d09c361d2d6592de17755d8a8', + '9a76893226693b6ea97e6a738f9d10fb3d0b43ae0e8b7d8123ea76ce97989c7e', + '8daedb9a271529dbb7dc3b607fe5eb2d3211770758dd3b0a3593d2d7954e2d5b', + '16dbc0aa5dd2c774f505100f733786d8a175fcbbb59c43e1fbff3e1eaf31cb4a', + '8606cb899c6aeaf51b9db0fe4924a9fd5dabc19f8826f2bc1c1d7da14d2c2c99', + '8479731aeda57bd37eadb51a507e307f3bd95e69dbca94f3bc21726066ad6dfd', + '58473a9ea82efa3f3b3d8fc83ed8863127b33ae8deae6307201edb6dde61de29', + '9a9255d53af116de8ba27ce35b4c7e15640657a0fcb888c70d95431dacd8f830', + '9eb05ffba39fd8596a45493e18d2510bf3ef065c51d6e13abe66aa57e05cfdb7', + '81dcc3a505eace3f879d8f702776770f9df50e521d1428a85daf04f9ad2150e0', + 'e3e3c4aa3acbbc85332af9d564bc24165e1687f6b1adcbfae77a8f03c72ac28c', + '6746c80b4eb56aea45e64e7289bba3edbf45ecf8206481ff6302122984cd526a', + '2b628e52764d7d62c0868b212357cdd12d9149822f4e9845d918a08d1ae990c0', + 'e4bfe80d58c91994613909dc4b1a12496896c004af7b5701483de45d2823d78e', + 'ebb4ba150cef2734345b5d641bbed03a21eafae933c99e009212ef04574a8530', + '3966ec73b154acc697ac5cf5b24b40bdb0db9e398836d76d4b880e3b2af1aa27', + 'ef7e4831b3a84636518d6e4bfce64a43db2a5dda9cca2b44f39033bdc40d6243', + '7abf6acf5c8e549ddbb15ae8d8b388c1c197e698737c9785501ed1f94930b7d9', + '88018ded66813f0ca95def474c630692019967b9e36888dadd94124719b682f6', + '3930876b9fc7529036b008b1b8bb997522a441635a0c25ec02fb6d9026e55a97', + '0a4049d57e833b5695fac93dd1fbef3166b44b12ad11248662383ae051e15827', + '81dcc0678bb6a765e48c3209654fe90089ce44ff5618477e39ab286476df052b', + 'e69b3a36a4461912dc08346b11ddcb9db796f885fd01936e662fe29297b099a4', + '5ac6503b0d8da6917646e6dcc87edc58e94245324cc204f4dd4af01563acd427', + 'df6dda21359a30bc271780971c1abd56a6ef167e480887888e73a86d3bf605e9', + 'e8e6e47071e7b7df2580f225cfbbedf84ce67746626628d33097e4b7dc571107', + '53e40ead62051e19cb9ba8133e3e5c1ce00ddcad8acf342a224360b0acc14777', + '9ccd53fe80be786aa984638462fb28afdf122b34d78f4687ec632bb19de2371a', + 'cbd48052c48d788466a3e8118c56c97fe146e5546faaf93e2bc3c47e45939753', + '256883b14e2af44dadb28e1b34b2ac0f0f4c91c34ec9169e29036158acaa95b9', + '4471b91ab42db7c4dd8490ab95a2ee8d04e3ef5c3d6fc71ac74b2b26914d1641', + 'a5eb08038f8f1155ed86e631906fc13095f6bba41de5d4e795758ec8c8df8af1', + 'dc1db64ed8b48a910e060a6b866374c578784e9ac49ab2774092ac71501934ac', + '285413b2f2ee873d34319ee0bbfbb90f32da434cc87e3db5ed121bb398ed964b', + '0216e0f81f750f26f1998bc3934e3e124c9945e685a60b25e8fbd9625ab6b599', + '38c410f5b9d4072050755b31dca89fd5395c6785eeb3d790f320ff941c5a93bf', + 'f18417b39d617ab1c18fdf91ebd0fc6d5516bb34cf39364037bce81fa04cecb1', + '1fa877de67259d19863a2a34bcc6962a2b25fcbf5cbecd7ede8f1fa36688a796', + '5bd169e67c82c2c2e98ef7008bdf261f2ddf30b1c00f9e7f275bb3e8a28dc9a2', + 'c80abeebb669ad5deeb5f5ec8ea6b7a05ddf7d31ec4c0a2ee20b0b98caec6746', + 'e76d3fbda5ba374e6bf8e50fadc3bbb9ba5c206ebdec89a3a54cf3dd84a07016', + '7bba9dc5b5db2071d17752b1044c1eced96aaf2dd46e9b433750e8ea0dcc1870', + 'f29b1b1ab9bab163018ee3da15232cca78ec52dbc34eda5b822ec1d80fc21bd0', + '9ee3e3e7e900f1e11d308c4b2b3076d272cf70124f9f51e1da60f37846cdd2f4', + '70ea3b0176927d9096a18508cd123a290325920a9d00a89b5de04273fbc76b85', + '67de25c02a4aaba23bdc973c8bb0b5796d47cc0659d43dff1f97de174963b68e', + 'b2168e4e0f18b0e64100b517ed95257d73f0620df885c13d2ecf79367b384cee', + '2e7dec2428853b2c71760745541f7afe9825b5dd77df06511d8441a94bacc927', + 'ca9ffac4c43f0b48461dc5c263bea3f6f00611ceacabf6f895ba2b0101dbb68d', + '7410d42d8fd1d5e9d2f5815cb93417998828ef3c4230bfbd412df0a4a7a2507a', + '5010f684516dccd0b6ee0852c2512b4dc0066cf0d56f35302978db8ae32c6a81', + 'acaab585f7b79b719935ceb89523ddc54827f75c56883856154a56cdcd5ee988', + '666de5d1440fee7331aaf0123a62ef2d8ba57453a0769635ac6cd01e633f7712', + 'a6f98658f6eabaf902d8b3871a4b101d16196e8a4b241e1558fe29966e103e8d', + '891546a8b29f3047ddcfe5b00e45fd55756373105ea8637dfcff547b6ea9535f', + '18dfbc1ac5d25b0761137dbd22c17c829d0f0ef1d82344e9c89c286694da24e8', + 'b54b9b67f8fed54bbf5a2666dbdf4b23cff1d1b6f4afc985b2e6d3305a9ff80f', + '7db442e132ba59bc1289aa98b0d3e806004f8ec12811af1e2e33c69bfde729e1', + '250f37cdc15e817d2f160d9956c71fe3eb5db74556e4adf9a4ffafba74010396', + '4ab8a3dd1ddf8ad43dab13a27f66a6544f290597fa96040e0e1db9263aa479f8', + 'ee61727a0766df939ccdc860334044c79a3c9b156200bc3aa32973483d8341ae', + '3f68c7ec63ac11ebb98f94b339b05c104984fda50103060144e5a2bfccc9da95', + '056f29816b8af8f56682bc4d7cf094111da7733e726cd13d6b3e8ea03e92a0d5', + 'f5ec43a28acbeff1f3318a5bcac7c66ddb5230b79db2d105bcbe15f3c1148d69', + '2a6960ad1d8dd547555cfbd5e4600f1eaa1c8eda34de0374ec4a26eaaaa33b4e', + 'dcc1ea7baab93384f76b796866199754742f7b96d6b4c120165c04a6c4f5ce10', + '13d5df179221379c6a78c07c793ff53487cae6bf9fe882541ab0e735e3eada3b', + '8c59e4407641a01e8ff91f9980dc236f4ecd6fcf52589a099a961633967714e1', + '833b1ac6a251fd08fd6d908fea2a4ee1e040bca93fc1a38ec3820e0c10bd82ea', + 'a244f927f3b40b8f6c391570c765418f2f6e708eac9006c51a7feff4af3b2b9e', + '3d99ed9550cf1196e6c4d20c259620f858c3d703374c128ce7b590310c83046d', + '2b35c47d7b87761f0ae43ac56ac27b9f25830367b595be8c240e94600c6e3312', + '5d11ed37d24dc767305cb7e1467d87c065ac4bc8a426de38991ff59aa8735d02', + 'b836478e1ca0640dce6fd910a5096272c8330990cd97864ac2bf14ef6b23914a', + '9100f946d6ccde3a597f90d39fc1215baddc7413643d85c21c3eee5d2dd32894', + 'da70eedd23e663aa1a74b9766935b479222a72afba5c795158dad41a3bd77e40', + 'f067ed6a0dbd43aa0a9254e69fd66bdd8acb87de936c258cfb02285f2c11fa79', + '715c99c7d57580cf9753b4c1d795e45a83fbb228c0d36fbe20faf39bdd6d4e85', + 'e457d6ad1e67cb9bbd17cbd698fa6d7dae0c9b7ad6cbd6539634e32a719c8492', + 'ece3ea8103e02483c64a70a4bdcee8ceb6278f2533f3f48dbeedfba94531d4ae', + '388aa5d3667a97c68d3d56f8f3ee8d3d36091f17fe5d1b0d5d84c93b2ffe40bd', + '8b6b31b9ad7c3d5cd84bf98947b9cdb59df8a25ff738101013be4fd65e1dd1a3', + '066291f6bbd25f3c853db7d8b95c9a1cfb9bf1c1c99fb95a9b7869d90f1c2903', + 'a707efbccdceed42967a66f5539b93ed7560d467304016c4780d7755a565d4c4', + '38c53dfb70be7e792b07a6a35b8a6a0aba02c5c5f38baf5c823fdfd9e42d657e', + 'f2911386501d9ab9d720cf8ad10503d5634bf4b7d12b56dfb74fecc6e4093f68', + 'c6f2bdd52b81e6e4f6595abd4d7fb31f651169d00ff326926b34947b28a83959', + '293d94b18c98bb3223366b8ce74c28fbdf28e1f84a3350b0eb2d1804a577579b', + '2c2fa5c0b51533165bc375c22e2781768270a383985d13bd6b67b6fd67f889eb', + 'caa09b82b72562e43f4b2275c091918e624d911661cc811bb5faec51f6088ef7', + '24761e45e674395379fb17729c78cb939e6f74c5dffb9c961f495982c3ed1fe3', + '55b70a82131ec94888d7ab54a7c515255c3938bb10bc784dc9b67f076e341a73', + '6ab9057b977ebc3ca4d4ce74506c25cccdc566497c450b5415a39486f8657a03', + '24066deee0ecee15a45f0a326d0f8dbc79761ebb93cf8c0377af440978fcf994', + '20000d3f66ba76860d5a950688b9aa0d76cfea59b005d859914b1a46653a939b', + 'b92daa79603e3bdbc3bfe0f419e409b2ea10dc435beefe2959da16895d5dca1c', + 'e947948705b206d572b0e8f62f66a6551cbd6bc305d26ce7539a12f9aadf7571', + '3d67c1b3f9b23910e3d35e6b0f2ccf44a0b540a45c18ba3c36264dd48e96af6a', + 'c7558babda04bccb764d0bbf3358425141902d22391d9f8c59159fec9e49b151', + '0b732bb035675a50ff58f2c242e4710aece64670079c13044c79c9b7491f7000', + 'd120b5ef6d57ebf06eaf96bc933c967b16cbe6e2bf00741c30aa1c54ba64801f', + '58d212ad6f58aef0f80116b441e57f6195bfef26b61463edec1183cdb04fe76d', + 'b8836f51d1e29bdfdba325565360268b8fad627473edecef7eaefee837c74003', + 'c547a3c124ae5685ffa7b8edaf96ec86f8b2d0d50cee8be3b1f0c76763069d9c', + '5d168b769a2f67853d6295f7568be40bb7a16b8d65ba87635d1978d2ab11ba2a', + 'a2f675dc7302638cb60201064ca55077714d71fe096a315f2fe7401277caa5af', + 'c8aab5cd0160ae78cd2e8ac5fb0e093cdb5c4b6052a0a97bb04216826fa7a437', + 'ff68ca4035bfeb43fbf145fddd5e43f1cea54f11f7bee13058f027329a4a5fa4', + '1d4e5487ae3c740f2ba6e541ac91bc2bfcd2999c518d807b426748803a350fd4', + '6d244e1a06ce4ef578dd0f63aff0936706735119ca9c8d22d86c801414ab9741', + 'decf7329dbcc827b8fc524c9431e8998029ece12ce93b7b2f3e769a941fb8cea', + '2fafcc0f2e63cbd07755be7b75ecea0adff9aa5ede2a52fdab4dfd0374cd483f', + 'aa85010dd46a546b535ef4cf5f07d65161e89828f3a77db7b9b56f0df59aae45', + '07e8e1ee732cb0d356c9c0d1069c89d17adf6a9a334f745ec7867332548ca8e9', + '0e01e81cada8162bfd5f8a8c818a6c69fedf02ceb5208523cbe5313b89ca1053', + '6bb6c6472655084399852e00249f8cb247896d392b02d73b7f0dd818e1e29b07', + '42d4636e2060f08f41c882e76b396b112ef627cc24c43dd5f83a1d1a7ead711a', + '4858c9a188b0234fb9a8d47d0b4133650a030bd0611b87c3892e94951f8df852', + '3fab3e36988d445a51c8783e531be3a02be40cd04796cfb61d40347442d3f794', + 'ebabc49636bd433d2ec8f0e518732ef8fa21d4d071cc3bc46cd79fa38a28b810', + 'a1d0343523b893fca84f47feb4a64d350a17d8eef5497ece697d02d79178b591', + '262ebfd9130b7d28760d08ef8bfd3b86cdd3b2113d2caef7ea951a303dfa3846', + 'f76158edd50a154fa78203ed2362932fcb8253aae378903eded1e03f7021a257', + '26178e950ac722f67ae56e571b284c0207684a6334a17748a94d260bc5f55274', + 'c378d1e493b40ef11fe6a15d9c2737a37809634c5abad5b33d7e393b4ae05d03', + '984bd8379101be8fd80612d8ea2959a7865ec9718523550107ae3938df32011b', + 'c6f25a812a144858ac5ced37a93a9f4759ba0b1c0fdc431dce35f9ec1f1f4a99', + '924c75c94424ff75e74b8b4e94358958b027b171df5e57899ad0d4dac37353b6', + '0af35892a63f45931f6846ed190361cd073089e077165714b50b81a2e3dd9ba1', + 'cc80cefb26c3b2b0daef233e606d5ffc80fa17427d18e30489673e06ef4b87f7', + 'c2f8c8117447f3978b0818dcf6f70116ac56fd184dd1278494e103fc6d74a887', + 'bdecf6bfc1ba0df6e862c831992207796acc797968358828c06e7a51e090098f', + '24d1a26e3dab02fe4572d2aa7dbd3ec30f0693db26f273d0ab2cb0c13b5e6451', + 'ec56f58b09299a300b140565d7d3e68782b6e2fbeb4b7ea97ac057989061dd3f', + '11a437c1aba3c119ddfab31b3e8c841deeeb913ef57f7e48f2c9cf5a28fa42bc', + '53c7e6114b850a2cb496c9b3c69a623eaea2cb1d33dd817e4765edaa6823c228', + '154c3e96fee5db14f8773e18af14857913509da999b46cdd3d4c169760c83ad2', + '40b9916f093e027a8786641818920620472fbcf68f701d1b680632e6996bded3', + '24c4cbba07119831a726b05305d96da02ff8b148f0da440fe233bcaa32c72f6f', + '5d201510250020b783689688abbf8ecf2594a96a08f2bfec6ce0574465dded71', + '043b97e336ee6fdbbe2b50f22af83275a4084805d2d5645962454b6c9b8053a0', + '564835cbaea774948568be36cf52fcdd83934eb0a27512dbe3e2db47b9e6635a', + 'f21c33f47bde40a2a101c9cde8027aaf61a3137de2422b30035a04c270894183', + '9db0ef74e66cbb842eb0e07343a03c5c567e372b3f23b943c788a4f250f67891', + 'ab8d08655ff1d3fe8758d562235fd23e7cf9dcaad658872a49e5d3183b6ccebd', + '6f27f77e7bcf46a1e963ade0309733543031dccdd47caac174d7d27ce8077e8b', + 'e3cd54da7e444caa6207569525a670ebae1278de4e3fe2684b3e33f5ef90cc1b', + 'b2c3e33a51d22c4c08fc0989c873c9cc4150579b1e6163fa694ad51d53d712dc', + 'be7fda983e13189b4c77e0a80920b6e0e0ea80c3b84dbe7e7117d253f48112f4', + 'b6008c28fae08aa427e5bd3aad36f10021f16c77cfeabed07f97cc7dc1f1284a', + '6e4e6760c538f2e97b3adbfbbcde57f8966b7ea8fcb5bf7efec913fd2a2b0c55', + '4ae51fd1834aa5bd9a6f7ec39fc663338dc5d2e20761566d90cc68b1cb875ed8', + 'b673aad75ab1fdb5401abfa1bf89f3add2ebc468df3624a478f4fe859d8d55e2', + '13c9471a9855913539836660398da0f3f99ada08479c69d1b7fcaa3461dd7e59', + '2c11f4a7f99a1d23a58bb636350fe849f29cbac1b2a1112d9f1ed5bc5b313ccd', + 'c7d3c0706b11ae741c05a1ef150dd65b5494d6d54c9a86e2617854e6aeeebbd9', + '194e10c93893afa064c3ac04c0dd808d791c3d4b7556e89d8d9cb225c4b33339', + '6fc4988b8f78546b1688991845908f134b6a482e6994b3d48317bf08db292185', + '5665beb8b0955525813b5981cd142ed4d03fba38a6f3e5ad268e0cc270d1cd11', + 'b883d68f5fe51936431ba4256738053b1d0426d4cb64b16e83badc5e9fbe3b81', + '53e7b27ea59c2f6dbb50769e43554df35af89f4822d0466b007dd6f6deafff02', + '1f1a0229d4640f01901588d9dec22d13fc3eb34a61b32938efbf5334b2800afa', + 'c2b405afa0fa6668852aee4d88040853fab800e72b57581418e5506f214c7d1f', + 'c08aa1c286d709fdc7473744977188c895ba011014247e4efa8d07e78fec695c', + 'f03f5789d3336b80d002d59fdf918bdb775b00956ed5528e86aa994acb38fe2d' + ] + + @golden_keyed = [ + '48a8997da407876b3d79c0d92325ad3b89cbb754d86ab71aee047ad345fd2c49', + '40d15fee7c328830166ac3f918650f807e7e01e177258cdc0a39b11f598066f1', + '6bb71300644cd3991b26ccd4d274acd1adeab8b1d7914546c1198bbe9fc9d803', + '1d220dbe2ee134661fdf6d9e74b41704710556f2f6e5a091b227697445dbea6b', + 'f6c3fbadb4cc687a0064a5be6e791bec63b868ad62fba61b3757ef9ca52e05b2', + '49c1f21188dfd769aea0e911dd6b41f14dab109d2b85977aa3088b5c707e8598', + 'fdd8993dcd43f696d44f3cea0ff35345234ec8ee083eb3cada017c7f78c17143', + 'e6c8125637438d0905b749f46560ac89fd471cf8692e28fab982f73f019b83a9', + '19fc8ca6979d60e6edd3b4541e2f967ced740df6ec1eaebbfe813832e96b2974', + 'a6ad777ce881b52bb5a4421ab6cdd2dfba13e963652d4d6d122aee46548c14a7', + 'f5c4b2ba1a00781b13aba0425242c69cb1552f3f71a9a3bb22b4a6b4277b46dd', + 'e33c4c9bd0cc7e45c80e65c77fa5997fec7002738541509e68a9423891e822a3', + 'fba16169b2c3ee105be6e1e650e5cbf40746b6753d036ab55179014ad7ef6651', + 'f5c4bec6d62fc608bf41cc115f16d61c7efd3ff6c65692bbe0afffb1fede7475', + 'a4862e76db847f05ba17ede5da4e7f91b5925cf1ad4ba12732c3995742a5cd6e', + '65f4b860cd15b38ef814a1a804314a55be953caa65fd758ad989ff34a41c1eea', + '19ba234f0a4f38637d1839f9d9f76ad91c8522307143c97d5f93f69274cec9a7', + '1a67186ca4a5cb8e65fca0e2ecbc5ddc14ae381bb8bffeb9e0a103449e3ef03c', + 'afbea317b5a2e89c0bd90ccf5d7fd0ed57fe585e4be3271b0a6bf0f5786b0f26', + 'f1b01558ce541262f5ec34299d6fb4090009e3434be2f49105cf46af4d2d4124', + '13a0a0c86335635eaa74ca2d5d488c797bbb4f47dc07105015ed6a1f3309efce', + '1580afeebebb346f94d59fe62da0b79237ead7b1491f5667a90e45edf6ca8b03', + '20be1a875b38c573dd7faaa0de489d655c11efb6a552698e07a2d331b5f655c3', + 'be1fe3c4c04018c54c4a0f6b9a2ed3c53abe3a9f76b4d26de56fc9ae95059a99', + 'e3e3ace537eb3edd8463d9ad3582e13cf86533ffde43d668dd2e93bbdbd7195a', + '110c50c0bf2c6e7aeb7e435d92d132ab6655168e78a2decdec3330777684d9c1', + 'e9ba8f505c9c80c08666a701f3367e6cc665f34b22e73c3c0417eb1c2206082f', + '26cd66fca02379c76df12317052bcafd6cd8c3a7b890d805f36c49989782433a', + '213f3596d6e3a5d0e9932cd2159146015e2abc949f4729ee2632fe1edb78d337', + '1015d70108e03be1c702fe97253607d14aee591f2413ea6787427b6459ff219a', + '3ca989de10cfe609909472c8d35610805b2f977734cf652cc64b3bfc882d5d89', + 'b6156f72d380ee9ea6acd190464f2307a5c179ef01fd71f99f2d0f7a57360aea', + 'c03bc642b20959cbe133a0303e0c1abff3e31ec8e1a328ec8565c36decff5265', + '2c3e08176f760c6264c3a2cd66fec6c3d78de43fc192457b2a4a660a1e0eb22b', + 'f738c02f3c1b190c512b1a32deabf353728e0e9ab034490e3c3409946a97aeec', + '8b1880df301cc963418811088964839287ff7fe31c49ea6ebd9e48bdeee497c5', + '1e75cb21c60989020375f1a7a242839f0b0b68973a4c2a05cf7555ed5aaec4c1', + '62bf8a9c32a5bccf290b6c474d75b2a2a4093f1a9e27139433a8f2b3bce7b8d7', + '166c8350d3173b5e702b783dfd33c66ee0432742e9b92b997fd23c60dc6756ca', + '044a14d822a90cacf2f5a101428adc8f4109386ccb158bf905c8618b8ee24ec3', + '387d397ea43a994be84d2d544afbe481a2000f55252696bba2c50c8ebd101347', + '56f8ccf1f86409b46ce36166ae9165138441577589db08cbc5f66ca29743b9fd', + '9706c092b04d91f53dff91fa37b7493d28b576b5d710469df79401662236fc03', + '877968686c068ce2f7e2adcff68bf8748edf3cf862cfb4d3947a3106958054e3', + '8817e5719879acf7024787eccdb271035566cfa333e049407c0178ccc57a5b9f', + '8938249e4b50cadaccdf5b18621326cbb15253e33a20f5636e995d72478de472', + 'f164abba4963a44d107257e3232d90aca5e66a1408248c51741e991db5227756', + 'd05563e2b1cba0c4a2a1e8bde3a1a0d9f5b40c85a070d6f5fb21066ead5d0601', + '03fbb16384f0a3866f4c3117877666efbf124597564b293d4aab0d269fabddfa', + '5fa8486ac0e52964d1881bbe338eb54be2f719549224892057b4da04ba8b3475', + 'cdfabcee46911111236a31708b2539d71fc211d9b09c0d8530a11e1dbf6eed01', + '4f82de03b9504793b82a07a0bdcdff314d759e7b62d26b784946b0d36f916f52', + '259ec7f173bcc76a0994c967b4f5f024c56057fb79c965c4fae41875f06a0e4c', + '193cc8e7c3e08bb30f5437aa27ade1f142369b246a675b2383e6da9b49a9809e', + '5c10896f0e2856b2a2eee0fe4a2c1633565d18f0e93e1fab26c373e8f829654d', + 'f16012d93f28851a1eb989f5d0b43f3f39ca73c9a62d5181bff237536bd348c3', + '2966b3cfae1e44ea996dc5d686cf25fa053fb6f67201b9e46eade85d0ad6b806', + 'ddb8782485e900bc60bcf4c33a6fd585680cc683d516efa03eb9985fad8715fb', + '4c4d6e71aea05786413148fc7a786b0ecaf582cff1209f5a809fba8504ce662c', + 'fb4c5e86d7b2229b99b8ba6d94c247ef964aa3a2bae8edc77569f28dbbff2d4e', + 'e94f526de9019633ecd54ac6120f23958d7718f1e7717bf329211a4faeed4e6d', + 'cbd6660a10db3f23f7a03d4b9d4044c7932b2801ac89d60bc9eb92d65a46c2a0', + '8818bbd3db4dc123b25cbba5f54c2bc4b3fcf9bf7d7a7709f4ae588b267c4ece', + 'c65382513f07460da39833cb666c5ed82e61b9e998f4b0c4287cee56c3cc9bcd', + '8975b0577fd35566d750b362b0897a26c399136df07bababbde6203ff2954ed4', + '21fe0ceb0052be7fb0f004187cacd7de67fa6eb0938d927677f2398c132317a8', + '2ef73f3c26f12d93889f3c78b6a66c1d52b649dc9e856e2c172ea7c58ac2b5e3', + '388a3cd56d73867abb5f8401492b6e2681eb69851e767fd84210a56076fb3dd3', + 'af533e022fc9439e4e3cb838ecd18692232adf6fe9839526d3c3dd1b71910b1a', + '751c09d41a9343882a81cd13ee40818d12eb44c6c7f40df16e4aea8fab91972a', + '5b73ddb68d9d2b0aa265a07988d6b88ae9aac582af83032f8a9b21a2e1b7bf18', + '3da29126c7c5d7f43e64242a79feaa4ef3459cdeccc898ed59a97f6ec93b9dab', + '566dc920293da5cb4fe0aa8abda8bbf56f552313bff19046641e3615c1e3ed3f', + '4115bea02f73f97f629e5c5590720c01e7e449ae2a6697d4d2783321303692f9', + '4ce08f4762468a7670012164878d68340c52a35e66c1884d5c864889abc96677', + '81ea0b7804124e0c22ea5fc71104a2afcb52a1fa816f3ecb7dcb5d9dea1786d0', + 'fe362733b05f6bedaf9379d7f7936ede209b1f8323c3922549d9e73681b5db7b', + 'eff37d30dfd20359be4e73fdf40d27734b3df90a97a55ed745297294ca85d09f', + '172ffc67153d12e0ca76a8b6cd5d4731885b39ce0cac93a8972a18006c8b8baf', + 'c47957f1cc88e83ef9445839709a480a036bed5f88ac0fcc8e1e703ffaac132c', + '30f3548370cfdceda5c37b569b6175e799eef1a62aaa943245ae7669c227a7b5', + 'c95dcb3cf1f27d0eef2f25d2413870904a877c4a56c2de1e83e2bc2ae2e46821', + 'd5d0b5d705434cd46b185749f66bfb5836dcdf6ee549a2b7a4aee7f58007caaf', + 'bbc124a712f15d07c300e05b668389a439c91777f721f8320c1c9078066d2c7e', + 'a451b48c35a6c7854cfaae60262e76990816382ac0667e5a5c9e1b46c4342ddf', + 'b0d150fb55e778d01147f0b5d89d99ecb20ff07e5e6760d6b645eb5b654c622b', + '34f737c0ab219951eee89a9f8dac299c9d4c38f33fa494c5c6eefc92b6db08bc', + '1a62cc3a00800dcbd99891080c1e098458193a8cc9f970ea99fbeff00318c289', + 'cfce55ebafc840d7ae48281c7fd57ec8b482d4b704437495495ac414cf4a374b', + '6746facf71146d999dabd05d093ae586648d1ee28e72617b99d0f0086e1e45bf', + '571ced283b3f23b4e750bf12a2caf1781847bd890e43603cdc5976102b7bb11b', + 'cfcb765b048e35022c5d089d26e85a36b005a2b80493d03a144e09f409b6afd1', + '4050c7a27705bb27f42089b299f3cbe5054ead68727e8ef9318ce6f25cd6f31d', + '184070bd5d265fbdc142cd1c5cd0d7e414e70369a266d627c8fba84fa5e84c34', + '9edda9a4443902a9588c0d0ccc62b930218479a6841e6fe7d43003f04b1fd643', + 'e412feef7908324a6da1841629f35d3d358642019310ec57c614836b63d30763', + '1a2b8edff3f9acc1554fcbae3cf1d6298c6462e22e5eb0259684f835012bd13f', + '288c4ad9b9409762ea07c24a41f04f69a7d74bee2d95435374bde946d7241c7b', + '805691bb286748cfb591d3aebe7e6f4e4dc6e2808c65143cc004e4eb6fd09d43', + 'd4ac8d3a0afc6cfa7b460ae3001baeb36dadb37da07d2e8ac91822df348aed3d', + 'c376617014d20158bced3d3ba552b6eccf84e62aa3eb650e90029c84d13eea69', + 'c41f09f43cecae7293d6007ca0a357087d5ae59be500c1cd5b289ee810c7b082', + '03d1ced1fba5c39155c44b7765cb760c78708dcfc80b0bd8ade3a56da8830b29', + '09bde6f152218dc92c41d7f45387e63e5869d807ec70b821405dbd884b7fcf4b', + '71c9036e18179b90b37d39e9f05eb89cc5fc341fd7c477d0d7493285faca08a4', + '5916833ebb05cd919ca7fe83b692d3205bef72392b2cf6bb0a6d43f994f95f11', + 'f63aab3ec641b3b024964c2b437c04f6043c4c7e0279239995401958f86bbe54', + 'f172b180bfb09740493120b6326cbdc561e477def9bbcfd28cc8c1c5e3379a31', + 'cb9b89cc18381dd9141ade588654d4e6a231d5bf49d4d59ac27d869cbe100cf3', + '7bd8815046fdd810a923e1984aaebdcdf84d87c8992d68b5eeb460f93eb3c8d7', + '607be66862fd08ee5b19facac09dfdbcd40c312101d66e6ebd2b841f1b9a9325', + '9fe03bbe69ab1834f5219b0da88a08b30a66c5913f0151963c360560db0387b3', + '90a83585717b75f0e9b725e055eeeeb9e7a028ea7e6cbc07b20917ec0363e38c', + '336ea0530f4a7469126e0218587ebbde3358a0b31c29d200f7dc7eb15c6aadd8', + 'a79e76dc0abca4396f0747cd7b748df913007626b1d659da0c1f78b9303d01a3', + '44e78a773756e0951519504d7038d28d0213a37e0ce375371757bc996311e3b8', + '77ac012a3f754dcfeab5eb996be9cd2d1f96111b6e49f3994df181f28569d825', + 'ce5a10db6fccdaf140aaa4ded6250a9c06e9222bc9f9f3658a4aff935f2b9f3a', + 'ecc203a7fe2be4abd55bb53e6e673572e0078da8cd375ef430cc97f9f80083af', + '14a5186de9d7a18b0412b8563e51cc5433840b4a129a8ff963b33a3c4afe8ebb', + '13f8ef95cb86e6a638931c8e107673eb76ba10d7c2cd70b9d9920bbeed929409', + '0b338f4ee12f2dfcb78713377941e0b0632152581d1332516e4a2cab1942cca4', + 'eaab0ec37b3b8ab796e9f57238de14a264a076f3887d86e29bb5906db5a00e02', + '23cb68b8c0e6dc26dc27766ddc0a13a99438fd55617aa4095d8f969720c872df', + '091d8ee30d6f2968d46b687dd65292665742de0bb83dcc0004c72ce10007a549', + '7f507abc6d19ba00c065a876ec5657868882d18a221bc46c7a6912541f5bc7ba', + 'a0607c24e14e8c223db0d70b4d30ee88014d603f437e9e02aa7dafa3cdfbad94', + 'ddbfea75cc467882eb3483ce5e2e756a4f4701b76b445519e89f22d60fa86e06', + '0c311f38c35a4fb90d651c289d486856cd1413df9b0677f53ece2cd9e477c60a', + '46a73a8dd3e70f59d3942c01df599def783c9da82fd83222cd662b53dce7dbdf', + 'ad038ff9b14de84a801e4e621ce5df029dd93520d0c2fa38bff176a8b1d1698c', + 'ab70c5dfbd1ea817fed0cd067293abf319e5d7901c2141d5d99b23f03a38e748', + '1fffda67932b73c8ecaf009a3491a026953babfe1f663b0697c3c4ae8b2e7dcb', + 'b0d2cc19472dd57f2b17efc03c8d58c2283dbb19da572f7755855aa9794317a0', + 'a0d19a6ee33979c325510e276622df41f71583d07501b87071129a0ad94732a5', + '724642a7032d1062b89e52bea34b75df7d8fe772d9fe3c93ddf3c4545ab5a99b', + 'ade5eaa7e61f672d587ea03dae7d7b55229c01d06bc0a5701436cbd18366a626', + '013b31ebd228fcdda51fabb03bb02d60ac20ca215aafa83bdd855e3755a35f0b', + '332ed40bb10dde3c954a75d7b8999d4b26a1c063c1dc6e32c1d91bab7bbb7d16', + 'c7a197b3a05b566bcc9facd20e441d6f6c2860ac9651cd51d6b9d2cdeeea0390', + 'bd9cf64ea8953c037108e6f654914f3958b68e29c16700dc184d94a21708ff60', + '8835b0ac021151df716474ce27ce4d3c15f0b2dab48003cf3f3efd0945106b9a', + '3bfefa3301aa55c080190cffda8eae51d9af488b4c1f24c3d9a75242fd8ea01d', + '08284d14993cd47d53ebaecf0df0478cc182c89c00e1859c84851686ddf2c1b7', + '1ed7ef9f04c2ac8db6a864db131087f27065098e69c3fe78718d9b947f4a39d0', + 'c161f2dcd57e9c1439b31a9dd43d8f3d7dd8f0eb7cfac6fb25a0f28e306f0661', + 'c01969ad34c52caf3dc4d80d19735c29731ac6e7a92085ab9250c48dea48a3fc', + '1720b3655619d2a52b3521ae0e49e345cb3389ebd6208acaf9f13fdacca8be49', + '756288361c83e24c617cf95c905b22d017cdc86f0bf1d658f4756c7379873b7f', + 'e7d0eda3452693b752abcda1b55e276f82698f5f1605403eff830bea0071a394', + '2c82ecaa6b84803e044af63118afe544687cb6e6c7df49ed762dfd7c8693a1bc', + '6136cbf4b441056fa1e2722498125d6ded45e17b52143959c7f4d4e395218ac2', + '721d3245aafef27f6a624f47954b6c255079526ffa25e9ff77e5dcff473b1597', + '9dd2fbd8cef16c353c0ac21191d509eb28dd9e3e0d8cea5d26ca839393851c3a', + 'b2394ceacdebf21bf9df2ced98e58f1c3a4bbbff660dd900f62202d6785cc46e', + '57089f222749ad7871765f062b114f43ba20ec56422a8b1e3f87192c0ea718c6', + 'e49a9459961cd33cdf4aae1b1078a5dea7c040e0fea340c93a724872fc4af806', + 'ede67f720effd2ca9c88994152d0201dee6b0a2d2c077aca6dae29f73f8b6309', + 'e0f434bf22e3088039c21f719ffc67f0f2cb5e98a7a0194c76e96bf4e8e17e61', + '277c04e2853484a4eba910ad336d01b477b67cc200c59f3c8d77eef8494f29cd', + '156d5747d0c99c7f27097d7b7e002b2e185cb72d8dd7eb424a0321528161219f', + '20ddd1ed9b1ca803946d64a83ae4659da67fba7a1a3eddb1e103c0f5e03e3a2c', + 'f0af604d3dabbf9a0f2a7d3dda6bd38bba72c6d09be494fcef713ff10189b6e6', + '9802bb87def4cc10c4a5fd49aa58dfe2f3fddb46b4708814ead81d23ba95139b', + '4f8ce1e51d2fe7f24043a904d898ebfc91975418753413aa099b795ecb35cedb', + 'bddc6514d7ee6ace0a4ac1d0e068112288cbcf560454642705630177cba608bd', + 'd635994f6291517b0281ffdd496afa862712e5b3c4e52e4cd5fdae8c0e72fb08', + '878d9ca600cf87e769cc305c1b35255186615a73a0da613b5f1c98dbf81283ea', + 'a64ebe5dc185de9fdde7607b6998702eb23456184957307d2fa72e87a47702d6', + 'ce50eab7b5eb52bdc9ad8e5a480ab780ca9320e44360b1fe37e03f2f7ad7de01', + 'eeddb7c0db6e30abe66d79e327511e61fcebbc29f159b40a86b046ecf0513823', + '787fc93440c1ec96b5ad01c16cf77916a1405f9426356ec921d8dff3ea63b7e0', + '7f0d5eab47eefda696c0bf0fbf86ab216fce461e9303aba6ac374120e890e8df', + 'b68004b42f14ad029f4c2e03b1d5eb76d57160e26476d21131bef20ada7d27f4', + 'b0c4eb18ae250b51a41382ead92d0dc7455f9379fc9884428e4770608db0faec', + 'f92b7a870c059f4d46464c824ec96355140bdce681322cc3a992ff103e3fea52', + '5364312614813398cc525d4c4e146edeb371265fba19133a2c3d2159298a1742', + 'f6620e68d37fb2af5000fc28e23b832297ecd8bce99e8be4d04e85309e3d3374', + '5316a27969d7fe04ff27b283961bffc3bf5dfb32fb6a89d101c6c3b1937c2871', + '81d1664fdf3cb33c24eebac0bd64244b77c4abea90bbe8b5ee0b2aafcf2d6a53', + '345782f295b0880352e924a0467b5fbc3e8f3bfbc3c7e48b67091fb5e80a9442', + '794111ea6cd65e311f74ee41d476cb632ce1e4b051dc1d9e9d061a19e1d0bb49', + '2a85daf6138816b99bf8d08ba2114b7ab07975a78420c1a3b06a777c22dd8bcb', + '89b0d5f289ec16401a069a960d0b093e625da3cf41ee29b59b930c5820145455', + 'd0fdcb543943fc27d20864f52181471b942cc77ca675bcb30df31d358ef7b1eb', + 'b17ea8d77063c709d4dc6b879413c343e3790e9e62ca85b7900b086f6b75c672', + 'e71a3e2c274db842d92114f217e2c0eac8b45093fdfd9df4ca7162394862d501', + 'c0476759ab7aa333234f6b44f5fd858390ec23694c622cb986e769c78edd733e', + '9ab8eabb1416434d85391341d56993c55458167d4418b19a0f2ad8b79a83a75b', + '7992d0bbb15e23826f443e00505d68d3ed7372995a5c3e498654102fbcd0964e', + 'c021b30085151435df33b007ccecc69df1269f39ba25092bed59d932ac0fdc28', + '91a25ec0ec0d9a567f89c4bfe1a65a0e432d07064b4190e27dfb81901fd3139b', + '5950d39a23e1545f301270aa1a12f2e6c453776e4d6355de425cc153f9818867', + 'd79f14720c610af179a3765d4b7c0968f977962dbf655b521272b6f1e194488e', + 'e9531bfc8b02995aeaa75ba27031fadbcbf4a0dab8961d9296cd7e84d25d6006', + '34e9c26a01d7f16181b454a9d1623c233cb99d31c694656e9413aca3e918692f', + 'd9d7422f437bd439ddd4d883dae2a08350173414be78155133fff1964c3d7972', + '4aee0c7aaf075414ff1793ead7eaca601775c615dbd60b640b0a9f0ce505d435', + '6bfdd15459c83b99f096bfb49ee87b063d69c1974c6928acfcfb4099f8c4ef67', + '9fd1c408fd75c336193a2a14d94f6af5adf050b80387b4b010fb29f4cc72707c', + '13c88480a5d00d6c8c7ad2110d76a82d9b70f4fa6696d4e5dd42a066dcaf9920', + '820e725ee25fe8fd3a8d5abe4c46c3ba889de6fa9191aa22ba67d5705421542b', + '32d93a0eb02f42fbbcaf2bad0085b282e46046a4df7ad10657c9d6476375b93e', + 'adc5187905b1669cd8ec9c721e1953786b9d89a9bae30780f1e1eab24a00523c', + 'e90756ff7f9ad810b239a10ced2cf9b2284354c1f8c7e0accc2461dc796d6e89', + '1251f76e56978481875359801db589a0b22f86d8d634dc04506f322ed78f17e8', + '3afa899fd980e73ecb7f4d8b8f291dc9af796bc65d27f974c6f193c9191a09fd', + 'aa305be26e5deddc3c1010cbc213f95f051c785c5b431e6a7cd048f161787528', + '8ea1884ff32e9d10f039b407d0d44e7e670abd884aeee0fb757ae94eaa97373d', + 'd482b2155d4dec6b4736a1f1617b53aaa37310277d3fef0c37ad41768fc235b4', + '4d413971387e7a8898a8dc2a27500778539ea214a2dfe9b3d7e8ebdce5cf3db3', + '696e5d46e6c57e8796e4735d08916e0b7929b3cf298c296d22e9d3019653371c', + '1f5647c1d3b088228885865c8940908bf40d1a8272821973b160008e7a3ce2eb', + 'b6e76c330f021a5bda65875010b0edf09126c0f510ea849048192003aef4c61c', + '3cd952a0beada41abb424ce47f94b42be64e1ffb0fd0782276807946d0d0bc55', + '98d92677439b41b7bb513312afb92bcc8ee968b2e3b238cecb9b0f34c9bb63d0', + 'ecbca2cf08ae57d517ad16158a32bfa7dc0382eaeda128e91886734c24a0b29d', + '942cc7c0b52e2b16a4b89fa4fc7e0bf609e29a08c1a8543452b77c7bfd11bb28', + '8a065d8b61a0dffb170d5627735a76b0e9506037808cba16c345007c9f79cf8f', + '1b9fa19714659c78ff413871849215361029ac802b1cbcd54e408bd87287f81f', + '8dab071bcd6c7292a9ef727b4ae0d86713301da8618d9a48adce55f303a869a1', + '8253e3e7c7b684b9cb2beb014ce330ff3d99d17abbdbabe4f4d674ded53ffc6b', + 'f195f321e9e3d6bd7d074504dd2ab0e6241f92e784b1aa271ff648b1cab6d7f6', + '27e4cc72090f241266476a7c09495f2db153d5bcbd761903ef79275ec56b2ed8', + '899c2405788e25b99a1846355e646d77cf400083415f7dc5afe69d6e17c00023', + 'a59b78c4905744076bfee894de707d4f120b5c6893ea0400297d0bb834727632', + '59dc78b105649707a2bb4419c48f005400d3973de3736610230435b10424b24f', + 'c0149d1d7e7a6353a6d906efe728f2f329fe14a4149a3ea77609bc42b975ddfa', + 'a32f241474a6c16932e9243be0cf09bcdc7e0ca0e7a6a1b9b1a0f01e41502377', + 'b239b2e4f81841361c1339f68e2c359f929af9ad9f34e01aab4631ad6d5500b0', + '85fb419c7002a3e0b4b6ea093b4c1ac6936645b65dac5ac15a8528b7b94c1754', + '9619720625f190b93a3fad186ab314189633c0d3a01e6f9bc8c4a8f82f383dbf', + '7d620d90fe69fa469a6538388970a1aa09bb48a2d59b347b97e8ce71f48c7f46', + '294383568596fb37c75bbacd979c5ff6f20a556bf8879cc72924855df9b8240e', + '16b18ab314359c2b833c1c6986d48c55a9fc97cde9a3c1f10a3177140f73f738', + '8cbbdd14bc33f04cf45813e4a153a273d36adad5ce71f499eeb87fb8ac63b729', + '69c9a498db174ecaefcc5a3ac9fdedf0f813a5bec727f1e775babdec7718816e', + 'b462c3be40448f1d4f80626254e535b08bc9cdcff599a768578d4b2881a8e3f0', + '553e9d9c5f360ac0b74a7d44e5a391dad4ced03e0c24183b7e8ecabdf1715a64', + '7a7c55a56fa9ae51e655e01975d8a6ff4ae9e4b486fcbe4eac044588f245ebea', + '2afdf3c82abc4867f5de111286c2b3be7d6e48657ba923cfbf101a6dfcf9db9a', + '41037d2edcdce0c49b7fb4a6aa0999ca66976c7483afe631d4eda283144f6dfc', + 'c4466f8497ca2eeb4583a0b08e9d9ac74395709fda109d24f2e4462196779c5d', + '75f609338aa67d969a2ae2a2362b2da9d77c695dfd1df7224a6901db932c3364', + '68606ceb989d5488fc7cf649f3d7c272ef055da1a93faecd55fe06f6967098ca', + '44346bdeb7e052f6255048f0d9b42c425bab9c3dd24168212c3ecf1ebf34e6ae', + '8e9cf6e1f366471f2ac7d2ee9b5e6266fda71f8f2e4109f2237ed5f8813fc718', + '84bbeb8406d250951f8c1b3e86a7c010082921833dfd9555a2f909b1086eb4b8', + 'ee666f3eef0f7e2a9c222958c97eaf35f51ced393d714485ab09a069340fdf88', + 'c153d34a65c47b4a62c5cacf24010975d0356b2f32c8f5da530d338816ad5de6', + '9fc5450109e1b779f6c7ae79d56c27635c8dd426c5a9d54e2578db989b8c3b4e', + 'd12bf3732ef4af5c22fa90356af8fc50fcb40f8f2ea5c8594737a3b3d5abdbd7', + '11030b9289bba5af65260672ab6fee88b87420acef4a1789a2073b7ec2f2a09e', + '69cb192b8444005c8c0ceb12c846860768188cda0aec27a9c8a55cdee2123632', + 'db444c15597b5f1a03d1f9edd16e4a9f43a667cc275175dfa2b704e3bb1a9b83', + '3fb735061abc519dfe979e54c1ee5bfad0a9d858b3315bad34bde999efd724dd' + ] + end + + def test_unkeyed + (0..255).each do |i| + buf = [] + + j = 0 + while j < i + buf << (j & 0xff) + j += 1 + end + + res = Blake2b.new(32, Blake2b::Key.none).digest(bytes_to_string(buf), :to_hex) + assert_kind_of String, res + assert_equal @golden[i], res + end + end + + def test_keyed_with_string + key = (0..31).map { |i| i } + + (0..255).each do |i| + buf = [] + + j = 0 + while j < i + buf << (j & 0xff) + j += 1 + end + + res = Blake2b.new(32, Blake2b::Key.from_string(bytes_to_string(key))).digest(bytes_to_string(buf), :to_hex) + assert_kind_of String, res + assert_equal @golden_keyed[i], res + end + end + + def test_keyed_with_hex + key = (0..31).map { |i| i } + key_hex = bytes_to_hex(key) + + (0..255).each do |i| + buf = [] + + j = 0 + while j < i + buf << (j & 0xff) + j += 1 + end + + res = Blake2b.new(32, Blake2b::Key.from_hex(key_hex)).digest(bytes_to_string(buf), :to_hex) + assert_kind_of String, res + assert_equal @golden_keyed[i], res + end + end + + # utility methods + ################# + + def bytes_to_string(bytes) + bytes.pack('C*') + end + + def bytes_to_hex(bytes) + hex = '' + bytes.each { |b| hex += sprintf('%02x', b) } + hex.downcase + end +end diff --git a/test/performance/blake2b_gc_test.rb b/test/performance/blake2b_gc_test.rb new file mode 100755 index 0000000..e90e089 --- /dev/null +++ b/test/performance/blake2b_gc_test.rb @@ -0,0 +1,9 @@ +require 'test_helper' + +class Blake2bGCTest < MiniTest::Test + def test_a_million_iteration + 1_000_000.times do |i| + Blake2b.new(32, Blake2b::Key.none).digest('abc', :to_hex) + end + end +end diff --git a/test/test_helper.rb b/test/test_helper.rb new file mode 100755 index 0000000..338172f --- /dev/null +++ b/test/test_helper.rb @@ -0,0 +1,3 @@ +require 'minitest/autorun' +require 'minitest/assertions' +require 'blake2b'