qub-protokolspesifikasie
qub is 'n protokol vir kriptografiese temporale verbintenisse: 'n stelsel om woorde aan 'n toekomstige datum te verseël en, wanneer daardie datum aanbreek, presies te bewys wat gesê is en wanneer.
Drie primitiewe laat dit werk. drand is 'n gedesentraliseerde willekeurigheidsbaken — die onthulling-datum is afdwingbaar deur fisika, nie deur enige party se welwillendheid nie. Permanente openbare berging is 'n peuter-bestande openbare stoor — geen party kan 'n qub redigeer of uitvee sodra dit verseël is nie. ML-DSA-65 is 'n post-kwantum digitale handtekening — elke qub is gekoppel aan 'n sleutelpaar waarvan die geheim nooit die outeur se toestel verlaat nie.
Saam maak hierdie primitiewe 'n stelling wat tyd-geslote, peuter-aandui, en toeskryfbaar is — 'n kwitansie waarvan die waarde toeneem soos die wêreld se vermoë om die verlede te vervals verbeter.
Die res van hierdie dokument is die normatiewe spesifikasie wat vir interoperabele implementasies vereis word.
qub-protokolspesifikasie
| Veld | Waarde |
|---|---|
| Weergawe | 1.0 (protokol-weergawe 0x01, buitenste omhulling-weergawe 0x01) |
| Datum | 2026-05-01 |
| Status | Konsep |
| Hersien deur | 2026-05-01 |
Hierdie dokument is die normatiewe protokolspesifikasie vir die qub tydverbintenis-stelsel. Dit definieer datastrukture, serialisering-reëls, afleidingsformules, en verifikasieprosedures wat vir interoperabele implementasies vereis word.
Omvang: die protokol-laag is opsetlik taal-neutraal — die qub-liggaam is ondeurskynende plaintext / markdown / verbond-grepe, en lokale-bewuste lewering is die kyker se verantwoordelikheid (qub.social-webtoepassing, <qub-embed> iframe, MCP-kliënte, ens.).
1. Notasie en konvensies
| Notasie | Betekenis |
|---|---|
u8, u64, i64 |
Onderteken/getekende heelgetalle van gespesifiseerde bisbreedte |
[u8; N] |
Vaste-lengte grepe-skikking van N grepe |
Vec<u8> |
Veranderlike-lengte grepe-skikking |
Option<T> |
Waarde van tipe T, of afwesig |
String |
UTF-8 teksstring, NFC genormaliseer |
| ` | |
SHA3-256(x) |
NIST SHA3-256 hash van greep-string x (FIPS 202) |
ceil(x) |
Plafonfunksie: kleinste heelgetal ≥ x |
| CBOR | Concise Binary Object Representation (RFC 8949) |
| big-endian | Mees beduidende greep eerste |
Alle heelgetalle in preimage-konstruksies word as big-endian vaste-breedte grepe-skikkings gekodeer (i64 → 8 grepe, u8 → 1 greep) tensy anders gespesifiseer.
Alle tydstempels is Unix-sekondes in UTC.
2. Datastrukture
2.1 ComposeQub (skepper-geheue-toestand)
Nie na CBOR geserialiseer nie. Nie in permanente berging gestoor nie. Plaaslik tot die skepper se toepassing.
ComposeQub {
draft_id: [u8; 16], // Random, generated locally
created_at: i64, // Unix seconds UTC
unlock_at: Option<i64>, // Unix seconds UTC; None while composing
visibility: u8, // 0x01 = public (only value in MVP)
content_type: u8, // 0x01 = text (only value in MVP)
plaintext: Vec<u8>, // UTF-8 qub body
sender_label: Option<String>, // Decorative display name; not authenticated
status: DraftStatus, // Composing | Sealed | Uploaded | Failed
}
2.2 QubEnvelope (gedekripteerde data-vrag)
Geserialiseer met kanonieke CBOR (§3). Geënkripteer binne die SealedQub. Dit is die struktuur wat inhouds-integriteit ná dekripsie bewys.
QubEnvelope {
version: u8, // Protocol major version (0x01 for v1)
qub_id: [u8; 32], // Derived (see §4.1)
content_type: u8, // Content type registry (see §6)
created_at: i64, // Unix seconds UTC
unlock_at: i64, // Unix seconds UTC
outcome_at: Option<i64>, // V1.1 — wanneer die werklikheid 'n oordeel vel (verdict-uplift-plan §3.1)
sender_label: Option<String>, // Decorative; not authenticated in MVP
reply_to: Option<[u8; 32]>,// Parent qub_id for reply chains; not in qub_id preimage; not signed (see §9.3)
body: Vec<u8>, // Content payload (UTF-8 for text, CBOR for pact)
body_hash: [u8; 32], // SHA3-256(body) (see §4.2)
sig_alg: u8, // Signature algorithm (see §9.2)
author_signature: Option<Vec<u8>>, // Set when sig_alg != 0x00
author_pubkey: Option<Vec<u8>>, // Set when sig_alg != 0x00
cosigner_pubkey: Option<Vec<u8>>, // Set for cosigned pact bilateral agreements
cosigner_signature: Option<Vec<u8>>, // Set for cosigned pact bilateral agreements
}
Basislyn (ongeteken-teks qub): version = 0x01, content_type = 0x01, sig_alg = 0x00, alle Option-velde afwesig.
Ander v1-konfigurasies: content_type = 0x03 (verbond-liggaam, sien §6.1); sig_alg = 0x01 (ML-DSA-65) met author_signature en author_pubkey teenwoordig (sien §9.3); cosigner_pubkey en cosigner_signature saam teenwoordig vir mede-onderteken verbonde (sien §9.7); reply_to gestel op die ouer-qub se qub_id vir antwoord-ketting qubs (sien §9.3 vir die handtekening-omvang implikasies).
2.3 SealedQub (kanonieke draadformaat)
Geserialiseer met kanonieke CBOR (§3). In permanente berging geskryf. Dit is die op-ketting artefak.
SealedQub {
version: u8, // Protocol major version (0x01 for v1)
qub_id: [u8; 32], // Same as QubEnvelope.qub_id
visibility: u8, // 0x01 = public; v1 viewers reject other values
unlock_at: i64, // Unix seconds UTC
outcome_at: Option<i64>, // V1.1 — vertoon op die oordeel-wag-CTA
// voor onthulling; weerspieël QubEnvelope.outcome_at;
// gebind aan qub_id via die §4.1 preimage.
drand_chain_id: String, // drand chain hash (hex string)
drand_round: u64, // Target drand round number
tlock_ciphertext: Vec<u8>, // tlock-encrypted QubEnvelope CBOR bytes
recipient_pubkey: Option<[u8; 32]>,// Reserved field; accepted by canonical CBOR
// but not interpreted by the v1 reference viewer
title: Option<String>, // Plaintext title surfaced on the viewer
// countdown before reveal. Bound to qub_id
// via title_hash (§4.1). 1..=100 NFC code
// points, no control characters.
}
2.4 RevealedQub (kyker-toepassingstoestand)
Nie na CBOR geserialiseer nie. Plaaslik tot die kyker se toepassing. Gekonstrueer ná suksesvolle dekripsie en verifikasie.
RevealedQub {
qub_id: [u8; 32],
arweave_tx_id: String,
visibility: u8,
content_type: u8,
created_at: i64,
unlock_at: i64,
outcome_at: Option<i64>, // V1.1 — oorgedra vanaf QubEnvelope.outcome_at / SealedQub.outcome_at; dryf die onthul-bladsy se uitspraak-wag-blok (verdict-uplift-plan §5.1)
drand_chain_id: String,
drand_round: u64,
sender_label: Option<String>,
title: Option<String>, // Carried forward from SealedQub.title
reply_to: Option<[u8; 32]>,
body: Vec<u8>,
body_hash: [u8; 32],
body_hash_verified: bool,
author_signature: Option<Vec<u8>>,
author_pubkey: Option<Vec<u8>>,
signature_verified: Option<bool>,
cosigner_pubkey: Option<Vec<u8>>,
cosigner_signature: Option<Vec<u8>>,
cosigner_verified: Option<bool>,
}
3. Kanonieke CBOR-profiel
Alle SealedQub- en QubEnvelope-serialisering MOET aan hierdie profiel voldoen. Twee implementasies wat dieselfde logiese struktuur ontvang MOET identiese grepe lewer.
3.1 Enkoderingsreëls
| Reël | Spesifikasie |
|---|---|
| Standaard | RFC 8949 §4.2.1 (Core Deterministic Encoding Requirements) |
| Kaart-sleutel orde | Gesorteer volgens gekodeerde greep-lengte eers (korter voor langer), dan leksikografies (greep-vir-greep vir gelyke-lengte enkoderings) |
| Heelgetal-enkodering | Kortste vorm: 0–23 in aanvanklike greep; 24–255 in 2 grepe; 256–65535 in 3 grepe; ens. |
| Lengte-enkodering | Slegs definitiewe lengtes. Geen onbepaalde-lengte skikkings, kaarte, greep-stringe, of teksstringe nie (additional info = 31 is verbode). |
| Etikette | Geen CBOR-etikette nie (hoof-tipe 6 is verbode). |
| Drywende-punt | Geen drywendes nie (hoof-tipes 7 waardes 0xF9–0xFB is verbode). |
| Teksstringe | UTF-8 gekodeer, NFC genormaliseer (Unicode Normalization Form C). |
| Greep-stringe | Rou grepe. Geen base64-enkodering by die CBOR-laag nie. |
| Duplikaat-sleutels | Verwerp met fout. Parsers MOET NIE stilweg duplikaat kaart-sleutels aanvaar nie. |
| Eenvoudige waardes | Slegs true (0xF5), false (0xF4), en null (0xF6) word toegelaat. |
| Opsionele velde | Afwesige opsionele velde word uitgelaat van die CBOR-kaart geheel (nie as null gekodeer nie). Teenwoordige opsionele velde word in gesorteerde sleutel-orde ingesluit. |
3.2 Geverifieerde kanonieke sleutel-ordes
Hierdie sleutel-ordes is normatief. Implementasies MOET sleutels presies in hierdie orde uitstuur. Foutsoek-aansprake BEHOORT ordening in nie-vrystellingsbouë te verifieer.
QubEnvelope (weergawe 0x01, ongeteken, alle opsionele velde afwesig):
"body" (5 encoded bytes)
"qub_id" (7 encoded bytes)
"sig_alg" (8 encoded bytes)
"version" (8 encoded bytes)
"reply_to" (9 encoded bytes) ← only if present (reply chains)
"body_hash" (10 encoded bytes)
"unlock_at" (10 encoded bytes)
"created_at" (11 encoded bytes)
"outcome_at" (11 encoded bytes) ← only if present (V1.1 verdict mechanic)
"content_type" (13 encoded bytes)
"sender_label" (13 encoded bytes) ← only if present
"author_pubkey" (14 encoded bytes) ← only if present
"cosigner_pubkey" (16 encoded bytes) ← only if present (pact cosign)
"author_signature" (17 encoded bytes) ← only if present
"cosigner_signature" (19 encoded bytes) ← only if present (pact cosign)
QubEnvelope sleutel-orde afleiding: elke sleutel is 'n CBOR-teksstring. Gekodeerde lengte = 1 greep kop + string-lengte (vir stringe onder 24 grepe). Sorteer eers volgens totale gekodeerde lengte, dan leksikografies vir sleutels van gelyke lengte.
SealedQub (weergawe 0x01, publiek, geen ontvanger):
"title" (6 encoded bytes) ← only if present
"qub_id" (7 encoded bytes)
"version" (8 encoded bytes)
"unlock_at" (10 encoded bytes)
"outcome_at" (11 encoded bytes) ← only if present (V1.1 verdict mechanic)
"visibility" (11 encoded bytes)
"drand_round" (12 encoded bytes)
"drand_chain_id" (15 encoded bytes)
"recipient_pubkey" (17 encoded bytes) ← only if present
"tlock_ciphertext" (17 encoded bytes)
PactTerms (verbond-liggaam, content_type 0x03):
"notes" (6 encoded bytes) ← only if present
"terms" (6 encoded bytes)
"title" (6 encoded bytes)
"party_a" (8 encoded bytes)
"party_b" (8 encoded bytes)
"pact_version" (13 encoded bytes)
PactTerm (ry van die terms-skikking):
"key" (4 encoded bytes)
"value" (6 encoded bytes)
PartyIdentifier (party_a / party_b kaart):
"label" (6 encoded bytes)
"contact" (8 encoded bytes) ← only if present
3.3 Greep-enkodering verwysing
| Tipe | CBOR-enkodering | Voorbeeld |
|---|---|---|
| SHA3-256 hash (32 grepe) | 0x58 0x20 + 32 grepe |
body_hash, qub_id |
| Tydstempels (i64) | Hoof-tipe 0 (positief) of 1 (negatief), kortste enkodering | Unix-sekondes |
| Weergawe (u8, waarde 1) | 0x01 (enkele greep) |
|
| Inhoudstipe (u8, waarde 1) | 0x01 (enkele greep) |
|
| sig_alg (u8, waarde 0) | 0x00 (enkele greep) |
|
| ML-DSA-65 handtekening (3 309 grepe) | 0x59 0x0C 0xED + 3 309 grepe |
author_signature, cosigner_signature |
| ML-DSA-65 publieke sleutel (1 952 grepe) | 0x59 0x07 0xA0 + 1 952 grepe |
author_pubkey, cosigner_pubkey |
4. Normatiewe afleidings
4.1 qub_id
Die qub_id identifiseer 'n qub uniek en bind die QubEnvelope aan die SealedQub. Dit word deterministies afgelei van die koevert-inhoud.
qub_id = SHA3-256(
"QUB_ID_V2" || // domain separator: ASCII bytes [0x51 0x55 0x42 0x5F 0x49 0x44 0x5F 0x56 0x32] (9 bytes) + 0x00 padding (1 byte) = 10 bytes
version || // u8 (1 byte)
content_type || // u8 (1 byte)
created_at || // i64 big-endian (8 bytes)
unlock_at || // i64 big-endian (8 bytes)
outcome_at_or_zero || // i64 big-endian (8 bytes; 0 when outcome_at is absent)
drand_round || // u64 big-endian (8 bytes)
body_hash || // [u8; 32] (32 bytes)
title_hash // [u8; 32] (32 bytes; absent-sentinel = [0u8; 32])
)
// Total preimage: 108 bytes → 32-byte output
Domein-skeier enkodering: Die string "QUB_ID_V2" is 9 ASCII-grepe. 'n Enkele 0x00-vullinggreep word bygevoeg om 10 grepe vir belyning te bereik. Implementasies MOET presies hierdie 10 grepe gebruik: [0x51, 0x55, 0x42, 0x5F, 0x49, 0x44, 0x5F, 0x56, 0x32, 0x00].
outcome_at-enkodering: V1.1 het die preimage van 92 na 100 grepe uitgebrei om die opsionele outcome_at-veld in die binding in te vou. 'n Afwesige outcome_at word as 8 nul-grepe gekodeer; die protokol se valideerders verwerp outcome_at <= 0 oral, sodat hierdie sentinel-waarde nie met 'n wettige waarde kan bots nie. Sien §3.2 (draadformaat) en die in-boom tasks/verdict-uplift-plan.md vir die oordeel-meganiek wat hierdie veld motiveer.
drand_round-kodering: V1.2 het die voorbeeld van 100 na 108 grepe uitgebrei om drand_round (die teiken-drand-rondte, §4.3) in die binding te vou, en die domeinskeier na QUB_ID_V2 opgegradeer. Dit bind die tydslotrondte in die qub-identiteit in: 'n poort kan nie die syferteks aan 'n ander rondte (bv. 'n reeds-verlede rondte) herbind as wat die vertoonde unlock_at impliseer nie. Die ontsluitprosedure (§8) verifieer boonop dat die rondte wat in die tlock-syferteksstrofe ingebak is, ooreenstem met unlock_round(unlock_at), sodat die vertoonde ontsluittyd bewysbaar die rondte is wat ontsleuteling beheer.
Eienskappe:
- Verandering van enige veld in die QubEnvelope (liggaam, tydstempels, inhoudstipe, weergawe) lewer 'n verskillende qub_id.
- Die qub_id word voor enkripsie bereken. Beide QubEnvelope en SealedQub dra dieselfde qub_id. Die kyker verifieer dat hulle ooreenstem ná dekripsie.
- qub_id is nie afhanklik van
sender_label,author_signature, ofauthor_pubkeynie. Dit beteken dieselfde inhoud wat op dieselfde tyd verseël word lewer dieselfde qub_id ongeag wie dit teken. - Verandering van die SealedQub
title(met alles anders vas) veranderqub_idviatitle_hash. 'n Brug kan dus nie die plaintext-titel wat op die aftelling vertoon word omruil sonder om die qub-identiteit ongeldig te maak nie. - Verandering van die SealedQub
outcome_at(met alles anders vas) veranderqub_idvia die preimage. 'n Brug kan nie die voor-onthulling oordeel-aan-datum wat op die aftelling vertoon word omruil sonder om die qub-identiteit ongeldig te maak nie. - Verandering van
drand_round(met alles anders vas) veranderqub_idvia die preimage. 'n Brug kan nie die tydslot-syferteks aan 'n ander rondte herbind sonder om die qub-identiteit ongeldig te maak nie; saam met die §8 ontsluittyd-strofe-rondtekontrole is die vertoondeunlock_atdie rondte wat ontsleuteling werklik beheer.
4.2 body_hash
body_hash = SHA3-256(body)
Waar body die rou Vec<u8> inhoud-vrag is. Vir teks-qubs is dit die UTF-8 gekodeerde qub-liggaam.
4.2.1 title_hash
title_hash = SHA3-256(NFC(title).utf8_bytes) if title is present
title_hash = [0u8; 32] if title is absent
Waar title die opsionele plaintext-titel is wat op die kyker-aftelling voor onthulling verskyn (sien §3.2). NFC-normalisering loop by hash-tyd sodat die spysverteringskode stabiel is oor visueel-ekwivalente kodepunt-rye. Die alles-nulle sentinel is gereserveer vir die afwesige geval; 'n leë string word by die kanonieke CBOR-grens verwerp as 'n nie-kanonieke enkodering van "afwesig" (die kanonieke enkodering laat die veld heeltemal uit).
4.3 Ontsluitings-rondte kartering
drand_round = ceil((unlock_at - chain_genesis_time) / chain_period_seconds)
| Parameter | Bron | Voorbeeld |
|---|---|---|
unlock_at |
Gebruiker-gekose Unix-sekondes UTC | 1735689600 (2025-01-01 00:00:00 UTC) |
chain_genesis_time |
drand ketting-info (genesis_time) |
1595431050 |
chain_period_seconds |
drand ketting-info (period) |
30 |
Die ceil()-bewerking kies die eerste drand-rondte waarvan die onthulling-tyd ≥ unlock_at is. Dit verseker die qub kan nie dekripteerbaar word voor die gekose ontsluitings-tyd nie.
Rand-geval: as (unlock_at - chain_genesis_time) presies deelbaar is deur chain_period_seconds, is die resultaat daardie presiese rondte — die qub ontsluit presies by daardie rondte se onthulling-tyd.
Validasie: unlock_at MOET in die toekoms wees by seël-tyd. unlock_at MOET NIE meer as 10 jaar van created_at af wees nie (om langtermyn drand-afhanklikheidsrisiko te beperk; die UI BEHOORT te waarsku vir ontsluitings-datums verby 2 jaar).
5. Draadformaat newtypes
Draadformaat-newtypes verskaf kompilasie-tyd veiligheid teen die verwarring van CBOR-grepe met JSON, rou plaintext, of ander greep-enkoderings.
| Tipe | Bevat | Geproduseer deur | Verbruik deur |
|---|---|---|---|
SealedQubCbor |
Kanonieke CBOR van SealedQub | serialize_sealed_qub() |
Permanente-berging-oplaai, kyker-aflewering |
QubEnvelopeCbor |
Kanonieke CBOR van QubEnvelope | serialize_qub_envelope() |
tlock-enkripsie-inset, tlock-dekripsie-uitset |
5.1 Konstruksie-reëls
// Production code — only through CBOR serialisers:
let sealed = SealedQubCbor::from_encoded(cbor_bytes);
// There is deliberately NO From<Vec<u8>> implementation.
// You cannot accidentally wrap arbitrary bytes in a wire format type.
// Accessing raw bytes:
let bytes: &[u8] = sealed.as_bytes();
let bytes: Vec<u8> = sealed.into_bytes();
5.2 Validasie by konstruksie
from_encoded() BEHOORT te valideer dat die inset met 'n geldige CBOR-kaart kop begin. Volledige strukturele validasie gebeur by ontleed-tyd, nie konstruksie-tyd nie, om dubbele-ontleding te vermy.
6. Inhoudstipe-register
| Waarde | Tipe | Maks. liggaam-grootte | Notas |
|---|---|---|---|
0x00 |
Gereserveer (ongeldig) | — | MOET NIE gebruik word nie |
0x01 |
Plat teks (UTF-8, beperkte Markdown) | 50 KB betaald / 10 KB gratis | Sien §10 vir lewering-reëls. Die gratis / betaalde verdeling word deur die oplaai-diens afgedwing; die protokol-laag harde plafon is 50 KB. |
0x02 |
Gereserveer (toekoms) | — | Toegeken vir 'n toekomstige inhoudstipe; nie geldig in v1 nie. Kykers MOET verwerp volgens die reël hieronder. |
0x03 |
Verbond (bilaterale ooreenkoms, CBOR-liggaam) | 100 KB | Liggaam is kanonieke CBOR PactTerms (§6.1). Mede-ondertekenaar ondertekening per §9.7. |
0x04 |
Uitspraak (skepper se self-beoordeling, CBOR-liggaam) | 8 KB | Liggaam is kanonieke CBOR VerdictBody (§6.2). Word slegs deur die stelsel-kant verdict-intensie uitgestuur. Ouer-verhouding is op die Parent-Tx-Id Arweave-merker, nie op die liggaam nie. Sien verdict-uplift-plan §3.4. |
Kykers MOET onbekende inhoudstipes met 'n duidelike gebruiker-sigbare fout verwerp. Kykers MOET NIE poog om onbekende tipes as teks te lewer nie.
6.1 Verbond-liggaam (content_type = 0x03)
'n Verbond-liggaam is die kanonieke CBOR-enkodering van 'n PactTerms-waarde:
PactTerms {
pact_version: u8, // 0x01 for structured/v1
title: String, // ≤ 200 bytes, NFC
terms: Vec<PactTerm>, // ≤ 20 rows
party_a: PartyIdentifier, // initiator
party_b: PartyIdentifier, // counter-signer
notes: Option<String>, // ≤ 5,000 bytes, NFC; absent key if none
}
PactTerm { key: String (≤ 100), value: String (≤ 2,000) } // NFC on both sides
PartyIdentifier{ label: String (≤ 100), contact: Option<String (≤ 320)> }
Kanonieke CBOR-sleutel-ordes vir al drie kaarte word in §3.2 gegee. Totale geserialiseerde verbond-CBOR MOET NIE 100 KB oorskry nie (stem ooreen met §6).
Skema-onderskeider. Die eerste ry in terms vir 'n structured/v1-verbond MOET wees { key: "pact_schema", value: "structured/v1" }. Rye sonder hierdie merker is "pasgemaakte" verbonde en ontvang geen gestruktureerde validasie of skema-bewuste lewering nie.
Bevrore erkenning-gleuwe. structured/v1-verbonde dra presies vier erkenning-rye onder hierdie sleutels:
"initiator_standard_terms"
"initiator_capacity_terms"
"counterparty_standard_terms"
"counterparty_capacity_terms"
Die value vir elk is een van agt bevrore Engelse stringe gekies deur die (role, kind)-paar, waar role ∈ { seller, buyer, provider, client } en kind ∈ { standard, capacity }. Die stringe self is normatiewe protokol-data — beide partye se ML-DSA-65 handtekeninge verbind tot die presiese grepe via body_hash. Hulle word NIE gelokaliseer nie; die ondertekende liggaam is taal-neutraal. Enige bewoording-verandering vereis 'n nuwe skema-weergawe (structured/v2).
Die agt stringe, hul opsoek (acknowledgement_for(role, kind)), en die rasionaal vir elkeen is vasgepen deur die verwysing-implementasie. Konforme implementasies MOET greep-identiese erkenning-waardes uitstuur; goue-vasstellings SHA3-256 liggaam-hash toetse wat al vier rol-kombinasies dek vang enige drywing.
Kyker-vertoonsorde. Die erkenning-stringe bevat frases soos "described above", wat veronderstel dat die beskrywing- / omvang-rye voor die erkennings lewer. Kykers MOET die terms-skikking in CBOR-orde lewer; herrangskikking breek die prosa-semantiek.
Teen-party kontak. Wanneer Party B se contact 'n geldige e-posadres is, stuur die qub-oplaaidiens outomaties 'n hersiening- / mede-ondertekening uitnodig-e-pos op verhoog-tyd uit en bind die uiteindelike mede-ondertekening aan verifikasie van dieselfde adres (§9.7). Verbonde waarvan die Party B-kontak afwesig is kan steeds mede-onderteken word, maar slegs deur 'n buite-band kanaal — die diens weier mede-ondertekening-versoeke wat nie 'n ooreenstemmende 15-minute e-pos-verifikasie merker kan lewer nie.
6.2 Uitspraak-liggaam (content_type = 0x04)
'n Uitspraak-liggaam is die kanonieke CBOR-enkodering van 'n VerdictBody-waarde:
VerdictBody {
verdict_version: u8, // 0x01 for structured/v1
outcome: u8, // 1=Right · 2=Partial · 3=Wrong · 4=Unfalsifiable
reflection: Option<String>, // ≤ 2,000 bytes NFC; "what changed, what did you learn"
evidence_url: Option<String>, // ≤ 2,048 bytes; HTTPS only; absent key when omitted
}
Kanonieke CBOR-sleutel-orde:
"outcome" (8 encoded bytes)
"reflection" (11 encoded bytes) ← only if present
"evidence_url" (13 encoded bytes) ← only if present
"verdict_version" (16 encoded bytes)
Totale geserialiseerde uitspraak-CBOR MOET NIE 8 KB oorskry nie (stem ooreen met die register-ry hierbo).
Uitkoms-opsomming. Die draadgreep is intensie-neutraal; die vier emmers Right / Partial / Wrong / Unfalsifiable dek elke uitspraak-draende intensie se uitkoms-ruimte. Per-intensie etikette ("Reg geraai" / "Nagekom" / "Gelewer" / "Bevestig" vir Right, ens.) is 'n kyker-kant lewering-aangeleentheid wat teen die ouer-qub se intensie opgelos word — die draad bly taal- en intensie-neutraal. Waardes buite 1..=4 MOET by dekodering verwerp word.
Ouer-koppeling. 'n Uitspraak-qub dra NIE die ouer-verwysing in sy liggaam nie. Die ouer-qub se Arweave-transaksie-id word as die Parent-Tx-Id berging-merker by oplaai-tyd uitgestuur (§7 berging-merker-laag). Dit hou die liggaam 'n self-bevattende ondertekende stelling van self-beoordeling; die oudit-ketting ("reg waaroor?") word via die Arweave-merker-opsoek gevestig.
Bewys-URL-veiligheid (normatief). Wanneer evidence_url teenwoordig is, MOET valideerders (komponeer-kant, draad-kant, Worker-rand) afdwing:
- Slegs HTTPS. Die string MOET met die greep-volgorde
https://begin. Enige ander skema —http,ftp,javascript,data,file, ens. — word verwerp. - Lengte-plafon. ≤ 2,048 grepe (praktiese URL-grens van blaaier).
- NFC + vyandige-kodepunt-toets. Dieselfde reël as
titleenreflection— bidi-oorheers- / nul-wydte- / merker-blok- / BOM- / C0- / C1-kodepunte word verwerp. Definisie stem ooreen met die Rustcrate::handle::contains_hostile_text_codepointen die TSworkers/api/src/utils/unicode.ts::isHostileCodepoint(hou in pas). - Geen wit-spasie, geen ASCII-beheerkarakters nie. Wit-spasie / DEL / sub-
0x20grepe enige plek in die URL word verwerp — sluit die\n/\t-inspuiting-vektor af wat die bidi-reël nie dek nie. - Nie-leë gasheer-segment. Alles tussen
https://en die eerste/,?, of#MOET nie-leeg wees.
Geen bediener-kant gaan haal nie. Die Worker MOET NIE die URL volmag, gaan haal, of voorskou nie. Die protokol stoor 'n string; lewering gebeur kyker-kant met rel="nofollow noopener noreferrer" target="_blank" en 'n sigbare gasheer vertoon langs die skakel-teks.
Refleksie. Opsionele skepper-geskrewe refleksie-teks ("wat het verander, wat het jy geleer"). Dieselfde NFC + vyandige-kodepunt-validasie as title. Leeg / slegs wit-spasie-inset val saam tot afwesig by konstruksie-tyd.
Skema-weergawe. v1 ondersteun slegs verdict_version = 0x01. Toekomstige skema-hersienings stoot hierdie greep op en land saam met 'n nuwe protokol-weergawe per §12.
7. Verseël-protokol
Die volledige verseël-volgorde. Elke stap is normatief.
1. User composes plaintext and metadata in ComposeQub.
2. Validate:
a. body is non-empty.
b. body size ≤ max for content_type and user tier (see §6).
c. unlock_at is in the future.
d. unlock_at ≤ created_at + 10 years.
e. content_type is a known, supported value.
3. Compute body_hash = SHA3-256(body).
4. Set created_at = current Unix seconds UTC.
5. Select drand chain. Load chain_genesis_time and chain_period_seconds, and
compute drand_round = ceil((unlock_at - chain_genesis_time) / chain_period_seconds).
(Computed here, before qub_id, because drand_round is bound into the qub_id
preimage — §4.1, V1.2.)
6. Compute qub_id (see §4.1), folding in drand_round from step 5.
7. Construct QubEnvelope with all fields.
8. Serialise QubEnvelope using canonical CBOR → bytes B.
Assert: serialised output matches canonical profile (§3).
9. Compute C = tlock_encrypt(B, drand_round, drand_chain_public_key).
10. Construct SealedQub with tlock_ciphertext = C, and matching qub_id, version,
unlock_at, drand_chain_id, drand_round.
12. Serialise SealedQub using canonical CBOR → SealedQubCbor.
12a. Generate K = 32 random bytes (CSPRNG) and N = 12 random bytes (CSPRNG).
Compute W = wrap_sealed_qub(SealedQubCbor, qub_id=qub_id, key=K, nonce=N)
per §13. The bytes uploaded to permanent storage are the OuterWrapper CBOR W,
never the bare SealedQubCbor. K leaves the device only as the URL
fragment in step 16.
13. Display seal-time disclosure. User confirms.
14. Validate upload eligibility via the qub upload service (bot-detection, entitlement, rate limits).
15. Submit W (the OuterWrapper bytes) to the qub upload service; the service
signs and uploads to permanent storage. The service is byte-blind to the inner
SealedQubCbor and never receives K.
16. Receive arweave_tx_id from the service. Construct delivery URL as
`<origin>/c/<arweave_tx_id>#<base64url(K)>` (or `<origin>/s/<short_code>#<base64url(K)>`
when a short code is allocated). Browsers do not transmit URL fragments
to servers, so K is never observed by qub.social or any storage gateway.
Bergingsetiket laag (buite-band). Die qub-oplaaidiens heg 'n opsetlik klein stel bergingstransaksie-etikette saam met die omhulde data-vrag. Content-Type=application/octet-stream word normatief vereis. Die verwysing-diens heg addisioneel drie opsionele etikette aan wanneer die skepper kies om hulle te wys: Intent (toelaatlys-gevalideerde komposisie-intensie — bv., quote, reply, commitment), Author (skepper se §9.3 publieke-sleutel vingerafdruk as 64-karakter kleinletter hex), en Parent-Tx-Id (ouer-qub se bergingstransaksie-ID vir antwoord-kettings, 43-karakter base64url).
Die Author-etiket is per-qub kies-in: die verwysing-skepper toepassing heg dit slegs aan wanneer die gebruiker openbare-toeskrywing eksplisiet by seël-tyd aktiveer. Wanneer die skakelaar af is — die verstek — word geen Author-etiket geskryf nie en die qub is nie toegeskryf op die ketting nie: niks in permanente berging koppel die oplaai aan 'n skepper se handvatsel, e-pos, of ander qubs nie. Wanneer die skakelaar aan is, los die Author-vingerafdruk op na die skepper se gekose @handvatsel via die §9.5 bevestigings-ketting. Antwoord-ketting verhoudings en Intent is nie-identifiserend. Die buitenste omhulling (§13) beskerm die binne liggaam teen ciphertext-korrelasie — wat verhinder dat 'n oeser qub-vormige oplaaie herken en grootmaat-dekripteer nadat hul drand-rondte gepubliseer is.
Die verwysing-diens heg opsetlik NIE App-Name-, App-Version-, of Type-etikette aan nie: enige sodanige enkel-waarde filter sou die hele qub-korpus na 'n GraphQL-navraag terugstuur, wat onversoenbaar is met die omhulling se liggaam-alleen vertroulikheid-omvang.
'n Konformerende verifieerder MOET NIE op enige bergingsetiket vir §11 derde-party verifikasie staatmaak nie; die liggaam-hash / qub_id / handtekening verbind slegs tot die binnenste CBOR, nooit tot die etiket-stel nie.
8. Ontsluit-protokol
Die volledige ontsluit-volgorde. Elke stap is normatief.
1. Viewer opens delivery URL. Extract arweave_tx_id from path AND
K = base64url_decode(fragment) from the URL fragment. If the fragment
is absent or malformed → display "this URL is missing its decryption
key" and stop; the viewer MUST NOT contact the storage gateway
without K, since fetching wrapped bytes the viewer cannot decrypt
serves no purpose and only leaks the access attempt.
2. Check denylist. If tx_id is denylisted → display block message. Stop.
3. Fetch OuterWrapper bytes from permanent storage (with multi-gateway fallback).
3a. Unwrap: parse the bytes as OuterWrapper (§13), verify the wrapper
`version` byte is `0x01`, and compute SealedQubCbor =
unwrap_sealed_qub(OuterWrapper, key=K). Any AEAD authentication
failure (wrong K, tampered ciphertext, swapped qub_id-as-AAD,
swapped nonce) → display "this URL's decryption key does not match
the stored qub" and stop. Authentication failures are
indistinguishable to the viewer per §13.5.
4. Parse SealedQubCbor → SealedQub.
5. Validate: SealedQub.version is known (0x01). Reject unknown versions.
6. If current time < SealedQub.unlock_at → display countdown. Poll or wait.
6a. Round-binding check (V1.2). Recompute expected_round =
ceil((SealedQub.unlock_at - chain_genesis_time) / chain_period_seconds).
Reject unless SealedQub.drand_round == expected_round AND the round baked
into the tlock ciphertext stanza (read via the age/tlock header, no signature
required) == expected_round. The stanza round is the one that actually gates
decryption; without this check a malicious creator could bind the ciphertext
to an already-past round while displaying a future countdown, so anyone
reading the stored bytes could decrypt before unlock_at. Implementations with
no chain identity (test mocks) skip this check.
7. Once current time ≥ SealedQub.unlock_at:
a. Fetch drand round signature for SealedQub.drand_round from drand network.
b. Compute B = tlock_decrypt(SealedQub.tlock_ciphertext, round_signature).
8. Parse B → QubEnvelope.
9. Validate QubEnvelope.version is known.
10. Verify: SHA3-256(QubEnvelope.body) == QubEnvelope.body_hash.
Fail → integrity error.
11. Verify: QubEnvelope.qub_id == SealedQub.qub_id.
Fail → integrity error.
12. Verify: QubEnvelope.unlock_at == SealedQub.unlock_at.
Fail → integrity error.
13. Verify: QubEnvelope.content_type is known and renderable.
Known values: 0x01 (text), 0x03 (pact). Unknown → display error.
14. If QubEnvelope.sig_alg != 0x00 → verify author signature (see §9.4).
15. If cosigner_pubkey or cosigner_signature present → verify cosigner (see §9.7).
16. Render content using appropriate renderer (see §10 for text, §6 for pact).
17. Construct RevealedQub for display.
9. Outeurskap-ondertekening
9.1 Rasionaal
Elke qub word in permanente berging gestoor. Outeurskap-handtekeninge moet onbedrieglik bly vir onbepaalde tyd, en daarom gebruik v1.0 die post-kwantum ML-DSA-65 skema (FIPS 204) eerder as 'n klassieke skema waarvan die sekuriteit mag verswak binne die qub se permanente leeftyd.
9.2 Algoritme-register
sig_alg |
Skema | Sleutel-grootte | Handtekening-grootte |
|---|---|---|---|
0x00 |
Geen handtekening (ongeteken) | — | — |
0x01 |
ML-DSA-65 (FIPS 204) | 1 952 grepe | 3 309 grepe |
Kykers MOET onbekende sig_alg-waardes verwerp.
9.3 Ondertekende preimage-konstruksie
sig_input = SHA3-256(
"QUB_AUTHOR_SIG_V1" || // domain separator (17 bytes)
version || // u8 (1 byte)
qub_id || // [u8; 32] (32 bytes)
body_hash || // [u8; 32] (32 bytes)
unlock_at || // i64 big-endian (8 bytes)
0x00 // u8 (1 byte): MUST be 0x00 in v1.0
)
// Total preimage: 91 bytes → 32-byte hash
signature = Sign(author_secret_key, sig_input)
Domein-skeier: "QUB_AUTHOR_SIG_V1" is 17 ASCII-grepe: [0x51, 0x55, 0x42, 0x5F, 0x41, 0x55, 0x54, 0x48, 0x4F, 0x52, 0x5F, 0x53, 0x49, 0x47, 0x5F, 0x56, 0x31]. Geen vulling.
Sleep-greep: die 91ste preimage-greep MOET 0x00 wees. Die verwysing-implementasie ontbloot dit as die konstante ORG_ID_PRESENT_INDIVIDUAL = 0x00 in crates/qub-core/src/signing.rs; kykers wat sig_input vir verifikasie herbou MOET dieselfde greep uitstuur.
Handtekening-omvang — wat gedek word en wat nie. sig_input verbind tot vier koevert-velde: version, qub_id, body_hash, unlock_at (plus die vaste domein-skeier en org_id_present-greep). Drie van daardie vier is strukturele invariante: qub_id word self afgelei van version, content_type, created_at, unlock_at, outcome_at, drand_round, en body_hash via die §4.1 preimage, dus enige verandering aan daardie velde lewer 'n verskillende qub_id en maak die handtekening transitief ongeldig. Die direk-geverifieerde oppervlak is dus:
| Veld | Geverifieer deur handtekening | Hoe |
|---|---|---|
version |
✓ | Direkte inset na sig_input |
qub_id |
✓ | Direkte inset |
body_hash |
✓ | Direkte inset |
unlock_at |
✓ | Direkte inset |
content_type |
✓ | Transitief, via qub_id-preimage |
created_at |
✓ | Transitief, via qub_id-preimage |
outcome_at |
✓ | Transitief, via qub_id-preimage |
drand_round |
✓ | Transitief, via qub_id-preimage (V1.2) |
body |
✓ | Transitief, via body_hash = SHA3-256(body) |
author_pubkey |
— (implisiet) | Sleutel wat die handtekening geverifieer het is per definisie die outeur |
sender_label |
✗ | Slegs-vertoon teks; veranderbaar sonder handtekening-breuk |
reply_to |
✗ | Draad-wyser; veranderbaar sonder handtekening-breuk |
cosigner_pubkey / cosigner_signature |
— | Onafhanklik onderteken oor dieselfde sig_input (sien §9.7) |
drand_chain_id, tlock_ciphertext, visibility |
— | Buitenste SealedQub-velde, nie binne die koevert nie — gedek deur hul eie strukturele invariante (rondte / ketting konsekwentheid) maar nie deur die outeur-handtekening nie. (drand_round word nou transitief gebind via die qub_id-preimage — sien hierbo.) |
Sekuriteits-implikasies van nie-geverifieerde velde.
- 'n Party met skryf-toegang tot die gestoorde grepe kan
sender_label("Alice" → "Mallory") omruil sonder om die outeur-handtekening ongeldig te maak. Dieauthor_pubkeybinne die koevert bly die ware identiteit-anker — kykers MOET die vertoon-identiteit vanauthor_pubkeyaflei (via die §9.5 bevestiging-laag) eerder as omsender_labelte vertrou. - 'n
reply_to-veld kan eweneens ná ondertekening geredigeer word. Omdatqub_idinhoud-geadresseer is, kan 'n aanvaller niereply_tona 'n nie-bestaande teiken laat wys nie, maar hulle kan stilweg 'n antwoord aan 'n ander bestaande qub her-koppel.
Implementasies wat sender_label of reply_to aan eind-gebruikers vertoon MOET die geverifieerde identiteit (publieke-sleutel vingerafdruk, bevestiging) as die primêre identiteit-sein vertoon, nie die etiket nie.
9.4 Verifikasie-prosedure
1. Read sig_alg from QubEnvelope.
2. If sig_alg == 0x00 → unsigned. No verification. Display "unsigned qub."
3. If sig_alg is unknown → reject. Display "unrecognised signature scheme."
4. Extract author_signature and author_pubkey. If either is absent → integrity error.
5. Reconstruct sig_input using fields from QubEnvelope (same formula as §9.3).
6. Verify(author_pubkey, sig_input, author_signature).
7. If verification succeeds → display "signed by [key fingerprint]."
8. If verification fails → display "signature verification failed."
Handtekening-verifikasie is die mees duur bewerking (veral ML-DSA-65). Dit BEHOORT uitgevoer te word nadat alle goedkoper kontroles (hash, qub_id, unlock_at) geslaag het.
9.5 Identiteit-bevestigings
Identiteit-bevestigings — die kartering van author_pubkey na mens-herkenbare identiteit-eise soos 'n qub-handvatsel, e-posadres, sosiale handvatsel, of passleutel-geloofsbrief — is 'n kyker-kant progressiewe verbetering en word nie vereis vir handtekening-verifikasie nie. Kykers wat bevestigings na 'n vertoon-identiteit oplos MOET die voorrang toepas:
handle > email > social > fingerprint
Die vingerafdruk-terugval is die kleinletter-hex van SHA3-256(author_pubkey); dit is altyd beskikbaar vir enige onderteken-qub. Kykers MAG dit afkort vir vertoning — die verwysing-kyker lewer qub: gevolg deur die eerste en laaste vier grepe (qub:<8 hex>…<8 hex>).
'n Konformerende verifieerder kan elke kontrole in §9.4 voltooi sonder om die qub-API te kontak, sonder enige netwerk buite permanente berging en drand, en sonder enige bediener-kant opsoek. Bevestiging-oplossing is 'n aparte beste-poging stap wat slegs uitgevoer word nadat handtekening-verifikasie geslaag het.
9.6 Grootte-impak
| Ed25519 | ML-DSA-65 | |
|---|---|---|
| Handtekening | 64 grepe | 3 309 grepe |
| Publieke sleutel | 32 grepe | 1 952 grepe |
| Totaal per qub | 96 grepe | 5 261 grepe |
| Bergingskoste delta (teen ~$5/MB) | ~$0.0005 | ~$0.026 |
Vir 'n teks-qub van 500–2 000 grepe, verdriedubbel ML-DSA-65 ongeveer die gestoorde grootte. Die absolute koste is weglaatbaar.
9.7 Mede-ondertekenaar-verifikasie (verbond bilaterale ooreenkomste)
Vir bilaterale ooreenkomste (content_type = 0x03) bewys 'n tweede handtekening-laag dat albei partye tot dieselfde voorwaardes ingestem het.
Koevert-velde:
cosigner_pubkey: ML-DSA-65 publieke sleutel van die teen-ondertekenaar (Party B).cosigner_signature: Handtekening oor dieselfdesig_inputas die outeur (§9.3).
Beide velde MOET saam teenwoordig wees of albei afwesig. As presies een teenwoordig is, MOET kykers 'n integriteitsfout rapporteer.
Verifikasie-prosedure:
1. If cosigner_pubkey absent and cosigner_signature absent → no cosigner. Done.
2. If exactly one is present → integrity error.
3. Verify cosigner_pubkey != author_pubkey (prevent self-cosigning).
Fail → display "cosigner pubkey must differ from author."
4. Reconstruct sig_input using the same formula as §9.3.
5. Verify(cosigner_pubkey, sig_input, cosigner_signature).
6. Success → display "co-signed by [cosigner fingerprint]."
7. Failure → display "co-signature verification failed."
Eienskappe:
- Die mede-ondertekenaar onderteken die identiese
sig_inputas die outeur — albei partye verbind tot dieselfdequb_id,body_hash, enunlock_at. qub_id-afleiding (§4.1) sluit NIE mede-ondertekenaar velde in nie. Om 'n mede-ondertekenaar by 'n bestaande koevert te voeg verander nie diequb_idnie.- 'n Verbond kan slegs outeur-onderteken wees (eensydige verbintenis), slegs mede-ondertekenaar (ongewoon), of beide (volle bilaterale bewys).
E-pos-bindings hek (operasioneel). Wanneer 'n verhoogde verbond 'n Party B e-pos-kontak dra (§6.1), MOET die qub-oplaaidiens die mede-ondertekening-versoek weier tensy 'n kort-leef e-pos-verifikasie merker bestaan wat ooreenstem met beide die verhoog-id en die genormaliseerde-e-pos hash van daardie kontak. Die merker word deur /api/v1/auth/verify geskryf wanneer die magiese-skakel teken 'n staging_id dra en die geverifieerde adres ooreenstem met SHA-256(normalise_email(party_b.contact)) — waar normalise_email(addr) die plaaslike-deel kas behoue hou en slegs die domein-deel na kleinletter omskakel (per RFC 5321 §2.3.11), en SHA-256 hier is die NIST FIPS 180-4 hash (onderskeie van die SHA3-256 wat in §4-afleidings gebruik word) — en verloop 900 sekondes (15 minute) ná uitgifte. Dit is 'n operasionele anti-personifikasie hek, NIE deel van die op-ketting qub-bewys nie — 'n derde-party verifieerder wat §11 herspeel benodig slegs permanente berging en drand, sonder enige bediener-kant opsoek. Die merker bestaan slegs bediener-kant en is nooit deel van die onderteken-liggaam nie.
Grootte-impak (ML-DSA-65 outeur + mede-ondertekenaar):
| Komponent | Grootte |
|---|---|
| Outeur-handtekening | 3 309 grepe |
| Outeur publieke sleutel | 1 952 grepe |
| Mede-ondertekenaar-handtekening | 3 309 grepe |
| Mede-ondertekenaar publieke sleutel | 1 952 grepe |
| Totale kripto-bo-koste | 10 522 grepe |
| Bergingskoste delta | ~$0.05 |
10. Markdown-lewering en saniteer
Hierdie afdeling is sekuriteit-krities. Die kyker lewer teks-qubs (content_type = 0x01) met 'n beperkte Markdown-subversameling.
10.1 Toegelate elemente
- Opskrifte:
#tot####(geen#####of######nie) - Beklemtoning: vet (
**), kursief (*), deurhaal (~~) - Lyste: geordend (
1.) en ongeordend (-,*) - Blok-aanhalings (
>) - Kode: inlyn-spanne (```) en omsluit-blokke (`````)
- Horisontale reëls (
---) - Lyn-breuke (twee sleep-spasies of leë lyn)
- Paragrawe
10.2 Verbode elemente
| Element | Hantering |
|---|---|
Rou HTML (<div>, <script>, ens.) |
Heeltemal verwyder. Geen HTML gaan deur. |
Beelde () |
Verwyder. Beeld-sintaks word uit uitset verwyder. |
Skakels ([text](url)) |
URL gelewer as sigbare plat teks. Nie outomaties geskakel nie. Nie klikbaar sonder eksplisiete gebruikersaksie nie. |
| Gevaarlike URL-skemas | javascript:, data:, vbscript:, file: — verwyder. |
| Iframes, ingebed, objekte | Verwyder. |
| HTML-entiteite | Gedekodeer na vertoon-karakters slegs as veilig. |
10.3 Implementasie
Implementasies MOET 'n streng toelaatlys-parser gebruik, nie 'n bloklys nie. Die aanbevole benadering:
- Ontleed Markdown met
pulldown-cmark(of ekwivalent). - Loop deur die AST en laat val enige nood wat nie in die toelaatlys is nie (§10.1).
- Vir skakel-nodes: stuur die URL as sigbare teks uit, nie as 'n klikbare
<a>-element nie. - Skakel die gefiltreerde AST om na 'n getipte tussen-verteenwoordiging (bv., 'n
MarkdownNode-enum met slegs veilige variante). Rou HTML is struktureel onverteenwoordigbaar in hierdie IR. - Lewer van die getipte IR na die teiken-aansig laag (bv., reaktiewe aansig-komponente, DOM-nodes). Geen HTML-string aaneenskakeling of
innerHTMLop enige punt nie.
Bloklys-benaderings is brokkelig omdat nuwe Markdown-uitbreidings of parser-eienaardighede ongefiltreerde elemente kan invoer. Die getipte-AST benadering maak XSS struktureel onmoontlik — daar is geen variant wat arbitrêre HTML kan dra nie.
10.4 Grootte- en struktuur-limiete
- Maksimum gelewerde opskrif-diepte:
####(H4).#####en dieper word as vet teks gelewer. - Geen limiet op paragraaf-tellings (liggaam-grootte limiete in §6 is die beperking).
- Omsluit-kode blokke: geen sintaks-beligting in MVP. Gelewer as monospace voorgeformatteerde teks.
11. Derde-party verifikasie
Enige derde party kan 'n publieke qub verifieer sonder qub-samewerking. Die verifikasie-prosedure:
1. Obtain arweave_tx_id (from delivery URL or direct knowledge).
2. Fetch SealedQubCbor from any storage gateway.
3. Confirm storage block inclusion (block height, block timestamp).
4. Parse SealedQubCbor → SealedQub.
5. Fetch drand round signature for SealedQub.drand_round.
6. tlock_decrypt(tlock_ciphertext, round_signature) → QubEnvelope CBOR bytes.
7. Parse → QubEnvelope.
8. Verify SHA3-256(body) == body_hash.
9. Verify QubEnvelope.qub_id == SealedQub.qub_id.
10. Verify QubEnvelope.unlock_at == SealedQub.unlock_at.
11. If sig_alg != 0x00: verify author_signature (see §9.4).
12. All checks pass → qub is verified.
Wat verifikasie bewys:
| Bewys | Wat dit vasstel |
|---|---|
| Verbintenis | Die ciphertext het bestaan teen die bergingsblok tydstempel. |
| Integriteit | Die plaintext-liggaam stem ooreen met die verbinde hash en is nie verander nie. |
| Tydsberekening | Die inhoud was onleesbaar tot die drand-rondte, wat ooreenstem met die gekose ontsluitings-tyd (onderhewig aan tlock- en drand-sekuriteits-aannames). |
Wat verifikasie NIE bewys nie:
| Nie-bewys | Hoekom |
|---|---|
| Outeurskap | Die sender_label is dekoratief. Sonder sig_alg ≥ 0x01 kon enigeen hierdie inhoud verseël het. |
| Intensie | Die qub bewys inhoud en tydsberekening, nie wat die skepper subjektief bedoel het nie. |
| Voor-gebeurtenis tydsberekening | Bergingsblok insluiting mag werklike oplaai met minute vertraag. Die verbintenis-tydstempel is die blok-tyd, nie die oomblik waarop die gebruiker "verseël" gedruk het nie. |
12. Weergawe-bestuur
12.1 Protokol-weergawe
Die version-veld (u8) in beide SealedQub en QubEnvelope identifiseer die hoof protokol-weergawe.
- Kykers MOET onbekende hoof-weergawes met 'n duidelike fout verwerp.
- Bekende hoof-weergawes MAG onbekende opsionele velde toelaat as voorwaartse versoenbaarheid-reëls dit toelaat (opsionele velde afwesig van die kanonieke sleutel-orde word geïgnoreer).
- Inhoudstipes (
content_type) en handtekening-skemas (sig_alg) is weergawe-gehek: nuwe waardes mag slegs saam met 'n nuwe protokol-weergawe of eksplisiete register-opdatering ingevoer word.
12.2 Weergawe-geskiedenis
| Weergawe | Waarde | Beskrywing |
|---|---|---|
| v1 | 0x01 |
Publieke teks-qubs (content_type 0x01), verbond bilaterale ooreenkomste (0x03, structured/v1-skema, ML-DSA-65 outeur + mede-ondertekenaar), tlock, SHA3-256 |
12.3 Voorwaartse versoenbaarheid
'n v1-kyker wat 'n QubEnvelope met onbekende opsionele CBOR-kaart sleutels teëkom (sleutels nie in die §3.2 kanonieke orde nie) BEHOORT daardie sleutels te ignoreer en voort te gaan met verifikasie met bekende velde. Dit laat toekomstige klein toevoegings toe (bv., nuwe metadata) sonder om 'n hoof-weergawe stamp te vereis.
'n v1-kyker wat sig_alg = 0x01 (ML-DSA-65) teëkom maar ML-DSA-65 verifikasie-ondersteuning kortkom BEHOORT die qub-inhoud met 'n "handtekening teenwoordig maar nie verifieerbaar nie" kennisgewing te vertoon, nie die qub geheel te verwerp nie. Die verwysing-implementasie verwerp vandag elke sig_alg-waarde anders as 0x00 en 0x01 omdat die v1-register geen ander geldige algoritme bevat nie — streng verwerping en sag-misluk is waarnemingsgewys identies tot 'n derde algoritme geregistreer word. Die sag-misluk gedrag hierbo word dra-belastend sodra §9.2 'n nuwe inskrywing toelaat, en die verwysing-kyker sal op daardie punt opgedateer word om sag te misluk.
12.4 Buitenste omhulling-weergawe
Die OuterWrapper wat in §13 beskryf word dra sy eie version-greep, onafhanklik van SealedQub.version en QubEnvelope.version. Die twee weergawe-ruimtes ontwikkel afsonderlik: 'n toekomstige post-kwantum-veilige simmetriese vervanging stamp die omhulling-greep sonder om die binne-protokol-weergawe aan te raak, en 'n toekomstige protokol-laag toevoeging (bv., 'n nuwe koevert-veld) stamp die binne-weergawe sonder om die omhulling-greep aan te raak.
OUTER_WRAPPER_VERSION_* |
Waarde | Algoritme | Status |
|---|---|---|---|
OUTER_WRAPPER_VERSION_1 |
0x01 |
AES-256-GCM met 12-greep nonce, 16-greep verifikasie-etiket, AAD gebind aan qub_id |
v1 verstek |
| — | 0x02–0xFF |
Gereserveer | Toekoms |
Kykers MOET onbekende omhulling-weergawes met 'n duidelike fout verwerp. Die protokol hou die omhulling-weergawe-ruimte opsetlik nou tot 'n konkrete migrasie-dryver verskyn (bv., NIST-leiding wat 'n ander AEAD bevoordeel); 'n 0x02-gleuf sal in dieselfde hersiening toegeken word wat die algoritme inlei.
13. Buitenste enkripsie-omhulling
13.1 Rasionaal
Die protokol-lae (QubEnvelope → tlock → SealedQub) maak 'n verseëlde qub tyd-geslote: die liggaam is onleesbaar totdat unlock_at en die drand-rondte handtekening gepubliseer is. Ná ontsluiting is die rondte-handtekening egter openbaar en die kanonieke CBOR-vorm van SealedQub is herkenbaar, sodat 'n oeser wat permanente-berging-transaksies geïndekseer het die hele qub-korpus grootmaat sou kon dekripteer.
Die buitenste enkripsie-omhulling sluit daardie kanaal deur 'n addisionele simmetriese AEAD-laag tussen die kanonieke SealedQubCbor en die grepe wat na permanente berging geskryf word te interponeer. Die 256-bis sleutel K leef slegs in die URL-fragment van die afleweringskakel en op gebruikers-toestelle; blaaiers stuur nie URL-fragmente na bedieners nie, dus is qub.social, elke bergingspoort, en elke CDN voor elkeen waarnemingsgewys blind vir K. Elke qub in permanente berging is dus 'n ondeurskynende ciphertext waarvan die plaintext nie herstelbaar is sonder die URL wat die skepper gekies het om te deel nie.
Netto effek:
- Enumerasie-immuniteit by verstek. Omhulde grepe in permanente berging is greep-ononderskeidbaar van arbitrêre ciphertext. 'n Oeser-strategie van "GraphQL-navraag vir qub-vormige oplaaie, grootmaat-dekripteer met publieke drand-handtekeninge" termineer nie met plaintext nie.
- Kripto-versnipper-privaatheid postuur. qub.social kan letterlik nie sy eie korpus dekripteer nie. Dagvaardings bereik ciphertext, nie plaintext nie.
- Twee-vlak vertroulikheid-leer. Verstek = skakel-beheerde toegang (hierdie afdeling). Ontvanger-geënkripteerde private qubs ('n gereserveerde Fase 2-kenmerk, nog nie gespesifiseer nie) laag bo-op as die tweede vlak.
13.2 Lae
plaintext body ← QubEnvelope.body (§2.2)
↓ canonical CBOR (§3)
envelope CBOR
↓ tlock encrypt to drand round (§7 step 10)
tlock_ciphertext (inside SealedQub) (§2.3)
↓ canonical CBOR (§3)
SealedQubCbor bytes ← inner wire artifact
↓ AES-256-GCM(K, nonce, AAD=qub_id) (§7 step 12a, this section)
OuterWrapper CBOR bytes ← uploaded to permanent storage (§7 step 15)
Verseël en ontsluit by die protokol-laag (§7, §8) is onveranderd onder die omhulling-grens; die omhulling heg aan by die oproep-plek van seal() en ontkoppel by die oproep-plek van unlock().
13.3 OuterWrapper-datastruktuur
struct OuterWrapper {
version: u8, // 0x01, see §12.4
qub_id: [u8; 32], // copied from inner SealedQub; AEAD AAD
nonce: [u8; 12], // 96-bit AEAD nonce
ciphertext: Vec<u8>, // AES-256-GCM(K, nonce, SealedQubCbor, AAD=qub_id) || 16-byte tag
}
Veld-invariante.
versionMOET gelyk wees aan0x01vir v1.0 omhulling-grepe.qub_idMOET gelyk wees aan diequb_id-veld van die SealedQub wat ná uitpak herstel word. Die uitpak-stap dwing dit nie direk af nie (die AEAD AAD-binding maak greep-vlak peuter onmoontlik), maar die ontsluit-laag toets die verhouding transitief: as 'n skepper 'nSealedQubCboromhul waarvan die binnequb_idnie ooreenstem met die omhulling sequb_idnie, misluk §8 stap 11.nonceMOET 96 bisse (12 grepe) wees, vars gegenereer deur 'n CSPRNG vir elke omhulling-bewerking. Die hergebruik van 'n nonce onder dieselfde sleutel laat AEAD nonce-hergebruik aanvalle toe wat die plaintext herwin; produsente MOET (key,nonce)-pare as een-skoot behandel.ciphertextis die AES-256-GCM uitset: ciphertext-grepe aaneengeskakel met die 16-greep verifikasie-etiket.ciphertext.len() == SealedQubCbor.len() + 16presies.
CBOR-enkodering. Kanonieke CBOR per §3, met dieselfde sleutel-orde reël (gesorteer volgens gekodeerde greep-lengte stygend, dan leksikografies). Die vier sleutels is:
| Sleutel | Gekodeerde grepe | Orde |
|---|---|---|
nonce |
6 | 1 |
qub_id |
7 | 2 |
version |
8 | 3 |
ciphertext |
11 | 4 |
Die eerste greep van die OuterWrapper CBOR is dus die definitiewe-lengte kaart-kop vir 'n 4-inskrywing kaart (0xA4).
13.4 AAD-binding aan qub_id
Die omhulling bind qub_id as AEAD bykomende geverifieerde data. Dit is die dra-belastende strukturele verdediging teen drie klasse aanvalle:
| Aanval | Verdediging |
|---|---|
Skuif ciphertext onder 'n verskillende qub_id-veld in die omhulling |
AAD-wanverhouding → AEAD-verifikasie misluk |
| Meng die URL-fragment van qub A met die permanente-berging-grepe van qub B | AAD-wanverhouding → AEAD-verifikasie misluk |
Peuter met die qub_id-veld van die omhulling ná oplaai |
AAD-wanverhouding → AEAD-verifikasie misluk |
Om qub_id in die omhulling-plaintext te dra verswak nie enumerasie-immuniteit op betekenisvolle wyse nie — qub_id is self 'n SHA3-256 hash van die §4.1 preimage met geen herwinbare preimage van die spysvertering nie, en 'n enumereerder wat reeds die omhulling-grepe geoes het leer niks van die sigbare qub_id wat hulle nie reeds van die bestaan van die oplaai self kon aflei nie.
13.5 Omhulling- en uitpak-algoritmes
wrap_sealed_qub(SealedQubCbor S, qub_id Q, key K, nonce N):
require K.len() == 32 and N.len() == 12 and Q.len() == 32
C := AES_256_GCM_encrypt(key=K, nonce=N, msg=S, aad=Q)
// C includes the 16-byte authentication tag at the end
return canonical_cbor_encode(OuterWrapper{
version: 0x01,
qub_id: Q,
nonce: N,
ciphertext: C,
})
unwrap_sealed_qub(OuterWrapper bytes W, key K):
require K.len() == 32
O := canonical_cbor_decode(W) as OuterWrapper
require O.version == 0x01 // §12.4
P := AES_256_GCM_decrypt(
key=K, nonce=O.nonce, ciphertext=O.ciphertext, aad=O.qub_id
)
// any AEAD failure → DECRYPT_FAILED, indistinguishable to caller
return P // P is the inner SealedQubCbor
Mislukking-modus inval. Verkeerde K, verkeerde nonce, AAD-wanverhouding, en gepeuterde ciphertext lewer almal dieselfde DECRYPT_FAILED fout. Dit is 'n opsetlike AEAD-eienskap: om die mislukking-modus te onderskei sou 'n sykanaal skep wat 'n afstand-aanvaller kon ondersoek deur misvormde omhullings te stuur en die antwoord te tydsbereken. Verwysing-implementasies MOET alle AEAD-mislukkings tot 'n enkele fout-vorm laat inval.
13.6 Sleutelmateriaal en verspreiding
Die omhullingssleutel K is 'n 256-bis eenvormige willekeurige waarde wat per-qub deur 'n CSPRNG gegenereer word. Die verwysing-implementasies bron dit uit:
- WASM skepper:
getrandom(WebCrypto onder diewasm_jsagterkant). - Worker-kant verseël-roete:
crypto.getRandomValues.
Verspreiding: K MOET URL-veilig base64 (RFC 4648 §5, geen vulling) gekodeer word en aan die afleweringskakel as die fragment-komponent aangeheg word:
delivery_url = <origin>/c/<arweave_tx_id>#<base64url(K)>
Die fragment word nooit deur 'n konformerende blaaier na enige bediener gestuur nie. Herwinning-kanale (bediener-kant geskiedenis-indeks, kies-in e-pos outo-stuur) wat die volle afleweringskakel — insluitend die fragment — buite die gebruiker se toestel volhou is 'n eksplisiete handelsverkeer teen die verstek kripto-versnipper postuur en MOET op eksplisiete gebruiker-toestemming gehek wees.
Fragment-verlies. As 'n gebruiker die URL-fragment verloor en geen herwinning-kanaal het nie, is die qub onleesbaar. Dit is die dra-belastende handelsverkeer van die ontwerp en MOET aan die gebruiker by seël-tyd geopenbaar word. Die MVP versterk die seël-tyd openbaring met eksplisiete "stoor hierdie URL" kopie en 'n geverifieerde-e-pos herwinning-kanaal vir gebruikers wat kies om in te skryf.
13.7 Buite omvang vir hierdie afdeling
- Outeurskap-ondertekening (§9) is onveranderd: handtekeninge word binne die binnenste
QubEnvelopebereken en word herwin ná uitpak → tlock-dekripteer → CBOR-ontleed. - Ontvanger-geënkripteerde private qubs ('n gereserveerde Fase 2-kenmerk, nog nie gespesifiseer nie) komponeer bo-op hierdie omhulling as 'n tweede vertroulikheid-vlak; albei vlakke kan gelyktydig aktief wees.
- Verbonde (§6, content_type
0x03) word presies soos teks-qubs omhul; die omhulling is greep-blind vir binne inhoudstipe.
13.8 Openbare qubs (omhulling-weglating)
Die buitenste omhulling is opsioneel by die aflewering-laag. 'n Skepper kan 'n qub as openbaar verseël, in welke geval die kanonieke SealedQubCbor direk na permanente berging geskryf word, sonder 'n OuterWrapper-laag en sonder sleutel K:
SealedQubCbor bytes ──(public)──▶ uploaded to permanent storage as-is
SealedQubCbor bytes ──(private)─▶ AES-256-GCM(K, …) ▶ OuterWrapper ▶ uploaded
'n Openbare qub is tyd-geslote maar nie skakel-gehek nie: dit bly onleesbaar totdat sy drand-rondte publiseer (die tlock-laag is onveranderd), maar ná ontsluiting kan enigeen wat die arweave_tx_id het dit dekripteer — geen URL-fragment word vereis nie, omdat daar geen K is nie. Dit is die opsetlike handelsverkeer vir oppervlakke wat die bediener moet dryf: onthul-kennisgewing-e-posse, derdeparty-inbeddings, en ryker ná-onthul SEO benodig almal 'n skakel wat werk sonder 'n geheim wat die bediener nooit hou nie (§13.6).
Gevolge waarvoor 'n produsent rekening MOET hou:
- Geen enumerasie-immuniteit nie. Openbare qubs sien per konstruksie van die §13.1 enumerasie-immuniteit-eienskap af. Die verwysing-oplaai-diens stempel 'n
Visibility: publicpermanente-berging-etiket op hulle (en slegs hulle) sodat hulle opsetlik vindbaar is; private qubs dra geen sodanige etiket nie en behou hul greep-ononderskeidbaarheid. - Plaintext-titel by seël-tyd blootgestel. Die §3.2
title-veld is plaintext binneSealedQubCbor. Onder die omhulling is dit versteek totdat 'n kykerKverskaf; sonder die omhulling is dit wêreld-leesbaar op permanente berging vanaf die oomblik van oplaai, voor ontsluiting. Konformerende skepper-toepassings MOET dit by seël-tyd openbaar. - Opsporing is struktureel. 'n Konformerende kyker/inbedding onderskei die twee vorms deur ontleding: grepe wat as
OuterWrapperontleed neem die uitpak-met-K-pad; grepe wat as 'n kaalSealedQubCborontleed word direk aanvaar. Geen draad-vlag word vereis nie, enqub_idbind nie sigbaarheid nie — dieselfde inhoud is greep-identies by dieSealedQub-laag of dit openbaar of privaat verseël is.
Privaat (omhul) bly die verstek; openbaar is 'n eksplisiete per-qub skepper-keuse.
14. Toets-vektore
14.1 qub_id-afleiding
Input:
version = 0x01
content_type = 0x01
created_at = 1735689600 (2025-01-01 00:00:00 UTC)
unlock_at = 1736294400 (2025-01-08 00:00:00 UTC)
outcome_at = absent
drand_round = 4695445 (= (1736294400 - 1595431050) / 30, drand mainnet params §14.2)
body = "Hello, future." (UTF-8, 14 bytes)
title = absent
Intermediate:
body_hash = SHA3-256("Hello, future.")
= 76ab8b3f843c6ed4f2d0fd75b9f457b4
ad49dd4450f9c22723ae430e3af3211d
title_hash = [0u8; 32] (title absent — §4.2.1 sentinel)
Domain separator (10 bytes):
[0x51, 0x55, 0x42, 0x5F, 0x49, 0x44, 0x5F, 0x56, 0x32, 0x00]
Preimage (108 bytes — V1.2):
domain_separator || // 10 bytes
0x01 || // version
0x01 || // content_type
0x0000000067748580 || // created_at as i64 big-endian (1735689600)
0x00000000677DC000 || // unlock_at as i64 big-endian (1736294400)
0x0000000000000000 || // outcome_at_or_zero (outcome_at absent)
0x000000000047A595 || // drand_round as u64 big-endian (4695445)
body_hash || // 32 bytes
title_hash // 32 bytes (all-zeros sentinel; title absent)
Expected output:
qub_id = SHA3-256(preimage)
= 3a9fcb31b750d985c262fada6d4f777f
d6a28be831d941d85c131f5a4bbaf8a4
Implementasies MOET identiese body_hash- en qub_id-waardes vir hierdie inset lewer. Hierdie toets-vektor BEHOORT die eerste eenheidstoets te wees wat geskryf word. Die kanonieke waardes hierbo is deur die verwysing-implementasie bereken en MOET bit-vir-bit ooreenstem. Historiese preimage-uitlegte (voor-bekendstelling — geen lewende qubs het op hierdie waardes gesteun nie): die 92-greep V1.0 qub_id was 3d9fc2390eab043d38a1669ed3b71be76f9eefe872b9569ab1aaa027b88392b0; die 100-greep V1.1 qub_id (ná die invou van outcome_at_or_zero) was b0d032898ad629795150fdcb3f84e518f59ed05b7a2a82bc24ebdb87f52144ed. V1.2 vou drand_round in en gradeer die domeinskeier op na QUB_ID_V2.
14.2 Ontsluitings-rondte kartering
Input:
unlock_at = 1735689600
chain_genesis_time = 1595431050
chain_period_seconds = 30
Calculation:
(1735689600 - 1595431050) / 30 = 4675285.0
ceil(4675285.0) = 4675285
drand_round = 4675285
14.3 Kanonieke CBOR rondreis
Implementasies MOET verifieer dat serialize(parse(serialize(qub))) == serialize(qub) vir alle geldige insette. Dit is 'n eienskap-toets, nie 'n enkele vektor nie.
14.4 PactTerms CBOR (content_type 0x03)
Input:
pact_version = 1
title = "Scooter deposit"
terms = [
{ key: "Item", value: "Honda Metropolitan scooter" },
{ key: "Price", value: "$100" },
{ key: "Deposit", value: "$10" }
]
party_a = { label: "Alice" }
party_b = { label: "Bob", contact: "bob@example.com" }
notes = absent
Canonical CBOR key order (PactTerms):
"notes"(6) < "terms"(6) < "title"(6) < "party_a"(8) < "party_b"(8) < "pact_version"(13)
Canonical CBOR key order (PactTerm):
"key"(4) < "value"(6)
Canonical CBOR key order (PartyIdentifier):
"label"(6) < "contact"(8)
Die kanonieke CBOR-grepe en SHA3-256 body_hash word deur die verwysing-implementasie bereken. Implementasies MOET greep-identiese CBOR vir hierdie inset lewer.
Implementasies MOET ook verifieer dat serialize(parse(serialize(pact))) == serialize(pact) vir alle geldige PactTerms-insette (eienskap-toets).
14.5 Buitenste omhulling kruis-taal vektore
Die buitenste omhulling (§13) het 'n aparte kanonieke vasstelling by crates/qub-core/tests/vectors/wrapper_v1.json. Elke geval pen 'n (key, nonce, qub_id, sealed_cbor)-tupel vas as ondeurskynende hex-insette en beweer 'n spesifieke expected_wrapper_hex-uitset. Albei verwysing-implementasies verbruik dieselfde JSON-lêer:
- Rust:
crates/qub-core/tests/wrapper_vectors.rs(cargo test -p qub-core --test wrapper_vectors). - TypeScript:
workers/api/src/crypto/__tests__/wrapper.test.ts(npm test).
Die vasstelling pen tans drie gevalle vas:
| Geval | Dekking |
|---|---|
basic-text-public |
Kleinste realistiese SealedQub-vorm; geen opsionele velde nie. Vestig die kanonieke omhulling-vorm vir 'n v1.0-tipiese qub. |
with-recipient-pubkey |
SealedQub met recipient_pubkey gestel (Fase 2-pad). Verskillende binne CBOR-sleutel stel, verskillende qub_id. |
longer-body |
~4 KiB liggaam — oefen multi-greep CBOR lengte-voorvoegsels binne beide die binne-koevert en die buitenste ciphertext. |
Implementasies MOET greep-identiese expected_wrapper_hex vir die opgeneemde insette lewer. Om die vasstelling te herskep vereis QUB_REGEN_VECTORS=1 cargo test -p qub-core --test wrapper_vectors en is gereserveer vir opsetlike formaat-veranderings.
15. Kripto-profiel-bestuur (toekoms)
Hierdie afdeling is informatief vir v1 en word normatief die eerste keer dat 'n tweede algoritme enige van qub se kriptografiese primitiewe binnegaan.
15.1 Huidige postuur
Protokol v1 bind presies een algoritme per primitief:
- Handtekening: ML-DSA-65 (
sig_alg = 0x01; 1952-greep publieke sleutel, 3309-greep handtekening) en ongeteken (sig_alg = 0x00). Die §9.2-register definieer geen ander waardes nie; 'n v1-verifieerder MOET elkesig_algbuite{0x00, 0x01}verwerp. 'n Toekomstige Ed25519-inskrywing word verwag (§15.3) maar is nie in v1 toegeken nie. - Tydslot: drand quicknet alleen — die ketting-hash, publieke sleutel, genese-tyd en periode is vaste netwerk-parameters wat deur die verwysing
DrandTimelockProvider::quicknet()(crates/qub-core/src/tlock.rs) enconfig/drand-endpoints.jsongedra word. - Buitenste omhulling: AES-256-GCM v1 alleen (§13).
Verifieerders hard-kodeer tans sleutel- en handtekening-lengtes per primitief. Geen ratheid-oppervlak word deur die draadformaat blootgestel nie.
15.2 Beoogde vorm
Wanneer 'n tweede algoritme die protokol binnegaan, sal die verifieerder gekonfigureer word vir 'n benoemde CryptoProfile (bv., ExqubV1) wat die presiese stel toegelate waardes per primitief lys — sig_algs, drand-kettings, omhulling-weergawes, inhoudstipes. Die profiel is by verifikasie-tyd vasgestel, nooit in-baand onderhandel nie. Enige waarde buite die aktiewe profiel word verwerp.
Dit waarborg dat die toevoeging van ML-DSA-87 of die aktivering van Ed25519 nie retrospektief bestaande verifieerder-konfigurasies kan verswak nie: 'n v1-verifieerder bly 'n v1-verifieerder selfs nadat 'n v2-profiel gepubliseer is.
15.3 Snellervoorwaardes
Bevorder §15 na normatiewe status wanneer enige van die volgende voorgestel word:
- 'n Tweede
sig_alg-greep (Ed25519-aktivering, ML-DSA-87, of enige nuwe inskrywing in die §9-register). - 'n Tweede drand-ketting in produksiegebruik.
- 'n Tweede buitenste-omhulling weergawe.
Tot dan is §15 'n plekhouer wat die migrasie-vorm vasstel sodat toekomstige PR's teen 'n bekende teiken land eerder as om die onderhandelings-oppervlak van vooraf te herbedink.