ssb_bfe/lib/ssb_bfe.ex

120 lines
2.8 KiB
Elixir

defmodule SsbBfe do
@moduledoc """
Binary Field Encodings (BFE) for Secure Scuttlebutt (SSB).
Encode and decode TFD values.
## Examples
iex> SsbBfe.encode("@HEqy940T6uB+T+d9Jaa58aNfRzLx9eRWqkZljBmnkmk=.ed25519")
<<0, 0, 28, 74, 178, 247, 141, 19, 234, 224, 126, 79, 231, 125, 37, 166, 185,
241, 163, 95, 71, 50, 241, 245, 228, 86, 170, 70, 101, 140, 25, 167, 146,
105>>
...> SsbBfe.decode(<<0, 0, 28, 74, 178, 247, 141, 19, 234, 224, 126, 79, 231, 125, 37, 166, 185,
241, 163, 95, 71, 50, 241, 245, 228, 86, 170, 70, 101, 140, 25, 167, 146,
105>>)
"@HEqy940T6uB+T+d9Jaa58aNfRzLx9eRWqkZljBmnkmk=.ed25519"
"""
# ENCODE
def encode(value) when is_list(value) do
Enum.map(value, fn x -> encode(x) end)
end
def encode(value) when is_map(value) do
Enum.reduce(
value,
%{},
fn {k, v}, acc ->
Map.put(acc, k, SsbBfe.encode(v))
end
)
end
def encode(value) when is_tuple(value) do
Enum.map(Tuple.to_list(value), fn x -> encode(x) end)
|> List.to_tuple()
end
def encode(value) when is_bitstring(value) do
cond do
String.starts_with?(value, "@") ->
SsbBfe.Encoder.encode_feed(value)
String.starts_with?(value, "%") ->
SsbBfe.Encoder.encode_msg(value)
String.starts_with?(value, "&") ->
SsbBfe.Encoder.encode_blob(value)
String.ends_with?(value, ".sig.ed25519") ->
SsbBfe.Encoder.encode_sig(value)
String.ends_with?(value, [".box", ".box2"]) ->
SsbBfe.Encoder.encode_box(value)
true ->
SsbBfe.Encoder.encode_str(value)
end
end
def encode(value) when is_boolean(value), do: SsbBfe.Encoder.encode_bool(value)
def encode(value) when is_number(value), do: value
def encode(value) when is_nil(value), do: SsbBfe.Encoder.encode_nil()
# DECODE
def decode(value) when is_binary(value) do
first_byte = :binary.first(value)
cond do
0 == first_byte ->
SsbBfe.Decoder.decode_feed(value)
1 == first_byte ->
SsbBfe.Decoder.decode_msg(value)
2 == first_byte ->
SsbBfe.Decoder.decode_blob(value)
4 == first_byte ->
SsbBfe.Decoder.decode_sig(value)
5 == first_byte ->
SsbBfe.Decoder.decode_box(value)
6 == first_byte ->
SsbBfe.Decoder.decode_generic(value)
true ->
nil
end
end
def decode(value) when is_number(value), do: value
def decode(value) when is_list(value) do
Enum.map(value, fn x -> decode(x) end)
end
def decode(value) when is_map(value) do
Enum.reduce(
value,
%{},
fn {k, v}, acc ->
Map.put(acc, k, SsbBfe.decode(v))
end
)
end
def decode(value) when is_tuple(value) do
Enum.map(Tuple.to_list(value), fn x -> decode(x) end)
|> List.to_tuple()
end
end