Skip to content
This repository was archived by the owner on Dec 1, 2023. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 60 additions & 12 deletions lib/nostrex/events/event.ex
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ defmodule Nostrex.Events.Event do
use Ecto.Schema
import Ecto.Changeset
alias Nostrex.Events.Tag
alias Bitcoinex.Secp256k1.{Point, Signature, Schnorr, PrivateKey}

@primary_key {:id, :string, autogenerate: false}
# @primary_key false
Expand Down Expand Up @@ -86,8 +87,7 @@ defmodule Nostrex.Events.Event do
event.pubkey,
event.created_at,
event.kind,
# TODO: add tag functionality next
[],
event.tags,
event.content
])
end
Expand All @@ -98,18 +98,66 @@ defmodule Nostrex.Events.Event do
"""
def calculate_id(event) do
{:ok, serialized_event} = serialize(event)

:crypto.hash(:sha256, serialized_event)
serialized_event
|> Bitcoinex.Utils.sha256()
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why use Bitcoinex here?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought it would be simpler to have Bitcoinex handle all the crypto-related functions. Should we switch it back?

|> Base.encode16(case: :lower)
end

# TODO
# defp validate(event) do
# validate event ID
# validate signature
# end
def validate(%__MODULE__{pubkey: pubkey, id: id, sig: signature} = event) do
# validate event ID
if id != calculate_id(event) do
{:error, "incorrect event id"}
else
# validate signature
validate_signature(pubkey, id, signature)
end
end

# TODO
# defp validate_signature(pubkey, event_id, sig) do
# end
defp validate_signature(pubkey, event_id, signature) do
{:ok, pk} = Point.lift_x(pubkey)
{:ok, sig} = Signature.parse_signature(signature)

z =
event_id
|> Base.decode16!(case: :lower)
|> :binary.decode_unsigned()

case {pk, sig} do
{{:error, msg}, _} ->
{:error, "failed to read event pubkey: #{msg}"}

{_, {:error, msg}} ->
{:error, "failed to read event signature: #{msg}"}

{%Point{} = pk, %Signature{} = sig} ->
Schnorr.verify_signature(pk, z, sig)
end
end

def sign(%__MODULE__{} = event, %PrivateKey{} = sk) do
id = calculate_id(event)
z =
id
|> Base.decode16!(case: :lower)
|> :binary.decode_unsigned()

aux = get_rand_uint(32)

{:ok, signature} = Schnorr.sign(sk, z, aux)
sig = serialize_signature(signature)

%__MODULE__{event | id: id, sig: sig}
end

defp get_rand_uint(len) do
len
|> :crypto.strong_rand_bytes()
|> :binary.decode_unsigned()
end

defp serialize_signature(%Signature{} = sig) do
sig
|> Signature.serialize_signature()
|> Base.encode16(case: :lower)
end
end
12 changes: 12 additions & 0 deletions lib/nostrex/events/events.ex
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ defmodule Nostrex.Events do

alias Nostrex.Repo
alias Nostrex.Events.{Event, Filter}
alias Bitcoinex.Secp256k1.PrivateKey
import Ecto.Changeset
import Ecto.Query
alias Phoenix.PubSub
Expand All @@ -16,6 +17,17 @@ defmodule Nostrex.Events do
|> Repo.insert()
end

@doc """
Only to be used for testing purposes. This makes it easy to test
serialization, signature verification, and signing
"""
def create_and_sign_event(params, %PrivateKey{} = sk) do
%Event{}
|> Event.test_only_changeset_no_validation( params)
|> Event.sign(e, sk)
|> Repo.insert()
end

@doc """
Only to be used for testing purposes. This makes it easy to test
filter logic with simple, human readable identifiers
Expand Down
3 changes: 2 additions & 1 deletion mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@ defmodule Nostrex.MixProject do
{:gettext, "~> 0.18"},
{:jason, "~> 1.2"},
{:plug_cowboy, "~> 2.5"},
{:credo, "~> 1.6", only: [:dev, :test], runtime: false}
{:credo, "~> 1.6", only: [:dev, :test], runtime: false},
{:bitcoinex, "~> 0.1.7"}
]
end

Expand Down
12 changes: 12 additions & 0 deletions mix.lock
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
%{
"bitcoinex": {:hex, :bitcoinex, "0.1.7", "2357049df10ba79e701138481692326863553476fd902c1c5a6e918d7f93b721", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:timex, "~> 3.1", [hex: :timex, repo: "hexpm", optional: false]}], "hexpm", "06f2d2c84b98ada2cf87106e54b7cc309497281f2bbf601e86b8528cfbd6e9fd"},
"bunt": {:hex, :bunt, "0.2.1", "e2d4792f7bc0ced7583ab54922808919518d0e57ee162901a16a1b6664ef3b14", [:mix], [], "hexpm", "a330bfb4245239787b15005e66ae6845c9cd524a288f0d141c148b02603777a5"},
"castore": {:hex, :castore, "0.1.20", "62a0126cbb7cb3e259257827b9190f88316eb7aa3fdac01fd6f2dfd64e7f46e9", [:mix], [], "hexpm", "a020b7650529c986c454a4035b6b13a328e288466986307bea3aadb4c95ac98a"},
"certifi": {:hex, :certifi, "2.9.0", "6f2a475689dd47f19fb74334859d460a2dc4e3252a3324bd2111b8f0429e7e21", [:rebar3], [], "hexpm", "266da46bdb06d6c6d35fde799bcb28d36d985d424ad7c08b5bb48f5b5cdd4641"},
"combine": {:hex, :combine, "0.10.0", "eff8224eeb56498a2af13011d142c5e7997a80c8f5b97c499f84c841032e429f", [:mix], [], "hexpm", "1b1dbc1790073076580d0d1d64e42eae2366583e7aecd455d1215b0d16f2451b"},
"connection": {:hex, :connection, "1.1.0", "ff2a49c4b75b6fb3e674bfc5536451607270aac754ffd1bdfe175abe4a6d7a68", [:mix], [], "hexpm", "722c1eb0a418fbe91ba7bd59a47e28008a189d47e37e0e7bb85585a016b2869c"},
"cowboy": {:hex, :cowboy, "2.9.0", "865dd8b6607e14cf03282e10e934023a1bd8be6f6bacf921a7e2a96d800cd452", [:make, :rebar3], [{:cowlib, "2.11.0", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "1.8.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "2c729f934b4e1aa149aff882f57c6372c15399a20d54f65c8d67bef583021bde"},
"cowboy_telemetry": {:hex, :cowboy_telemetry, "0.4.0", "f239f68b588efa7707abce16a84d0d2acf3a0f50571f8bb7f56a15865aae820c", [:rebar3], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7d98bac1ee4565d31b62d59f8823dfd8356a169e7fcbb83831b8a5397404c9de"},
Expand All @@ -14,12 +17,17 @@
"file_system": {:hex, :file_system, "0.2.10", "fb082005a9cd1711c05b5248710f8826b02d7d1784e7c3451f9c1231d4fc162d", [:mix], [], "hexpm", "41195edbfb562a593726eda3b3e8b103a309b733ad25f3d642ba49696bf715dc"},
"floki": {:hex, :floki, "0.34.0", "002d0cc194b48794d74711731db004fafeb328fe676976f160685262d43706a8", [:mix], [], "hexpm", "9c3a9f43f40dde00332a589bd9d389b90c1f518aef500364d00636acc5ebc99c"},
"gettext": {:hex, :gettext, "0.20.0", "75ad71de05f2ef56991dbae224d35c68b098dd0e26918def5bb45591d5c8d429", [:mix], [], "hexpm", "1c03b177435e93a47441d7f681a7040bd2a816ece9e2666d1c9001035121eb3d"},
"hackney": {:hex, :hackney, "1.18.1", "f48bf88f521f2a229fc7bae88cf4f85adc9cd9bcf23b5dc8eb6a1788c662c4f6", [:rebar3], [{:certifi, "~> 2.9.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "~> 6.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "~> 1.0.0", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~> 1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.3.1", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~> 1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "a4ecdaff44297e9b5894ae499e9a070ea1888c84afdd1fd9b7b2bc384950128e"},
"hammer": {:hex, :hammer, "6.1.0", "f263e3c3e9946bd410ea0336b2abe0cb6260af4afb3a221e1027540706e76c55", [:make, :mix], [{:poolboy, "~> 1.5", [hex: :poolboy, repo: "hexpm", optional: false]}], "hexpm", "b47e415a562a6d072392deabcd58090d8a41182cf9044cdd6b0d0faaaf68ba57"},
"hpax": {:hex, :hpax, "0.1.2", "09a75600d9d8bbd064cdd741f21fc06fc1f4cf3d0fcc335e5aa19be1a7235c84", [:mix], [], "hexpm", "2c87843d5a23f5f16748ebe77969880e29809580efdaccd615cd3bed628a8c13"},
"idna": {:hex, :idna, "6.1.1", "8a63070e9f7d0c62eb9d9fcb360a7de382448200fbbd1b106cc96d3d8099df8d", [:rebar3], [{:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "92376eb7894412ed19ac475e4a86f7b413c1b9fbb5bd16dccd57934157944cea"},
"jason": {:hex, :jason, "1.4.0", "e855647bc964a44e2f67df589ccf49105ae039d4179db7f6271dfd3843dc27e6", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "79a3791085b2a0f743ca04cec0f7be26443738779d09302e01318f97bdb82121"},
"metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm", "69b09adddc4f74a40716ae54d140f93beb0fb8978d8636eaded0c31b6f099f16"},
"mime": {:hex, :mime, "2.0.3", "3676436d3d1f7b81b5a2d2bd8405f412c677558c81b1c92be58c00562bb59095", [:mix], [], "hexpm", "27a30bf0db44d25eecba73755acf4068cbfe26a4372f9eb3e4ea3a45956bff6b"},
"mimerl": {:hex, :mimerl, "1.2.0", "67e2d3f571088d5cfd3e550c383094b47159f3eee8ffa08e64106cdf5e981be3", [:rebar3], [], "hexpm", "f278585650aa581986264638ebf698f8bb19df297f66ad91b18910dfc6e19323"},
"mint": {:hex, :mint, "1.4.2", "50330223429a6e1260b2ca5415f69b0ab086141bc76dc2fbf34d7c389a6675b2", [:mix], [{:castore, "~> 0.1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:hpax, "~> 0.1.1", [hex: :hpax, repo: "hexpm", optional: false]}], "hexpm", "ce75a5bbcc59b4d7d8d70f8b2fc284b1751ffb35c7b6a6302b5192f8ab4ddd80"},
"mint_web_socket": {:hex, :mint_web_socket, "1.0.2", "0933a4c82f2376e35569b2255cdce94f2e3f993c0d5b04c360460cb8beda7154", [:mix], [{:mint, ">= 1.4.0", [hex: :mint, repo: "hexpm", optional: false]}], "hexpm", "067c5e15439be060f2ab57c468ee4ab29e39cb20b498ed990cb94f62db0efc3a"},
"parse_trans": {:hex, :parse_trans, "3.3.1", "16328ab840cc09919bd10dab29e431da3af9e9e7e7e6f0089dd5a2d2820011d8", [:rebar3], [], "hexpm", "07cd9577885f56362d414e8c4c4e6bdf10d43a8767abb92d24cbe8b24c54888b"},
"phoenix": {:git, "https://github.com/phoenixframework/phoenix.git", "7f1085472662d96479a9969d6e94c3738a56e5e7", []},
"phoenix_ecto": {:hex, :phoenix_ecto, "4.4.0", "0672ed4e4808b3fbed494dded89958e22fb882de47a97634c0b13e7b0b5f7720", [:mix], [{:ecto, "~> 3.3", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "09864e558ed31ee00bd48fcc1d4fc58ae9678c9e81649075431e69dbabb43cc1"},
"phoenix_html": {:hex, :phoenix_html, "3.2.0", "1c1219d4b6cb22ac72f12f73dc5fad6c7563104d083f711c3fcd8551a1f4ae11", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "36ec97ba56d25c0136ef1992c37957e4246b649d620958a1f9fa86165f8bc54f"},
Expand All @@ -35,10 +43,14 @@
"poolboy": {:hex, :poolboy, "1.5.2", "392b007a1693a64540cead79830443abf5762f5d30cf50bc95cb2c1aaafa006b", [:rebar3], [], "hexpm", "dad79704ce5440f3d5a3681c8590b9dc25d1a561e8f5a9c995281012860901e3"},
"postgrex": {:hex, :postgrex, "0.16.5", "fcc4035cc90e23933c5d69a9cd686e329469446ef7abba2cf70f08e2c4b69810", [:mix], [{:connection, "~> 1.1", [hex: :connection, repo: "hexpm", optional: false]}, {:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "edead639dc6e882618c01d8fc891214c481ab9a3788dfe38dd5e37fd1d5fb2e8"},
"ranch": {:hex, :ranch, "1.8.0", "8c7a100a139fd57f17327b6413e4167ac559fbc04ca7448e9be9057311597a1d", [:make, :rebar3], [], "hexpm", "49fbcfd3682fab1f5d109351b61257676da1a2fdbe295904176d5e521a2ddfe5"},
"ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.6", "cf344f5692c82d2cd7554f5ec8fd961548d4fd09e7d22f5b62482e5aeaebd4b0", [:make, :mix, :rebar3], [], "hexpm", "bdb0d2471f453c88ff3908e7686f86f9be327d065cc1ec16fa4540197ea04680"},
"swoosh": {:hex, :swoosh, "1.9.0", "23b0678abc29158d3881970d2264724ecf960ac12b8657b657a717445ac01a8f", [:mix], [{:cowboy, "~> 1.1 or ~> 2.4", [hex: :cowboy, repo: "hexpm", optional: true]}, {:ex_aws, "~> 2.1", [hex: :ex_aws, repo: "hexpm", optional: true]}, {:finch, "~> 0.6", [hex: :finch, repo: "hexpm", optional: true]}, {:gen_smtp, "~> 0.13 or ~> 1.0", [hex: :gen_smtp, repo: "hexpm", optional: true]}, {:hackney, "~> 1.9", [hex: :hackney, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mail, "~> 0.2", [hex: :mail, repo: "hexpm", optional: true]}, {:mime, "~> 1.1 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_cowboy, ">= 1.0.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "548e8f680182064e94354264065275d424eb60bc207fcd1891bcdc3d40845704"},
"telemetry": {:hex, :telemetry, "1.2.0", "a8ce551485a9a3dac8d523542de130eafd12e40bbf76cf0ecd2528f24e812a44", [:rebar3], [], "hexpm", "1427e73667b9a2002cf1f26694c422d5c905df889023903c4518921d53e3e883"},
"telemetry_metrics": {:hex, :telemetry_metrics, "0.6.1", "315d9163a1d4660aedc3fee73f33f1d355dcc76c5c3ab3d59e76e3edf80eef1f", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7be9e0871c41732c233be71e4be11b96e56177bf15dde64a8ac9ce72ac9834c6"},
"telemetry_poller": {:hex, :telemetry_poller, "1.0.0", "db91bb424e07f2bb6e73926fcafbfcbcb295f0193e0a00e825e589a0a47e8453", [:rebar3], [{:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "b3a24eafd66c3f42da30fc3ca7dda1e9d546c12250a2d60d7b81d264fbec4f6e"},
"timex": {:hex, :timex, "3.7.9", "790cdfc4acfce434e442f98c02ea6d84d0239073bfd668968f82ac63e9a6788d", [:mix], [{:combine, "~> 0.10", [hex: :combine, repo: "hexpm", optional: false]}, {:gettext, "~> 0.10", [hex: :gettext, repo: "hexpm", optional: false]}, {:tzdata, "~> 1.1", [hex: :tzdata, repo: "hexpm", optional: false]}], "hexpm", "64691582e5bb87130f721fc709acfb70f24405833998fabf35be968984860ce1"},
"tzdata": {:hex, :tzdata, "1.1.1", "20c8043476dfda8504952d00adac41c6eda23912278add38edc140ae0c5bcc46", [:mix], [{:hackney, "~> 1.17", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "a69cec8352eafcd2e198dea28a34113b60fdc6cb57eb5ad65c10292a6ba89787"},
"unicode_util_compat": {:hex, :unicode_util_compat, "0.7.0", "bc84380c9ab48177092f43ac89e4dfa2c6d62b40b8bd132b1059ecc7232f9a78", [:rebar3], [], "hexpm", "25eee6d67df61960cf6a794239566599b09e17e668d3700247bc498638152521"},
"websock": {:hex, :websock, "0.4.3", "184ac396bdcd3dfceb5b74c17d221af659dd559a95b1b92041ecb51c9b728093", [:mix], [], "hexpm", "5e4dd85f305f43fd3d3e25d70bec4a45228dfed60f0f3b072d8eddff335539cf"},
"websock_adapter": {:hex, :websock_adapter, "0.4.5", "30038a3715067f51a9580562c05a3a8d501126030336ffc6edb53bf57d6d2d26", [:mix], [{:bandit, "~> 0.6", [hex: :bandit, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.6", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:websock, "~> 0.4", [hex: :websock, repo: "hexpm", optional: false]}], "hexpm", "1d9812dc7e703c205049426fd4fe0852a247a825f91b099e53dc96f68bafe4c8"},
}
38 changes: 38 additions & 0 deletions test/nostrex/events/events_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,32 @@ defmodule Nostrex.EventsTest do
alias Nostrex.Events.Event
alias Nostrex.FixtureFactory

@valid_events [
%Event{
id: "bfe9a9f57c61d04493c74189dc6ffa73f54522d0bf470b6194dcf33c323eb3c0",
pubkey: "f7b642493ed5a462c2faebb5d6cd208e42b8ea36f0b479f2aa2f5f5bf6f67aa7",
created_at: 1673931680,
kind: 1,
tags: [],
content: "running bitcoin",
sig: "6815aaa87665e68a43639631d9dbac7c3f6b825ff14e6689a100eef2d307f54701ec6b28fa9ab9c9ea01215f07db4e507d8e06a0e01527035f0b0ae9e4c2779c"
},
%Event{
# TODO(sachin): incorrect ID
id: "035c202e0f98df0ca71ef0167a0d00bccc88cf290481a8c8f21be40e65f6da5f",
pubkey: "b0448252cddc47798e5e726b5c6de25f3c486a01427d736915071f6d320abaab",
created_at: 1673931868,
kind: 1,
tags: [
["p", "f7b642493ed5a462c2faebb5d6cd208e42b8ea36f0b479f2aa2f5f5bf6f67aa7", "random"],
["e", "bfe9a9f57c61d04493c74189dc6ffa73f54522d0bf470b6194dcf33c323eb3c0", "other"]
],
content: "It might make sense just to get some in case it catches on.",
# TODO(sachin): incorrect sig
sig: "f0f6d65f6a2257b3af1a8e1760a697ed1dd2ad8839e3fb708e33555ad1d01206d7a68f9a944387c6505a7fd8cbfac29fc8151bf9109e62b5efbb1479893a8bca"
},
]

defp sample_event_params do
map = %{
id: "75b79351140f7f0002b050d9b2fef4d1f2d5f4ade7a3b04ed24604672d326009",
Expand Down Expand Up @@ -106,6 +132,18 @@ defmodule Nostrex.EventsTest do
test "ensure kind value is valid" do
end

describe "ensure signatures validation works" do
test "valid signatures pass check" do
for e <- @valid_events do
assert Event.validate(e)
end
end

test "invalid signatures fail check" do

end
end

test "ensure invalid signature events don't get persisted" do
end

Expand Down
25 changes: 19 additions & 6 deletions test/support/fixture_factory.ex
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,24 @@ defmodule Nostrex.FixtureFactory do

import Ecto.Changeset

def create_signed_event(opts \\ []) do
# Event.sign will overwrite the random id and sig
{:ok, event} =
opts
|> populate_default_event_params()
|> Events.create_and_sign_event()
event
end

def create_event_no_validation(opts \\ []) do
{:ok, event} =
opts
|> populate_default_event_params()
|> Events.create_event_no_validation()
event
end

defp populate_default_event_params(opts \\ []) do
defaults = %{
id: rand_identifier(),
pubkey: rand_identifier(),
Expand Down Expand Up @@ -47,10 +64,7 @@ defmodule Nostrex.FixtureFactory do

raw = Jason.encode!(params)

params = Map.put(params, :raw, raw)

{:ok, event} = Events.create_event_no_validation(params)
event
Map.put(params, :raw, raw)
end

def create_filter(opts \\ []) do
Expand Down Expand Up @@ -86,7 +100,6 @@ defmodule Nostrex.FixtureFactory do

defp rand_identifier do
:crypto.hash(:sha256, Integer.to_string(:rand.uniform(99_999_999_999)))
|> Base.encode16()
|> String.downcase()
|> Base.encode16(case: :lower)
end
end