The Open Location Network
Kafumu's local messages are part of an open network anyone can read from, write to and run a node of. Here's how it works and how to connect.
What it is
The Open Location Network is a way to leave short public messages at a place without
accounts, servers you must trust, or location tracking. A message is plain text plus hashtags. The place is a
hashtag too: #geo followed by the first six characters of the area's
plus code (about 5 km across), e.g. #geo8ccgmw.
Anyone can store, index and pass these messages on; a node is just something that does that.
Instead of an account, every message carries a small proof of work: the sender's device tries numbers until the message's SHA-1 hash starts with enough zero bits. One message costs a phone a fraction of a second; a thousand cost a spammer real time. More work buys a longer life: a message lives one hour at the required work and twice as long for every extra bit (up to a week). When an area gets busy, the required work goes up a little, so floods price themselves out.
The proof of concept
OLN started as eolnpoc, a small Go proof of concept from long before Kafumu, and Kafumu speaks its format exactly, so messages move between the two unchanged. Kafumu is one OLN node: its local messages, questions, answers and reactions are all OLN messages.
The message format
nonce;YYYYMMDDhhmmss;base64url(text);#geo8ccgmw #langeng #coffee
- nonce: the number the sender searched for.
- date: when it was made, in UTC; nodes accept a ±10 minute clock difference.
- text: the message, UTF-8, base64url without padding.
- keywords: space-separated hashtags; exactly one
#geo…cell. Kafumu also uses#lang<iso639-3>,#askfor questions and#re<10 hex>for answers and reactions.
The work is the number of leading zero bits of SHA-1 over the whole line. The message id is the hex
SHA-1 of the line.
Reading: GET /oln.json
Live messages of a cell and its neighbours, in eolnpoc's olnjson format (server info, messages by id,
a tag index, and where to push):
curl 'https://kafumu.com/oln.json?cell=8ccgmw'
Writing: POST /api/oln
First ask how much work the cell currently wants, then mine and post the raw line:
curl 'https://kafumu.com/api/oln/required?cell=8ccgmw' # {"bits": 12}
curl -X POST --data-binary 'nonce;20261004183000;SGVsbG8;#geo8ccgmw' https://kafumu.com/api/oln
Answers: 200 with the stored message (and its expiry), 402 when the work is too low
(mine more bits), 400 for a malformed line, a clock off by more than ten minutes, or not exactly one
#geo cell.
Mining in JavaScript, in a few lines:
// sha1 → leading zero bits; try nonces until there are enough.
async function mine(text, keywords, bits) {
const date = new Date().toISOString().replace(/[-:T]/g, "").slice(0, 14);
const b64 = btoa(String.fromCharCode(...new TextEncoder().encode(text)))
.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
for (let n = 0; ; n++) {
const line = `${n};${date};${b64};${keywords}`;
const h = new Uint8Array(await crypto.subtle.digest("SHA-1", new TextEncoder().encode(line)));
let z = 0; for (const b of h) { if (b === 0) { z += 8; continue; } z += Math.clz32(b) - 24; break; }
if (z >= bits) return line;
}
}
Questions by subject: GET /api/asks
Live questions (#ask) about any of the given subjects, from anywhere; filter by distance yourself:
curl 'https://kafumu.com/api/asks?tags=opensource,esperanto'
Run your own node
Store messages you receive, serve them as oln.json, accept posts with enough work, and pull from or
push to other nodes (Kafumu lists /api/oln as its push address). The source of Kafumu is
open, and so is eolnpoc.