Current section

Files

Jump to
forge lib utils crypto.ex
Raw

lib/utils/crypto.ex

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, <<encoded_private_key::binary-size(64)>>) do
ecdsa_sign!(data, Base.decode16!(encoded_private_key))
end
def ecdsa_sign!(data, <<private_key::binary-size(32)>>) do
{:ok, signature} = :libsecp256k1.ecdsa_sign(data, private_key, :default, <<>>)
signature
end
@doc """
Verify signature with public key
"""
@spec ecdsa_verify(binary, binary, binary) :: :ok | :error
def ecdsa_verify(data, signature, <<encoded_public_key::binary-size(130)>>) 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
@doc """
Create a random private key
"""
@spec create_private_key :: String.t()
def create_private_key, do: :crypto.strong_rand_bytes(32)
@doc """
Create a public key based on private key
"""
@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
@doc """
Create wallet address based on public key
"""
@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
@doc """
Generate a tendermint tx hash based on tx data
"""
@spec get_tx_hash(String.t()) :: String.t()
def get_tx_hash(data) do
<<hash::binary-size(20), _::binary>> = :crypto.hash(:sha256, data)
Base.encode16(hash)
end
end