Packages

Gleam based implementation of TentHash for Erlang targets

Current section

Files

Jump to
tenthash src tenthash.erl
Raw

src/tenthash.erl

-module(tenthash).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]).
-export([hash_bitarray/1, hash/1]).
-export_type([hash_state/0]).
-type hash_state() :: {hash_state,
bigi:big_int(),
bigi:big_int(),
bigi:big_int(),
bigi:big_int()}.
-file("/Users/gareth/Development/gleam/tenthash/src/tenthash.gleam", 167).
-spec bitmask(integer()) -> bigi:big_int().
bitmask(Size) ->
_assert_subject = bigi_ffi:power(bigi_ffi:from(2), bigi_ffi:from(Size)),
{ok, Bitmask} = case _assert_subject of
{ok, _} -> _assert_subject;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
value => _assert_fail,
module => <<"tenthash"/utf8>>,
function => <<"bitmask"/utf8>>,
line => 168})
end,
bigi_ffi:subtract(Bitmask, bigi_ffi:from(1)).
-file("/Users/gareth/Development/gleam/tenthash/src/tenthash.gleam", 172).
-spec rot_left(bigi:big_int(), integer(), bigi:big_int()) -> bigi:big_int().
rot_left(I, Count, Bitmask) ->
P1 = bigi_ffi:bitwise_and(bigi_ffi:bitwise_shift_left(I, Count), Bitmask),
P2 = bigi_ffi:bitwise_shift_right(I, 64 - Count),
bigi_ffi:bitwise_or(P1, P2).
-file("/Users/gareth/Development/gleam/tenthash/src/tenthash.gleam", 62).
-spec initial_state() -> {ok, hash_state()} | {error, nil}.
initial_state() ->
[A, B, C, D] = case [<<"6732230515997387111"/utf8>>,
<<"16297768295691943732"/utf8>>,
<<"14578299661238189102"/utf8>>,
<<"9893891307554648435"/utf8>>] of
[_, _, _, _] -> [<<"6732230515997387111"/utf8>>,
<<"16297768295691943732"/utf8>>,
<<"14578299661238189102"/utf8>>,
<<"9893891307554648435"/utf8>>];
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
value => _assert_fail,
module => <<"tenthash"/utf8>>,
function => <<"initial_state"/utf8>>,
line => 63})
end,
gleam@result:'try'(
bigi_ffi:from_string(A),
fun(A@1) ->
gleam@result:'try'(
bigi_ffi:from_string(B),
fun(B@1) ->
gleam@result:'try'(
bigi_ffi:from_string(C),
fun(C@1) ->
gleam@result:'try'(
bigi_ffi:from_string(D),
fun(D@1) ->
{ok, {hash_state, A@1, B@1, C@1, D@1}}
end
)
end
)
end
)
end
).
-file("/Users/gareth/Development/gleam/tenthash/src/tenthash.gleam", 147).
-spec mix_hash(hash_state()) -> hash_state().
mix_hash(State) ->
Bitmask = bitmask(64),
gleam@list:fold(
[[16, 28], [14, 57], [11, 22], [35, 34], [57, 16], [59, 40], [44, 13]],
State,
fun(State@1, C) ->
[C1, C2] = case C of
[_, _] -> C;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
value => _assert_fail,
module => <<"tenthash"/utf8>>,
function => <<"mix_hash"/utf8>>,
line => 150})
end,
A = bigi_ffi:add(
erlang:element(2, State@1),
erlang:element(4, State@1)
),
A@1 = bigi_ffi:bitwise_and(A, Bitmask),
B = bigi_ffi:add(
erlang:element(3, State@1),
erlang:element(5, State@1)
),
B@1 = bigi_ffi:bitwise_and(B, Bitmask),
C@1 = rot_left(erlang:element(4, State@1), C1, Bitmask),
C@2 = bigi_ffi:bitwise_exclusive_or(C@1, A@1),
D = rot_left(erlang:element(5, State@1), C2, Bitmask),
D@1 = bigi_ffi:bitwise_exclusive_or(D, B@1),
A2 = A@1,
A@2 = B@1,
B@2 = A2,
{hash_state, A@2, B@2, C@2, D@1}
end
).
-file("/Users/gareth/Development/gleam/tenthash/src/tenthash.gleam", 104).
-spec hash_bits(
bitstring(),
bitstring(),
bitstring(),
bitstring(),
hash_state()
) -> {ok, hash_state()} | {error, nil}.
hash_bits(A, B, C, D, State) ->
A@1 = bigi_ffi:from_bytes(A, little_endian, unsigned),
B@1 = bigi_ffi:from_bytes(B, little_endian, unsigned),
C@1 = bigi_ffi:from_bytes(C, little_endian, unsigned),
D@1 = bigi_ffi:from_bytes(D, little_endian, unsigned),
case {A@1, B@1, C@1, D@1} of
{{ok, A@2}, {ok, B@2}, {ok, C@2}, {ok, D@2}} ->
{ok,
mix_hash(
{hash_state,
bigi_ffi:bitwise_exclusive_or(
erlang:element(2, State),
A@2
),
bigi_ffi:bitwise_exclusive_or(
erlang:element(3, State),
B@2
),
bigi_ffi:bitwise_exclusive_or(
erlang:element(4, State),
C@2
),
bigi_ffi:bitwise_exclusive_or(
erlang:element(5, State),
D@2
)}
)};
{_, _, _, _} ->
{error, nil}
end.
-file("/Users/gareth/Development/gleam/tenthash/src/tenthash.gleam", 71).
-spec do_hash(bitstring(), hash_state()) -> {ok, hash_state()} | {error, nil}.
do_hash(Data, State) ->
case Data of
<<A:8/binary, B:8/binary, C:8/binary, D:8/binary, Rest/bitstring>> ->
gleam@result:'try'(
hash_bits(A, B, C, D, State),
fun(Hashed_bits) -> do_hash(Rest, Hashed_bits) end
);
<<>> ->
{ok, State};
<<A@1/bitstring>> ->
Extra_bits = 32 - erlang:byte_size(A@1),
A@2 = gleam_stdlib:bit_array_concat(
[A@1, <<0:(lists:max([((Extra_bits * 8)), 0]))>>]
),
case A@2 of
<<A@3:8/binary, B@1:8/binary, C@1:8/binary, D@1/binary>> ->
gleam@result:'try'(
hash_bits(A@3, B@1, C@1, D@1, State),
fun(Hashed_bits@1) -> do_hash(<<>>, Hashed_bits@1) end
);
_ ->
{error, nil}
end;
_ ->
{error, nil}
end.
-file("/Users/gareth/Development/gleam/tenthash/src/tenthash.gleam", 129).
-spec finalise_hash(hash_state(), integer()) -> {ok, bigi:big_int()} |
{error, nil}.
finalise_hash(State, Len) ->
State@1 = erlang:setelement(
2,
State,
bigi_ffi:bitwise_exclusive_or(
erlang:element(2, State),
bigi_ffi:from(Len)
)
),
Final_state = mix_hash(mix_hash(State@1)),
_assert_subject = bigi_ffi:to_bytes(
erlang:element(2, Final_state),
little_endian,
unsigned,
8
),
{ok, A} = case _assert_subject of
{ok, _} -> _assert_subject;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
value => _assert_fail,
module => <<"tenthash"/utf8>>,
function => <<"finalise_hash"/utf8>>,
line => 136})
end,
_assert_subject@1 = bigi_ffi:to_bytes(
erlang:element(3, Final_state),
little_endian,
unsigned,
8
),
{ok, B} = case _assert_subject@1 of
{ok, _} -> _assert_subject@1;
_assert_fail@1 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
value => _assert_fail@1,
module => <<"tenthash"/utf8>>,
function => <<"finalise_hash"/utf8>>,
line => 138})
end,
_assert_subject@2 = bigi_ffi:to_bytes(
erlang:element(4, Final_state),
little_endian,
unsigned,
8
),
{ok, C} = case _assert_subject@2 of
{ok, _} -> _assert_subject@2;
_assert_fail@2 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
value => _assert_fail@2,
module => <<"tenthash"/utf8>>,
function => <<"finalise_hash"/utf8>>,
line => 140})
end,
Ba = gleam@bit_array:append(A, gleam@bit_array:append(B, C)),
_assert_subject@3 = gleam_stdlib:bit_array_slice(Ba, 0, 20),
{ok, Slice} = case _assert_subject@3 of
{ok, _} -> _assert_subject@3;
_assert_fail@3 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
value => _assert_fail@3,
module => <<"tenthash"/utf8>>,
function => <<"finalise_hash"/utf8>>,
line => 143})
end,
bigi_ffi:from_bytes(Slice, big_endian, unsigned).
-file("/Users/gareth/Development/gleam/tenthash/src/tenthash.gleam", 54).
-spec hash_bitarray(bitstring()) -> {ok, bigi:big_int()} | {error, nil}.
hash_bitarray(Data) ->
gleam@result:'try'(
initial_state(),
fun(Init_state) ->
gleam@result:'try'(
do_hash(Data, Init_state),
fun(Final_state) ->
finalise_hash(Final_state, erlang:byte_size(Data) * 8)
end
)
end
).
-file("/Users/gareth/Development/gleam/tenthash/src/tenthash.gleam", 47).
-spec hash(binary()) -> {ok, bigi:big_int()} | {error, nil}.
hash(Data) ->
hash_bitarray(gleam_stdlib:identity(Data)).