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.
Onbekende sleutels Verwerp met fout. Parsers MOET NIE kaart-sleutels buite die tipe se kanonieke sleutel-stel duld nie — twee onderskeie kanonieke greep-stringe moet nooit na dieselfde waarde dekodeer nie (encode(decode(x)) == x), en vir ondertekende data-vragte sou 'n ekstra sleutel versteekte inhoud wees waartoe beide handtekeninge verbind. Skema-ontwikkeling gaan deur version, nooit deur ekstra sleutels 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:

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:

  1. Slegs HTTPS. Die string MOET met die greep-volgorde https:// begin. Enige ander skema — http, ftp, javascript, data, file, ens. — word verwerp.
  2. Lengte-plafon. ≤ 2,048 grepe (praktiese URL-grens van blaaier).
  3. NFC + vyandige-kodepunt-toets. Dieselfde reël as title en reflection — bidi-oorheers- / nul-wydte- / merker-blok- / BOM- / C0- / C1-kodepunte word verwerp. Definisie stem ooreen met die Rust crate::handle::contains_hostile_text_codepoint en die TS workers/api/src/utils/unicode.ts::isHostileCodepoint (hou in pas).
  4. Geen wit-spasie, geen ASCII-beheerkarakters nie. Wit-spasie / DEL / sub-0x20 grepe enige plek in die URL word verwerp — sluit die \n/\t-inspuiting-vektor af wat die bidi-reël nie dek nie.
  5. 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

Twee preimage-weergawes het bestaan. Alle handtekeninge MOET V2 gebruik, en verifieerders MOET slegs V2 aanvaar. Die verouderde V1-preimage (hieronder gedokumenteer vir historiese verwysing) is as 'n slegs-verifikasie terugval tydens die V2-migrasie aanvaar; daardie terugval is uit diens gestel en 'n slegs-V1-handtekening word nou verwerp.

V2 (huidig — geproduseer deur alle nuwe outeur-ondertekening, en deur albei handtekeninge van die verbond se verhoog- / mede-ondertekenvloei):

sig_input = SHA3-256(
    "QUB_AUTHOR_SIG_V2"  ||    // 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.x
    sender_label_hash    ||    // [u8; 32]: SHA3-256(NFC(sender_label)),
                               //   or 32 zero bytes when absent
    reply_to_or_zero           // [u8; 32]: parent qub_id, or 32 zero
                               //   bytes when absent
)

// Total preimage: 155 bytes → 32-byte hash

signature = Sign(author_secret_key, sig_input)

sender_label_hash volg dieselfde afwesig-sentinel-konvensie as title_hash (§4.2.1): 32 nul-grepe is nie 'n geldige SHA3-256-uitset nie, dus kan "afwesig" nooit met 'n teenwoordige etiket bots nie. Alle velde is vaste-breedte, dus is die preimage ondubbelsinnig sonder lengte-voorvoegsels.

V1 (verouderd — UIT DIENS GESTEL; nie meer geproduseer nie en nie meer aanvaar op verifikasie nie):

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

Die V1-preimage het sender_label en reply_to weggelaat. Dit is as 'n slegs-verifikasie terugval tydens die migrasie na V2 aanvaar; daardie terugval is sedertdien uit diens gestel — verifieerders MOET slegs die V2-preimage aanvaar. Die definisie word hier behou vir historiese verwysing en om die domein-skeier hieronder te verduidelik. 'n Handtekening wat slegs teen V1 verifieer MOET as 'n verifikasie-mislukking hanteer word.

Domein-skeiers: "QUB_AUTHOR_SIG_V1" / "QUB_AUTHOR_SIG_V2" is elk 17 ASCII-grepe ([0x51, 0x55, 0x42, 0x5F, 0x41, 0x55, 0x54, 0x48, 0x4F, 0x52, 0x5F, 0x53, 0x49, 0x47, 0x5F, 0x56, 0x31/0x32]). Geen vulling. Die verskillende skeier skei die twee konstruksies domein-gewys, dus kan 'n handtekening oor die een preimage nooit as die ander verifieer nie.

org_id_present-greep: die greep ná unlock_at 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. Die V2-sig_input verbind direk tot version, qub_id, body_hash, unlock_at, sender_label, en reply_to (plus die vaste domein-skeier en org_id_present-greep). 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 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
sender_label Direkte inset via sender_label_hash (V2-preimage — die enigste aanvaarde vorm)
reply_to Direkte inset via reply_to_or_zero (V2-preimage — die enigste aanvaarde vorm)
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
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.)

Waarom V2 die enigste aanvaarde preimage is.

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 (V2 formula, §9.3).
6. Verify(author_pubkey, sig_input, author_signature). The V2 preimage is the
   only accepted form — the legacy V1 fallback is retired (§9.3), so a
   signature that does not verify against V2 fails, full stop.
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:

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 (V2 only — the
   legacy V1 fallback is retired; all pact clients produce V2 signatures).
5. Verify(cosigner_pubkey, sig_input, cosigner_signature).
6. Success → display "co-signed by [cosigner fingerprint]."
7. Failure → display "co-signature verification failed."

Eienskappe:

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

10.2 Verbode elemente

Element Hantering
Rou HTML (<div>, <script>, ens.) Heeltemal verwyder. Geen HTML gaan deur.
Beelde (![alt](url)) 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:

  1. Ontleed Markdown met pulldown-cmark (of ekwivalent).
  2. Loop deur die AST en laat val enige nood wat nie in die toelaatlys is nie (§10.1).
  3. Vir skakel-nodes: stuur die URL as sigbare teks uit, nie as 'n klikbare <a>-element nie.
  4. 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.
  5. Lewer van die getipte IR na die teiken-aansig laag (bv., reaktiewe aansig-komponente, DOM-nodes). Geen HTML-string aaneenskakeling of innerHTML op 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


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_alg0x01 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.

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 CBOR-kaart-sleutels teëkom (sleutels nie in die §3.2 kanonieke orde nie) MOET dit met 'n dekodeer-fout verwerp (§3.1). Voorwaartse versoenbaarheid berus op die version-veld, nie op sleutel-toleransie nie: toekomstige toevoegings — selfs geringe metadata — verskyn onder 'n nuwe version-waarde, wat 'n v1-kyker met 'n duidelike "nuwer protokol"-fout verwerp eerder as om inhoud waartoe die handtekeninge verbind stilweg te laat val.

'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
0x020xFF 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:

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.

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:

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

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:

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:

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:

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:

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.


16. Deursigtigheid-log en Duursaamheid-vlakke (Ontwerp — hersiening voltooi)

Status. Hierdie afdeling is 'n ontwerp-spesifikasie. Die draadformate, hashing, en vertrouensmodel hieronder is normatief vir die implementasie, maar geen deursigtigheid-log-kode is nog gestuur nie. Die W5 eksterne hersiening is voltooi: §16.15 teken die opgeloste besluite aan en die bindende bekendstellingsbeperkings wat daaruit gekom het. Implementasie mag onder daardie beperkings voortgaan. §16 bly vooruitskouend in dieselfde sin as §15 — dit pen die teiken vas sodat die implementasie teen 'n bedaagde ontwerp land eerder as om die vertrouensmodel in kode-hersiening te herlei. Dit is streng addisioneel — elke bestaande qub behou sy individuele Arweave-transaksie en daar is geen verandering aan die SealedQub / QubEnvelope draadformaat nie.

16.1 Rasionaal en Duursaamheid-vlakke

Vandag rus 'n qub se duursaamheid en sy temporale verbintenis albei op 'n enkele per-qub Arweave-transaksie (§11). Dit koppel seël-latensie aan Arweave-finaliteit, maak die per-qub oplaai 'n produk-kostelimiet (ARWEAVE_DAILY_CEILING), en gee geen peuter-bewysbare ordening oor qubs heen nie. Die deursigtigheid-log voeg twee lae onder en om daardie enkele vlak by:

Vlak Naam Waarborg Wanneer
T1 R2-eerste sinchroniese erkenning Duursaamheid-vloer — verseëlde grepe word na duursame berging geskryf voordat die seël terugkeer (< 300 ms p95). Elke qub, sinchronies (§16.10).
T2 Gebondelde deursigtigheid-log-insluiting Universele slegs-aanvoeg, peuter-bewysbare verbintenis + totale ordening, geanker aan Arweave. Elke qub, uitgestel + gebondel (§16.5–16.7).
T3 Per-qub Arweave-permanensie 'n Individuele Arweave-transaksie vir die qub. Betaalde opverkoop, en die Arweave-onbeskikbaarheid-terugval (§16.8).

T2 maak per-qub Arweave 'n keuse (T3) eerder as die enigste duursaamheid-pad. ARWEAVE_DAILY_CEILING word as 'n produk-limiet afgetree en gedegradeer tot 'n stroombreker op slegs die toegewyde anker-beursie (§16.7); gebruiker-seëls word nooit verwerp omdat hulle dit oorskry nie.

Duursaamheid-eerlikheid (opgelos — §16.15 Q6). Duursaamheid agteruit nie: die T1 R2-skryf is sinchronies en skryf-eenmaal, dus is 'n gratis-vlak qub wat nie T3 gekoop het nie ten volle duursaam die oomblik wat die seël terugkeer. Wat verruwe, is die bewysbare bo-grens verbintenis-tyd: vir 'n gratis qub word dit die anker-bloktyd eerder as 'n per-qub transaksie-bloktyd. By lae volume — die realistiese vroeë-bekendstelling- en buite-spitstoestand — is die volle daaglikse kadens die tipiese vloer, nie 'n seldsame randgeval nie. Die produk-raming is daarom 'n bo-grens met geen toegesegde numeriese latensie — "verseël en duursaam nou; 'n onafhanklike openbare tydstempel word by die volgende log-anker bygevoeg (tipies daagliks)" — en presiese-uur verbintenis-bewys is 'n betaalde T3-eienskap, openbaar by die vlak-vergelyking-oppervlak en in die voorwaardes (§16.11, §16.15 Q6). Enige tydsgrens is slegs 'n interne SLO, nooit 'n bemarkte SLA nie.

16.2 LogLeaf-struktuur (twee verbinde vorms)

'n Log-inskrywing is 'n LogLeaf, gekodeer as handgeskrewe kanonieke CBOR onder die §3.1-profiel (definitiewe-lengte, geen etikette, geen swewende punte, kortste-vorm heelgetalle, NFC-teks, opsionele velde weggelaat wanneer afwesig, sleutels georden volgens gekodeerde-greep-lengte stygend dan greepsgewys). Die §3.1 parse → herkodeer → vergelyk kanonieke wag word op die kodeerpad voor hashing toegepas (nie net op dekodering nie), sodat twee implementasies nie oor die blaar-grepe kan verskil deur 'n heelgetalwydte- of sleutel-orde-verskil nie. Alle heelgetalle is u8 / u64 / i64; alle spysverterings is 32-greep greepstringe (bstr[32]). 'n Gebergde Arweave-transaksie-id is 'n rou 32-greep SHA-256-spysvertering gedra as bstr[32], nooit 'n base64url-teksstring nie (stem ooreen met §3.3).

Die blaar het twee vorms gekies deur 'n kind-greep, omdat die Worker op die verstek-oplaaipad greep-blind is: POST /api/v1/upload ontvang slegs qub_id en unlock_at as onvertroude kliënt-beweringsbody_hash, drand_round, created_at, en drand_chain_version is almal binne die §13 buitenste omhulling verseël, waarvan die Worker nooit die sleutel hou nie. Slegs die bediener-seël-pad (POST /api/v1/seal) lei body_hash / drand_round uit plaintext af. 'n Enkele blaar-vorm wat body_hash + drand_round dra sou daarom waardes verbind wat die operateur nooit vir die meerderheid van werklike qubs geverifieer het nie. Die verdeling hou elke verbinde waarde eerlik:

Sleutel Enk. len Tipe Teenwoordigheid Betekenis
seq 4 u64 vereis Globale 0-gebaseerde blaar-indeks; die posisie waartoe die insluitingsbewys verbind.
kind 5 u8 vereis 0x01 geattesteer (bediener-seël) of 0x02 beweer (kliënt-seël / greep-blind oplaai).
ref 4 bstr[32] vereis Blaar-verwysing-id. Geattesteer → rou qub_id. Beweer → die verblinde id SHA3-256(qub_id ‖ log_blind_secret) (§16.2.1).
chash 6 bstr[32] vereis Inhoud-adres SHA3-256(stored_bytes) — die een inhoud-band wat die Worker altyd eerlik kan bereken, op albei paaie.
unlock_at 10 i64 vereis Gekopieer (geattesteer) of beweer (beweer); gevalideer > 0 voordat dit die blaar betree.
received_at 12 i64 vereis Worker muurklok by R2-erkenning. Nie-bewysmateriaal (operateur-beweer; §16.6). Teenwoordig vir self-beskrywing, nooit 'n bewys nie. Gevalideer > 0.
body_hash 10 bstr[32] slegs kind=0x01 Weggelaat op 0x02 — die Worker kort dit onder §13.
drand_round 12 u64 slegs kind=0x01 Weggelaat op 0x02.

'n kind=0x02-blaar verbind doelbewus nóg body_hash nóg drand_round: dit attesteer die verbintenis en ordening van 'n ondeurskynende ciphertext by inhoud-adres chash, wat qub_id en unlock_at eis — nie sy plaintext of rondte nie. Die plaintext-/rondte-bene vir 'n beweerde qub kom van die bestaande §11 .qub-bundel-verifikasie, nie van die log nie (§16.11). drand_chain_version is nie in die blaar nie (dit is binne die omhulling op die verstekpad); ketting-granulariteit leef op die anker (§16.7). Kodeerder-dissipline: verwerp 'n geheel-nul ref of chash, en verwerp nie-positiewe unlock_at / received_at, in spieël met die outcome_at > 0 sentinel-wag in cbor.rs.

16.2.1 Private-qub verblinding

Die log moet nie die enumerasie-orakel word wat die §13 buitenste omhulling bestaan om te voorkom nie (§13.1). Vir 'n private (omhulde) qub verbind die asserted-blaar die verblinde identifiseerder SHA3-256(qub_id ‖ log_blind_secret), waar log_blind_secret 'n bediener-gehoue geheim is, en laat body_hash weg. 'n Derde party kan nie so 'n blaar aan 'n spesifieke qub_id koppel nie; die qub se houer, wat die afleweringskakel en daarom qub_id het, kan die verblinding herbereken om hul eie insluiting te bevestig. 'n Openbare qub (reeds enumereerbaar, dra reeds die Visibility: public Arweave-etiket per §13.8) verbind die rou qub_id. Dit is die een plek waar selfstandige verifieerbaarheid doelbewus toegee aan 'n dra-belastende privaatheid-invariant; die selfstandige band vir private qubs is chash (§16.9).

log_blind_secret-bewaring (opgelos — §16.15 Q4). Die verblinding beskerm blaar-ontkoppelbaarheid, nie plaintext-vertroulikheid nie (die §13 omhulling hou dit onafhanklik). By 'n log_blind_secret-kompromittering herbereken die teenstander, vir enige qub_id wat dit reeds hou of kan rekonstrueer (elke qub waarvan dit die bundel/URL het, plus enige lae-entropie of publieke qub_id), die blaar ref in een hash en koppel dit — dit is direkte koppeling van 'n bekende bevolking, nie 'n brute-krag oor 'n onbekende ruimte nie. Klassifiseer log_blind_secret as 'n korrelasie/Sybil-graad geheim in dieselfde bewaring-vlak as ander bediener-geheime, en roteer slegs vorentoe ('n rotasie herverblind toekomstige blare; dit kan nie reeds-geankerde blare retrospektief ontkoppel nie).

16.3 Blaar- en Knoop-hashing

RFC 6962 §2.1 domein-geskeide hashing met SHA-256 vervang deur SHA3-256:

leaf_hash      = SHA3-256(0x00 || canonical_cbor(LogLeaf))
node_hash(l,r) = SHA3-256(0x01 || l || r)
empty tree     = SHA3-256("")          // defined but never anchored

Domein-voorvoegsel grepe 0x02 (inskrywingsketting, §16.4) en 0x03 (STH-hash, §16.6) is gereserveer en disjunk van hierdie. Hulle is enkele grepe en kan dus nie met die bestaande 10-greep ASCII-domeinskeiers (QUB_ID_V2, ens.) bots nie. Die boom is die RFC 6962 links-vol ongebalanseerde boom (elke binne-splitsing by die grootste mag van twee streng minder as die subboom se blaar-telling), wat insluitings- en konsekwentheidsbewyse 'n enkele oudit-pad-algoritme laat deel. Die verwysing-spesifikasie dra eksplisiete links/regs-afleiding-pseudokode en pen 'n nie-mag-van-twee (5-blaar) toets-vektor vas sodat die regterrand-bevordering-geval — wat 'n 4-blaar-vektor verberg — uitgeoefen word.

16.4 Hash-kettings (intern)

Die LogDO onderhou 'n interne inskrywingsketting slegs vir ineenstortings-konsekwentheid. Dit word nooit gepubliseer en nooit verifieerder-gerig nie:

entry_chain[seq] = SHA3-256(0x02 || entry_chain[seq-1] || leaf_hash[seq])
entry_chain[-1]  = SHA3-256("QUB_TLOG_GENESIS_V1")

Die gepubliseerde slegs-aanvoeg-gesag is die kumulatiewe Merkle-wortel + sy anker (§16.5–16.6), nooit die rou orde waarin die operateur toevallig blare bedien nie: die ketting herbereken vir enige orde wat bedien word, dus pen slegs die geankerde wortel die kanonieke posisie vas.

16.5 Kumulatiewe Merkle-boom en Bondeling

Daar is een ewig-groeiende RFC 6962-boom oor alle blare in seq-orde — nie geïsoleerde per-bondel-bome nie. ('n Dra-blaar-gekettingde per-bondel-konstruksie is verwerp: dit is nie 'n ware voorvoegsel-verhouding nie, dus is sy "konsekwentheidsbewyse" onklank.) Die kumulatiewe boom gee egte RFC 9162 konsekwentheidsbewyse en laat 'n enkele onlangse anker insluiting bewys vir enige ouer qub.

Die LogDO Durable Object is die enkele skrywer (blockConcurrencyWhile, in spieël met QuotaDO / EntitlementDO) — aanvoeging by 'n gedeelde log is lees-wysig-skryf op gedeelde toestand en MOET dus deur 'n DO gaan, nooit KV nie. Dit kas die boom se regterrand-grens (O(log n) hashes) sodat die sluiting van 'n bondel O(batch) is. 'n Bondel is die stel blare wat saam geanker word; sy snellers is konfigureerbaar, nie protokol-bevries nie: 'n tree_size-vooruitgang van ten minste LOG_BATCH_MAX_LEAVES (verstek 4096), of ouderdom wat die anker-kadens bereik, of 'n geforseerde spoeling wanneer 'n betaalde T3-seël land. root_i is die kumulatiewe Merkle-boom-hash oor blare 0 .. tree_size_i.

16.6 Ondertekende Boomkop via Arweave-anker

Die Arweave-anker-transaksie is die Ondertekende Boomkop en vervang 'n operateur-handtekening vir die boomkop self: die daaglikse anker benodig geen qub-sleutel nie omdat die Arweave-tx owner die handtekening is. Die slot-tese hou — die onveranderlike substraat, nie 'n qub-gehoue geheim nie, is dra-belastend vir die geankerde wortel.

Daar is presies een warm qub-ondertekensleutel in die ontwerp, en dit is vasgepen: die per-seël kwitansie-sleutel (§16.10). Sy publieke sleutel word in LogProfile verbind (versprei met die verifieerder) en kruis-onderteken deur anchor_owner, sodat 'n verifieerder 'n kwitansie teen die dieselfde vasgepende wortel as die anker valideer. Dit is die oplossing van §16.15 Q2 — 'n ongepende, operateur-roteerbare kwitansie-sleutel sou herroepbaar wees (die operateur kon ontken die sleutel was hulle s'n), wat die kwitansie se aanspreeklikheidswaarde teen die operateur-vlak teenstander waarteen die kwitansie bestaan om af te skrik, sou nietig maak. Dus: qub hou geen ongepende log-ondertekensleutel nie; die kwitansie-sleutel is vasgepen en anchor_owner-kruis-onderteken.

Die SignedTreeHead is kanonieke CBOR (sleutels volgens gekodeerde lengte): size:u64, root:bstr[32], batch:u64, prev:bstr[32] (vorige sth_hash; genese = 32 nul-grepe), log_id:bstr[32], first_seq:u64, anchored_at:i64. Sy hash is sth_hash = SHA3-256(0x03 || canonical_cbor(SignedTreeHead)).

Vasgepende vertrouenswortel. log_id = SHA3-256("QUB_TLOG_V1" || anchor_owner_address). 'n Konformerende verifieerder MOET anchor_tx.owner == LogProfile.anchor_owner vereis, waar anchor_owner (en die kwitansie-sleutel se publieke sleutel) in qub_core ingebak word as die LogProfile — naas die quicknet-konstantes wat reeds in DrandTimelockProvider::quicknet() is — en versprei word met die verifieerder-binêre lêer. Die verifieerder MOET ook die Arweave-tx data → tx_id binding plaaslik verifieer eerder as om 'n poort se /raw/-antwoord te vertrou. Dit sluit die rogue-beursie-ekwivokasie-gat: "geanker op Arweave" is betekenisloos totdat die verifieerder watter beursie vaspen.

Rotasie is 'n §15-bestuur-uitbreiding, nie 'n hergebruik nie (opgelos — §16.15 Q3). §15.2 se profiel-oppervlak enumereer tans slegs sig_algs / drand-kettings / omhulling-weergawes / inhoudstipes, en §15.3 se snellers lys geen van hierdie nie — LogProfile / anchor_owner is nog nie in §15 se oppervlak nie. Rotasie-bestuur moet daarom gebou word: §15.3 word uitgebrei (hieronder) om die LogProfile-sneller by te voeg, en 'n rotasie is 'n ondertekende LogProfile-stamp gestuur in 'n verifieerder-opdatering. 'n Beplande rotasie dra 'n uitgaande → inkomende kruis-handtekening; 'n kompromittering-gedrewe rotasie kan nie (die uitgaande sleutel is onvertrou/onbeskikbaar juis dan) en val terug op die §15-bestuurde stamp, met die vorige-anker-vurk-toets (hieronder) wat skade in die tussentyd begrens.

Ekwivokasie-venster (eersteklas vertrouensparameter). 'n Blaar is ekwivokasie-bestand slegs sodra sy dekkende anker Arweave-bevestig is. Die venster is received_at → anker-bevestiging (≤ kadens + Arweave-finaliteit). Daarin is die enigste waarborge die vasgepende seël-kwitansie (§16.10) en qub se operasionele integriteit. Drie aanspreeklikheids-artefakte maak dit eerlik eerder as handgewuif (die getuie-model is §16.15 Q2 se oplossing):

  1. Vasgepende ondertekende seël-kwitansie — die SCT-analoog wat in die oplaai-antwoord teruggegee word (§16.10), onderteken deur die vasgepende, anchor_owner-kruis-onderteken kwitansie-sleutel. 'n Blaar wat voor sy anker laat val word, los die slagoffer 'n nie-herroepbare kwitansie om te publiseer, wat die stille-weglating-gat sluit.
  2. Gepubliseerde monitor-metodologie + vorige-ketting-stap — die anker prev-ketting word kop→genese geloop; 'n vurk (twee ankers by een size met verskillende root, of 'n gebroke prev) is publiseerbare bewys van wangedrag. Ekwivokasie-opsporing is 'n verklaarde operasionele toesegging, nie 'n stille aanname nie.
  3. Dubbele self-gepubliseerde koppe — elke nuwe kop {sth_hash, tree_size} word na 'n toegewyde qub-besit openbare, slegs-aanvoeg GitHub-bewaarplek geplaas (die dra-belastende peuter-bewysbare self-publikasie-been), met 'n sosiale plasing as slegs beste-poging-stawing. 'n Mislukte plasing MOET roep (nie stil misluk nie).

Eerlikheid-grens (bindende beperking). Omdat qub albei plasing-oppervlakke beheer, is dit self-gepubliseer, nie onafhanklik getuig nie. Geen produk-, bemarking-, of regsoppervlak mag eis dat die log "onafhanklik getuig" word nie; die toegelate eis is dat ekwivokasie opspoorbaar is en 'n nie-herroepbare kwitansie laat. 'n Ware onafhanklike derdeparty-getuie word uitgestel tot 'n toekomstige §15-bestuur-stamp.

received_at is operateur-beweer en geen eis mag daarop steun nie — dit word nooit as bewys of as dispuut-stawing op enige produk- / regs- / API- / bewys-lewering-oppervlak vertoon nie. Die Arweave-anker-bloktyd T is die enigste vertrouenslose tydstempel ('n bo-grens op "gelog teen"). Enige monitor-sanity-toets op received_at MOET teen T vergelyk, nie teen die operateur-beheerde anchored_at STH-veld nie; so 'n toets is 'n wag teen 'n eerlike operateur se klok-fout alleen, nie 'n aanspreeklikheidskontrole teen 'n kwaadwillige operateur nie (§16.15 Q5).

16.7 Anker-transaksie-formaat en Kadens

Die AnchorBundle is die kanonieke-CBOR Arweave-transaksie-liggaam, geskryf via die §16.8-bondelaar: ver:u8, sth:bstr (kanonieke SignedTreeHead-grepe), prev_anchor:bstr (vorige anker-tx-id rou grepe; weggelaat by genese), chain_hash:tstr (die drand-ketting in werking — quicknet), en die bondel se blaar-CBOR-stroom in seq-orde sodat die anker self-bevat is: 'n monitor herlei root uit die liggaam met nul qub-afhanklikheid. (As die blaar-stroom groot word by hoë volume, mag 'n toekomstige hersiening slegs 'n blaar-reeks per verwysing verbind; aangeteken, nie aangeneem in v1 nie.)

Arweave-etikette is doelbewus enumereerbaar — die log is bedoel om gevind te word, anders as private qubs: App-Name: qub-tlog, Anchor-Format: 1, Log-Id: <hex>, Batch: <n>, Tree-Size: <n>, Root: <hex>, Prev-Anchor: <tx>, Content-Type: application/cbor. Etikette is onvertroude wenke; die CBOR-liggaam is die enigste gesag.

Kadens: daagliks by verstek, hersien met volume (die grootte-sneller verkort outomaties die effektiewe kadens onder las); 'n betaalde T3-seël forseer 'n anker sodat betalende kliënte nooit 'n dag wag nie. Die anker-beursie is toegewyd en lae-snelheid, apart van die oplaai-beursie — dit MOET sy eie JWK wees ('n afsonderlike sleutel, nie 'n logiese rol op die oplaai-beursie nie) sodat 'n oplaai-beursie-kompromittering nie ankers kan vervals nie — met 'n harde per-dag anker-transaksie-begroting (die gedegradeerde ARWEAVE_DAILY_CEILING). Die bewaring-postuur word reguit gestel: 'n nou-omvang warm sleutel met 'n streng stroombreker en lae saldo, nie "koud" nie — 'n beursie wat daagliks outo-onderteken kan nie koud wees nie, en die spesifikasie maak nie of dit andersins nie.

16.8 ANS-104-bondelaar

'n In-huis ANS-104 DataItem-kodeerder en diep-hash-ondertekenaar, ongeveer 300 reëls, slegs Web Crypto, nul npm-afhanklikhede (albei Turbo SDK's misluk die npm ci --ignore-scripts voorsieningsketting-hek). DataItem greep-uitleg:

signatureType (2, LE) || raw_signature || owner || target(flag+0|32) || anchor(flag+0|32) || num_tags(8, LE) || tags_len(8, LE) || avro_tags || data

Ondertekening is Arweave deepHash — 'n rekursiewe SHA-384-spysvertering (Arweave se draadvereiste, crypto.subtle.digest("SHA-384")) oor ["dataitem", "1", sig_type, owner, target, anchor, encoded_tags, data] — dan RSA-PSS oor die diep hash met die beursie-JWK via crypto.subtle; id = base64url(SHA-256(signature)). Die SHA-384 hier is gekwarantyn as 'n slegs-Arweave-draad primitief, nooit 'n qub-vertrouensprimitief nie (§15 teken die heining aan; qub-vertrouens-hashing is SHA3-256 deurgaans).

Een kode-pad bedien drie verbruikers: betaalde T3 per-qub permanensie, die Arweave-onbeskikbaarheid-terugval (plaas die DataItem in die ry, gee die R2-eerste erkenning ongeag terug — dit sluit die huidige ARWEAVE_UNAVAILABLE 503-doodloop), en die skryf van die AnchorBundle. Handtekening-skema (opgelos — §16.15 Q8): v1 onderteken met RSA-PSS (handtekening-tipe 1) wat die bestaande Arweave-beursie-JWK-meganisme hergebruik (nul nuwe langlewende sleutel-bewaring, wat die "een minder geheim"-tese dien); Ed25519 word uitgestel na die §15 PQ-migrasie-pad.

Die handgerolde diep hash is die hoogste-risiko, laagste-natuurlike-dekking kode in W5, dus is sy heking nie-onderhandelbaar (§16.15 Q8):

  1. Die kruis-taal vasstelling tlog_v1.json (Rust + TS, die §14.5 wrapper_v1.json-patroon) dek diep-hash, DataItem-grepe + id, blaar-hashes, 'n 5-blaar wortel + oudit-pad, 'n STH-hash, 'n insluitingsbewys, en 'n konsekwentheidsbewys — in beide die onderteken- en die verifieer-rigtings (die verifieer-rigting maak saak omdat §16.6 se plaaslike tx → tx_id-toets die diep hash in elke selfstandige verifieerder intrek, nie net die skrywer nie).
  2. 'n Eenmalige interop-rondreis deur 'n verwysing-ANS-104-bondelaar, verbruik as slegs statiese toetsdata — nooit 'n npm-looptyd-afhanklikheid nie (die slegs-Web-Crypto / geen-installeer-skripte postuur staan).
  3. Die diep-hash + RSA-PSS-pad moet 'n rondreis maak deur die dieselfde crypto.subtle-primitiewe as wat produksie gebruik, sodat die in-huis kodeerder greep-versoenbaar is.
  4. 'n Deurlopende na-bondel aanvaarding-monitor bevestig dat elke anker / terugval DataItem werklik Arweave-aanvaarding behaal, met 'n alarm + stroombreker — omdat die diep hash ook die Arweave-onbeskikbaarheid-terugval-ry bedien, sodat 'n stille agteruitgang daardie ry met netwerk-verwerpte items sou vul gedurende presies die onderbreking wat dit bestaan om te dek.

16.9 Insluitings- en Konsekwentheidsbewyse

Albei is RFC 9162, SHA3-256, bedien as kanonieke CBOR.

InclusionProofGET /api/v1/qub/:tx_id/proof: ver:u8, leaf:bstr (die presiese blaar-CBOR — die verifieerder herbereken leaf_hash self en vertrou nooit 'n verskafte hash nie), index:u64, size:u64, audit:[bstr[32]], root:bstr[32], anchor:{ txid:bstr[32], batch:u64, sth:bstr[32], log_id:bstr[32], block_height?:u64, anchored_at?:i64 }.

ConsistencyProofGET /api/v1/log/consistency?first=<size_a>&second=<size_b>: ver:u8, first_size:u64, second_size:u64, first_root:bstr[32], second_root:bstr[32], nodes:[bstr[32]], first_anchor, second_anchor. 'n Enkele ondubbelsinnige sleutel-lys, vasgepen deur toets-vektor.

Selfstandige verifikasie (geen qub-bediener, brei §11 uit):

1.  Parse .qub bundle → SealedQub; recompute qub_id (§4.1).
2.  Read leaf.kind.
3a. kind=0x01 (attested):
      assert leaf.ref == qub_id
      assert leaf.body_hash   == SHA3-256(body)
      assert leaf.drand_round == unlock_round(unlock_at)
3b. kind=0x02 (asserted):
      assert leaf.ref == SHA3-256(qub_id || blind)   // holder supplies blind
      OR treat ref as opaque and bind via leaf.chash == SHA3-256(stored_bytes)
4.  Recompute leaf_hash = SHA3-256(0x00 || leaf); fold `audit` per RFC 6962
    using index/size; require derived root == proof.root.
5.  Fetch anchor.txid from any gateway; verify the tx data → tx_id binding
    (do not trust a gateway /raw/ response); REQUIRE anchor_tx.owner ==
    LogProfile.anchor_owner.
6.  Parse AnchorBundle; require committed root == proof.root and size ==
    proof.size; read the Arweave block time T.
7.  Emit the claim scoped by leaf.kind (§16.11).

Bewys-bedienende berging MOET koördinaat-gesleutel wees (opgelos — §16.15 Q7, blokkerende voorwaarde). Koue-blaar bewys-generering is korrektheid-neutraal slegs as die R2-oudit-materiaal 'n volgehoue Merkle-knoop-berging gesleutel deur absolute boom-koördinaat (level, index) is — nie per-batch knoop-deltas nie. Met 'n koördinaat-gesleutelde berging is enige (leaf i, size N) oudit-pad 'n stel O(log N) direkte R2 GET's met geen herberekening oor bondel-grense nie; met 'n bondel-gesleutelde berging is dit nie, wat die berging-uitleg-gaping is wat hierdie oplossing sluit. Die blaar-liggame is eweneens inhoud-adresseerbaar deur seq. 'n W5 toets-vektor MOET 'n genese-era koue blaar teen 'n veel-later wortel bewys met slegs R2 + Arweave met die LogDO-berging uitgevee, sodat die herwinning-veiligheid-eis in §16.13 gerugsteun word eerder as beweer word. Die O(log N) sekwensiële R2 GET's behoort slegs op die asinchroniese bewys-eindpunt — nooit op die seël-warmpad (§16.10) of 'n per-tik cron nie.

16.10 R2-eerste Erkenning-ordening

Die POST /api/v1/upload-volgorde word:

  1. Voorhelfte-hekke (auth, validasie, idempotensie-skerf-sleutel) — onveranderd.
  2. Sinchronies await QUB_CACHE.put(qub-cache/<tx_id>, wrappedBytes) — die duursaamheid-vloer; sluit ook W1 se voorkas-wedloop (voorheen 'n ctx.waitUntil ná die Arweave-indiening).
  3. Sinchronies await LogDO.append(leaf) — een in-colo DO RPC; die enkele skrywer ken seq toe, brei die inskrywingsketting uit, en werk die grens by. (RMW op gedeelde toestand → DO, nooit KV nie.) Die append RPC doen slegs dit — die O(batch) Merkle-bondel-sluiting-werk loop af van hierdie RPC op die LogDO-alarm, anders spits die append p95 elke LOG_BATCH_MAX_LEAVES-de seël.
  4. Gee die erkenning nou terug — met die seël-kwitansie (onderteken deur die vasgepende kwitansie-sleutel, §16.6) en { tx_id, log_seq, anchor_status: "pending" }. Die multi-sekonde Arweave-uitwaaiering word uit die kritieke pad verwyder.
  5. Een ctx.waitUntil plaas die uitgestelde werk in die ry: die per-qub Arweave-indiening (nou beste-poging / betaald; by mislukking roeteer dit na die bondelaar-terugval-ry eerder as om die gebruiker te 503) plus die bestaande voorlopige-meta-skrywes. Bondel-sluiting en ankering loop onafhanklik vanaf die LogDO-alarm en die daaglikse anker-cron. Geen ctx.waitUntil binne 'n lus nie; die bestaande idempotensie-skerf-sleutel word behou.

Latensie-begroting (opgelos — §16.15 Q7). Die < 300 ms p95-teiken is 'n gemete bekendstellings-hek, nie 'n aanname nie. Die eerlike kritieke pad is die voorhelfte KV-lesings + een R2 PUT + twee in-serie Durable Objects — die bestaande QuotaDO seël-kwota-debiet en die nuwe LogDO-append — dus moet die begroting reken vir twee in-colo DO-rondreise, nie een nie. Stuur 'n LogDO-latensie-alarm wat QuotaDO s'n weerspieël en behandel 'n p95-agteruitgang as 'n vrystelling-blokkeerder.

16.11 Vertrouensmodel — die presiese eis, geskaal per blaar-soort

Vir kind=0x01 (geattesteer): "Hierdie inhoud — liggaam wat ooreenstem met body_hash, geïdentifiseer deur qub_id — is by posisie seq tot qub se slegs-aanvoeg-log verbind en het bestaan nie later as Arweave-bloktyd T nie; dit was kriptografies onleesbaar tot drand-rondte R = unlock_round(unlock_at)." Dit is die volle {tlock-rondte-binding + Merkle-insluiting + geankerde wortel} drietal.

Vir kind=0x02 (beweer, die verstek): "'n Ondeurskynende ciphertext met inhoud-adres chash, wat qub_id en unlock_at eis, is by posisie seq tot die slegs-aanvoeg-log verbind en het bestaan nie later as Arweave-bloktyd T nie." Die rondte- en liggaam-bene word verskaf deur die bestaande §11 .qub-bundel-verifikasie (qub_core::unlock), nie deur die log nie; wat die log byvoeg bo 'n kaal per-qub transaksie is peuter-bewysbare ordening, 'n vertrouenslose bo-grens verbintenis-tyd, en ekwivokasie-weerstand.

Albei eise sluit uit, per §11: outeurskap sonder sig_alg ≥ 0x01, intensie, en sub-anker-granulariteit tydsberekening. Nóg een laat enige eis op received_at steun nie.

Eis-plafon (bindende bekendstellingsbeperking — opgelos §16.15 Q1). Vir gratis / verstek (kind=0x02) qubs is die geskaalde kind=0x02-eis hierbo die plafon op wat enige produk-, bemarking-, voorwaardes-, of bewys-lewering-oppervlak mag beweer. Geen oppervlak mag stel of impliseer dat die log die inhoud of die ontsluit-rondte van 'n verstek-qub bewys nie — die log bewys ordening + 'n vertrouenslose bo-grens verbintenis-tyd van 'n ondeurskynende ciphertext. Inhoud- en rondte-bewys kom uitsluitlik van die bestaande §11 .qub-bundel-verifikasie, wat log-onafhanklik is. Dit is 'n harde bekendstellings-blokkeerder op kopie, nie 'n stilistiese voorkeur nie; dit is die oplossing wat die greep-blind verstekpad eerlik hou.

16.12 Weergawe-bestuur en W3-koördinasie

Daar is geen SealedQub-draadstamp nie en daarom geen protokol-weergawe-stamp nie (§12.1): die log is 'n sykanaal wat tot bestaande velde en grepe verbind, dus betree dit nie die §12.2 protokol-weergawe-geskiedenis nie. W3 se opsionele drand_chain_version bly onaangeraak en bly die enigste opsionele SealedQub-veld. Die log stel eerder sy eie onafhanklike weergawe-ruimtes bekend — LOG_VERSION_1, ANCHOR_FORMAT_1, InclusionProof.ver — wat die §12.4 omhulling-weergawe-onafhanklikheid weerspieël (die omhulling dra 'n weergawe-greep onafhanklik van die protokol-weergawe, en die log-weergawes volg dieselfde skeiding).

Bewys-aflewering word by verstek gehaal, met 'n opsionele saamry. 'n Bewys kan nie by seël-tyd bestaan nie (die anker is nog nie geskryf nie), dus bly die seël-tyd .qub-bundel bewys-vry. W7 se verifieerder haal GET …/proof een keer, of in ten volle-aflyn-modus rekonstrueer dit die bewys uit die publieke AnchorBundle via 'n Arweave-navraag op Log-Id. Die .qub-bundel (W7) reserveer 'n opsionele inclusion_proof-lid — afwesig by seël, gevul deur 'n na-anker her-uitvoer vir koue argivering — wat dieselfde "opsioneel, weggelaat by verstek, addisioneel"-patroon as W3 se drand_chain_version volg.

16.13 Behoud

Behoud-vensters vir die LogDO oop-stert, die R2 bewys-bedienende substraat, die anker-stroombreker-tellers, en die bondelaar-terugval-ry word in docs/DATA-RETENTION.md gespesifiseer. Beginsel: die log se warm per-inskrywing-berging (LogDO) is post-anker herwinbaar; sy oudit-materiaal — die koördinaat-gesleutelde (level, index) Merkle-knoop-berging + die seq-geadresseerde blaar-liggame (§16.9) + die Arweave-ankers — is permanent. Om 'n koue blaar uit die DO te herwin maak nooit 'n uitgereikte bewys ongeldig nie, want 'n bewys los op teen daardie permanente R2-knoop-berging en die Arweave-anker, nie die DO nie (en die §16.9 uitgeveegde-DO-toets-vektor bewys dit).

16.14 Toets-vektore

W5 stuur die kruis-taal vasstelling tlog_v1.json (§16.8) plus uitgewerkte vektore: 'n kind=0x01 en 'n kind=0x02 blaar → leaf_hash; die 5-blaar kumulatiewe wortel; een insluitingsbewys; een konsekwentheidsbewys; een AnchorBundle; en een DataItem-id. Hierdie leef naas die §14.5 buitenste-omhulling-vektore en word deur beide die Rust (qub-core) en TypeScript (Worker) implementasies uitgeoefen.

16.15 Hersiening-besluite (W5 — opgelos)

Die W5 eksterne hersiening ('n teenstrydige ontwerp-deurgang + eienaar-goedkeuring) is voltooi. Elke besluit hieronder is bedaard en weerspieël in die §16-teks hierbo; die bindende bekendstellingsbeperkings word aan die einde herhaal. Implementasie mag onder hulle voortgaan.

  1. Verstekpad (kind=0x02) blaar-eerlikheid — OPGELOS. Stuur die twee-blaar-soort verdeling soos gespesifiseer: kind=0x02 verbind nóg body_hash nóg drand_round. Geen *_body_hash-veld op die greep-blind pad nie (dit sou die mees leesbare valse "geverifieerde"-sein vir integreerders wees en is 'n gerief wat §11 reeds uit die bundel verskaf). MOENIE bediener-seël vir log-geattesteerde qubs vereis nie (dit sou plaintext deur die Worker forseer en die kripto-versnipper-slot vernietig). Enige self-beskrywende kortsluiting hoort in die .qub-bundel / bewys-koevert as 'n verifieerder-herberekende veld, nooit 'n blaar-veld nie. Eienaar-bevestigde eis-plafon: §16.11.
  2. Ekwivokasie / weglating aanspreeklikheid — OPGELOS. Die seël-kwitansie-sleutel is vasgepen in LogProfile + anchor_owner-kruis-onderteken (sluit die vorige "geen ondertekensleutel"-teenstrydigheid; §16.6). Bekendstellings-getuie-model: vasgepende kwitansie + monitor-metodologie + vorige-ketting-stap + dubbele self-gepubliseerde koppe (qub-besit openbare GitHub-bewaarplek, sosiaal beste-poging), bemark as opspoorbaar + gekwiteer, nooit onafhanklik getuig nie. 'n Ware derdeparty-getuie word uitgestel na 'n §15-bestuur-stamp.
  3. Vasgepende anker-eienaar vertrouenswortel + rotasie — OPGELOS. Aanvaar die LogProfile-pen (§16.6); die verifieerder toets anchor_tx.owner == anchor_owner en verifieer die tx data → tx_id binding plaaslik. Rotasie-bestuur is 'n §15 uitbreiding om te bou (§15.3-sneller bygevoeg), nie 'n hergebruik nie; beplande rotasies kruis-onderteken, kompromittering-gedrewe rotasies val terug op die §15-stamp met die vurk-toets wat skade begrens.
  4. Private-qub blaar-verblinding — OPGELOS. Behou verblinding vir private qubs (ref = SHA3-256(qub_id ‖ log_blind_secret)), rou qub_id vir openbare qubs (reeds §16.2.1), chash as die selfstandige band. log_blind_secret is 'n korrelasie/Sybil-graad geheim, slegs-vorentoe-roteer (§16.2.1).
  5. received_at — OPGELOS. Behou dit in die blaar, verbind maar eksplisiet nie-bewysmateriaal; nooit as bewys of dispuut-stawing op enige oppervlak vertoon nie. Enige monitor-sanity-toets vergelyk teen die Arweave-bloktyd T, nie die operateur-beheerde anchored_at nie (§16.6).
  6. Gratis-vlak bewysbare-tydsberekening — OPGELOS (eienaar-goedkeuring). Duursaamheid agteruit nie; slegs die bewysbare bo-grens verbintenis-tyd verruwe tot die anker-bloktyd. Gratis-vlak kopie gebruik geen numeriese SLA nie ("…bygevoeg by die volgende log-anker, tipies daagliks"); presiese-uur bewys is 'n betaalde T3-eienskap, openbaar by die vlak-vergelyking-oppervlak + in voorwaardes (§16.1).
  7. Kumulatiewe boom op Workers — OPGELOS. Enkele kumulatiewe RFC 9162-boom + grens-gekasde enkele-skrywer LogDO (gemaklike speelruimte teenoor die ~1k skrywes/sek DO-plafon; stel Merkle-van-skerf-wortels skerwing uit tot naby dit). Blokkerende voorwaarde: koördinaat-gesleutelde (level, index) R2-knoop-berging + die uitgeveegde-DO koue-blaar toets-vektor (§16.9); < 300 ms is 'n gemete bekendstellings-hek oor twee in-serie DO's (§16.10).
  8. ANS-104 handtekening-skema + diep-hash — OPGELOS. RSA-PSS (sig-tipe 1, wat die toegewyde anker-beursie-JWK hergebruik); Ed25519 uitgestel na die §15 PQ-pad. Die handgerolde SHA-384 diep hash is gehek op die beide-rigtings kruis-impl vasstelling, 'n slegs-statiese verwysing-bondelaar interop-toets, die gedeelde-crypto.subtle rondreis, en die na-bondel Arweave-aanvaarding-monitor (§16.8).

Bindende bekendstellingsbeperkings (dra in implementasie + produk-/regs-hersiening):