Subject: [bitcoin-dev] joinstr: coinjoin implementation using nostr

From: alicexbt <[email-masked]>
Date: Sat, 20 Aug 2022 08:20:00 +0000

Hi Bitcoin Developers,

I have written a python script as proof of concept for the [coinjoin implementation][1] using [nostr][2]. I used a lot of Python scripts created by others in school, so it feels nice to offer something that could be useful to others.

The implementation uses Bitcoin Core wallet and RPCs: `listunspent`, `getnewaddress`, `scantxoutset`, `createpsbt`, `combinepsbt`, `finalizepsbt` and `sendrawtransaction`. It requires python-nostr library because nostr is used for coordination between peers. Nostr is a decentralized network based on cryptographic keypairs. It is not peer-to-peer however simple and scalable.

Every step is published as an event using a nostr relay and 5 peers coordinate to create, sign and broadcast a coinjoin transaction.  I need to write a NIP that would be an alternative to blind signatures. Relay will share a random secret with clients for one round which should be present in output registration request although never gets published. If someone tries to register an output without registering any inputs, request would not have the number initially shared with inputs so request would get rejected or published as unverified. Relay would not be able to link inputs and outputs as the number is same for all inputs in a round and they get registered at different times with new keys and IP address. Clients can use multiple relays at the same time to avoid trusting one relay. This would result in different shared secret number but same process. If a relay tries to cheat, users will not sign the transaction and avoid using it in future.

Usage:

 1)Run `python coinjoin.py` and enter descriptor for one of the inputs.
 2)Script will check inputs for this round in every 30 seconds and register a new adddress for output once 5 inputs are registered.
 3)Similar check happens every 30 seconds for outputs. Last peer should create a PSBT.
 4)Unsigned PSBT will be printed and signed by wallet with `walletprocesspsbt` RPC.
 5)Script will check signed PSBTs and last peer to sign should finalize coinjoin transaction once 5 signed PSBTs are received.
 6)Coinjoin transaction will be broadcasted and txid will printed.

Example:

```
List of utxos in wallet:

wpkh([53830dca/84'/1'/0'/0/0]02449be5fb74725255eeeb50eba930fa87705f21e99d13cd710cf2c1f21153c808)#x2hyyeg5

Enter descriptor for the input registration: wpkh([53830dca/84'/1'/0'/0/0]02449be5fb74725255eeeb50eba930fa87705f21e99d13cd710cf2c1f21153c808)#x2hyyeg5

event id:  bcbbe62d75d99fed73f1e50ac58a38d1840b658951893e63c0322b378d7d56f0

```
```
tb1qhxrp4zl54ul0twtyz0gury5399q7z0kvqqrl6m registered for output

event id: 9449c9065bef356d21507a98f88b028b17fc1c49eb195c8d4420604fcaaef041
```
```
Unsigned PSBT: cHNidP8BAP1yAQIAAAAFtMaoJYcXvOG5L3Yaz3YyS7gIt4h5/zzOrRRS3hrVvwoAAAAAAP////+o83geaSm4L76KToIUl5MiZqLAUbIDJLq6DWrjP/3b8AEAAAAA/////zEF3CXIvVHpIa7No1s1yg+KtyOfXTRSyWnOdXMfzcDwAQAAAAD/////wMa4XAgnU+39Ien+KG9rYtv8bLMNYakmZyY/QFfwLRcAAAAAAP/////5M42ID6uLmQTb2tnFHnN7UMpnDD25uN8ZX7A+GNSM3QEAAAAA/////wV4xwEAAAAAABYAFLmGGov0rz71uWQT0cGSkSlB4T7MeMcBAAAAAAAWABSc0/FM6Hdbdxh10IJkYOklVFWqjnjHAQAAAAAAFgAUPSZKe/w6PT6qIF+WhL4wHaFymjd4xwEAAAAAABYAFMx0rxYlpPWB3NFry4Ctk2eVi/UNeMcBAAAAAAAWABSzc4xK0VTfvjK0MHXrAUFLYgYnOgAAAAAAAAAAAAAAAAAAAA==

event id: 976744b38fa9343fb79e1b5215512ead6ee08e5890d79a201fc5b872f6de4eba
```
```
Signed PSBT: cHNidP8BAP1yAQIAAAAFtMaoJYcXvOG5L3Yaz3YyS7gIt4h5/zzOrRRS3hrVvwoAAAAAAP////+o83geaSm4L76KToIUl5MiZqLAUbIDJLq6DWrjP/3b8AEAAAAA/////zEF3CXIvVHpIa7No1s1yg+KtyOfXTRSyWnOdXMfzcDwAQAAAAD/////wMa4XAgnU+39Ien+KG9rYtv8bLMNYakmZyY/QFfwLRcAAAAAAP/////5M42ID6uLmQTb2tnFHnN7UMpnDD25uN8ZX7A+GNSM3QEAAAAA/////wV4xwEAAAAAABYAFLmGGov0rz71uWQT0cGSkSlB4T7MeMcBAAAAAAAWABSc0/FM6Hdbdxh10IJkYOklVFWqjnjHAQAAAAAAFgAUPSZKe/w6PT6qIF+WhL4wHaFymjd4xwEAAAAAABYAFMx0rxYlpPWB3NFry4Ctk2eVi/UNeMcBAAAAAAAWABSzc4xK0VTfvjK0MHXrAUFLYgYnOgAAAAAAAQBxAgAAAAG+qpMXZCy6tBuUlgo8JD0GVXKp60FkhwDeg2sF1fkFkwMAAAAA/f///wLo9wEAAAAAABYAFFfLA5xarC/w/SxeMDQ5tuXrYJLUWwMAAAAAAAAWABRfPf//hwMjHB4OKj87cU19XOSh7yOWAQABAR/o9wEAAAAAABYAFFfLA5xarC/w/SxeMDQ5tuXrYJLUAQhrAkcwRAIgOIhLoC5348U8YkEr4GU1K4yWskIOEXgW4Wsk/W2cR7ICIEJXqtOuDJ5CkwrSuwJLWtzab4dslbN3KuL/pyooMnOCASECRJvl+3RyUlXu61DrqTD6h3BfIemdE81xDPLB8hFTyAgAAAAAACICA77Cnd6o3kr0yc+91eabpOn5igs/MUMbudNYSS6oyMWMGFODDcpUAACAAQAAgAAAAIAAAAAAFAAAAAAAAAAA

event id: 5846b6e6902f3c5a43496d7d9785ed62444aa74963f03c33d637d8b09ee7a139
```
```
Coinjoin tx: 75e490b10b15a6a0422f25ff66ad98ef70390c8fecaac02712705dce8cc3564b

event id: 9b5d4bf279b59e2b6e539e683fba83da72dce2b640360aa95db1b1400be93190
```

There are lot of things that could be improved and a few suggestions are in the gist that described the [idea][3]. I would love read to any opinions about this experiment and will start working on creating an Android app for joinstr next week.

Credits:

- fiatjaf (Nostr)
- Andrew Chow (PSBT)
- Jeff Thibault (python-nostr)
- Existing coinjoin implmentations

[1]: https://github.com/1440000bytes/joinstr
[2]: https://github.com/nostr-protocol/nostr
[3]: https://gist.github.com/1440000bytes/1c305097b070c8374cc3b91f50314a45

/dev/fd0

Sent with Proton Mail secure email.