-
@ Chris
2023-02-26 12:24:14In order to maintain consistency and ensure proper functioning of the system, a standard protocol for communication needs to be defined. This is where the Nostr Implementation Possibilities (NIPs) come in. In this article, we will focus on the basics of the event described in NIP-01.
Events
The only object type that exists is the event. Each event has a unique ID, public key, creation timestamp, kind, tags, content, and signature. When you are interacting with the protocol whether posting to or reading from relays (we'll talk more about relays in the next article) you will be posting or reading some variant of the following object:
json { "id": <32-bytes lowercase hex-encoded sha256 of the the serialized event data> "pubkey": <32-bytes lowercase hex-encoded public key of the event creator>, "created_at": <unix timestamp in seconds>, "kind": <integer>, "tags": [ ["e", <32-bytes hex of the id of another event>, <recommended relay URL>], ["p", <32-bytes hex of the key>, <recommended relay URL>], ... // other kinds of tags may be included later ], "content": <arbitrary string>, "sig": <64-bytes hex of the signature of the sha256 hash of the serialized event data, which is the same as the "id" field> }
In the previous article I showed you how to setup a typescript project and get started with
nostr-tools
to generate a public and private keypair. The public key that you generated will be used as the public key in the aforementioned event. All of the code from the previous tutorial can be found on github. So either clone this repo or pick up where you left off.Let's start by creating a file called
02-event.ts
.sh touch 02-event.ts
Step 1: Import Functions
Open the file with a text editor and import the following functions from
nostr-tools
:ts import { validateEvent, verifySignature, signEvent, getEventHash, generatePrivateKey, getPublicKey, Event } from 'nostr-tools'
Step 2: Generate Private & Public Keys
Next we'll generate a private key and derive a public key used in the event object.
ts const privateKey = generatePrivateKey(); const publicKey = getPublicKey(privateKey);
Step 3: Create Event Object
We'll create a basic event which will initially include 5 of the 7 fields. We can't include the id yet since it will be a hash based on the first 5 fields in the object. Similarly after we calculate and add the id field we can update the event by adding the signature.
ts let event: Event = { id: "", kind: 1, created_at: Math.floor(Date.now() / 1000), tags: [ ["t", "some tag"], ["t", "another tag"] ], content: 'hello', pubkey: publicKey, sig: "", }
This creates a new Nostr event object with the following properties:
-
kind: The kind of event. In this case, it is set to 1.
-
created_at: The timestamp of when the event was created. It is set to the current Unix timestamp using Math.floor(Date.now() / 1000).
-
tags: An array of tags associated with the event.
-
content: The content of the event. In this case, it is set to the string "hello".
-
pubkey: The public key of the event creator. It is set to the public key generated earlier.
Step 4: Calculate the ID & Signature of the Event
ts event.id = getEventHash(event) event.sig = signEvent(event, privateKey)
This calculates the ID and signature of the event using the
getEventHash
andsignEvent
functions from 'nostr-tools'. The ID is added to the event object as a new property called id, and the signature is added as a new property called sig. Notice how thesignEvent
function takes theevent
andprivateKey
as arguments. This is because the private key is used to sign the event which proves it came from the public key derived from the private key.Step 5: Validate & Verify the Signature
ts let ok = validateEvent(event) let veryOk = verifySignature(event)
You can easily verify the validity of the event using the validateEvent() and verifySignature() functions. If the event is valid, ok will be set to true. If the signature is valid, veryOk will be set to true.
Step 6: Log the Event
ts console.log(event)
The final code should look like the following:
```ts import { validateEvent, verifySignature, signEvent, getEventHash, generatePrivateKey, getPublicKey, Event, } from "nostr-tools";
const privateKey = generatePrivateKey(); const publicKey = getPublicKey(privateKey);
let event: Event = { id: "", kind: 1, created_at: Math.floor(Date.now() / 1000), tags: [ ["t", "some tag"], ["t", "another tag"], ], content: "hello", pubkey: publicKey, sig: "", };
event.id = getEventHash(event); event.sig = signEvent(event, privateKey);
let ok = validateEvent(event); let veryOk = verifySignature(event);
console.log(event); ```
Step 7: Run the Code
Now we can build and run our code:
sh npm run build node dist/02-event.js
You should see an output similar to:
json { id: '968c36698d0b8cd8c18be008f3c55e1bd4a1059dc93319c90f143932f6c7a864', kind: 1, created_at: 1677411967, tags: [ [ 't', 'some tag' ], [ 't', 'another tag' ] ], content: 'hello', pubkey: 'a7d96cc172ec06101592ca17187dfcdf39eb8295a4c2508b293ddc1e634b5773', sig: '146ff3afafa9d04408a1ce9d374986deb0a664fe664a646dd999de1b6db885b51d5d22ba6e350131aba7fc0b17b9acfaa4af8b4ff316556e6efd4 8c364d522e7' }
Conclusion
In summary, we created a new Nostr event object with some sample data, calculated the ID and signature of the event, and verified that the event is valid. In the next article we'll talk about subscribing and posting events to relays.
-