Current section
Files
Jump to
Current section
Files
src/gsiphash.erl
-module(gsiphash).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]).
-export([siphash/4, siphash_2_4/2]).
-spec i64_cast(integer()) -> integer().
i64_cast(Value) ->
erlang:'band'(Value, 16#ffffffffffffffff).
-spec i64_get(bitstring()) -> {ok, integer()} | {error, binary()}.
i64_get(Data) ->
case gleam_stdlib:bit_array_slice(<<Data/bitstring, 16#00:64>>, 0, 8) of
{ok, <<Value:64/unsigned-little>>} ->
{ok, Value};
_ ->
{error, <<"gsiphash.i64_get: couldn't get integer from data"/utf8>>}
end.
-spec rotate_left(integer(), integer()) -> integer().
rotate_left(Value, Bits) ->
erlang:'bor'(
i64_cast(erlang:'bsl'(Value, Bits)),
i64_cast(erlang:'bsr'(Value, (8 * 8) - Bits))
).
-spec sip_round(integer(), integer(), integer(), integer()) -> {integer(),
integer(),
integer(),
integer()}.
sip_round(V0, V1, V2, V3) ->
V0@1 = i64_cast(V0 + V1),
V1@1 = rotate_left(V1, 13),
V1@2 = erlang:'bxor'(V1@1, V0@1),
V0@2 = rotate_left(V0@1, 32),
V2@1 = i64_cast(V2 + V3),
V3@1 = rotate_left(V3, 16),
V3@2 = erlang:'bxor'(V3@1, V2@1),
V2@2 = i64_cast(V2@1 + V1@2),
V1@3 = rotate_left(V1@2, 17),
V1@4 = erlang:'bxor'(V1@3, V2@2),
V2@3 = rotate_left(V2@2, 32),
V0@3 = i64_cast(V0@2 + V3@2),
V3@3 = rotate_left(V3@2, 21),
V3@4 = erlang:'bxor'(V3@3, V0@3),
{V0@3, V1@4, V2@3, V3@4}.
-spec siphash(bitstring(), bitstring(), integer(), integer()) -> {ok, integer()} |
{error, binary()}.
siphash(Data, Key, C, D) ->
Data_length = erlang:byte_size(Data),
gleam@bool:guard(
C =< 0,
{error,
<<"gsiphash.siphash: the count of C rounds must be greater than zero"/utf8>>},
fun() ->
gleam@bool:guard(
D =< 0,
{error,
<<"gsiphash.siphash: the count of D rounds must be greater than zero"/utf8>>},
fun() ->
gleam@bool:guard(
erlang:byte_size(Key) /= 16,
{error,
<<"gsiphash.siphash: the length of the key must be 16 bytes (128 bits)"/utf8>>},
fun() ->
Left_out_bytes_count = case 8 of
0 -> 0;
Gleam@denominator -> Data_length rem Gleam@denominator
end,
gleam@result:'try'(
(gleam@result:'try'(
gleam@result:replace_error(
gleam_stdlib:bit_array_slice(Key, 0, 8),
<<"gsiphash.siphash: couldn't get the MSB slice of the key"/utf8>>
),
fun(Slice) -> i64_get(Slice) end
)),
fun(K0) ->
gleam@result:'try'(
(gleam@result:'try'(
gleam@result:replace_error(
gleam_stdlib:bit_array_slice(
Key,
8,
8
),
<<"gsiphash.siphash: couldn't get the LSB slice of the key"/utf8>>
),
fun(Slice@1) -> i64_get(Slice@1) end
)),
fun(K1) ->
V0 = erlang:'bxor'(
K0,
16#736f6d6570736575
),
V1 = erlang:'bxor'(
K1,
16#646f72616e646f6d
),
V2 = erlang:'bxor'(
K0,
16#6c7967656e657261
),
V3 = erlang:'bxor'(
K1,
16#7465646279746573
),
gleam@result:'try'(
gleam@iterator:fold(
begin
_pipe = gleam@iterator:iterate(
0,
fun(X) -> X + 8 end
),
gleam@iterator:take(
_pipe,
case 8 of
0 -> 0;
Gleam@denominator@1 -> (Data_length
- Left_out_bytes_count)
div Gleam@denominator@1
end
)
end,
{ok, {V0, V1, V2, V3}},
fun(Acc, Position) ->
gleam@result:'try'(
(gleam@result:'try'(
gleam@result:replace_error(
gleam_stdlib:bit_array_slice(
Data,
Position,
gleam@int:min(
8,
Data_length
)
),
<<"gsiphash.siphash: couldn't get message block at position "/utf8,
(gleam@int:to_string(
Position
))/binary>>
),
fun(Slice@2) ->
i64_get(
Slice@2
)
end
)),
fun(Message_block) ->
gleam@result:'try'(
Acc,
fun(_use0) ->
{V0@1,
V1@1,
V2@1,
V3@1} = _use0,
V3@2 = erlang:'bxor'(
V3@1,
Message_block
),
{V0@3,
V1@3,
V2@3,
V3@4} = gleam@iterator:fold(
gleam@iterator:range(
1,
C
),
{V0@1,
V1@1,
V2@1,
V3@2},
fun(
Acc@1,
_
) ->
{V0@2,
V1@2,
V2@2,
V3@3} = Acc@1,
sip_round(
V0@2,
V1@2,
V2@2,
V3@3
)
end
),
V0@4 = erlang:'bxor'(
V0@3,
Message_block
),
{ok,
{V0@4,
V1@3,
V2@3,
V3@4}}
end
)
end
)
end
),
fun(_use0@1) ->
{V0@5, V1@4, V2@4, V3@5} = _use0@1,
Last_message_block = i64_cast(
erlang:'bsl'(
Data_length,
56
)
),
gleam@result:'try'(
case Left_out_bytes_count
> 0 of
false ->
{ok,
Last_message_block};
true ->
gleam@iterator:fold(
gleam@iterator:range(
Data_length
- Left_out_bytes_count,
Data_length
- 1
),
{ok,
Last_message_block},
fun(
Acc@2,
Position@1
) ->
gleam@result:'try'(
Acc@2,
fun(
Last_message_block@1
) ->
gleam@result:'try'(
(gleam@result:'try'(
gleam@result:replace_error(
gleam_stdlib:bit_array_slice(
Data,
Position@1,
1
),
<<"gsiphash.siphash: couldn't get the left out byte at position "/utf8,
(gleam@int:to_string(
Position@1
))/binary>>
),
fun(
Slice@3
) ->
i64_get(
Slice@3
)
end
)),
fun(
Left_out_byte
) ->
Bits_to_shift = 8
* (Position@1
- (Data_length
- Left_out_bytes_count)),
Last_message_block@2 = erlang:'bor'(
Last_message_block@1,
i64_cast(
erlang:'bsl'(
Left_out_byte,
Bits_to_shift
)
)
),
{ok,
Last_message_block@2}
end
)
end
)
end
)
end,
fun(
Last_message_block@3
) ->
V3@6 = erlang:'bxor'(
V3@5,
Last_message_block@3
),
{V0@7,
V1@6,
V2@6,
V3@8} = gleam@iterator:fold(
gleam@iterator:range(
1,
C
),
{V0@5,
V1@4,
V2@4,
V3@6},
fun(Acc@3, _) ->
{V0@6,
V1@5,
V2@5,
V3@7} = Acc@3,
sip_round(
V0@6,
V1@5,
V2@5,
V3@7
)
end
),
V0@8 = erlang:'bxor'(
V0@7,
Last_message_block@3
),
V2@7 = erlang:'bxor'(
V2@6,
16#ff
),
{V0@10,
V1@8,
V2@9,
V3@10} = gleam@iterator:fold(
gleam@iterator:range(
1,
D
),
{V0@8,
V1@6,
V2@7,
V3@8},
fun(Acc@4, _) ->
{V0@9,
V1@7,
V2@8,
V3@9} = Acc@4,
sip_round(
V0@9,
V1@7,
V2@8,
V3@9
)
end
),
Result = erlang:'bxor'(
erlang:'bxor'(
V0@10,
V1@8
),
erlang:'bxor'(
V2@9,
V3@10
)
),
{ok, Result}
end
)
end
)
end
)
end
)
end
)
end
)
end
).
-spec siphash_2_4(bitstring(), bitstring()) -> {ok, integer()} |
{error, binary()}.
siphash_2_4(Data, Key) ->
siphash(Data, Key, 2, 4).