Hello everybody,
Sorry for the noob question, but is there a way to encode to base 16 in Erlang?
I am trying to replicate this line, from Elixir to Erlang…
:crypto.mac(:hmac, :sha256, secret, source) |> Base.encode16 |> String.downcase
The closest I have is this
Hmac = crypto:mac(hmac, sha256, Secret, Source).
string:to_lower(...)
I could not find the equivalent of Base.encode16/1
I saw a base16 package on hex.pm, but wanted to know if this exists in std lib.
Thanks for taking time.
4 Likes
cons
May 23, 2022, 4:50am
2
You can use io_lib:format("~.16b", [HMac])
to get the number as a hex string (which is assume that you want). Note that using the formatting directive b
generates lower case directly, where B
would give you uppercase.
There is also erlang:integer_to_list(HMac, 16)
, but that gives uppercase and you would need to use string:to_lower/1
on the the result.
Hope this helps.
4 Likes
A simple way but not the fastest way to encode a binary in base16 is to use a binary comprehension:
base16_bc(Bin) when is_binary(Bin) ->
<< <<(integer_to_binary(N, 16))/bitstring>> || <<N:4>> <= Bin >>.
It will produce a string with uppercase hex digits.
A faster way is the following:
base16_loop(Bin) when is_binary(Bin) ->
base16_loop(Bin, <<>>).
base16_loop(<<N:8/unit:4,Rest/bitstring>>, Acc) ->
Hex = integer_to_binary(N, 16),
PadLen = 8 - byte_size(Hex),
base16_loop(Rest, <<Acc/binary,
<<"00000000">>:PadLen/binary,
(integer_to_binary(N, 16))/binary>>);
base16_loop(<<N:1/unit:4,Rest/bitstring>>, Acc) ->
base16_loop(Rest, <<Acc/binary, (integer_to_binary(N, 16))/binary>>);
base16_loop(<<>>, Acc) ->
Acc.
According to erlperf
running on my computer, this version is roughly three times faster:
$ erlperf 'r(X) -> t:base16_bc(X).' --init_runner 'rand:bytes(1_000_000).' 'r(X) -> t:base16_loop(X).' --init_runner 'rand:bytes(1_000_000).'
Code || QPS Time Rel
r(X) -> t:base16_loop(X). 1 41 24390 us 100%
r(X) -> t:base16_bc(X). 1 14 71429 us 34%
4 Likes
There is also binary:encode_hex/1
and binary:decode_hex/1
, recently added to the binary module: Erlang -- binary
11 Likes
I forgot that those have been added. binary:encode_hex/1
is roughly three times as fast as base16_loop/1
according to erlperf
:
$ erlperf 'r(X) -> t:base16_bc(X).' --init_runner 'rand:bytes(1_000_000).' 'r(X) -> t:base16_loop(X).' --init_runner 'rand:bytes(1_000_000).' 'r(X) -> binary:encode_hex(X).' --init_runner 'rand:bytes(1_000_000).'
Code || QPS Time Rel
r(X) -> binary:encode_hex(X). 1 108 9259 us 100%
r(X) -> t:base16_loop(X). 1 39 25641 us 36%
r(X) -> t:base16_bc(X). 1 13 76923 us 12%
8 Likes
Thank You very much everybody…
There are different solutions to my problem, but the latest addition binary:encode_hex/1 seems to fit the most what I am looking for.
Thanks a lot again
4 Likes