Compare commits
4 Commits
Author | SHA1 | Date | |
---|---|---|---|
7290fa2366 | |||
12587a70ca | |||
77c4e048ae | |||
f02b765b93 |
1
Emakefile
Normal file
1
Emakefile
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"src/*", [debug_info, {i, "include/"}, {outdir, "ebin/"}]}.
|
203
LICENSE
Normal file
203
LICENSE
Normal file
@ -0,0 +1,203 @@
|
|||||||
|
|
||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright 2018 SUZUKI Tetsuya <tetsuya.suzuki@gmail.com>
|
||||||
|
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
19
README.md
19
README.md
@ -1,21 +1,30 @@
|
|||||||
erlang-sha3
|
erlang-sha3
|
||||||
===========
|
===========
|
||||||
|
|
||||||
[](http://travis-ci.org/szktty/erlang-sha3)
|
This repository contains:
|
||||||
|
1. the original 64-bit SHA-3 NIF library (forked from https://github.com/szktty/erlang-sha3 )
|
||||||
|
2. Complete native Erlang fallback functions for both the Keccak and SHA-3 variants of the underlying algorithm
|
||||||
|
|
||||||
SHA-3 for Erlang (64 bit only)
|
The native Erlang version of the function not only provides a more complete cross-platform implementation than either
|
||||||
|
the original Keccak C library and the current SHA-3 implementation that ships with the Erlang stdlib.
|
||||||
|
This is also by far the most readable and understandable implementation in any language currently.
|
||||||
|
|
||||||
|
If you are a student of the Keccack hashing algorithm, the code in this repository is extremely useful.
|
||||||
|
|
||||||
|
Peter Harpending wrote the original implementation with readability in mind,
|
||||||
|
and Hans Svensson greatly improved the performance of the readable implementation.
|
||||||
|
|
||||||
Licenses
|
Licenses
|
||||||
--------
|
--------
|
||||||
|
|
||||||
This program is distributed under Apache License 2.0.
|
This program is distributed under the Apache License 2.0
|
||||||
|
|
||||||
Keccak source files are distributed under CC0 1.0 Universal (CC0 1.0) Public Domain Dedication license.
|
Keccak source files are distributed under CC0 1.0 Universal (CC0 1.0) Public Domain Dedication license.
|
||||||
|
|
||||||
|
|
||||||
Author
|
Authors
|
||||||
------
|
------
|
||||||
|
|
||||||
SUZUKI Tetsuya <tetsuya.suzuki@gmail.com>
|
Orginal NIF wrapper: SUZUKI Tetsuya <tetsuya.suzuki@gmail.com>
|
||||||
|
|
||||||
|
Native Erlang functions: Peter Harpending, Hans Svensson, Craig Everett
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
{application, sha3,
|
{application, sha3,
|
||||||
[
|
[
|
||||||
{description, ""},
|
{description, "SHA-3 and Keccak in NIF and native Erlang."},
|
||||||
{vsn, "0.1.2"},
|
{vsn, "0.1.5"},
|
||||||
{registered, []},
|
{registered, []},
|
||||||
{applications, [
|
{applications, [
|
||||||
kernel,
|
kernel,
|
||||||
|
598
src/sha3.erl
598
src/sha3.erl
@ -1,8 +1,20 @@
|
|||||||
|
%%% @doc
|
||||||
|
%%% 2023-02-14: Update - Craig Everett
|
||||||
|
%%% Adapting native Erlang Keccak implementation as a NIF fallback
|
||||||
|
%%% to increase portability. Native Keccak implementation provided
|
||||||
|
%%% courtesy of Peter Harpending and Hans Svensson.
|
||||||
|
%%%
|
||||||
|
%%% Kek repo:
|
||||||
|
%%% https://github.com/pharpend/kek
|
||||||
|
%%%
|
||||||
|
%%% Peter Harpending: https://github.com/pharpend https://git.qpq.swiss/pharpend
|
||||||
|
%%% Hans Svensson: https://github.com/hanssv https://git.qpq.swiss/hanssv
|
||||||
|
%%% Craig Everett: https://gitlab.com/zxq9 https://git.qpq.swiss/zxq9
|
||||||
|
|
||||||
-module(sha3).
|
-module(sha3).
|
||||||
|
-vsn("0.1.5").
|
||||||
|
-export([hash_init/1, hash_update/2, hash_final/1, hash/2, kek/2, kek/3, shake128/2, shake256/2]).
|
||||||
|
|
||||||
-export([hash_init/1, hash_update/2, hash_final/1, hash/2]).
|
|
||||||
|
|
||||||
-export([hexhash/2]).
|
|
||||||
|
|
||||||
-on_load(init/0).
|
-on_load(init/0).
|
||||||
|
|
||||||
@ -16,50 +28,586 @@
|
|||||||
-export_type([bitlen/0, context/0, digest/0]).
|
-export_type([bitlen/0, context/0, digest/0]).
|
||||||
|
|
||||||
-define(nif_stub, nif_stub_error(?LINE)).
|
-define(nif_stub, nif_stub_error(?LINE)).
|
||||||
|
|
||||||
nif_stub_error(Line) ->
|
nif_stub_error(Line) ->
|
||||||
erlang:nif_error({nif_not_loaded,module,?MODULE,line,Line}).
|
erlang:nif_error({nif_not_loaded, module, ?MODULE, line, Line}).
|
||||||
|
|
||||||
|
|
||||||
init() ->
|
init() ->
|
||||||
PrivDir = case code:priv_dir(?MODULE) of
|
PrivDir =
|
||||||
{error, bad_name} ->
|
case code:priv_dir(?MODULE) of
|
||||||
EbinDir = filename:dirname(code:which(?MODULE)),
|
{error, bad_name} ->
|
||||||
AppPath = filename:dirname(EbinDir),
|
EbinDir = filename:dirname(code:which(?MODULE)),
|
||||||
filename:join(AppPath, "priv");
|
AppPath = filename:dirname(EbinDir),
|
||||||
Path ->
|
filename:join(AppPath, "priv");
|
||||||
Path
|
Path ->
|
||||||
end,
|
Path
|
||||||
erlang:load_nif(filename:join(PrivDir, sha3_nif), 0).
|
end,
|
||||||
|
case erlang:load_nif(filename:join(PrivDir, sha3_nif), 0) of
|
||||||
|
ok ->
|
||||||
|
logger:info("erlang-sha3 NIF loaded.");
|
||||||
|
{error, {Reason, Message}} ->
|
||||||
|
Format =
|
||||||
|
"erlang-sha3 NIF failed to load with ~tw: ~ts. "
|
||||||
|
"Falling back to Erlang implementation.",
|
||||||
|
logger:info(Format, [Reason, Message])
|
||||||
|
end.
|
||||||
|
|
||||||
|
|
||||||
|
-spec hash_init(bitlen()) -> context().
|
||||||
%% @doc Returns a new context for hash operation.
|
%% @doc Returns a new context for hash operation.
|
||||||
%% Bit length of digest (`BitLen') must be one of 224, 256, 384 and 512.
|
%% Bit length of digest (`BitLen') must be one of 224, 256, 384 and 512.
|
||||||
%% @see hash_update/2
|
%% @see hash_update/2
|
||||||
-spec hash_init(bitlen()) -> context().
|
|
||||||
hash_init(_BitLen) ->
|
hash_init(_BitLen) ->
|
||||||
?nif_stub.
|
?nif_stub.
|
||||||
|
|
||||||
|
|
||||||
|
-spec hash_update(context(), binary()) -> context().
|
||||||
%% @doc Updates the digest by `Context' generated with `hash_init/1'
|
%% @doc Updates the digest by `Context' generated with `hash_init/1'
|
||||||
%% using the given `Data' and returns a new updated context.
|
%% using the given `Data' and returns a new updated context.
|
||||||
%% `Data' can be any length.
|
%% `Data' can be any length.
|
||||||
%% The returned context can e used `hash_update/2' or `hash_final/1'.
|
%% The returned context can e used `hash_update/2' or `hash_final/1'.
|
||||||
%% @see hash_final/1
|
%% @see hash_final/1
|
||||||
-spec hash_update(context(), binary()) -> context().
|
|
||||||
hash_update(_Context, _Binary) ->
|
hash_update(_Context, _Binary) ->
|
||||||
?nif_stub.
|
?nif_stub.
|
||||||
|
|
||||||
|
|
||||||
|
-spec hash_final(context()) -> digest().
|
||||||
%% @doc Finalizes the hash operation with `Context' and
|
%% @doc Finalizes the hash operation with `Context' and
|
||||||
%% returns a message digest.
|
%% returns a message digest.
|
||||||
%% Length of the digest is determined by an argument of `hash_init/1'.
|
%% Length of the digest is determined by an argument of `hash_init/1'.
|
||||||
-spec hash_final(context()) -> digest().
|
|
||||||
hash_final(_Context) ->
|
hash_final(_Context) ->
|
||||||
?nif_stub.
|
?nif_stub.
|
||||||
|
|
||||||
%% @doc Computes a message digest from `Binary'.
|
|
||||||
%% Bit length of digest (`BitLen') must be one of 224, 256, 384 and 512.
|
|
||||||
-spec hash(bitlen(), binary()) -> digest().
|
|
||||||
hash(_BitLen, _Binary) ->
|
|
||||||
?nif_stub.
|
|
||||||
|
|
||||||
-spec hexhash(bitlen(), binary()) -> binary().
|
-spec hash(OutputBitLength, Message) -> Digest
|
||||||
hexhash(Bitlen, Binary) ->
|
when OutputBitLength :: pos_integer(),
|
||||||
Hash = hash(Bitlen, Binary),
|
Message :: bitstring(),
|
||||||
list_to_binary(hex2bin:bin_to_hexstr(Hash)).
|
Digest :: bitstring().
|
||||||
|
%% @doc
|
||||||
|
%% SHA-3 with an arbitrary output bit length.
|
||||||
|
%%
|
||||||
|
%% This means Keccak with Capacity = 2 * OutputBitLength. Additionally, SHA3
|
||||||
|
%% concatenates the bits 01 onto the end of the input, before sending the
|
||||||
|
%% Message to keccak/3.
|
||||||
|
%% @end
|
||||||
|
|
||||||
|
hash(224, Message) -> kek(224, Message);
|
||||||
|
hash(256, Message) -> kek(256, Message);
|
||||||
|
hash(384, Message) -> kek(382, Message);
|
||||||
|
hash(512, Message) -> kek(512, Message);
|
||||||
|
hash(_, _) -> error(badarg).
|
||||||
|
|
||||||
|
|
||||||
|
kek(Length, Message) ->
|
||||||
|
kek(Length, Message, keccak).
|
||||||
|
|
||||||
|
kek(OutputBitLength, Message, keccak) ->
|
||||||
|
Capacity = 2 * OutputBitLength,
|
||||||
|
keccak(Capacity, Message, <<>>, OutputBitLength);
|
||||||
|
kek(OutputBitLength, Message, nist) ->
|
||||||
|
Capacity = 2 * OutputBitLength,
|
||||||
|
keccak(Capacity, Message, <<2#01:2>>, OutputBitLength).
|
||||||
|
|
||||||
|
|
||||||
|
-spec shake128(Message, OutputBitLength) -> Digest
|
||||||
|
when Message :: bitstring(),
|
||||||
|
OutputBitLength :: pos_integer(),
|
||||||
|
Digest :: bitstring().
|
||||||
|
%% @doc
|
||||||
|
%% This is the SHAKE variable-length hash with Capacity 256 = 2*128 bits.
|
||||||
|
%% @end
|
||||||
|
|
||||||
|
shake128(Message, OutputBitLength) ->
|
||||||
|
shake(128, Message, OutputBitLength).
|
||||||
|
|
||||||
|
|
||||||
|
-spec shake256(Message, OutputBitLength) -> Digest
|
||||||
|
when Message :: bitstring(),
|
||||||
|
OutputBitLength :: pos_integer(),
|
||||||
|
Digest :: bitstring().
|
||||||
|
%% @doc
|
||||||
|
%% This is the SHAKE variable-length hash with Capacity 512 = 2*256 bits.
|
||||||
|
%% @end
|
||||||
|
|
||||||
|
shake256(Message, OutputBitLength) ->
|
||||||
|
shake(256, Message, OutputBitLength).
|
||||||
|
|
||||||
|
|
||||||
|
-spec shake(ShakeNumber, Message, OutputBitLength) -> Digest
|
||||||
|
when ShakeNumber :: pos_integer(),
|
||||||
|
Message :: bitstring(),
|
||||||
|
OutputBitLength :: pos_integer(),
|
||||||
|
Digest :: bitstring().
|
||||||
|
%% @doc
|
||||||
|
%% This is the SHAKE variable-length hash with Capacity 512 = 2*ShakeNumber bits.
|
||||||
|
%%
|
||||||
|
%% This concatenates the bitstring 1111 onto the end of the Message before
|
||||||
|
%% sending the message to keccak/4.
|
||||||
|
%% @end
|
||||||
|
|
||||||
|
shake(ShakeNumber, Message, OutputBitLength) ->
|
||||||
|
Capacity = 2 * ShakeNumber,
|
||||||
|
keccak(Capacity, Message, <<2#1111:4>>, OutputBitLength).
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
%%% OUTER KECCAK
|
||||||
|
%%%
|
||||||
|
%%% Keccak pads the input, absorbs it into the sponge, and squeezes the bits out
|
||||||
|
%%% of the sponge. The absorption and squeezing phases invoke "inner keccak",
|
||||||
|
%%% which is the heart of the algorithm.
|
||||||
|
%%%
|
||||||
|
%%% - keccak/3
|
||||||
|
%%% - pad/2
|
||||||
|
%%% - absorb/4
|
||||||
|
%%% - squeeze/3
|
||||||
|
|
||||||
|
|
||||||
|
-spec keccak(Capacity, Message, Delimiter, OutputBitLength) -> Digest
|
||||||
|
when Capacity :: pos_integer(),
|
||||||
|
Message :: bitstring(),
|
||||||
|
Delimiter :: bitstring(),
|
||||||
|
OutputBitLength :: pos_integer(),
|
||||||
|
Digest :: bitstring().
|
||||||
|
%% @doc
|
||||||
|
%% Note: this is Keccak 1600, the only one used in practice
|
||||||
|
%%
|
||||||
|
%% Capacity must be strictly less than 1600
|
||||||
|
%% @end
|
||||||
|
|
||||||
|
keccak(Capacity, Message, Delimiter, OutputBitLength) ->
|
||||||
|
BitRate = 1600 - Capacity,
|
||||||
|
PaddedMessage = pad(Message, Delimiter, BitRate),
|
||||||
|
InitialSponge = <<0:1600>>,
|
||||||
|
WetSponge = absorb(PaddedMessage, BitRate, Capacity, InitialSponge),
|
||||||
|
ResultBits = squeeze(WetSponge, OutputBitLength, BitRate),
|
||||||
|
ResultBits.
|
||||||
|
|
||||||
|
|
||||||
|
-spec pad(Message, Delimiter, BitRate) -> NewMessage
|
||||||
|
when Message :: bitstring(),
|
||||||
|
Delimiter :: bitstring(),
|
||||||
|
BitRate :: pos_integer(),
|
||||||
|
NewMessage :: bitstring().
|
||||||
|
%% @private
|
||||||
|
%% padding
|
||||||
|
%% divide the message into r-bit blocks
|
||||||
|
%%
|
||||||
|
%% the message ends with 1000...0001
|
||||||
|
%%
|
||||||
|
%% sha3 calls this /10*1/ as in the regex
|
||||||
|
%%
|
||||||
|
%% Reference: https://en.wikipedia.org/wiki/SHA-3#Padding
|
||||||
|
%% @end
|
||||||
|
|
||||||
|
pad(Msg, Delimiter, BitRate) ->
|
||||||
|
MsgBits = bit_size(Msg),
|
||||||
|
DlmBits = bit_size(Delimiter),
|
||||||
|
<<Msg0:(MsgBits div 8)/bytes, Msg1/bitstring>> = Msg,
|
||||||
|
case (MsgBits + DlmBits) rem BitRate of
|
||||||
|
0 -> %% We add a complete RWord + flip the last chunk of the message
|
||||||
|
<<Msg0/binary, (rev_pad(Msg1, Delimiter, BitRate - 2))/bitstring>>;
|
||||||
|
N when N == BitRate - 1 -> %% Slightly retarded case
|
||||||
|
<<Msg0/binary, (rev_pad(Msg1, Delimiter, BitRate - 1))/bitstring>>;
|
||||||
|
N ->
|
||||||
|
<<Msg0/binary, (rev_pad(Msg1, Delimiter, BitRate - N - 2))/bitstring>>
|
||||||
|
end.
|
||||||
|
|
||||||
|
%% Instead of reverting message bits, work with a "reversed" padding
|
||||||
|
rev_pad(Msg, Delimiter, PadZeros) ->
|
||||||
|
Pad = <<Msg/bitstring, Delimiter/bitstring, 1:1, 0:PadZeros, 1:1>>,
|
||||||
|
<< (flip_bits(X)) || <<X:8>> <= Pad >>.
|
||||||
|
|
||||||
|
flip_bits(0) -> <<0:8>>;
|
||||||
|
flip_bits(<<A:1, B:1, C:1, D:1, E:1, F:1, G:1, H:1>>) ->
|
||||||
|
<<H:1, G:1, F:1, E:1, D:1, C:1, B:1, A:1>>;
|
||||||
|
flip_bits(N) -> flip_bits(<<N:8>>).
|
||||||
|
|
||||||
|
-spec absorb(PaddedMessage, BitRate, Capacity, SpongeAcc) -> WetSponge
|
||||||
|
when PaddedMessage :: bitstring(),
|
||||||
|
BitRate :: pos_integer(),
|
||||||
|
Capacity :: pos_integer(),
|
||||||
|
SpongeAcc :: <<_:1600>>,
|
||||||
|
WetSponge :: <<_:1600>>.
|
||||||
|
%% @private
|
||||||
|
%% Assumptions:
|
||||||
|
%% 1. BitRate + Capacity = 1600,
|
||||||
|
%% 2. BitRate divides the PaddedMessage length (i.e. already have done padding)
|
||||||
|
%% @end
|
||||||
|
|
||||||
|
% can pull off r bits from the start of the message
|
||||||
|
absorb(PaddedMessageBits, BitRate = _r, Capacity = _c, Sponge) when BitRate =< bit_size(PaddedMessageBits) ->
|
||||||
|
<<ThisRWord:BitRate, Rest/bitstring>> = PaddedMessageBits,
|
||||||
|
% we bitwise xor the sponge against the r word followed by a bunch of 0s
|
||||||
|
<<SpongeInt:1600>> = Sponge,
|
||||||
|
<<Foo:1600>> = <<ThisRWord:BitRate, 0:Capacity>>,
|
||||||
|
FInputInt = SpongeInt bxor Foo,
|
||||||
|
FInputBits = <<FInputInt:1600>>,
|
||||||
|
NewSponge = inner_keccak(FInputBits),
|
||||||
|
absorb(Rest, BitRate, Capacity, NewSponge);
|
||||||
|
% empty string, return the sponge
|
||||||
|
absorb(<<>>, _r, _c, FinalSponge) ->
|
||||||
|
FinalSponge.
|
||||||
|
|
||||||
|
|
||||||
|
-spec squeeze(WetSponge, OutputBitLength, BitRate) -> ResultBits
|
||||||
|
when WetSponge :: <<_:1600>>,
|
||||||
|
OutputBitLength :: pos_integer(),
|
||||||
|
BitRate :: pos_integer(),
|
||||||
|
ResultBits :: bitstring().
|
||||||
|
%% @private
|
||||||
|
%% squeeze the output bits out of the sponge
|
||||||
|
%% @end
|
||||||
|
|
||||||
|
%%% % simple case: bit length is less than (or equal to) the sponge size, just grab
|
||||||
|
%%% % the first ones
|
||||||
|
%%% % this is the case for the shas
|
||||||
|
%%% squeeze(<<ResultBits:OutputBitLength, _Rest/bitstring>>, OutputBitLength, _BitRate) ->
|
||||||
|
%%% <<ResultBits:OutputBitLength>>;
|
||||||
|
% general case: output bit length is greater than the sponge size, construct
|
||||||
|
% accumulatively
|
||||||
|
% this is the case for the variable-length encodings
|
||||||
|
squeeze(WetSponge, OutputBitLength, BitRate) ->
|
||||||
|
InitOutputAcc = <<>>,
|
||||||
|
really_squeeze(WetSponge, OutputBitLength, BitRate, InitOutputAcc).
|
||||||
|
|
||||||
|
% terminal case: we have enough bits in the output, return those
|
||||||
|
really_squeeze(_WetSponge, OutputBitLength, _BitRate, FinalAccBits) when OutputBitLength =< bit_size(FinalAccBits) ->
|
||||||
|
<<ResultBits:OutputBitLength, _/bitstring>> = FinalAccBits,
|
||||||
|
<<ResultBits:OutputBitLength>>;
|
||||||
|
% general case: need moar bits
|
||||||
|
% in this case
|
||||||
|
% - we grab the first r bits of the sponge, add them to the accumulator
|
||||||
|
% - re-kek the sponge
|
||||||
|
% - try again
|
||||||
|
really_squeeze(WetSponge, OutputBitLength, BitRate, ResultAcc)->
|
||||||
|
<<ThisRWord:BitRate, _/bitstring>> = WetSponge,
|
||||||
|
NewResultAcc = <<ResultAcc/bitstring, ThisRWord:BitRate>>,
|
||||||
|
NewWetSponge = inner_keccak(WetSponge),
|
||||||
|
really_squeeze(NewWetSponge, OutputBitLength, BitRate, NewResultAcc).
|
||||||
|
|
||||||
|
|
||||||
|
%%% THE DREADED INNER KECCAK
|
||||||
|
%%%
|
||||||
|
%%% This is the "f" function that appears in all the documentation.
|
||||||
|
%%%
|
||||||
|
%%% The input is the 1600-bit sponge array. inner_keccak/1 sends the input
|
||||||
|
%%% through 24 "rounds". Each round consists of the 5 Greek letter steps, each of
|
||||||
|
%%% which is a weird transformation on the array.
|
||||||
|
%%%
|
||||||
|
%%% Here the rounds are unrolled in terms of 64bit integers - for efficiency
|
||||||
|
|
||||||
|
|
||||||
|
inner_keccak(<<_:1600>> = State) ->
|
||||||
|
IntState0 = list_to_tuple([ X || <<X:64/little>> <= State ]),
|
||||||
|
IntState6 = inner_keccak_fast(IntState0),
|
||||||
|
<< <<X:64/little>> || X <- tuple_to_list(IntState6) >>.
|
||||||
|
|
||||||
|
inner_keccak_fast(IntState0) ->
|
||||||
|
IntState1 = fast_round(IntState0, {16#0000000000000001, 16#0000000000008082, 16#800000000000808A, 16#8000000080008000}),
|
||||||
|
IntState2 = fast_round(IntState1, {16#000000000000808B, 16#0000000080000001, 16#8000000080008081, 16#8000000000008009}),
|
||||||
|
IntState3 = fast_round(IntState2, {16#000000000000008A, 16#0000000000000088, 16#0000000080008009, 16#000000008000000A}),
|
||||||
|
IntState4 = fast_round(IntState3, {16#000000008000808B, 16#800000000000008B, 16#8000000000008089, 16#8000000000008003}),
|
||||||
|
IntState5 = fast_round(IntState4, {16#8000000000008002, 16#8000000000000080, 16#000000000000800A, 16#800000008000000A}),
|
||||||
|
fast_round(IntState5, {16#8000000080008081, 16#8000000000008080, 16#0000000080000001, 16#8000000080008008}).
|
||||||
|
|
||||||
|
-define(INT64, 16#FFFFFFFFFFFFFFFF).
|
||||||
|
-define(BSL64(X, N), ((X bsl N) band ?INT64)).
|
||||||
|
-define(BSR64(X, N), (X bsr N)).
|
||||||
|
|
||||||
|
-define(ROTL64(X, N), (?BSL64(X, N) bor ?BSR64(X, (64 - N)))).
|
||||||
|
-define(CAN64(A, B), ((A bxor B) band A)).
|
||||||
|
|
||||||
|
fast_round(As0, {RC0, RC1, RC2, RC3}) ->
|
||||||
|
As1 = fast_round1(As0, RC0),
|
||||||
|
As2 = fast_round2(As1, RC1),
|
||||||
|
As3 = fast_round3(As2, RC2),
|
||||||
|
fast_round4(As3, RC3).
|
||||||
|
|
||||||
|
fast_round1({A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22, A23, A24}, RC0) ->
|
||||||
|
%% Round 1
|
||||||
|
BC0_0 = A0 bxor A5 bxor A10 bxor A15 bxor A20,
|
||||||
|
BC1_0 = A1 bxor A6 bxor A11 bxor A16 bxor A21,
|
||||||
|
BC2_0 = A2 bxor A7 bxor A12 bxor A17 bxor A22,
|
||||||
|
BC3_0 = A3 bxor A8 bxor A13 bxor A18 bxor A23,
|
||||||
|
BC4_0 = A4 bxor A9 bxor A14 bxor A19 bxor A24,
|
||||||
|
D0 = BC4_0 bxor ?ROTL64(BC1_0, 1),
|
||||||
|
D1 = BC0_0 bxor ?ROTL64(BC2_0, 1),
|
||||||
|
D2 = BC1_0 bxor ?ROTL64(BC3_0, 1),
|
||||||
|
D3 = BC2_0 bxor ?ROTL64(BC4_0, 1),
|
||||||
|
D4 = BC3_0 bxor ?ROTL64(BC0_0, 1),
|
||||||
|
|
||||||
|
BC0_1 = A0 bxor D0,
|
||||||
|
BC1_1 = ?ROTL64(A6 bxor D1, 44),
|
||||||
|
BC2_1 = ?ROTL64(A12 bxor D2, 43),
|
||||||
|
BC3_1 = ?ROTL64(A18 bxor D3, 21),
|
||||||
|
BC4_1 = ?ROTL64(A24 bxor D4, 14),
|
||||||
|
A0_1 = BC0_1 bxor ?CAN64(BC2_1, BC1_1) bxor RC0,
|
||||||
|
A6_1 = BC1_1 bxor ?CAN64(BC3_1, BC2_1),
|
||||||
|
A12_1 = BC2_1 bxor ?CAN64(BC4_1, BC3_1),
|
||||||
|
A18_1 = BC3_1 bxor ?CAN64(BC0_1, BC4_1),
|
||||||
|
A24_1 = BC4_1 bxor ?CAN64(BC1_1, BC0_1),
|
||||||
|
|
||||||
|
BC2_2 = ?ROTL64(A10 bxor D0, 3),
|
||||||
|
BC3_2 = ?ROTL64(A16 bxor D1, 45),
|
||||||
|
BC4_2 = ?ROTL64(A22 bxor D2, 61),
|
||||||
|
BC0_2 = ?ROTL64(A3 bxor D3, 28),
|
||||||
|
BC1_2 = ?ROTL64(A9 bxor D4, 20),
|
||||||
|
A10_1 = BC0_2 bxor ?CAN64(BC2_2, BC1_2),
|
||||||
|
A16_1 = BC1_2 bxor ?CAN64(BC3_2, BC2_2),
|
||||||
|
A22_1 = BC2_2 bxor ?CAN64(BC4_2, BC3_2),
|
||||||
|
A3_1 = BC3_2 bxor ?CAN64(BC0_2, BC4_2),
|
||||||
|
A9_1 = BC4_2 bxor ?CAN64(BC1_2, BC0_2),
|
||||||
|
|
||||||
|
BC4_3 = ?ROTL64(A20 bxor D0, 18),
|
||||||
|
BC0_3 = ?ROTL64(A1 bxor D1, 1),
|
||||||
|
BC1_3 = ?ROTL64(A7 bxor D2, 6),
|
||||||
|
BC2_3 = ?ROTL64(A13 bxor D3, 25),
|
||||||
|
BC3_3 = ?ROTL64(A19 bxor D4, 8),
|
||||||
|
A20_1 = BC0_3 bxor ?CAN64(BC2_3, BC1_3),
|
||||||
|
A1_1 = BC1_3 bxor ?CAN64(BC3_3, BC2_3),
|
||||||
|
A7_1 = BC2_3 bxor ?CAN64(BC4_3, BC3_3),
|
||||||
|
A13_1 = BC3_3 bxor ?CAN64(BC0_3, BC4_3),
|
||||||
|
A19_1 = BC4_3 bxor ?CAN64(BC1_3, BC0_3),
|
||||||
|
|
||||||
|
BC1_4 = ?ROTL64(A5 bxor D0, 36),
|
||||||
|
BC2_4 = ?ROTL64(A11 bxor D1, 10),
|
||||||
|
BC3_4 = ?ROTL64(A17 bxor D2, 15),
|
||||||
|
BC4_4 = ?ROTL64(A23 bxor D3, 56),
|
||||||
|
BC0_4 = ?ROTL64(A4 bxor D4, 27),
|
||||||
|
A5_1 = BC0_4 bxor ?CAN64(BC2_4, BC1_4),
|
||||||
|
A11_1 = BC1_4 bxor ?CAN64(BC3_4, BC2_4),
|
||||||
|
A17_1 = BC2_4 bxor ?CAN64(BC4_4, BC3_4),
|
||||||
|
A23_1 = BC3_4 bxor ?CAN64(BC0_4, BC4_4),
|
||||||
|
A4_1 = BC4_4 bxor ?CAN64(BC1_4, BC0_4),
|
||||||
|
|
||||||
|
BC3_5 = ?ROTL64(A15 bxor D0, 41),
|
||||||
|
BC4_5 = ?ROTL64(A21 bxor D1, 2),
|
||||||
|
BC0_5 = ?ROTL64(A2 bxor D2, 62),
|
||||||
|
BC1_5 = ?ROTL64(A8 bxor D3, 55),
|
||||||
|
BC2_5 = ?ROTL64(A14 bxor D4, 39),
|
||||||
|
A15_1 = BC0_5 bxor ?CAN64(BC2_5, BC1_5),
|
||||||
|
A21_1 = BC1_5 bxor ?CAN64(BC3_5, BC2_5),
|
||||||
|
A2_1 = BC2_5 bxor ?CAN64(BC4_5, BC3_5),
|
||||||
|
A8_1 = BC3_5 bxor ?CAN64(BC0_5, BC4_5),
|
||||||
|
A14_1 = BC4_5 bxor ?CAN64(BC1_5, BC0_5),
|
||||||
|
|
||||||
|
{A0_1, A1_1, A2_1, A3_1, A4_1, A5_1, A6_1, A7_1, A8_1, A9_1, A10_1, A11_1, A12_1, A13_1,
|
||||||
|
A14_1, A15_1, A16_1, A17_1, A18_1, A19_1, A20_1, A21_1, A22_1, A23_1, A24_1}.
|
||||||
|
|
||||||
|
fast_round2({A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22, A23, A24}, RC1) ->
|
||||||
|
%% Round 2
|
||||||
|
BC0_0 = A0 bxor A5 bxor A10 bxor A15 bxor A20,
|
||||||
|
BC1_0 = A1 bxor A6 bxor A11 bxor A16 bxor A21,
|
||||||
|
BC2_0 = A2 bxor A7 bxor A12 bxor A17 bxor A22,
|
||||||
|
BC3_0 = A3 bxor A8 bxor A13 bxor A18 bxor A23,
|
||||||
|
BC4_0 = A4 bxor A9 bxor A14 bxor A19 bxor A24,
|
||||||
|
D0 = BC4_0 bxor ?ROTL64(BC1_0, 1),
|
||||||
|
D1 = BC0_0 bxor ?ROTL64(BC2_0, 1),
|
||||||
|
D2 = BC1_0 bxor ?ROTL64(BC3_0, 1),
|
||||||
|
D3 = BC2_0 bxor ?ROTL64(BC4_0, 1),
|
||||||
|
D4 = BC3_0 bxor ?ROTL64(BC0_0, 1),
|
||||||
|
|
||||||
|
BC0_1 = A0 bxor D0,
|
||||||
|
BC1_1 = ?ROTL64(A16 bxor D1, 44),
|
||||||
|
BC2_1 = ?ROTL64(A7 bxor D2, 43),
|
||||||
|
BC3_1 = ?ROTL64(A23 bxor D3, 21),
|
||||||
|
BC4_1 = ?ROTL64(A14 bxor D4, 14),
|
||||||
|
A0_1 = BC0_1 bxor ?CAN64(BC2_1, BC1_1) bxor RC1,
|
||||||
|
A16_1 = BC1_1 bxor ?CAN64(BC3_1, BC2_1),
|
||||||
|
A7_1 = BC2_1 bxor ?CAN64(BC4_1, BC3_1),
|
||||||
|
A23_1 = BC3_1 bxor ?CAN64(BC0_1, BC4_1),
|
||||||
|
A14_1 = BC4_1 bxor ?CAN64(BC1_1, BC0_1),
|
||||||
|
|
||||||
|
BC2_2 = ?ROTL64(A20 bxor D0, 3),
|
||||||
|
BC3_2 = ?ROTL64(A11 bxor D1, 45),
|
||||||
|
BC4_2 = ?ROTL64(A2 bxor D2, 61),
|
||||||
|
BC0_2 = ?ROTL64(A18 bxor D3, 28),
|
||||||
|
BC1_2 = ?ROTL64(A9 bxor D4, 20),
|
||||||
|
A20_1 = BC0_2 bxor ?CAN64(BC2_2, BC1_2),
|
||||||
|
A11_1 = BC1_2 bxor ?CAN64(BC3_2, BC2_2),
|
||||||
|
A2_1 = BC2_2 bxor ?CAN64(BC4_2, BC3_2),
|
||||||
|
A18_1 = BC3_2 bxor ?CAN64(BC0_2, BC4_2),
|
||||||
|
A9_1 = BC4_2 bxor ?CAN64(BC1_2, BC0_2),
|
||||||
|
|
||||||
|
BC4_3 = ?ROTL64(A15 bxor D0, 18),
|
||||||
|
BC0_3 = ?ROTL64(A6 bxor D1, 1),
|
||||||
|
BC1_3 = ?ROTL64(A22 bxor D2, 6),
|
||||||
|
BC2_3 = ?ROTL64(A13 bxor D3, 25),
|
||||||
|
BC3_3 = ?ROTL64(A4 bxor D4, 8),
|
||||||
|
A15_1 = BC0_3 bxor ?CAN64(BC2_3, BC1_3),
|
||||||
|
A6_1 = BC1_3 bxor ?CAN64(BC3_3, BC2_3),
|
||||||
|
A22_1 = BC2_3 bxor ?CAN64(BC4_3, BC3_3),
|
||||||
|
A13_1 = BC3_3 bxor ?CAN64(BC0_3, BC4_3),
|
||||||
|
A4_1 = BC4_3 bxor ?CAN64(BC1_3, BC0_3),
|
||||||
|
|
||||||
|
BC1_4 = ?ROTL64(A10 bxor D0, 36),
|
||||||
|
BC2_4 = ?ROTL64(A1 bxor D1, 10),
|
||||||
|
BC3_4 = ?ROTL64(A17 bxor D2, 15),
|
||||||
|
BC4_4 = ?ROTL64(A8 bxor D3, 56),
|
||||||
|
BC0_4 = ?ROTL64(A24 bxor D4, 27),
|
||||||
|
A10_1 = BC0_4 bxor ?CAN64(BC2_4, BC1_4),
|
||||||
|
A1_1 = BC1_4 bxor ?CAN64(BC3_4, BC2_4),
|
||||||
|
A17_1 = BC2_4 bxor ?CAN64(BC4_4, BC3_4),
|
||||||
|
A8_1 = BC3_4 bxor ?CAN64(BC0_4, BC4_4),
|
||||||
|
A24_1 = BC4_4 bxor ?CAN64(BC1_4, BC0_4),
|
||||||
|
|
||||||
|
BC3_5 = ?ROTL64(A5 bxor D0, 41),
|
||||||
|
BC4_5 = ?ROTL64(A21 bxor D1, 2),
|
||||||
|
BC0_5 = ?ROTL64(A12 bxor D2, 62),
|
||||||
|
BC1_5 = ?ROTL64(A3 bxor D3, 55),
|
||||||
|
BC2_5 = ?ROTL64(A19 bxor D4, 39),
|
||||||
|
A5_1 = BC0_5 bxor ?CAN64(BC2_5, BC1_5),
|
||||||
|
A21_1 = BC1_5 bxor ?CAN64(BC3_5, BC2_5),
|
||||||
|
A12_1 = BC2_5 bxor ?CAN64(BC4_5, BC3_5),
|
||||||
|
A3_1 = BC3_5 bxor ?CAN64(BC0_5, BC4_5),
|
||||||
|
A19_1 = BC4_5 bxor ?CAN64(BC1_5, BC0_5),
|
||||||
|
|
||||||
|
{A0_1, A1_1, A2_1, A3_1, A4_1, A5_1, A6_1, A7_1, A8_1, A9_1, A10_1, A11_1, A12_1, A13_1,
|
||||||
|
A14_1, A15_1, A16_1, A17_1, A18_1, A19_1, A20_1, A21_1, A22_1, A23_1, A24_1}.
|
||||||
|
|
||||||
|
fast_round3({A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22, A23, A24}, RC2) ->
|
||||||
|
%% Round 3
|
||||||
|
BC0_0 = A0 bxor A5 bxor A10 bxor A15 bxor A20,
|
||||||
|
BC1_0 = A1 bxor A6 bxor A11 bxor A16 bxor A21,
|
||||||
|
BC2_0 = A2 bxor A7 bxor A12 bxor A17 bxor A22,
|
||||||
|
BC3_0 = A3 bxor A8 bxor A13 bxor A18 bxor A23,
|
||||||
|
BC4_0 = A4 bxor A9 bxor A14 bxor A19 bxor A24,
|
||||||
|
D0 = BC4_0 bxor ?ROTL64(BC1_0, 1),
|
||||||
|
D1 = BC0_0 bxor ?ROTL64(BC2_0, 1),
|
||||||
|
D2 = BC1_0 bxor ?ROTL64(BC3_0, 1),
|
||||||
|
D3 = BC2_0 bxor ?ROTL64(BC4_0, 1),
|
||||||
|
D4 = BC3_0 bxor ?ROTL64(BC0_0, 1),
|
||||||
|
|
||||||
|
BC0_1 = A0 bxor D0,
|
||||||
|
BC1_1 = ?ROTL64(A11 bxor D1, 44),
|
||||||
|
BC2_1 = ?ROTL64(A22 bxor D2, 43),
|
||||||
|
BC3_1 = ?ROTL64(A8 bxor D3, 21),
|
||||||
|
BC4_1 = ?ROTL64(A19 bxor D4, 14),
|
||||||
|
A0_1 = BC0_1 bxor ?CAN64(BC2_1, BC1_1) bxor RC2,
|
||||||
|
A11_1 = BC1_1 bxor ?CAN64(BC3_1, BC2_1),
|
||||||
|
A22_1 = BC2_1 bxor ?CAN64(BC4_1, BC3_1),
|
||||||
|
A8_1 = BC3_1 bxor ?CAN64(BC0_1, BC4_1),
|
||||||
|
A19_1 = BC4_1 bxor ?CAN64(BC1_1, BC0_1),
|
||||||
|
|
||||||
|
BC2_2 = ?ROTL64(A15 bxor D0, 3),
|
||||||
|
BC3_2 = ?ROTL64(A1 bxor D1, 45),
|
||||||
|
BC4_2 = ?ROTL64(A12 bxor D2, 61),
|
||||||
|
BC0_2 = ?ROTL64(A23 bxor D3, 28),
|
||||||
|
BC1_2 = ?ROTL64(A9 bxor D4, 20),
|
||||||
|
A15_1 = BC0_2 bxor ?CAN64(BC2_2, BC1_2),
|
||||||
|
A1_1 = BC1_2 bxor ?CAN64(BC3_2, BC2_2),
|
||||||
|
A12_1 = BC2_2 bxor ?CAN64(BC4_2, BC3_2),
|
||||||
|
A23_1 = BC3_2 bxor ?CAN64(BC0_2, BC4_2),
|
||||||
|
A9_1 = BC4_2 bxor ?CAN64(BC1_2, BC0_2),
|
||||||
|
|
||||||
|
BC4_3 = ?ROTL64(A5 bxor D0, 18),
|
||||||
|
BC0_3 = ?ROTL64(A16 bxor D1, 1),
|
||||||
|
BC1_3 = ?ROTL64(A2 bxor D2, 6),
|
||||||
|
BC2_3 = ?ROTL64(A13 bxor D3, 25),
|
||||||
|
BC3_3 = ?ROTL64(A24 bxor D4, 8),
|
||||||
|
A5_1 = BC0_3 bxor ?CAN64(BC2_3, BC1_3),
|
||||||
|
A16_1 = BC1_3 bxor ?CAN64(BC3_3, BC2_3),
|
||||||
|
A2_1 = BC2_3 bxor ?CAN64(BC4_3, BC3_3),
|
||||||
|
A13_1 = BC3_3 bxor ?CAN64(BC0_3, BC4_3),
|
||||||
|
A24_1 = BC4_3 bxor ?CAN64(BC1_3, BC0_3),
|
||||||
|
|
||||||
|
BC1_4 = ?ROTL64(A20 bxor D0, 36),
|
||||||
|
BC2_4 = ?ROTL64(A6 bxor D1, 10),
|
||||||
|
BC3_4 = ?ROTL64(A17 bxor D2, 15),
|
||||||
|
BC4_4 = ?ROTL64(A3 bxor D3, 56),
|
||||||
|
BC0_4 = ?ROTL64(A14 bxor D4, 27),
|
||||||
|
A20_1 = BC0_4 bxor ?CAN64(BC2_4, BC1_4),
|
||||||
|
A6_1 = BC1_4 bxor ?CAN64(BC3_4, BC2_4),
|
||||||
|
A17_1 = BC2_4 bxor ?CAN64(BC4_4, BC3_4),
|
||||||
|
A3_1 = BC3_4 bxor ?CAN64(BC0_4, BC4_4),
|
||||||
|
A14_1 = BC4_4 bxor ?CAN64(BC1_4, BC0_4),
|
||||||
|
|
||||||
|
BC3_5 = ?ROTL64(A10 bxor D0, 41),
|
||||||
|
BC4_5 = ?ROTL64(A21 bxor D1, 2),
|
||||||
|
BC0_5 = ?ROTL64(A7 bxor D2, 62),
|
||||||
|
BC1_5 = ?ROTL64(A18 bxor D3, 55),
|
||||||
|
BC2_5 = ?ROTL64(A4 bxor D4, 39),
|
||||||
|
A10_1 = BC0_5 bxor ?CAN64(BC2_5, BC1_5),
|
||||||
|
A21_1 = BC1_5 bxor ?CAN64(BC3_5, BC2_5),
|
||||||
|
A7_1 = BC2_5 bxor ?CAN64(BC4_5, BC3_5),
|
||||||
|
A18_1 = BC3_5 bxor ?CAN64(BC0_5, BC4_5),
|
||||||
|
A4_1 = BC4_5 bxor ?CAN64(BC1_5, BC0_5),
|
||||||
|
|
||||||
|
{A0_1, A1_1, A2_1, A3_1, A4_1, A5_1, A6_1, A7_1, A8_1, A9_1, A10_1, A11_1, A12_1, A13_1,
|
||||||
|
A14_1, A15_1, A16_1, A17_1, A18_1, A19_1, A20_1, A21_1, A22_1, A23_1, A24_1}.
|
||||||
|
|
||||||
|
fast_round4({A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22, A23, A24}, RC3) ->
|
||||||
|
%% Round 4
|
||||||
|
BC0_0 = A0 bxor A5 bxor A10 bxor A15 bxor A20,
|
||||||
|
BC1_0 = A1 bxor A6 bxor A11 bxor A16 bxor A21,
|
||||||
|
BC2_0 = A2 bxor A7 bxor A12 bxor A17 bxor A22,
|
||||||
|
BC3_0 = A3 bxor A8 bxor A13 bxor A18 bxor A23,
|
||||||
|
BC4_0 = A4 bxor A9 bxor A14 bxor A19 bxor A24,
|
||||||
|
D0 = BC4_0 bxor ?ROTL64(BC1_0, 1),
|
||||||
|
D1 = BC0_0 bxor ?ROTL64(BC2_0, 1),
|
||||||
|
D2 = BC1_0 bxor ?ROTL64(BC3_0, 1),
|
||||||
|
D3 = BC2_0 bxor ?ROTL64(BC4_0, 1),
|
||||||
|
D4 = BC3_0 bxor ?ROTL64(BC0_0, 1),
|
||||||
|
|
||||||
|
BC0_1 = A0 bxor D0,
|
||||||
|
BC1_1 = ?ROTL64(A1 bxor D1, 44),
|
||||||
|
BC2_1 = ?ROTL64(A2 bxor D2, 43),
|
||||||
|
BC3_1 = ?ROTL64(A3 bxor D3, 21),
|
||||||
|
BC4_1 = ?ROTL64(A4 bxor D4, 14),
|
||||||
|
A0_1 = BC0_1 bxor ?CAN64(BC2_1, BC1_1) bxor RC3,
|
||||||
|
A1_1 = BC1_1 bxor ?CAN64(BC3_1, BC2_1),
|
||||||
|
A2_1 = BC2_1 bxor ?CAN64(BC4_1, BC3_1),
|
||||||
|
A3_1 = BC3_1 bxor ?CAN64(BC0_1, BC4_1),
|
||||||
|
A4_1 = BC4_1 bxor ?CAN64(BC1_1, BC0_1),
|
||||||
|
|
||||||
|
BC2_2 = ?ROTL64(A5 bxor D0, 3),
|
||||||
|
BC3_2 = ?ROTL64(A6 bxor D1, 45),
|
||||||
|
BC4_2 = ?ROTL64(A7 bxor D2, 61),
|
||||||
|
BC0_2 = ?ROTL64(A8 bxor D3, 28),
|
||||||
|
BC1_2 = ?ROTL64(A9 bxor D4, 20),
|
||||||
|
A5_1 = BC0_2 bxor ?CAN64(BC2_2, BC1_2),
|
||||||
|
A6_1 = BC1_2 bxor ?CAN64(BC3_2, BC2_2),
|
||||||
|
A7_1 = BC2_2 bxor ?CAN64(BC4_2, BC3_2),
|
||||||
|
A8_1 = BC3_2 bxor ?CAN64(BC0_2, BC4_2),
|
||||||
|
A9_1 = BC4_2 bxor ?CAN64(BC1_2, BC0_2),
|
||||||
|
|
||||||
|
BC4_3 = ?ROTL64(A10 bxor D0, 18),
|
||||||
|
BC0_3 = ?ROTL64(A11 bxor D1, 1),
|
||||||
|
BC1_3 = ?ROTL64(A12 bxor D2, 6),
|
||||||
|
BC2_3 = ?ROTL64(A13 bxor D3, 25),
|
||||||
|
BC3_3 = ?ROTL64(A14 bxor D4, 8),
|
||||||
|
A10_1 = BC0_3 bxor ?CAN64(BC2_3, BC1_3),
|
||||||
|
A11_1 = BC1_3 bxor ?CAN64(BC3_3, BC2_3),
|
||||||
|
A12_1 = BC2_3 bxor ?CAN64(BC4_3, BC3_3),
|
||||||
|
A13_1 = BC3_3 bxor ?CAN64(BC0_3, BC4_3),
|
||||||
|
A14_1 = BC4_3 bxor ?CAN64(BC1_3, BC0_3),
|
||||||
|
|
||||||
|
BC1_4 = ?ROTL64(A15 bxor D0, 36),
|
||||||
|
BC2_4 = ?ROTL64(A16 bxor D1, 10),
|
||||||
|
BC3_4 = ?ROTL64(A17 bxor D2, 15),
|
||||||
|
BC4_4 = ?ROTL64(A18 bxor D3, 56),
|
||||||
|
BC0_4 = ?ROTL64(A19 bxor D4, 27),
|
||||||
|
A15_1 = BC0_4 bxor ?CAN64(BC2_4, BC1_4),
|
||||||
|
A16_1 = BC1_4 bxor ?CAN64(BC3_4, BC2_4),
|
||||||
|
A17_1 = BC2_4 bxor ?CAN64(BC4_4, BC3_4),
|
||||||
|
A18_1 = BC3_4 bxor ?CAN64(BC0_4, BC4_4),
|
||||||
|
A19_1 = BC4_4 bxor ?CAN64(BC1_4, BC0_4),
|
||||||
|
|
||||||
|
BC3_5 = ?ROTL64(A20 bxor D0, 41),
|
||||||
|
BC4_5 = ?ROTL64(A21 bxor D1, 2),
|
||||||
|
BC0_5 = ?ROTL64(A22 bxor D2, 62),
|
||||||
|
BC1_5 = ?ROTL64(A23 bxor D3, 55),
|
||||||
|
BC2_5 = ?ROTL64(A24 bxor D4, 39),
|
||||||
|
A20_1 = BC0_5 bxor ?CAN64(BC2_5, BC1_5),
|
||||||
|
A21_1 = BC1_5 bxor ?CAN64(BC3_5, BC2_5),
|
||||||
|
A22_1 = BC2_5 bxor ?CAN64(BC4_5, BC3_5),
|
||||||
|
A23_1 = BC3_5 bxor ?CAN64(BC0_5, BC4_5),
|
||||||
|
A24_1 = BC4_5 bxor ?CAN64(BC1_5, BC0_5),
|
||||||
|
|
||||||
|
{A0_1, A1_1, A2_1, A3_1, A4_1, A5_1, A6_1, A7_1, A8_1, A9_1, A10_1, A11_1, A12_1, A13_1,
|
||||||
|
A14_1, A15_1, A16_1, A17_1, A18_1, A19_1, A20_1, A21_1, A22_1, A23_1, A24_1}.
|
||||||
|
102
src/sha3.py
Normal file
102
src/sha3.py
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Implementation by Gilles Van Assche, hereby denoted as "the implementer".
|
||||||
|
#
|
||||||
|
# For more information, feedback or questions, please refer to our website:
|
||||||
|
# https://keccak.team/
|
||||||
|
#
|
||||||
|
# To the extent possible under law, the implementer has waived all copyright
|
||||||
|
# and related or neighboring rights to the source code in this file.
|
||||||
|
# http://creativecommons.org/publicdomain/zero/1.0/
|
||||||
|
|
||||||
|
def ROL64(a, n):
|
||||||
|
return ((a >> (64-(n%64))) + (a << (n%64))) % (1 << 64)
|
||||||
|
|
||||||
|
def KeccakF1600onLanes(lanes):
|
||||||
|
R = 1
|
||||||
|
for round in range(24):
|
||||||
|
# θ
|
||||||
|
C = [lanes[x][0] ^ lanes[x][1] ^ lanes[x][2] ^ lanes[x][3] ^ lanes[x][4] for x in range(5)]
|
||||||
|
D = [C[(x+4)%5] ^ ROL64(C[(x+1)%5], 1) for x in range(5)]
|
||||||
|
lanes = [[lanes[x][y]^D[x] for y in range(5)] for x in range(5)]
|
||||||
|
# ρ and π
|
||||||
|
(x, y) = (1, 0)
|
||||||
|
current = lanes[x][y]
|
||||||
|
for t in range(24):
|
||||||
|
(x, y) = (y, (2*x+3*y)%5)
|
||||||
|
(current, lanes[x][y]) = (lanes[x][y], ROL64(current, (t+1)*(t+2)//2))
|
||||||
|
# χ
|
||||||
|
for y in range(5):
|
||||||
|
T = [lanes[x][y] for x in range(5)]
|
||||||
|
for x in range(5):
|
||||||
|
lanes[x][y] = T[x] ^((~T[(x+1)%5]) & T[(x+2)%5])
|
||||||
|
# ι
|
||||||
|
for j in range(7):
|
||||||
|
R = ((R << 1) ^ ((R >> 7)*0x71)) % 256
|
||||||
|
if (R & 2):
|
||||||
|
lanes[0][0] = lanes[0][0] ^ (1 << ((1<<j)-1))
|
||||||
|
return lanes
|
||||||
|
|
||||||
|
def load64(b):
|
||||||
|
return sum((b[i] << (8*i)) for i in range(8))
|
||||||
|
|
||||||
|
def store64(a):
|
||||||
|
return list((a >> (8*i)) % 256 for i in range(8))
|
||||||
|
|
||||||
|
def KeccakF1600(state):
|
||||||
|
lanes = [[load64(state[8*(x+5*y):8*(x+5*y)+8]) for y in range(5)] for x in range(5)]
|
||||||
|
lanes = KeccakF1600onLanes(lanes)
|
||||||
|
state = bytearray(200)
|
||||||
|
for x in range(5):
|
||||||
|
for y in range(5):
|
||||||
|
state[8*(x+5*y):8*(x+5*y)+8] = store64(lanes[x][y])
|
||||||
|
return state
|
||||||
|
|
||||||
|
def Keccak(rate, capacity, inputBytes, delimitedSuffix, outputByteLen):
|
||||||
|
outputBytes = bytearray()
|
||||||
|
state = bytearray([0 for i in range(200)])
|
||||||
|
rateInBytes = rate//8
|
||||||
|
blockSize = 0
|
||||||
|
if (((rate + capacity) != 1600) or ((rate % 8) != 0)):
|
||||||
|
return
|
||||||
|
inputOffset = 0
|
||||||
|
# === Absorb all the input blocks ===
|
||||||
|
while(inputOffset < len(inputBytes)):
|
||||||
|
blockSize = min(len(inputBytes)-inputOffset, rateInBytes)
|
||||||
|
for i in range(blockSize):
|
||||||
|
state[i] = state[i] ^ inputBytes[i+inputOffset]
|
||||||
|
inputOffset = inputOffset + blockSize
|
||||||
|
if (blockSize == rateInBytes):
|
||||||
|
state = KeccakF1600(state)
|
||||||
|
blockSize = 0
|
||||||
|
# === Do the padding and switch to the squeezing phase ===
|
||||||
|
state[blockSize] = state[blockSize] ^ delimitedSuffix
|
||||||
|
if (((delimitedSuffix & 0x80) != 0) and (blockSize == (rateInBytes-1))):
|
||||||
|
state = KeccakF1600(state)
|
||||||
|
state[rateInBytes-1] = state[rateInBytes-1] ^ 0x80
|
||||||
|
state = KeccakF1600(state)
|
||||||
|
# === Squeeze out all the output blocks ===
|
||||||
|
while(outputByteLen > 0):
|
||||||
|
blockSize = min(outputByteLen, rateInBytes)
|
||||||
|
outputBytes = outputBytes + state[0:blockSize]
|
||||||
|
outputByteLen = outputByteLen - blockSize
|
||||||
|
if (outputByteLen > 0):
|
||||||
|
state = KeccakF1600(state)
|
||||||
|
return outputBytes
|
||||||
|
|
||||||
|
def SHAKE128(inputBytes, outputByteLen):
|
||||||
|
return Keccak(1344, 256, inputBytes, 0x1F, outputByteLen)
|
||||||
|
|
||||||
|
def SHAKE256(inputBytes, outputByteLen):
|
||||||
|
return Keccak(1088, 512, inputBytes, 0x1F, outputByteLen)
|
||||||
|
|
||||||
|
def SHA3_224(inputBytes):
|
||||||
|
return Keccak(1152, 448, inputBytes, 0x06, 224//8)
|
||||||
|
|
||||||
|
def SHA3_256(inputBytes):
|
||||||
|
return Keccak(1088, 512, inputBytes, 0x06, 256//8)
|
||||||
|
|
||||||
|
def SHA3_384(inputBytes):
|
||||||
|
return Keccak(832, 768, inputBytes, 0x06, 384//8)
|
||||||
|
|
||||||
|
def SHA3_512(inputBytes):
|
||||||
|
return Keccak(576, 1024, inputBytes, 0x06, 512//8)
|
@ -34,31 +34,30 @@ hash_224_test() ->
|
|||||||
?assertEqual(<<16#038907E89C919CD8F90A7FBC5A88FF9278108DAEF3EBCDA0CEB383E1:224>>,
|
?assertEqual(<<16#038907E89C919CD8F90A7FBC5A88FF9278108DAEF3EBCDA0CEB383E1:224>>,
|
||||||
sha3:hash(224, <<16#00112233445566778899AABBCCDDEEFF:128>>)).
|
sha3:hash(224, <<16#00112233445566778899AABBCCDDEEFF:128>>)).
|
||||||
|
|
||||||
|
hash_224_native_test() ->
|
||||||
|
?assertEqual(<<16#038907E89C919CD8F90A7FBC5A88FF9278108DAEF3EBCDA0CEB383E1:224>>,
|
||||||
|
sha3:kek(224, <<16#00112233445566778899AABBCCDDEEFF:128>>)).
|
||||||
|
|
||||||
hash_256_test() ->
|
hash_256_test() ->
|
||||||
?assertEqual(<<16#22BCE46032802AF0ABFACF3768F7BE04A34F5F01DF60F44FFD52D3CA937350C0:256>>,
|
?assertEqual(<<16#22BCE46032802AF0ABFACF3768F7BE04A34F5F01DF60F44FFD52D3CA937350C0:256>>,
|
||||||
sha3:hash(256, <<16#00112233445566778899AABBCCDDEEFF:128>>)).
|
sha3:hash(256, <<16#00112233445566778899AABBCCDDEEFF:128>>)).
|
||||||
|
|
||||||
|
hash_256_native_test() ->
|
||||||
|
?assertEqual(<<16#22BCE46032802AF0ABFACF3768F7BE04A34F5F01DF60F44FFD52D3CA937350C0:256>>,
|
||||||
|
sha3:kek(256, <<16#00112233445566778899AABBCCDDEEFF:128>>)).
|
||||||
|
|
||||||
hash_384_test() ->
|
hash_384_test() ->
|
||||||
?assertEqual(<<16#25FAC1ADECBE1B254976FE32C2FE78829B23D7D84316141ECD208D6806A9DB4352A014ADA4106BA0D210DDA0FD18E150:384>>,
|
?assertEqual(<<16#25FAC1ADECBE1B254976FE32C2FE78829B23D7D84316141ECD208D6806A9DB4352A014ADA4106BA0D210DDA0FD18E150:384>>,
|
||||||
sha3:hash(384, <<16#00112233445566778899AABBCCDDEEFF:128>>)).
|
sha3:hash(384, <<16#00112233445566778899AABBCCDDEEFF:128>>)).
|
||||||
|
|
||||||
|
hash_384_native_test() ->
|
||||||
|
?assertEqual(<<16#25FAC1ADECBE1B254976FE32C2FE78829B23D7D84316141ECD208D6806A9DB4352A014ADA4106BA0D210DDA0FD18E150:384>>,
|
||||||
|
sha3:kek(384, <<16#00112233445566778899AABBCCDDEEFF:128>>)).
|
||||||
|
|
||||||
hash_512_test() ->
|
hash_512_test() ->
|
||||||
?assertEqual(<<16#94EE7851163C39C3489373AA0BF885D95925EAD7484C586D2E0D01D9C8069D3C30E2EEA2DC63A91B517FE53E43A31D764A2154A2DA92876366B138ABC4406805:512>>,
|
?assertEqual(<<16#94EE7851163C39C3489373AA0BF885D95925EAD7484C586D2E0D01D9C8069D3C30E2EEA2DC63A91B517FE53E43A31D764A2154A2DA92876366B138ABC4406805:512>>,
|
||||||
sha3:hash(512, <<16#00112233445566778899AABBCCDDEEFF:128>>)).
|
sha3:hash(512, <<16#00112233445566778899AABBCCDDEEFF:128>>)).
|
||||||
|
|
||||||
hexhash_224_test() ->
|
hash_512_native_test() ->
|
||||||
?assertEqual(<<"038907E89C919CD8F90A7FBC5A88FF9278108DAEF3EBCDA0CEB383E1">>,
|
?assertEqual(<<16#94EE7851163C39C3489373AA0BF885D95925EAD7484C586D2E0D01D9C8069D3C30E2EEA2DC63A91B517FE53E43A31D764A2154A2DA92876366B138ABC4406805:512>>,
|
||||||
sha3:hexhash(224, <<16#00112233445566778899AABBCCDDEEFF:128>>)).
|
sha3:kek(512, <<16#00112233445566778899AABBCCDDEEFF:128>>)).
|
||||||
|
|
||||||
hexhash_256_test() ->
|
|
||||||
?assertEqual(<<"22BCE46032802AF0ABFACF3768F7BE04A34F5F01DF60F44FFD52D3CA937350C0">>,
|
|
||||||
sha3:hexhash(256, <<16#00112233445566778899AABBCCDDEEFF:128>>)).
|
|
||||||
|
|
||||||
hexhash_384_test() ->
|
|
||||||
?assertEqual(<<"25FAC1ADECBE1B254976FE32C2FE78829B23D7D84316141ECD208D6806A9DB4352A014ADA4106BA0D210DDA0FD18E150">>,
|
|
||||||
sha3:hexhash(384, <<16#00112233445566778899AABBCCDDEEFF:128>>)).
|
|
||||||
|
|
||||||
hexhash_512_test() ->
|
|
||||||
?assertEqual(<<"94EE7851163C39C3489373AA0BF885D95925EAD7484C586D2E0D01D9C8069D3C30E2EEA2DC63A91B517FE53E43A31D764A2154A2DA92876366B138ABC4406805">>,
|
|
||||||
sha3:hexhash(512, <<16#00112233445566778899AABBCCDDEEFF:128>>)).
|
|
||||||
|
|
||||||
|
17
zomp.meta
Normal file
17
zomp.meta
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
{name,"Erlang SHA-3/Keccak"}.
|
||||||
|
{type,lib}.
|
||||||
|
{modules,[]}.
|
||||||
|
{prefix,none}.
|
||||||
|
{author,"Craig Everett"}.
|
||||||
|
{desc,"SHA-3 and Keccak in NIF and native Erlang."}.
|
||||||
|
{package_id,{"otpr","sha3",{0,1,5}}}.
|
||||||
|
{deps,[]}.
|
||||||
|
{key_name,none}.
|
||||||
|
{a_email,"zxq9@zxq9.com"}.
|
||||||
|
{c_email,"tetsuya.suzuki@gmail.com"}.
|
||||||
|
{copyright,"SUZUKI Tetsuya"}.
|
||||||
|
{file_exts,[]}.
|
||||||
|
{license,"Apache-2.0"}.
|
||||||
|
{repo_url,"https://github.com/zxq9/erlang-sha3"}.
|
||||||
|
{tags,["aeternity","sha3","blockchain","keccak"]}.
|
||||||
|
{ws_url,[]}.
|
Loading…
x
Reference in New Issue
Block a user