How to implement NOSTR Protocol from scratch with Python (NIP-01)
Using Jupyter Notebook
This tutorial teach you the simple way to implement NOSTR Protocol without NOSTR toolkit. The focus is only to implement a simple event.
IMPORTANT:
You can use any relay from nostr.watch, the relay applied in this tutorial is only for example usage - it's NOT a recommendation OR preference.
CLAUSE 1: To have a well-formed Relay or Client you MUST support NIP-01 features and syntax. Another NIPs are all optional, and you CAN create your own custom features.
Follow the bellow code reading the comments to understand what's happening.
MORE INFORMATION: This is a complementary tutorial, if you need more details about the meaning of each word please refer to NIP-01 declaration.
# Package installation for Python in a non-Jupyter environment
pip install websockets secp256k1 sha256
# Package installation on Jupyter Notebook environment
! pip install websockets # Connect you with the Relay
! pip install secp256k1 # Generate the private key and public key
! pip install sha256 # Generate needed hash
# package importation
import asyncio
import websockets
import secrets
import secp256k1
import time
import json
from hashlib import sha256
from time import time
# The custom content of note that will be publish in this tutorial
content = "Hello, world!" #input("What's your message to the world?")
# Token applied to generate public-private keypair
secrets_token_32bit = secrets.token_bytes(32)
# User's private key (use print(private_key.hex()) to print)
private_key = secp256k1.PrivateKey(secrets_token_32bit)
# User's public key
public_key = private_key.pubkey.serialize()[1:].hex()
# Definition of required elements according to NIP-01
tags = []
kind = 0
timestamp = int(time()) # timestamp in SECONDS
# Define the property "event_id"
event_id = sha256(
json.dumps([
0, # ZERO is a CONSTANT, don't confuse with kind
public_key,
timestamp,
kind,
tags,
content], separators=(',', ':'))
.encode('utf-8'))
.hexdigest()
# Define the property "sig"
sig = private_key.schnorr_sign(bytes.fromhex(event_id), None, raw=True).hex()
# Define the note to send to Relays
note = json.dumps(["EVENT", {
"id": event_id,
"pubkey": public_key,
"created_at": timestamp,
"kind": kind,
"tags": tags,
"content": content,
"sig": sig
}], separators=(',', ':'))
# Define the Relay for this tutorial (only for example)
relay : str = "wss://relay.geekiam.services"
# Connect to the Relay using Socket and send the note
async with websockets.connect(relay) as websocket:
await websocket.send(note)
print(f">>> {note}")
greeting = await websocket.recv()
print(f"<<< {greeting}")
You will receive the answer from the Relay. If the note was well-formed then the note will be published for the NOSTR network of relays and clients, if ill-formed you will receive an error message.