PoW Pub

How does it work


Nostr public keys are Schnorr public keys.

A private key on secp256k1 is a scalar k. Multiplying it by G gives the public key K:

kG = K

This means there is a linear relation between the private and the public keys:

(k+x)G = kG + xG = K + X

Alice wants a vanity public key V, but doesn't have the time or the hardware to mine it herself. Bob offers to mine her such a pubkey, but she doesn't want him to know the resulting private key.

Bob offers to trustlessly mine her vanity key, in exchange for a fee, as follows:

K + xG = K + X = V
kG + xG = (k+x)G = vG = V

The protocol is not fully trustless, because Bob cannot reveal the scalar x without trusting that Alice will pay. Similarly, Alice cannot know for sure Bob will mine and deliver the scalar after she pays.

To mitigate Bob's risk, in the protocol described below Bob will only start mining once Alice pays.

Alice's risk is addressed by allowing multiple providers to bid for the trade, while at the same time giving Alice a way to determine the provider's reputation based on past trades.


Clients can purchase the mining of a scalar x for a specific type of vanity pubkey V. The simplest example is that V has a chosen prefix, but it can also have a chosen suffix, or match a pattern.

Knowing the conditions for V, Providers can find the mining difficulty and therefore quote a price and an estimated time to find x.

The steps are as follows:

Each of these steps happen as a Nostr event and is linked to the previous through an e tag. This means all steps of a trade can pe publicly audited, especially whether the Provider:

Providers don't have to trust that Clients will pay, because they get paid upfront. If a Client doesn't pay an invoice, it means he's not interested in that offer.

Clients can choose which Providers to trust based on the Provider's reputation. As part of the Nostr message format, each trade step is signed. Therefore a Client can check the past trade activity of a Provider's pubkey and see in how many trades this Provider was paid and delivered, or was paid and didn't deliver, or was paid and delivered an invalid x.

Example trade

Provider output:

Received Ask for prefix 12345
Posting invoice for 1 sats
Received preimage
Starting to mine for pubkey prefix 12345
Found matching scalar
client_pk  : 20ea67796d2fdfd6fe79cd329eddbbad7eae6119ffa363d2922331296d4d92db
scalar     : 2446df556947ec1130c63c4f6f87a313624fc68e3df2790718748b73969e9295
scalar_pk  : 8e49ae23101c87ee0c4563b7d8631a15a6ec66b06389c45b26d2ccc73431fecd
result_pk  : 123455b733e3baa77bea932bbe83eaa2eef8ded9db7aa05da0d1a1b1c45d3ea8
iterations : 769501 in 22.712 sec @ hashrate ~33880.81 h/s
Sending scalar response

Client output:

Sending PoW Ask for prefix 12345
Received offer and invoice for 1 sats, trying to pay it
Posting proof of payment (preimage)
Received mined scalar       : 2446df556947ec1130c63c4f6f87a313624fc68e3df2790718748b73969e9295
Local secret key            : 85929d88abc62fb211abe13cb21af1b0293631d1cf7a2b846c0449dd2b473b2b
Combined (final) secret key : a9d97cde150e1bc342721d8c21a294c38b85f8600d6ca48b8478d550c1e5cdc0
Combined (final) public key : 123455b733e3baa77bea932bbe83eaa2eef8ded9db7aa05da0d1a1b1c45d3ea8

Querying provider reputation with view-provider-reputations.sh:

PoW Pub Provider pubkey                                          | +Rep | -Rep
6a13a4646c2b24dc998642da236b18b8bc89a72db8c6fb1ac9eb0a04e0a663e1 |    3 |    0
302d426b0df5b6375b3b2a0ea882e726c589f2780f43cec381e7352ef1169693 |    1 |    0
+Rep = Positive reputation (trades this provider got paid and delivered)
-Rep = Negative reputation (trades this provider got paid but did not deliver)

Known issues and Open Questions