Berichtenprotocol
Een bericht in Hashiverse is HTML — geschreven in de browser met een rich-text-editor, DOMPurify-gesaneerd voor weergave. Tussen auteurschap en weergave zit een pijplijn van compressie, versleuteling, ondertekening, twee-fase-indiening, DHT-routing en bundle-aggregatie. Deze pagina volgt een bericht door die pijplijn.
Het gecodeerde bericht
EncodedPostV1 is het draadformaat voor een enkel bericht. Het bevat:
- header: bytes van de verificatiesleutel, post-quantum verbintenisbytes, tijdstempel, berichtlengte en
linked_base_ids— verwijzingen naar eerdere berichten waarop dit bericht antwoordt of voortbouwt. - signature: Ed25519 (of PQ) handtekening over de header- en bericht-hashes.
- post: de HTML-inhoud, Brotli-gecomprimeerd en versleuteld.
- post_id: Blake3-hash van de handtekening — een stabiel, verifieerbaar inhoudsadres.
Versleuteling gebruikt meerdere wachtwoordzinnen — één per context waarin het bericht
verschijnt — via een aangepast multi-key-schema geïnspireerd op het
age-versleutelingsformaat. Een bericht dat zowel in de tijdlijn van een
gebruiker als onder een hashtag staat, wordt versleuteld met zowel de publieke ID van de
gebruiker als de hashtag-string als wachtwoordzinnen. Beide sleutels ontsleutelen het.
Servers die de versleutelde bytes bewaren kunnen geen van beide lezen.
Indiening: Claim dan Commit
Bericht-indiening is een twee-fase-protocol:
- SubmitClaim: De client stuurt een claim-verzoek met PoW. De server valideert de PoW en, als de bericht-ID nog niet aanwezig is, geeft een token uit dat toestemming verleent om te commit'en.
- SubmitCommit: De client stuurt de werkelijke berichtbytes met het token. De server slaat het bericht op en retourneert een bevestigingshandtekening.
Het scheiden van claim en commit voorkomt aanvallen via payload-flooding: een server kan claims te kwader trouw goedkoop afwijzen (alleen PoW verifiëren) voordat een grote payload wordt geaccepteerd. De bevestigingshandtekening van de server is voor de client het bewijs dat het bericht is geaccepteerd.
Bron: hashiverse-server/src/server/handlers/
Bundles en buckets
Berichten worden niet individueel opgeslagen of opgehaald — ze worden gegroepeerd in
EncodedPostBundleV1-objecten, één bundle per bucket per server. Een bundle
bevat ongeveer 20 berichten van een bepaalde location-ID (een specifiek tijdvenster voor
een specifieke gebruiker, hashtag of antwoord-context), maar dit getal kan groter zijn
door healing en eventuele consistentievertragingen. Bundles worden ondertekend door de
bedienende peer.
De tijdlijn van een gebruiker ophalen betekent de bucket-hiërarchie recursief
doorlopen: begin met de maandelijkse bucket, drill in de wekelijkse, dagelijkse,
uurlijkse en fijnere buckets waar berichten bestaan. De
RecursiveBucketVisitor behandelt dit met een callback die op elk niveau
beslist of er in fijnere granulariteit moet worden recursied of overgeslagen, wat
efficiënte paginering mogelijk maakt zelfs over spaarzame tijdlijnen.
Bron: encoded_post_bundle.rs,
hashiverse-lib/src/client/timeline/
Bucket-types
Vier (op het moment van schrijven) bucket-types bepalen hoe berichten worden geïndexeerd en ontdekt:
- User (0): de persoonlijke tijdlijn van de auteur
- Hashtag (1): berichten met een gegeven hashtag
- Mention (2): berichten die een specifieke gebruiker noemen
- ReplyToPost (3): berichten die antwoorden op een specifiek bericht
Een enkel bericht kan tegelijkertijd in meerdere buckets verschijnen, elk versleuteld met de passende wachtwoordzin voor die bucket.
Bron: buckets.rs
Opslag
Op de server worden bericht-bundles op schijf gepersisteerd, terwijl hun metadata wordt gepersisteerd naar fjall — een puur-Rust ingebedde key-value-store met automatische compactie en goede schrijfdoorvoer. fjall is gekozen boven redb en sled vanwege zijn onderhoudsstaat van dienst en operationele eenvoud. Berichten worden opgeslagen als Brotli-gecomprimeerde, versleutelde bytes.
Op de browserclient worden berichten gecached in IndexedDB via
indexed_db_futures, met een in-memory stub voor testen. Elke categorie
client-side-data wordt in rust versleuteld met een andere sleutel, gekozen om bij zijn
toegangsmodel te passen.
Bron: hashiverse-server/src/environment/,
wasm_client_storage.rs