1 Commits

Author SHA1 Message Date
zxq9 feae15740a WIP 2025-12-31 01:06:20 +09:00
16 changed files with 1284 additions and 3885 deletions
+2 -2
View File
@@ -8,9 +8,9 @@ cancer
erl_crash.dump erl_crash.dump
ebin/*.beam ebin/*.beam
doc/*.html doc/*.html
doc/erlang.png doc/*.css
doc/stylesheet.css
doc/edoc-info doc/edoc-info
doc/erlang.png
rel/example_project rel/example_project
.concrete/DEV_MODE .concrete/DEV_MODE
.rebar .rebar
Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

-75
View File
@@ -1,75 +0,0 @@
/* standard EDoc style sheet */
body {
font-family: Verdana, Arial, Helvetica, sans-serif;
margin-left: .25in;
margin-right: .2in;
margin-top: 0.2in;
margin-bottom: 0.2in;
color: #696969;
background-color: #ffffff;
}
a:link{
color: #000000;
}
a:visited{
color: #000000;
}
a:hover{
color: #d8613c;
}
h1,h2 {
margin-left: -0.2in;
}
div.navbar {
background-color: #000000;
padding: 0.2em;
}
h2.indextitle {
padding: 0.4em;
color: #dfdfdf;
background-color: #000000;
}
div.navbar a:link {
color: #dfdfdf;
}
div.navbar a:visited {
color: #dfdfdf;
}
div.navbar a:hover {
color: #d8613c;
}
h3.function,h3.typedecl {
background-color: #000000;
color: #dfdfdf;
padding-left: 1em;
}
div.spec {
margin-left: 2em;
background-color: #eeeeee;
}
a.module {
text-decoration:none
}
a.module:hover {
background-color: #eeeeee;
}
ul.definitions {
list-style-type: none;
}
ul.index {
list-style-type: none;
background-color: #eeeeee;
}
/*
* Minor style tweaks
*/
ul {
list-style-type: square;
}
table {
border-collapse: collapse;
}
td {
padding: 3
}
+3 -4
View File
@@ -1,6 +1,5 @@
@author Craig Everett <craigeverett@qpq.swiss> [https://zxq9.com] @author Craig Everett <craigeverett@qpq.swiss> [https://git.qpq.swiss/QPQ-AG/hakuzaru]
@author Jarvis Carrol <jarviscarrol@qpq.swiss> [https://jarviscarroll.net/] @version 0.8.0
@version 0.9.2
@title Hakuzaru: Gajumaru blockchain bindings for Erlang @title Hakuzaru: Gajumaru blockchain bindings for Erlang
@doc @doc
@@ -22,7 +21,7 @@ After startup `hz_man' must be given the address and port of a list of Gajumaru
Note that the service nodes will need to have the dry-run endpoint enabled and the internal service query port made available in order to provide dry-runs and transaction submission. Note that the service nodes will need to have the dry-run endpoint enabled and the internal service query port made available in order to provide dry-runs and transaction submission.
When configuring chain nodes a list of nodes should be provided. When configuring chain nodes a list of nodes should be provided.
To avoid sync issues in the case of fast transaction formation/submission to the chain, only one node from the list of chain nodes is used for submitting transactions and querying `next_nonce/1'. To avoid sync issues in the case of fast transaction formation/submission to the chain, only one node from the list of chain nodes is used for submitting transactions and querying `next_nonce/1`.
This node is called "the sticky node". This node is called "the sticky node".
The first node in the list of chain nodes provided during configuration is designated as the sticky node. The first node in the list of chain nodes provided during configuration is designated as the sticky node.
+3 -3
View File
@@ -3,7 +3,7 @@
{included_applications,[]}, {included_applications,[]},
{applications,[stdlib,kernel]}, {applications,[stdlib,kernel]},
{description,"Gajumaru interoperation library"}, {description,"Gajumaru interoperation library"},
{vsn,"0.9.2"}, {vsn,"0.8.2"},
{modules,[hakuzaru,hz,hz_aaci,hz_fetcher,hz_format,hz_grids, {modules,[hakuzaru,hz,hz_fetcher,hz_format,hz_grids,
hz_key_master,hz_man,hz_sophia,hz_sup]}, hz_key_master,hz_man,hz_sup]},
{mod,{hakuzaru,[]}}]}. {mod,{hakuzaru,[]}}]}.
+1 -1
View File
@@ -6,7 +6,7 @@
%%% @end %%% @end
-module(hakuzaru). -module(hakuzaru).
-vsn("0.9.2"). -vsn("0.8.2").
-author("Craig Everett <ceverett@tsuriai.jp>"). -author("Craig Everett <ceverett@tsuriai.jp>").
-copyright("Craig Everett <ceverett@tsuriai.jp>"). -copyright("Craig Everett <ceverett@tsuriai.jp>").
-license("GPL-3.0-or-later"). -license("GPL-3.0-or-later").
+1197 -293
View File
File diff suppressed because it is too large Load Diff
-1673
View File
File diff suppressed because it is too large Load Diff
+1 -9
View File
@@ -1,13 +1,5 @@
%%% @private
%%% Hakuzaru Request Fetcher
%%%
%%% This module defines the request workers.
%%% Each request to a remote chain node is handled by a worker that is spawned
%%% to handle it and terminates on completion.
%%% @end
-module(hz_fetcher). -module(hz_fetcher).
-vsn("0.9.2"). -vsn("0.8.2").
-author("Craig Everett <ceverett@tsuriai.jp>"). -author("Craig Everett <ceverett@tsuriai.jp>").
-copyright("Craig Everett <ceverett@tsuriai.jp>"). -copyright("Craig Everett <ceverett@tsuriai.jp>").
-license("MIT"). -license("MIT").
+1 -18
View File
@@ -21,7 +21,7 @@
%%% @end %%% @end
-module(hz_format). -module(hz_format).
-vsn("0.9.2"). -vsn("0.8.2").
-author("Craig Everett <ceverett@tsuriai.jp>"). -author("Craig Everett <ceverett@tsuriai.jp>").
-copyright("Craig Everett <ceverett@tsuriai.jp>"). -copyright("Craig Everett <ceverett@tsuriai.jp>").
-license("GPL-3.0-or-later"). -license("GPL-3.0-or-later").
@@ -462,26 +462,9 @@ ranks(heresy) ->
["k ", "m ", "b ", "t ", "q ", "e ", "z ", "y ", "r ", "Q "]. ["k ", "m ", "b ", "t ", "q ", "e ", "z ", "y ", "r ", "Q "].
-spec mark(Unit) -> Mark
when Unit :: gaju | puck,
Mark :: $木 | $本.
%% @doc
%% Retrieve the unicode codepoint for the `gaju' mark (木) or the `puck' mark (本).
mark(gaju) -> $木; mark(gaju) -> $木;
mark(puck) -> $本. mark(puck) -> $本.
-spec one(Unit) -> Pucks
when Unit :: gaju | puck,
Pucks :: 1_000_000_000_000_000_000 | 1.
%% @doc
%% Quickly resolve the number of pucks in a given unit.
%%
%% The number of pucks in a gaju is so large that it can be a little bit annoying
%% to remember the exact amount. This is a helper to simplify this when writing
%% an app against the hakuzaru library when dealing in either unit.
one(gaju) -> 1_000_000_000_000_000_000; one(gaju) -> 1_000_000_000_000_000_000;
one(puck) -> 1. one(puck) -> 1.
+42 -44
View File
@@ -37,8 +37,8 @@
%%% @end %%% @end
-module(hz_grids). -module(hz_grids).
-vsn("0.9.2"). -vsn("0.8.2").
-export([url/2, url/3, url/4, parse/1, req/2, req/3, req/4]). -export([url/2, url/3, url/4, parse/1, req/2, req/3]).
-spec url(Instruction, HTTP) -> Result -spec url(Instruction, HTTP) -> Result
@@ -47,7 +47,7 @@
Result :: {ok, GRIDS} | uri_string:uri_error(), Result :: {ok, GRIDS} | uri_string:uri_error(),
GRIDS :: uri_string:uri_string(). GRIDS :: uri_string:uri_string().
%% @doc %% @doc
%% Takes an instruction and an HTTP endpoint location and forms a GRIDS URL. %% Takes
url(Instruction, HTTP) -> url(Instruction, HTTP) ->
case uri_string:parse(HTTP) of case uri_string:parse(HTTP) of
@@ -134,8 +134,6 @@ qwargs(Amount, Payload) ->
Amount :: non_neg_integer(), Amount :: non_neg_integer(),
Payload :: binary(), Payload :: binary(),
URL :: string(). URL :: string().
%% @doc
%% Translate a GRIDS URL into an Erlang terms instruction.
parse(GRIDS) -> parse(GRIDS) ->
case uri_string:parse(GRIDS) of case uri_string:parse(GRIDS) of
@@ -192,61 +190,61 @@ l_to_i(S) ->
end. end.
-spec req(Type, Message) -> Format -spec req(Type, Message) -> RequestMap
when Type :: sign | tx | ack, when Type :: {sign, message | binary | bitcoin}
Message :: string() | binary(), | tx
Format :: map(). | ack
| sign,
Message :: binary(),
RequestMap :: map().
%% @doc %% @doc
%% @equiv req(Type, Message, false) %% GRIDS maps always contain the following keys:
%% ```
%% #{"grids" => 1,
%% "chain" => "gajumaru",
%% "network_id" => "groot.mainnet.gajumaru.io",
%% "type" => "message" | "binary" | "binary" | "tx" | "ack"
%% "public_id" => term(),
%% "payload" => string()};
%% '''
req(Type, Message) -> req(Type, Message) ->
req(Type, Message, false). req(Type, Message, false).
req({sign, message}, Message, ID) ->
-spec req(Type, Message, ID) -> Format
when Type :: sign | tx | ack,
Message :: string() | binary(),
ID :: false | string() | binary(),
Format :: map().
%% @doc
%% Creates a GRIDS message format with the current `NetworkID'.
%%
%% The `ID' parameter indicates which key the requestee should sign with or
%% is `false' to indicate that which key to sign with is up to the requestee.
%% @equiv req(Type, Message, ID, CurrentNetworkID)
req(Type, Message, ID) ->
{ok, NetworkID} = hz:network_id(),
req(Type, Message, ID, NetworkID).
-spec req(Type, Message, ID, NetworkID) -> Format
when Type :: sign | tx | ack,
Message :: string() | binary(),
ID :: false | string() | binary(),
NetworkID :: string() | binary(),
Format :: map().
%% @doc
%% Creates a GRIDS message format.
req(sign, Message, ID, NetworkID) ->
#{"grids" => 1, #{"grids" => 1,
"chain" => "gajumaru", "chain" => "gajumaru",
"network_id" => NetworkID, "network_id" => hz:network_id(),
"type" => "message", "type" => "message",
"public_id" => ID, "public_id" => ID,
"payload" => Message}; "payload" => Message};
req(tx, Data, ID, NetworkID) -> req({sign, binary}, Binary, ID) ->
#{"grids" => 1, #{"grids" => 1,
"chain" => "gajumaru", "chain" => "gajumaru",
"network_id" => NetworkID, "network_id" => hz:network_id(),
"type" => "binary",
"public_id" => ID,
"payload" => base64:encode(Binary)};
req({sign, bitcoin}, Binary, ID) ->
#{"grids" => 1,
"chain" => "gajumaru",
"network_id" => hz:network_id(),
"type" => "bitcoin",
"public_id" => ID,
"payload" => base64:encode(Binary)};
req(tx, Data, ID) ->
#{"grids" => 1,
"chain" => "gajumaru",
"network_id" => hz:network_id(),
"type" => "tx", "type" => "tx",
"public_id" => ID, "public_id" => ID,
"payload" => Data}; "payload" => Data};
req(ack, Message, ID, NetworkID) -> req(ack, Message, ID) ->
#{"grids" => 1, #{"grids" => 1,
"chain" => "gajumaru", "chain" => "gajumaru",
"network_id" => NetworkID, "network_id" => hz:network_id(),
"type" => "ack", "type" => "ack",
"public_id" => ID, "public_id" => ID,
"payload" => Message}. "payload" => Message};
req(sign, Message, ID) ->
req({sign, message}, Message, ID).
+29 -238
View File
@@ -1,43 +1,18 @@
%%% @doc %%% @doc
%%% Hakuzaru Key Functions %%% Key functions
%%% %%%
%%% The Gajumaru's default key type is based on Elliptical Curve Cryptography (ECC). %%% The main reason this is a module of its own is that in the original architecture
%%% The specific curve used is 25519, and the typical key representation is Ed25519. %%% it was a process rather than just a library of functions. Now that it exists, though,
%%% %%% there is little motivation to cram everything here into the controller process's
%%% The "Ed" in "Ed25519" stands for Harold Edwards. This form represents %%% code.
%%% a coordinate on a "Twisted Edwards Curve".
%%%
%%% The "X" in "X25519" stands for the X-coordinate, also known as the
%%% "Montgomery u-coordinate" on a "Montgomery Curve".
%%%
%%% The two are equivalent, but have meaningfully different properties.
%%% @end %%% @end
-module(hz_key_master). -module(hz_key_master).
-vsn("0.9.2"). -vsn("0.8.2").
-export([make_key/0, make_key/1, encode/1, decode/1]).
-export([shared_secret_a/6, shared_secret_b/6,
ed25519_pk_to_x25519/1, ed25519_sk_to_x25519/1,
hkdf/4, hkdf/5]).
-spec make_key() -> {ID, KeyPair} -export([make_key/1, encode/1, decode/1]).
when ID :: string(), -export([lcg/1]).
KeyPair :: #{secret => binary(), public => binary()}.
%% @doc
%% @equiv make_key(<<>>)
make_key() ->
make_key(<<>>).
-spec make_key(Secret) -> {ID, KeyPair}
when Secret :: <<>> | <<_:32*8>>,
ID :: string(),
KeyPair :: #{secret => binary(), public => binary()}.
%% @doc
%% Generate a Ed25519 keypair tagged with the corresponding Gajumaru ID.
make_key(<<>>) -> make_key(<<>>) ->
Pair = #{public := Public} = ecu_eddsa:sign_keypair(), Pair = #{public := Public} = ecu_eddsa:sign_keypair(),
@@ -151,212 +126,28 @@ sumcheck(Width, Bits) ->
end. end.
-spec shared_secret_a(A_E_E_SK, B_P_E_PK, B_E_E_PK, Protocol, Version, Salt) -> SS
when A_E_E_SK :: binary(), -spec lcg(integer()) -> integer().
B_P_E_PK :: <<_:32*8>>, %% A simple PRNG that fits into 32 bits and is easy to implement anywhere (Kotlin).
B_E_E_PK :: <<_:32*8>>, %% Specifically, it is a "linear congruential generator" of the Lehmer variety.
Protocol :: binary(), %% The constants used are based on recommendations from Park, Miller and Stockmeyer:
Version :: binary(), %% https://www.firstpr.com.au/dsp/rand31/p105-crawford.pdf#page=4
Salt :: binary(),
SS :: <<_:32*8>>.
%% @doc
%% Alice's side of a shared key derivation based on ed25519 keys as generated by this module.
%% %%
%% Typically Alice would be providing an ephemeral key to establish %% The input value should be between 1 and 2^31-1.
%% a shared secret while remaining (at least initially) anonymous from Bob. Bob,
%% on the other hand, is providing a permanent key and also an ephemeral key,
%% proving identity without exposing the shared secret in the future were one of
%% the secrets to be compromised.
%% <ul>
%% <li>`A_E_E_SK' Alice's Ephemeral Ed25519 Secret Key.</li>
%% <li>`B_P_E_PK' Bob's Permanent Ed25519 Public Key.</li>
%% <li>`B_E_E_PK' Bob's Ephemeral Ed25519 Public Key.</li>
%% <li>`Protocol' is an arbitrary binary string, typically a protocol name in UTF-8.</li>
%% <li>`Version' is another arbitrary binary string, typically a protocol version in UTF-8.</li>
%% <li>`Salt' is a binary salt, which if empty will be replaced by a binary string of zeroes.</li>
%% <li>`SS' is the resulting 32-byte shared secret.</li>
%% </ul>
shared_secret_a(A_E_E_SK, B_P_E_PK, B_E_E_PK, Protocol, Version, Salt) ->
A_E_X_SK = ed25519_sk_to_x25519(A_E_E_SK),
B_P_X_PK = ed25519_pk_to_x25519(B_P_E_PK),
B_E_X_PK = ed25519_pk_to_x25519(B_E_E_PK),
DH_Permanent = crypto:compute_key(ecdh, B_P_X_PK, A_E_X_SK, x25519),
DH_Ephemeral = crypto:compute_key(ecdh, B_E_X_PK, A_E_X_SK, x25519),
finalize_hkdf(DH_Permanent, DH_Ephemeral, Protocol, Version, Salt).
-spec shared_secret_b(B_P_E_SK, B_E_E_SK, A_E_E_PK, Protocol, Version, Salt) -> SS
when B_P_E_SK :: binary(),
B_E_E_SK :: binary(),
A_E_E_PK :: <<_:32*8>>,
Protocol :: binary(),
Version :: binary(),
Salt :: binary(),
SS :: <<_:32*8>>.
%% @doc
%% Bobs's side of a shared key derivation based on ed25519 keys as generated by this module.
%% %%
%% Typically Alice would be providing an ephemeral key to establish %% The purpose of this PRNG is for password-based dictionary shuffling.
%% a shared secret while remaining (at least initially) anonymous from Bob. Bob,
%% on the other hand, is providing a permanent key and also an ephemeral key,
%% proving identity without exposing the shared secret in the future were one of
%% the secrets to be compromised.
%% <ul>
%% <li>`B_P_E_SK' Bob's Permanent Ed25519 Secret Key.</li>
%% <li>`B_E_E_SK' Bob's Ephemeral Ed25519 Secret Key.</li>
%% <li>`A_E_E_PK' Alice's Ephemeral Ed25519 Public Key.</li>
%% <li>`Protocol' is an arbitrary binary string, typically a protocol name in UTF-8.</li>
%% <li>`Version' is another arbitrary binary string, typically a protocol version in UTF-8.</li>
%% <li>`Salt' is a binary salt, which if empty will be replaced by a binary string of zeroes.</li>
%% <li>`SS' is the resulting 32-byte shared secret.</li>
%% </ul>
shared_secret_b(B_P_E_SK, B_E_E_SK, A_E_E_PK, Protocol, Version, Salt) -> lcg(N) ->
B_P_X_SK = ed25519_sk_to_x25519(B_P_E_SK), M = 16#7FFFFFFF,
B_E_X_SK = ed25519_sk_to_x25519(B_E_E_SK), A = 48271,
A_E_X_PK = ed25519_pk_to_x25519(A_E_E_PK), Q = 44488, % M div A
DH_Permanent = crypto:compute_key(ecdh, A_E_X_PK, B_P_X_SK, x25519), R = 3399, % M rem A
DH_Ephemeral = crypto:compute_key(ecdh, A_E_X_PK, B_E_X_SK, x25519), Div = N div Q,
finalize_hkdf(DH_Permanent, DH_Ephemeral, Protocol, Version, Salt). Rem = N rem Q,
S = Rem * A,
finalize_hkdf(DH_Permanent, DH_Ephemeral, Protocol, Version, Salt) -> T = Div * R,
MixedInput = <<DH_Permanent/binary, DH_Ephemeral/binary>>, Result = S - T,
Info = <<Protocol/binary, ":", Version/binary, ":">>, case Result < 0 of
hkdf(sha256, MixedInput, Salt, Info). false -> Result;
true -> Result + M
%% Curve25519 Prime Field Constant: 2^255 - 19
%% Yes, in hex it reads kind of like "lucky fed"
p() -> 16#7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFED.
-spec ed25519_pk_to_x25519(ED25519_PubKey) -> X25519_PubKey
when ED25519_PubKey :: <<_:32*8>>,
X25519_PubKey :: <<_:32*8>>.
%% @doc
%% Convert a curve 25519 public key from Edwards representation to X-coordinate
%% representation.
ed25519_pk_to_x25519(<<ED25519_PK:32/binary>>) ->
<<CompressedInt:256/little-integer>> = ED25519_PK,
% Clear the sign bit (MSB) to get the raw y-coordinate
Y = CompressedInt band ((1 bsl 255) - 1),
% Compute u = (1 + y) / (1 - y) mod P
Num = (1 + Y) rem p(),
Den = (1 - Y + p()) rem p(),
case Den =:= 0 of
true ->
% If y == 1, the point maps to the point at infinity.
% On X25519, this translates to u = 0.
<<0:256/little-integer>>;
false ->
U = (Num * mod_inv(Den, p())) rem p(),
<<U:256/little-integer>>
end. end.
-spec ed25519_sk_to_x25519(ED25519_SecKey) -> X25519_SecKey
when ED25519_SecKey :: binary(),
X25519_SecKey :: <<_:32*8>>.
%% @doc
%% Convert a curve 25519 secret key from Edwards representation to X-coordinate
%% representation.
ed25519_sk_to_x25519(<<ED25519_SK_Secret:32/binary, _/binary>>) ->
<<X25519_SK:32/binary, _/binary>> = crypto:hash(sha512, ED25519_SK_Secret),
X25519_SK.
mod_inv(A, M) ->
{1, X, _} = ext_gcd(A, M),
(X + M) rem M.
ext_gcd(A, 0) ->
{A, 1, 0};
ext_gcd(A, B) ->
{G, X1, Y1} = ext_gcd(B, A rem B),
{G, Y1, X1 - (A div B) * Y1}.
-spec hkdf(Hash, IKM, Salt, Info) -> DerivedKey
when Hash :: md5 | sha | sha224 | sha256 | sha384 | sha512,
IKM :: binary(),
Salt :: binary(),
Info :: binary(),
DerivedKey :: <<_:32*8>>.
%% @doc
%% 32-byte HMAC-Based Extract-and-Expand Key Derivation
%% @equiv hkdf(Hash, IKM, Salt, Info, 32)
hkdf(Hash, IKM, Salt, Info) ->
hkdf(Hash, IKM, Salt, Info, 32).
-spec hkdf(Hash, IKM, Salt, Info, Length) -> DerivedKey
when Hash :: md5 | sha | sha224 | sha256 | sha384 | sha512,
IKM :: binary(),
Salt :: binary(),
Info :: binary(),
Length :: 16 | 20 | 28 | 32 | 48 | 64,
DerivedKey :: binary().
%% @doc
%% RFC-5869 compliant HMAC-Based Extract-and-Expand Key Derivation
%%
%% RFC-5869:
%% <a href="https://datatracker.ietf.org/doc/html/rfc5869">https://datatracker.ietf.org/doc/html/rfc5869</a>
%%
%% The purpose of HKDF is to take an initial, raw secret input that might
%% be mathematically strong but structurally "clumpy" and transform it into one
%% or more uniform, high-entropy keys suitable for use in cryptography.
%%
%% The problem is that when Alice and Bob compute a Diffie-Hellman shared secret
%% over X25519, the resulting bytes are mathematically secure, but they are not
%% evenly distributed as random noise. Cryptographic ciphers expect keys where
%% every single bit has an exactly 50% chance of being a 0 or a 1. Passing raw
%% DH outputs straight into a cipher can introduce subtle, exploitable patterns.
%%
%% HKDF "smooths out" the entropy.
%%
%% HMAC stands for "Keyed-Hash Message Authentication Code", but without the
%% leading "K" just to keep us on our toes. The problem it solves is that simply
%% concatenating a secret and some target data and hashing them together to produce
%% a message authentication hash leaves the resulting hash vulnerable to a "length
%% extension attack". An attacker can append additional data to the end of the
%% message and arrive at a valid new hash without ever knowing the secret.
%%
%% RFC-2104 provides good background information on the technique:
%% <a href="https://datatracker.ietf.org/doc/html/rfc2104">https://datatracker.ietf.org/doc/html/rfc2104</a>
hkdf(Hash, IKM, Salt, Info, Length) ->
PRK = extract(Hash, Salt, IKM),
expand(Hash, PRK, Info, Length).
extract(Hash, <<>>, IKM) ->
%% If salt is empty RFC 5869 requires a string of zeros equal to hash size
Salt = binary:copy(<<0>>, hash_size(Hash)),
extract(Hash, Salt, IKM);
extract(Hash, Salt, IKM) ->
crypto:mac(hmac, Hash, Salt, IKM).
expand(Hash, PRK, Info, OutLen) ->
HashLen = hash_size(Hash),
BlockCount = (OutLen + HashLen - 1) div HashLen,
true = BlockCount =< 255,
FullBlocks = expand_loop(Hash, PRK, Info, BlockCount, 1, <<>>, <<>>),
<<Output:OutLen/binary, _/binary>> = FullBlocks,
Output.
expand_loop(Hash, PRK, Info, N, Counter, PrevT, Acc) when Counter =< N ->
Payload = <<PrevT/binary, Info/binary, Counter:8>>,
T = crypto:mac(hmac, Hash, PRK, Payload),
expand_loop(Hash, PRK, Info, N, Counter + 1, T, <<Acc/binary, T/binary>>);
expand_loop(_, _, _, _, _, _, Acc) ->
Acc.
hash_size(md5) -> 16;
hash_size(sha) -> 20;
hash_size(sha224) -> 28;
hash_size(sha256) -> 32;
hash_size(sha384) -> 48;
hash_size(sha512) -> 64.
+2 -1
View File
@@ -9,7 +9,7 @@
%%% @end %%% @end
-module(hz_man). -module(hz_man).
-vsn("0.9.2"). -vsn("0.8.2").
-behavior(gen_server). -behavior(gen_server).
-author("Craig Everett <ceverett@tsuriai.jp>"). -author("Craig Everett <ceverett@tsuriai.jp>").
-copyright("Craig Everett <ceverett@tsuriai.jp>"). -copyright("Craig Everett <ceverett@tsuriai.jp>").
@@ -172,6 +172,7 @@ start_link() ->
%% preparatory work necessary for proper function. %% preparatory work necessary for proper function.
init(none) -> init(none) ->
ok = io:format("hz_man starting.~n"),
State = #s{}, State = #s{},
{ok, State}. {ok, State}.
-1521
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -9,7 +9,7 @@
%%% @end %%% @end
-module(hz_sup). -module(hz_sup).
-vsn("0.9.2"). -vsn("0.8.2").
-behaviour(supervisor). -behaviour(supervisor).
-author("Craig Everett <zxq9@zxq9.com>"). -author("Craig Everett <zxq9@zxq9.com>").
-copyright("Craig Everett <zxq9@zxq9.com>"). -copyright("Craig Everett <zxq9@zxq9.com>").
+2 -2
View File
@@ -2,9 +2,9 @@
{type,app}. {type,app}.
{modules,[]}. {modules,[]}.
{prefix,"hz"}. {prefix,"hz"}.
{author,"Craig Everett"}.
{desc,"Gajumaru interoperation library"}. {desc,"Gajumaru interoperation library"}.
{package_id,{"otpr","hakuzaru",{0,9,2}}}. {author,"Craig Everett"}.
{package_id,{"otpr","hakuzaru",{0,8,2}}}.
{deps,[{"otpr","sophia",{9,0,0}}, {deps,[{"otpr","sophia",{9,0,0}},
{"otpr","gmserialization",{0,1,3}}, {"otpr","gmserialization",{0,1,3}},
{"otpr","gmbytecode",{3,4,1}}, {"otpr","gmbytecode",{3,4,1}},