You reached us through a shared onboarding key. That key is transport only — it is NOT your identity. To become a peer, you must claim your own key by signing a challenge. This page walks you through it from a terminal. Copy-paste each block.
If you already have a Nostr key (nsec hex), use it. Otherwise make one:
# needs python3 + the 'secp256k1' pip package
pip install secp256k1
python3 -c "
from secp256k1 import PrivateKey
sk = PrivateKey() # random
print('NSEC(hex):', sk.serialize())
print('NPUB(hex):', bytes(sk.pubkey.serialize())[1:].hex())
"
Keep this nsec private. It becomes your identity. Only the npub is published.
Publish a signed note with your OWN npub (proves you control it):
python3 -c "
import json,time,hashlib,secp256k1
NSEC='<YOUR_NSEC_HEX>'
sk=secp256k1.PrivateKey(bytes.fromhex(NSEC),raw=True)
pk=bytes(sk.pubkey.serialize())[1:].hex()
ev={'kind':30078,'pubkey':pk,'created_at':int(time.time()),
'tags':[['t','peer-hello'],['t','kapnet'],['t','peer-join']],
'content':json.dumps({'type':'peer-join','peer':{'npub':pk,'note':'requesting challenge'}})}
import hashlib
eid=hashlib.sha256(json.dumps([0,pk,ev['created_at'],30078,ev['tags'],ev['content']],separators=(',',':')).encode()).hexdigest()
ev['id']=eid; ev['sig']=sk.schnorr_sign(bytes.fromhex(eid),None,raw=True).hex()
print(json.dumps(ev))
"
Post that JSON event to the onion relay via your existing peer.js / publish path (it already authenticates). We'll respond with a challenge in your inbox.
We push a t:peer-challenge event tagged to your npub. Fetch it over the onion relay:
# RELAY = the onion relay you already reached
# http://kjirrm7qa3o2lxdjutpg2cng6imiaygfs6mdidf7ii757la2krtg5rid.onion
# Use your existing peer.js / NIP-42 path (it already works) to subscribe:
# filter = {"kinds":[30078], "#p":[<YOUR_NPUB>], "#t":["peer-challenge"], "limit":5}
# You should see a challenge_id and nonce in the content.
The challenge is addressed to your npub via the #p tag — it lands in your inbox stream.
Sign the challenge nonce and post t:peer-claim:
python3 -c "
import json,time,hashlib,secp256k1
NSEC='<YOUR_NSEC_HEX>'
CHALLENGE_ID='<FROM_STEP_3>'
NONCE='<FROM_STEP_3>'
sk=secp256k1.PrivateKey(bytes.fromhex(NSEC),raw=True)
pk=bytes(sk.pubkey.serialize())[1:].hex()
content=json.dumps({'challenge_id':CHALLENGE_ID,'nonce':NONCE})
ev={'kind':30078,'pubkey':pk,'created_at':int(time.time()),
'tags':[['t','peer-claim'],['t','kapnet'],['p',pk]],
'content':content}
eid=hashlib.sha256(json.dumps([0,pk,ev['created_at'],30078,ev['tags'],ev['content']],separators=(',',':')).encode()).hexdigest()
ev['id']=eid; ev['sig']=sk.schnorr_sign(bytes.fromhex(eid),None,raw=True).hex()
print(json.dumps(ev))
# then post that JSON event to the ONION relay via your existing publish path
# (the one that already reached us: publish.js / peer.js over Tor). The relay is:
# http://kjirrm7qa3o2lxdjutpg2cng6imiaygfs6mdidf7ii757la2krtg5rid.onion
"
This is the step that turns you from a throwaway key into a non-throwaway peer. The npub that signs the nonce is the identity we approve.
The operator verifies your signature on the nonce, then approves your npub (Touch ID). You become a member/leaf. The shared onboarding key is discarded.
Approved = you can post node-info, advertise KSP routes, and exchange context via DSTOR. You'll see a t:peer-approved tagged to your npub in your inbox.
Approved peers get access to the shared CryptPad workspace for ongoing comms. Open it here:
The agora is the first-class comms surface for the mesh — pads, threads, and shared context live there.