defmodule Forge.Crypto do @moduledoc """ Crypto related functions """ @doc """ Generate an Ethereum compatible sha3 """ @spec sha3(binary) :: binary def sha3(data), do: :keccakf1600.hash(:sha3_256, data) @spec sha3(binary, :upper | :lower) :: binary def sha3(data, :upper), do: data |> sha3() |> Base.encode16() def sha3(data, :lower), do: data |> sha3() |> Base.encode16(case: :lower) @doc """ Sign data with private key """ @spec ecdsa_sign!(binary, binary) :: binary def ecdsa_sign!(data, <>) do ecdsa_sign!(data, Base.decode16!(encoded_private_key)) end def ecdsa_sign!(data, <>) do {:ok, signature} = :libsecp256k1.ecdsa_sign(data, private_key, :default, <<>>) signature end @spec ecdsa_verify(binary, binary, binary) :: :ok | :error def ecdsa_verify(data, signature, <>) do ecdsa_verify(data, signature, Base.decode16!(encoded_public_key)) end def ecdsa_verify(data, signature, <<4::size(8), _::binary-size(64)>> = public_key) do :libsecp256k1.ecdsa_verify(data, signature, public_key) end @spec create_private_key :: String.t() def create_private_key, do: :crypto.strong_rand_bytes(32) @spec create_public_key(String.t()) :: String.t() def create_public_key(private_key) do {:ok, public_key} = :libsecp256k1.ec_pubkey_create(private_key, :uncompressed) public_key end @spec create_wallet_address(String.t()) :: String.t() def create_wallet_address(public_key) do <<4::size(8), key::binary-size(64)>> = public_key <<_::binary-size(12), address::binary-size(20)>> = sha3(key) Base.encode16(address, case: :lower) end @spec get_tx_hash(String.t()) :: String.t() def get_tx_hash(data) do <> = :crypto.hash(:sha256, data) Base.encode16(hash) end end