qub protokollspecifikáció
A qub egy protokoll kriptográfiai időbeli kötelezettségvállalásokhoz: olyan rendszer, amely szavakat zár le egy jövőbeli dátumhoz, és amikor ez a dátum elérkezik, bizonyítja, hogy pontosan mit mondtak és mikor.
Három alapelem teszi mindezt lehetővé. A drand egy decentralizált véletlenszerűségi jeladó — a felfedési dátumot a fizika érvényesíti, nem pedig bármely fél jóindulata. Az állandó nyilvános tárhely egy hamisíthatatlan nyilvános tár — egyetlen fél sem tudja szerkeszteni vagy törölni a qubot, miután lezárták. Az ML-DSA-65 egy posztkvantum digitális aláírás — minden qub egy kulcspárhoz kötődik, amelynek titkos kulcsa soha nem hagyja el a szerző eszközét.
Együttesen ezek az alapelemek olyan kijelentést hoznak létre, amely időzárolt, hamisítás-érzékeny és tulajdonítható — egy nyugta, amelynek értéke azzal nő, ahogy a világ képessége a múlt meghamisítására fejlődik.
A dokumentum hátralévő része az interoperábilis megvalósításokhoz szükséges normatív specifikáció.
qub protokoll-specifikáció
| Mező | Érték |
|---|---|
| Verzió | 1.0 (protokollverzió 0x01, külső burkoló verziója 0x01) |
| Dátum | 2026-05-01 |
| Állapot | Tervezet |
| Átnézve eddig | 2026-05-01 |
Ez a dokumentum a qub időzített kötelezettségvállalási rendszer normatív protokoll-specifikációja. Meghatározza az interoperábilis megvalósításokhoz szükséges adatstruktúrákat, szerializációs szabályokat, levezetési képleteket és ellenőrzési eljárásokat.
Hatókör: a protokollréteg szándékosan nyelvfüggetlen — a qub törzse átlátszatlan egyszerű szöveg / markdown / paktum-bájtok, és a területi beállításnak megfelelő megjelenítés a megjelenítő felelőssége (qub.social webalkalmazás, <qub-embed> iframe, MCP-kliensek stb.).
1. Jelölés és konvenciók
| Jelölés | Jelentés |
|---|---|
u8, u64, i64 |
Megadott bitszélességű előjel nélküli/előjeles egészek |
[u8; N] |
N bájt fix hosszúságú bájttömb |
Vec<u8> |
Változó hosszúságú bájttömb |
Option<T> |
T típusú érték, vagy hiányzó |
String |
UTF-8 szöveges karakterlánc, NFC-normalizált |
| ` | |
SHA3-256(x) |
Az x bájtsorozat NIST SHA3-256 kivonata (FIPS 202) |
ceil(x) |
Felső egészrész függvény: a legkisebb egész ≥ x |
| CBOR | Concise Binary Object Representation (RFC 8949) |
| big-endian | A legjelentősebb bájt elöl |
A bemeneti képek (preimage) konstrukcióiban minden egész szám big-endian fix szélességű bájttömbként van kódolva (i64 → 8 bájt, u8 → 1 bájt), hacsak másként nincs megadva.
Minden időbélyeg Unix másodperc UTC-ben.
2. Adatstruktúrák
2.1 ComposeQub (alkotó memóriában lévő állapota)
Nem szerializálódik CBOR-ba. Nem íródik állandó tárhelyre. Az alkotó alkalmazásához helyi.
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 (visszafejtett hasznos adat)
Kanonikus CBOR-ral szerializálva (§3). A SealedQub belsejében titkosítva. Ez a struktúra bizonyítja a tartalom integritását a visszafejtés után.
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 — when reality renders judgment (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
}
Alapeset (aláíratlan szöveges qub): version = 0x01, content_type = 0x01, sig_alg = 0x00, minden Option mező hiányzik.
Egyéb v1 konfigurációk: content_type = 0x03 (paktum-törzs, lásd §6.1); sig_alg = 0x01 (ML-DSA-65) jelen lévő author_signature és author_pubkey mezőkkel (lásd §9.3); cosigner_pubkey és cosigner_signature együttesen jelen van a társaláírt paktumoknál (lásd §9.7); reply_to a szülő qub qub_id értékére állítva a válaszlánc-qubokhoz (az aláírás-hatókör következményeiért lásd §9.3).
2.3 SealedQub (kanonikus wire-formátum)
Kanonikus CBOR-ral szerializálva (§3). Állandó tárhelyre írva. Ez a láncon lévő műtermék.
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 — surfaced on the verdict-watch CTA
// before reveal; mirrors QubEnvelope.outcome_at;
// bound to qub_id via the §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 (megjelenítő alkalmazás állapota)
Nem szerializálódik CBOR-ba. A megjelenítő alkalmazáshoz helyi. Sikeres visszafejtés és ellenőrzés után épül fel.
RevealedQub {
qub_id: [u8; 32],
arweave_tx_id: String,
visibility: u8,
content_type: u8,
created_at: i64,
unlock_at: i64,
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. Kanonikus CBOR-profil
Minden SealedQub és QubEnvelope szerializációnak meg KELL felelnie ennek a profilnak. Két megvalósításnak ugyanazon logikai struktúra esetén azonos bájtokat KELL előállítania.
3.1 Kódolási szabályok
| Szabály | Specifikáció |
|---|---|
| Szabvány | RFC 8949 §4.2.1 (Core Deterministic Encoding Requirements) |
| Kulcsrendezés a térképben | Először a kódolt bájthossz szerint rendezve (rövidebb a hosszabb előtt), majd lexikografikusan (bájtonként az azonos hosszúságú kódolásoknál) |
| Egész szám kódolása | Legrövidebb forma: 0–23 a kezdeti bájtban; 24–255 2 bájtban; 256–65535 3 bájtban; stb. |
| Hosszkódolás | Csak határozott hosszúságok. Nincsenek határozatlan hosszúságú tömbök, térképek, bájtsorozatok vagy szöveges karakterláncok (a kiegészítő info = 31 tilos). |
| Címkék | Nincsenek CBOR-címkék (a 6-os főtípus tilos). |
| Lebegőpontos | Nincsenek lebegőpontos számok (a 7-es főtípus 0xF9–0xFB értékei tiltottak). |
| Szöveges karakterláncok | UTF-8 kódolt, NFC-normalizált (Unicode Normalization Form C). |
| Bájtsorozatok | Nyers bájtok. Nincs base64 kódolás a CBOR-rétegen. |
| Duplikált kulcsok | Hibával elutasítva. Az elemzők NEM fogadhatják el csendben a duplikált térképkulcsokat. |
| Egyszerű értékek | Csak a true (0xF5), false (0xF4) és null (0xF6) megengedett. |
| Opcionális mezők | A hiányzó opcionális mezők teljesen kihagyásra kerülnek a CBOR-térképből (nem null-ként kódolva). A jelen lévő opcionális mezők rendezett kulcssorrendben szerepelnek. |
3.2 Ellenőrzött kanonikus kulcssorrendek
Ezek a kulcssorrendek normatívak. A megvalósításoknak pontosan ebben a sorrendben KELL kibocsátaniuk a kulcsokat. A hibakeresési ellenőrzéseknek (debug assertions) ELLENŐRIZNIÜK KELLENE a sorrendet a nem kiadási buildekben.
QubEnvelope (0x01-es verzió, aláíratlan, minden opcionális mező hiányzik):
"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 kulcssorrend levezetése: minden kulcs egy CBOR szöveges karakterlánc. Kódolt hossz = 1 bájt fejléc + a karakterlánc hossza (24 bájtnál rövidebb karakterláncoknál). Először a teljes kódolt hossz szerint rendezve, majd lexikografikusan az azonos hosszúságú kulcsoknál.
SealedQub (0x01-es verzió, nyilvános, címzett nélkül):
"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 (paktum-törzs, 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 (a terms tömb egy sora):
"key" (4 encoded bytes)
"value" (6 encoded bytes)
PartyIdentifier (party_a / party_b térkép):
"label" (6 encoded bytes)
"contact" (8 encoded bytes) ← only if present
3.3 Bájtkódolási referencia
| Típus | CBOR-kódolás | Példa |
|---|---|---|
| SHA3-256 kivonat (32 bájt) | 0x58 0x20 + 32 bájt |
body_hash, qub_id |
| Időbélyegek (i64) | 0-s főtípus (pozitív) vagy 1-es (negatív), legrövidebb kódolás | Unix másodperc |
| Verzió (u8, 1-es érték) | 0x01 (egyetlen bájt) |
|
| Tartalomtípus (u8, 1-es érték) | 0x01 (egyetlen bájt) |
|
| sig_alg (u8, 0-s érték) | 0x00 (egyetlen bájt) |
|
| ML-DSA-65 aláírás (3 309 bájt) | 0x59 0x0C 0xED + 3 309 bájt |
author_signature, cosigner_signature |
| ML-DSA-65 nyilvános kulcs (1 952 bájt) | 0x59 0x07 0xA0 + 1 952 bájt |
author_pubkey, cosigner_pubkey |
4. Normatív levezetések
4.1 qub_id
A qub_id egyedileg azonosít egy qubot, és összeköti a QubEnvelope-ot a SealedQub-bal. Determinisztikusan vezetődik le a boríték tartalmából.
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
Tartománymegkülönböztető kódolása: a "QUB_ID_V2" karakterlánc 9 ASCII-bájt. Egyetlen 0x00 kitöltőbájt fűződik hozzá, hogy elérje a 10 bájtot az igazításhoz. A megvalósításoknak pontosan ezt a 10 bájtot KELL használniuk: [0x51, 0x55, 0x42, 0x5F, 0x49, 0x44, 0x5F, 0x56, 0x32, 0x00].
outcome_at kódolása: a V1.1 92 bájtról 100 bájtra bővítette a bemeneti képet, hogy az opcionális outcome_at mezőt a kötésbe fonja. A hiányzó outcome_at 8 nulla bájtként kódolódik; a protokoll-validátorok mindenhol elutasítják az outcome_at <= 0 értékeket, így ez az őrérték nem ütközhet egy érvényes értékkel. Lásd a §3.2-t (wire-formátum) és a fán belüli tasks/verdict-uplift-plan.md fájlt a mezőt motiváló ítélet-mechanikáért.
drand_round kódolása: A V1.2 a preimage-et 100 bájtról 108 bájtra bővítette, hogy a drand_round mezőt (a cél drand-kör, §4.3) is bekösse a kötésbe, és a tartományelválasztót QUB_ID_V2-re emelte. Ez beköti az időzáras kört a qub identitásába: egy átjáró nem kötheti át a titkosított szöveget egy másik (pl. már elmúlt) körhöz, mint amit a megjelenített unlock_at sugall. A feloldási eljárás (§8) ezen felül igazolja, hogy a tlock titkosított szöveg szakaszába (stanza) sütött kör megegyezik az unlock_round(unlock_at) értékével, így a megjelenített feloldási idő bizonyíthatóan az a kör, amely a visszafejtést kapuzza.
Tulajdonságok:
- A QubEnvelope bármely mezőjének (törzs, időbélyegek, tartalomtípus, verzió) megváltoztatása eltérő qub_id-t eredményez.
- A qub_id a titkosítás előtt számítódik ki. Mind a QubEnvelope, mind a SealedQub ugyanazt a qub_id-t hordozza. A megjelenítő ellenőrzi, hogy egyeznek-e a visszafejtés után.
- A qub_id nem függ a
sender_label,author_signaturevagyauthor_pubkeymezőktől. Ez azt jelenti, hogy ugyanaz a tartalom ugyanabban az időpontban lezárva ugyanazt a qub_id-t eredményezi, függetlenül attól, ki írja alá. - A SealedQub
titlemezőjének megváltoztatása (minden más rögzítve) megváltoztatja aqub_id-t atitle_hash-en keresztül. Egy átjáró tehát nem cserélheti ki a visszaszámláláson megjelenített egyszerű szöveges címet a qub-identitás érvénytelenné tétele nélkül. - A SealedQub
outcome_atmezőjének megváltoztatása (minden más rögzítve) megváltoztatja aqub_id-t a bemeneti képen keresztül. Egy átjáró nem cserélheti ki a visszaszámláláson a felfedés előtt megjelenített ítéletnap-dátumot a qub-identitás érvénytelenné tétele nélkül. - A
drand_roundmegváltoztatása (minden mást fixen hagyva) a preimage-en keresztül megváltoztatja aqub_idértékét. Egy átjáró nem kötheti át az időzáras titkosított szöveget egy másik körhöz a qub identitásának érvénytelenítése nélkül; a §8 feloldáskori szakasz-kör-ellenőrzéssel együtt a megjelenítettunlock_ataz a kör, amely ténylegesen kapuzza a visszafejtést.
4.2 body_hash
body_hash = SHA3-256(body)
Ahol a body a nyers Vec<u8> tartalom-hasznosadat. Szöveges qubok esetén ez az UTF-8 kódolt qub-törzs.
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
Ahol a title az opcionális egyszerű szöveges cím, amely a megjelenítő visszaszámlálásán jelenik meg a felfedés előtt (lásd §3.2). Az NFC-normalizálás a kivonatképzés idején fut, így a kivonat stabil a vizuálisan egyenértékű kódpont-sorozatok között. A csupa nulla őrérték a hiányzó esetre van fenntartva; az üres karakterlánc a kanonikus CBOR-határon a „hiányzó” nem kanonikus kódolásaként kerül elutasításra (a kanonikus kódolás teljesen kihagyja a mezőt).
4.3 Feloldási kör leképezése
drand_round = ceil((unlock_at - chain_genesis_time) / chain_period_seconds)
| Paraméter | Forrás | Példa |
|---|---|---|
unlock_at |
Felhasználó által választott Unix másodperc UTC | 1735689600 (2025-01-01 00:00:00 UTC) |
chain_genesis_time |
drand-lánc info (genesis_time) |
1595431050 |
chain_period_seconds |
drand-lánc info (period) |
30 |
A ceil() művelet az első olyan drand-kört választja ki, amelynek felfedési ideje ≥ unlock_at. Ez biztosítja, hogy a qub ne váljon visszafejthetővé a választott feloldási idő előtt.
Szélső eset: ha az (unlock_at - chain_genesis_time) pontosan osztható a chain_period_seconds értékkel, az eredmény pontosan az a kör — a qub pontosan az adott kör felfedési idejében oldódik fel.
Validáció: az unlock_at értéknek a lezárás idején a jövőben KELL lennie. Az unlock_at NEM lehet több mint 10 évvel a created_at után (a hosszú távú drand-függőség kockázatának korlátozása érdekében; a felhasználói felületnek FIGYELMEZTETNIE KELLENE a 2 éven túli feloldási dátumoknál).
5. Wire-formátum newtype-ok
A wire-formátum newtype-ok fordítási idejű biztonságot nyújtanak a CBOR-bájtok JSON-nal, nyers egyszerű szöveggel vagy más bájtkódolásokkal való összetévesztése ellen.
| Típus | Tartalmazza | Előállítja | Felhasználja |
|---|---|---|---|
SealedQubCbor |
A SealedQub kanonikus CBOR-ja | serialize_sealed_qub() |
Állandó tárhelyre feltöltés, megjelenítő lekérés |
QubEnvelopeCbor |
A QubEnvelope kanonikus CBOR-ja | serialize_qub_envelope() |
tlock-titkosítás bemenete, tlock-visszafejtés kimenete |
5.1 Konstrukciós szabályok
// 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 Validáció a konstrukciónál
A from_encoded()-nak ELLENŐRIZNIE KELLENE, hogy a bemenet érvényes CBOR-térképfejléccel kezdődik. A teljes szerkezeti validáció az elemzés idején történik, nem a konstrukció idején, hogy elkerülje a dupla elemzést.
6. Tartalomtípus-nyilvántartás
| Érték | Típus | Max. törzsméret | Megjegyzések |
|---|---|---|---|
0x00 |
Fenntartott (érvénytelen) | — | NEM HASZNÁLHATÓ |
0x01 |
Egyszerű szöveg (UTF-8, korlátozott Markdown) | 50 KB fizetős / 10 KB ingyenes | A megjelenítési szabályokért lásd §10. Az ingyenes / fizetős felosztást a feltöltési szolgáltatás érvényesíti; a protokollréteg kemény felső határa 50 KB. |
0x02 |
Fenntartott (jövőbeli) | — | Jövőbeli tartalomtípus számára lefoglalva; v1-ben nem érvényes. A megjelenítőknek el KELL utasítaniuk az alábbi szabály szerint. |
0x03 |
Paktum (kétoldalú megállapodás, CBOR-törzs) | 100 KB | A törzs kanonikus CBOR PactTerms (§6.1). Társaláírás a §9.7 szerint. |
A megjelenítőknek el KELL utasítaniuk az ismeretlen tartalomtípusokat egyértelmű, felhasználó számára látható hibával. A megjelenítők NEM kísérelhetik meg az ismeretlen típusok szövegként való megjelenítését.
6.1 Paktum-törzs (content_type = 0x03)
A paktum-törzs egy PactTerms érték kanonikus CBOR-kódolása:
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)> }
A három térkép kanonikus CBOR-kulcssorrendjeit a §3.2 adja meg. A teljes szerializált paktum-CBOR NEM haladhatja meg a 100 KB-ot (megegyezik a §6-tal).
Sémamegkülönböztető. A structured/v1 paktum terms tömbjének első sorának { key: "pact_schema", value: "structured/v1" }-nek KELL lennie. Az ezen jelölés nélküli sorok „egyedi” paktumok, és nem kapnak strukturált validációt vagy sématudatos megjelenítést.
Fagyasztott visszaigazolási helyek. A structured/v1 paktumok pontosan négy visszaigazolási sort hordoznak ezeken a kulcsokon:
"initiator_standard_terms"
"initiator_capacity_terms"
"counterparty_standard_terms"
"counterparty_capacity_terms"
Mindegyik value mezője nyolc fagyasztott angol karakterlánc egyike, amelyet a (role, kind) pár választ ki, ahol role ∈ { seller, buyer, provider, client } és kind ∈ { standard, capacity }. Maguk a karakterláncok normatív protokolladatok — mindkét fél ML-DSA-65 aláírása a body_hash-en keresztül a pontos bájtokra kötelez. NEM lokalizáltak; az aláírt törzs nyelvfüggetlen. Bármely szövegezési változtatás új sémaverziót igényel (structured/v2).
A nyolc karakterláncot, keresésüket (acknowledgement_for(role, kind)) és mindegyik indoklását a referencia-megvalósítás rögzíti. A megfelelő megvalósításoknak bájtazonos visszaigazolási értékeket KELL kibocsátaniuk; mind a négy szerepkombinációt lefedő arany-fixture SHA3-256 body-hash tesztek elkapnak bármely eltérést.
Megjelenítő-megjelenítési sorrend. A visszaigazolási karakterláncok olyan kifejezéseket tartalmaznak, mint a „described above” (fent leírt), amely feltételezi, hogy a leírás / hatókör sorok a visszaigazolások előtt jelennek meg. A megjelenítőknek a terms tömböt CBOR-sorrendben KELL megjeleníteniük; az átrendezés megtöri a prózai szemantikát.
Ellenérdekelt fél kapcsolata. Amikor a B fél contact mezője érvényes e-mail-cím, a qub feltöltési szolgáltatás automatikusan elküld egy áttekintési / társaláírási meghívó e-mailt a színrevitel idején, és az esetleges társaláírást ugyanazon cím ellenőrzéséhez köti (§9.7). Azok a paktumok, amelyek B felének kapcsolata hiányzik, továbbra is társaláírhatók, de csak sávon kívüli csatornán keresztül — a szolgáltatás visszautasítja azokat a társaláírási kéréseket, amelyek nem tudnak megfelelő 15 perces e-mail-ellenőrzési jelölőt előállítani.
6.2 Ítélet-törzs (content_type = 0x04)
Az ítélet-törzs egy VerdictBody érték kanonikus CBOR-kódolása:
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
}
Kanonikus CBOR-kulcssorrend:
"outcome" (8 encoded bytes)
"reflection" (11 encoded bytes) ← only if present
"evidence_url" (13 encoded bytes) ← only if present
"verdict_version" (16 encoded bytes)
A teljes szerializált ítélet-CBOR NEM haladhatja meg a 8 KB-ot (megegyezik a fenti regisztrációs sorral).
Eredmény-enumeráció. A wire-bájt szándéktól független; a négy kategória — Right / Partial / Wrong / Unfalsifiable — lefedi minden ítéletet hordozó szándék eredményterét. A szándékfüggő címkék („Megmondtam” / „Megtartottam” / „Terv szerint szállítottuk” / „Az események igazolták” a Right esetében stb.) a megjelenítő oldali renderelés kérdése, a szülő qub szándéka alapján — a wire nyelv- és szándék-független marad. Az 1..=4 tartományon kívüli értékeket dekódoláskor el KELL utasítani.
Szülő-kapcsolat. Egy ítélet-qub NEM hordozza a szülő-hivatkozást a törzsében. A szülő qub Arweave-tranzakcióazonosítója a Parent-Tx-Id tárolási címkeként kerül kibocsátásra feltöltéskor (§7 tárolási címkeréteg). Ez a törzset önálló, aláírt önértékelési nyilatkozatként tartja meg; az audit-lánc („mire vonatkozóan volt igaza?”) az Arweave-címke keresése révén jön létre.
Bizonyíték-URL biztonsága (normatív). Amikor az evidence_url jelen van, a validátoroknak (összeállítás-oldal, wire-oldal, Worker él) érvényesíteniük KELL:
- Csak HTTPS. A karakterláncnak a
https://bájtsorozattal KELL kezdődnie. Bármely más séma —http,ftp,javascript,data,filestb. — elutasításra kerül. - Hosszkorlát. ≤ 2 048 bájt (gyakorlati böngésző-URL-korlát).
- NFC + ellenséges-kódpont-ellenőrzés. Ugyanaz a szabály, mint a
titleésreflectionesetén — bidi-felülírás / nulla szélességű / tag-blokk / BOM / C0 / C1 kódpontok elutasításra kerülnek. A definíció megegyezik a Rustcrate::handle::contains_hostile_text_codepointés a TSworkers/api/src/utils/unicode.ts::isHostileCodepointfüggvényekkel (tartsd őket szinkronban). - Nincs szóköz, nincsenek ASCII-vezérlők. A szóközök / DEL /
0x20alatti bájtok az URL bármely pontján elutasításra kerülnek — ez zárja le a\n/\tinjekciós vektort, amelyet a bidi-szabály nem fed le. - Nem üres gazdagép-szegmens. A
https://és az első/,?vagy#közötti tartománynak nem üresnek KELL lennie.
Nincs szerveroldali lekérés. A Worker NEM proxyzhatja, kérheti le vagy nézheti meg előnézetben az URL-t. A protokoll egy karakterláncot tárol; a megjelenítés megjelenítő-oldalon történik rel="nofollow noopener noreferrer" target="_blank" attribútumokkal és a linkszöveg mellett láthatóan megjelenített gazdagéppel.
Reflexió. Opcionális alkotó által írt reflexiós szöveg („mi változott, mit tanultál”). Ugyanaz az NFC + ellenséges-kódpont-validáció, mint a title esetében. Az üres / csak szóközből álló bemenet az építéskor hiányzóra esik vissza.
Sémaverzió. A v1 csak verdict_version = 0x01 értéket támogat. A jövőbeli sémaverziók megemelik ezt a bájtot, és új protokollverzióval együtt érkeznek a §12 szerint.
7. Lezárási protokoll
A teljes lezárási sorozat. Minden lépés normatív.
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. Válaszd ki a drand láncot. Töltsd be a chain_genesis_time és chain_period_seconds
értékeket, és számítsd ki: drand_round = ceil((unlock_at - chain_genesis_time) / chain_period_seconds).
(Itt számoljuk ki, a qub_id előtt, mert a drand_round be van kötve a qub_id
preimage-be — §4.1, V1.2.)
6. Számítsd ki a qub_id-t (lásd §4.1), bekötve az 5. lépés drand_round értékét.
7. Hozd létre a QubEnvelope-ot minden mezővel.
8. Szerializáld a QubEnvelope-ot kanonikus CBOR-ral → B bájtok.
Ellenőrzés: a szerializált kimenet megfelel a kanonikus profilnak (§3).
9. Számítsd ki: C = tlock_encrypt(B, drand_round, drand_chain_public_key).
10. Hozd létre a SealedQub-ot tlock_ciphertext = C értékkel, és egyező qub_id, version,
unlock_at, drand_chain_id, drand_round mezőkkel.
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.
Tárolási címkeréteg (sávon kívül). A qub feltöltési szolgáltatás szándékosan kis halmaz tárolási tranzakciós címkét csatol a becsomagolt hasznos adat mellé. A Content-Type=application/octet-stream normatívan kötelező. A referencia-szolgáltatás emellett három opcionális címkét csatol, amikor az alkotó úgy dönt, hogy megjeleníti őket: Intent (engedélylistával validált összeállítási szándék — pl. quote, reply, commitment), Author (az alkotó §9.3 nyilvános kulcsának ujjlenyomata 64 karakteres kisbetűs hexként) és Parent-Tx-Id (a szülő qub tárolási tranzakciós azonosítója válaszláncokhoz, 43 karakteres base64url).
Az Author címke qubonként választható: a referencia-alkotóalkalmazás csak akkor csatolja, ha a felhasználó kifejezetten engedélyezi a nyilvános tulajdonítást a lezárás idején. Amikor a kapcsoló ki van kapcsolva — ez az alapértelmezett —, nem íródik Author címke, és a qub a láncon tulajdonítatlan: semmi az állandó tárhelyen nem köti össze a feltöltést egy alkotó kezelőjével, e-mail-címével vagy más qubjaival. Amikor a kapcsoló be van kapcsolva, az Author ujjlenyomat az alkotó által választott @kezelő-re oldódik fel a §9.5 attesztációs láncon keresztül. A válaszlánc-kapcsolatok és az Intent nem azonosítóak. A külső burkoló (§13) védi a belső törzset a rejtjelezett szöveg korrelációjától — megakadályozva, hogy egy gyűjtő felismerje és tömegesen visszafejtse a qub formájú feltöltéseket, miután a drand-körük közzétételre kerül.
A referencia-szolgáltatás szándékosan NEM csatol App-Name, App-Version vagy Type címkéket: bármely ilyen egyértékű szűrő egy GraphQL-lekérdezésnek a teljes qub-korpuszt visszaadná, ami nincs összhangban a burkoló csak-törzs bizalmassági hatókörével.
A megfelelő ellenőrzőnek NEM szabad semmilyen tárolási címkétől függenie a §11 harmadik fél általi ellenőrzéshez; a body hash / qub_id / aláírás csak a belső CBOR-ra kötelez, soha nem a címkehalmazra.
8. Feloldási protokoll
A teljes feloldási sorozat. Minden lépés normatív.
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. Körkötés-ellenőrzés (V1.2). Számold újra az expected_round =
ceil((SealedQub.unlock_at - chain_genesis_time) / chain_period_seconds) értéket.
Utasítsd el, kivéve ha SealedQub.drand_round == expected_round ÉS a tlock titkosított
szöveg szakaszába (stanza) sütött kör (az age/tlock fejlécből beolvasva, aláírás nélkül)
== expected_round. A szakasz köre az, amely ténylegesen kapuzza a visszafejtést; ezen
ellenőrzés nélkül egy rosszindulatú szerző egy már elmúlt körhöz köthetné a titkosított
szöveget, miközben jövőbeli visszaszámlálást jelenít meg, így bárki, aki beolvassa a
tárolt bájtokat, az unlock_at előtt visszafejthetné. A láncidentitás nélküli
implementációk (tesztmockok) kihagyják ezt az ellenőrzést.
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. Szerzőség aláírása
9.1 Indoklás
A qubok állandó tárhelyen tárolódnak. A szerzőségi aláírásoknak határozatlan ideig hamisíthatatlannak kell maradniuk, ezért a v1.0 a posztkvantum ML-DSA-65 sémát (FIPS 204) használja, nem pedig egy klasszikus sémát, amelynek biztonsága a qub állandó élettartamán belül romolhat.
9.2 Algoritmus-nyilvántartás
sig_alg |
Séma | Kulcsméret | Aláírásméret |
|---|---|---|---|
0x00 |
Nincs aláírás (aláíratlan) | — | — |
0x01 |
ML-DSA-65 (FIPS 204) | 1 952 bájt | 3 309 bájt |
A megjelenítőknek el KELL utasítaniuk az ismeretlen sig_alg értékeket.
9.3 Aláírt bemeneti kép konstrukciója
sig_input = SHA3-256(
"QUB_AUTHOR_SIG_V1" || // domain separator (17 bytes)
version || // u8 (1 byte)
qub_id || // [u8; 32] (32 bytes)
body_hash || // [u8; 32] (32 bytes)
unlock_at || // i64 big-endian (8 bytes)
0x00 // u8 (1 byte): MUST be 0x00 in v1.0
)
// Total preimage: 91 bytes → 32-byte hash
signature = Sign(author_secret_key, sig_input)
Tartománymegkülönböztető: a "QUB_AUTHOR_SIG_V1" 17 ASCII-bájt: [0x51, 0x55, 0x42, 0x5F, 0x41, 0x55, 0x54, 0x48, 0x4F, 0x52, 0x5F, 0x53, 0x49, 0x47, 0x5F, 0x56, 0x31]. Nincs kitöltés.
Záró bájt: a bemeneti kép 91. bájtjának 0x00-nak KELL lennie. A referencia-megvalósítás ezt ORG_ID_PRESENT_INDIVIDUAL = 0x00 konstansként teszi elérhetővé a crates/qub-core/src/signing.rs fájlban; az ellenőrzéshez sig_input-ot újraépítő megjelenítőknek ugyanazt a bájtot KELL kibocsátaniuk.
Aláírás-hatókör — mi van és mi nincs lefedve. A sig_input négy borítékmezőre kötelez: version, qub_id, body_hash, unlock_at (plusz a rögzített tartománymegkülönböztető és az org_id_present bájt). E négyből három szerkezeti invariáns: a qub_id maga is a version, content_type, created_at, unlock_at és body_hash mezőkből vezetődik le a §4.1 bemeneti képen keresztül, így a content_type vagy created_at bármely változtatása eltérő qub_id-t eredményez, és tranzitíven érvényteleníti az aláírást. A közvetlenül hitelesített felület tehát:
| Mező | Aláírás által hitelesített | Hogyan |
|---|---|---|
version |
✓ | Közvetlen bemenet a sig_input-hoz |
qub_id |
✓ | Közvetlen bemenet |
body_hash |
✓ | Közvetlen bemenet |
unlock_at |
✓ | Közvetlen bemenet |
content_type |
✓ | Tranzitíven, a qub_id bemeneti képen keresztül |
created_at |
✓ | Tranzitíven, a qub_id bemeneti képen keresztül |
body |
✓ | Tranzitíven, a body_hash = SHA3-256(body)-on keresztül |
author_pubkey |
— (implicit) | Az aláírást ellenőrző kulcs definíció szerint a szerző |
sender_label |
✗ | Csak megjelenítési szöveg; az aláírás megtörése nélkül módosítható |
reply_to |
✗ | Szálazási mutató; az aláírás megtörése nélkül módosítható |
cosigner_pubkey / cosigner_signature |
— | Függetlenül aláírva ugyanazon sig_input-ra (lásd §9.7) |
drand_chain_id, tlock_ciphertext, visibility |
— | Külső SealedQub mezők, nem a borítékon belül — saját szerkezeti invariánsaik (kör- / lánckonzisztencia) fedik le őket, de nem a szerzői aláírás (A drand_round mostantól tranzitívan kötve van a qub_id preimage-en keresztül — lásd fent.) |
A nem hitelesített mezők biztonsági következményei.
- A tárolt bájtokhoz írási hozzáféréssel rendelkező fél kicserélhetné a
sender_label-t („Alice” → „Mallory”) a szerzői aláírás érvénytelenné tétele nélkül. A borítékon belüliauthor_pubkeymarad a valódi identitáshorgony — a megjelenítőknek a megjelenítési identitást azauthor_pubkey-ből KELL levezetniük (a §9.5 attesztációs rétegen keresztül), nem pedig asender_label-ben bízva. - A
reply_tomező hasonlóképpen szerkeszthető az aláírás után. Mivel aqub_idtartalom-címzett, a támadó nem irányíthatja areply_to-t nem létező célpontra, de csendben átszülőzhet egy választ egy másik létező qubra.
Azoknak a megvalósításoknak, amelyek sender_label-t vagy reply_to-t jelenítenek meg a végfelhasználóknak, a hitelesített identitást (nyilvános kulcs ujjlenyomata, attesztáció) KELL elsődleges identitásjelzésként megjeleníteniük, nem a címkét.
9.4 Ellenőrzési eljárás
1. Read sig_alg from QubEnvelope.
2. If sig_alg == 0x00 → unsigned. No verification. Display "unsigned qub."
3. If sig_alg is unknown → reject. Display "unrecognised signature scheme."
4. Extract author_signature and author_pubkey. If either is absent → integrity error.
5. Reconstruct sig_input using fields from QubEnvelope (same formula as §9.3).
6. Verify(author_pubkey, sig_input, author_signature).
7. If verification succeeds → display "signed by [key fingerprint]."
8. If verification fails → display "signature verification failed."
Az aláírás-ellenőrzés a legdrágább művelet (különösen az ML-DSA-65). Az összes olcsóbb ellenőrzés (kivonat, qub_id, unlock_at) sikeres áthaladása UTÁN KELLENE elvégezni.
9.5 Identitás-attesztációk
Az identitás-attesztációk — az author_pubkey leképezése ember számára felismerhető identitási állításokra, mint például egy qub-kezelő, e-mail-cím, közösségi kezelő vagy passkey hitelesítő adat — megjelenítő-oldali progresszív fejlesztés, és nem szükségesek az aláírás-ellenőrzéshez. Azoknak a megjelenítőknek, amelyek megjelenítési identitásra oldják fel az attesztációkat, az alábbi elsőbbséget KELL alkalmazniuk:
handle > email > social > fingerprint
Az ujjlenyomat-tartalékérték a SHA3-256(author_pubkey) kisbetűs hexa formája; mindig elérhető bármely aláírt qubhoz. A megjelenítők megjelenítés céljából RÖVIDÍTHETIK — a referencia-megjelenítő a qub: előtagot, majd az első és utolsó négy bájtot jeleníti meg (qub:<8 hex>…<8 hex>).
A megfelelő ellenőrző a §9.4 minden ellenőrzését el tudja végezni anélkül, hogy a qub API-val kapcsolatba lépne, az állandó tárhelyen és a drandon túli bármilyen hálózat nélkül, és bármilyen szerveroldali keresés nélkül. Az attesztáció feloldása külön, legjobb erőfeszítésű lépés, amelyet csak az aláírás-ellenőrzés sikeres befejezése után végeznek el.
9.6 Méretre gyakorolt hatás
| Ed25519 | ML-DSA-65 | |
|---|---|---|
| Aláírás | 64 bájt | 3 309 bájt |
| Nyilvános kulcs | 32 bájt | 1 952 bájt |
| Összesen qubonként | 96 bájt | 5 261 bájt |
| Tárolási költségkülönbség (~$5/MB-nál) | ~$0,0005 | ~$0,026 |
Egy 500–2 000 bájtos szöveges qub esetén az ML-DSA-65 nagyjából megháromszorozza a tárolt méretet. Az abszolút költség elhanyagolható.
9.7 Társaláíró-ellenőrzés (paktum kétoldalú megállapodások)
Kétoldalú megállapodásoknál (content_type = 0x03) egy második aláírási réteg bizonyítja, hogy mindkét fél hozzájárult ugyanazokhoz a feltételekhez.
Borítékmezők:
cosigner_pubkey: az ellenérdekelt aláíró (B fél) ML-DSA-65 nyilvános kulcsa.cosigner_signature: aláírás ugyanazonsig_input-ra, mint a szerzőé (§9.3).
Mindkét mezőnek együtt KELL jelen lennie, vagy mindkettőnek hiányoznia. Ha pontosan az egyik van jelen, a megjelenítőknek integritáshibát KELL jelenteniük.
Ellenőrzési eljárás:
1. If cosigner_pubkey absent and cosigner_signature absent → no cosigner. Done.
2. If exactly one is present → integrity error.
3. Verify cosigner_pubkey != author_pubkey (prevent self-cosigning).
Fail → display "cosigner pubkey must differ from author."
4. Reconstruct sig_input using the same formula as §9.3.
5. Verify(cosigner_pubkey, sig_input, cosigner_signature).
6. Success → display "co-signed by [cosigner fingerprint]."
7. Failure → display "co-signature verification failed."
Tulajdonságok:
- A társaláíró ugyanazt a
sig_input-ot írja alá, mint a szerző — mindkét fél ugyanarra aqub_id-ra,body_hash-re ésunlock_at-ra kötelez. - A
qub_idlevezetése (§4.1) NEM tartalmazza a társaláíró-mezőket. Társaláíró hozzáadása egy meglévő borítékhoz nem változtatja meg aqub_id-t. - Egy paktum lehet csak szerző által aláírt (egyoldalú kötelezettségvállalás), csak társaláírt (szokatlan) vagy mindkettő (teljes kétoldalú bizonyíték).
E-mail-kötési kapu (működési). Amikor egy színrevitt paktum B fél e-mail-kapcsolatot hordoz (§6.1), a qub feltöltési szolgáltatásnak el KELL utasítania a társaláírási kérést, hacsak nem létezik rövid élettartamú e-mail-ellenőrzési jelölő, amely megegyezik mind a színrevitel azonosítójával, mind az adott kapcsolat normalizált e-mail-kivonatával. A jelölőt a /api/v1/auth/verify írja, amikor a magic-link token staging_id-t hordoz, és az ellenőrzött cím megegyezik a SHA-256(normalise_email(party_b.contact))-tal — ahol a normalise_email(addr) megőrzi a helyi rész kis-/nagybetűjét, és csak a tartományrészt kisbetűsíti (az RFC 5321 §2.3.11 szerint), és a SHA-256 itt a NIST FIPS 180-4 kivonat (eltérő a §4 levezetésekben használt SHA3-256-tól) —, és 900 másodperccel (15 perccel) a kibocsátás után lejár. Ez működési megszemélyesítés-elleni kapu, NEM a láncon lévő qub-bizonyíték része — egy harmadik fél ellenőrzőnek, amely a §11-et lejátssza, csak állandó tárhelyre és drandra van szüksége, bármilyen szerveroldali keresés nélkül. A jelölő csak szerveroldalon létezik, és soha nem része az aláírt törzsnek.
Méretre gyakorolt hatás (ML-DSA-65 szerző + társaláíró):
| Komponens | Méret |
|---|---|
| Szerzői aláírás | 3 309 bájt |
| Szerzői nyilvános kulcs | 1 952 bájt |
| Társaláírói aláírás | 3 309 bájt |
| Társaláírói nyilvános kulcs | 1 952 bájt |
| Teljes kriptográfiai többletteher | 10 522 bájt |
| Tárolási költségkülönbség | ~$0,05 |
10. Markdown-megjelenítés és -tisztítás
Ez a szakasz biztonságkritikus. A megjelenítő a szöveges qubokat (content_type = 0x01) korlátozott Markdown-részhalmazzal jeleníti meg.
10.1 Engedélyezett elemek
- Címsorok:
#-tól####-ig (nincs#####vagy######) - Kiemelés: félkövér (
**), dőlt (*), áthúzott (~~) - Listák: rendezett (
1.) és rendezetlen (-,*) - Idézetblokkok (
>) - Kód: soron belüli szakaszok (```) és bekerített blokkok (`````)
- Vízszintes vonalak (
---) - Sortörések (két záró szóköz vagy üres sor)
- Bekezdések
10.2 Tiltott elemek
| Elem | Kezelés |
|---|---|
Nyers HTML (<div>, <script> stb.) |
Teljesen eltávolítva. Semmilyen HTML nem jut át. |
Képek () |
Eltávolítva. A kép-szintaxis eltávolításra kerül a kimenetből. |
Hivatkozások ([text](url)) |
Az URL látható egyszerű szövegként jelenik meg. Nincs automatikus hivatkozás. Kifejezett felhasználói művelet nélkül nem kattintható. |
| Veszélyes URL-sémák | javascript:, data:, vbscript:, file: — eltávolítva. |
| Iframe-ek, beágyazások, objektumok | Eltávolítva. |
| HTML-entitások | Megjelenítési karakterekké dekódolva, csak ha biztonságosak. |
10.3 Megvalósítás
A megvalósításoknak szigorú engedélylista-elemzőt KELL használniuk, nem tiltólistát. Az ajánlott megközelítés:
- A Markdown elemzése
pulldown-cmark(vagy egyenértékű) használatával. - Az AST bejárása, és bármely olyan csomópont elvetése, amely nincs az engedélylistán (§10.1).
- Hivatkozási csomópontoknál: az URL kibocsátása látható szövegként, nem kattintható
<a>elemként. - A szűrt AST átalakítása típusos köztes ábrázolássá (pl. egy
MarkdownNodeenum csak biztonságos variánsokkal). A nyers HTML szerkezetileg nem ábrázolható ebben a köztes ábrázolásban. - Megjelenítés a típusos köztes ábrázolásból a cél megjelenítési rétegbe (pl. reaktív megjelenítési komponensek, DOM-csomópontok). Semmilyen ponton nincs HTML-karakterlánc-összefűzés vagy
innerHTML.
A tiltólista-megközelítések törékenyek, mert az új Markdown-bővítmények vagy elemző-furcsaságok szűretlen elemeket vezethetnek be. A típusos-AST megközelítés szerkezetileg lehetetlenné teszi az XSS-t — nincs olyan variáns, amely tetszőleges HTML-t hordozhatna.
10.4 Méret- és szerkezeti korlátok
- Maximális megjelenített címsormélység:
####(H4). A#####és mélyebbek félkövér szövegként jelennek meg. - Nincs korlát a bekezdések számára (a §6-ban lévő törzsméret-korlátok a megszorítás).
- Bekerített kódblokkok: nincs szintaxiskiemelés az MVP-ben. Monospace előformázott szövegként jelennek meg.
11. Harmadik fél általi ellenőrzés
Bármely harmadik fél ellenőrizhet egy nyilvános qubot a qub együttműködése nélkül. Az ellenőrzési eljárás:
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.
Mit bizonyít az ellenőrzés:
| Bizonyíték | Mit állapít meg |
|---|---|
| Kötelezettségvállalás | A rejtjelezett szöveg létezett a tárolási blokk időbélyege idején. |
| Integritás | Az egyszerű szöveges törzs megegyezik a vállalt kivonattal, és nem módosították. |
| Időzítés | A tartalom olvashatatlan volt a drand-körig, amely megfelel a választott feloldási időnek (a tlock és a drand biztonsági feltételezéseitől függően). |
Mit NEM bizonyít az ellenőrzés:
| Nem-bizonyíték | Miért |
|---|---|
| Szerzőség | A sender_label dekoratív. sig_alg ≥ 0x01 nélkül bárki lezárhatta volna ezt a tartalmat. |
| Szándék | A qub a tartalmat és az időzítést bizonyítja, nem azt, amit az alkotó szubjektíven gondolt. |
| Esemény előtti időzítés | A tárolási blokkba kerülés perceket késhet a tényleges feltöltéshez képest. A kötelezettségvállalás időbélyege a blokk ideje, nem az a pillanat, amikor a felhasználó megnyomta a „lezárás”-t. |
12. Verziókezelés
12.1 Protokollverzió
A version mező (u8) mind a SealedQub-ban, mind a QubEnvelope-ban a fő protokollverziót azonosítja.
- A megjelenítőknek el KELL utasítaniuk az ismeretlen fő verziókat egyértelmű hibával.
- Az ismert fő verziók TOLERÁLHATNAK ismeretlen opcionális mezőket, ha az előrekompatibilitási szabályok megengedik (a kanonikus kulcssorrendből hiányzó opcionális mezők figyelmen kívül maradnak).
- A tartalomtípusok (
content_type) és aláírási sémák (sig_alg) verzió-vezéreltek: új értékek csak új protokollverzió vagy kifejezett nyilvántartás-frissítés mellett vezethetők be.
12.2 Verziótörténet
| Verzió | Érték | Leírás |
|---|---|---|
| v1 | 0x01 |
Nyilvános szöveges qubok (content_type 0x01), paktum kétoldalú megállapodások (0x03, structured/v1 séma, ML-DSA-65 szerző + társaláíró), tlock, SHA3-256 |
12.3 Előrekompatibilitás
Egy v1-megjelenítőnek, amely ismeretlen opcionális CBOR-térképkulcsokat (a §3.2 kanonikus sorrendjében nem szereplő kulcsokat) tartalmazó QubEnvelope-ba ütközik, FIGYELMEN KÍVÜL KELLENE HAGYNIA ezeket a kulcsokat, és folytatnia kellene az ellenőrzést az ismert mezők használatával. Ez lehetővé teszi a jövőbeli kisebb kiegészítéseket (pl. új metaadatok) a fő verzió emelése nélkül.
Egy v1-megjelenítőnek, amely sig_alg = 0x01 (ML-DSA-65) értékbe ütközik, de hiányzik az ML-DSA-65 ellenőrzési támogatása, a qub-tartalmat „aláírás jelen van, de nem ellenőrizhető” megjegyzéssel KELLENE megjelenítenie, nem pedig a qubot teljesen elutasítania. A referencia-megvalósítás ma minden sig_alg értéket elutasít a 0x00 és 0x01 kivételével, mert a v1 nyilvántartás nem tartalmaz más érvényes algoritmust — a szigorú elutasítás és a lágy hiba megfigyelhetően azonosak, amíg egy harmadik algoritmus regisztrálásra nem kerül. A fenti lágy-hiba viselkedés akkor válik teherviselővé, amikor a §9.2 új bejegyzést fogad be, és a referencia-megjelenítő ezen a ponton frissül lágy-hibára.
12.4 Külső burkoló verziója
A §13-ban leírt OuterWrapper saját version bájtot hordoz, függetlenül a SealedQub.version és QubEnvelope.version mezőktől. A két verziótér külön fejlődik: egy jövőbeli posztkvantum-biztonságos szimmetrikus csere megemeli a burkoló bájtját anélkül, hogy a belső protokollverziót érintené, és egy jövőbeli protokollréteg-kiegészítés (pl. egy új borítékmező) megemeli a belső verziót anélkül, hogy a burkoló bájtját érintené.
OUTER_WRAPPER_VERSION_* |
Érték | Algoritmus | Állapot |
|---|---|---|---|
OUTER_WRAPPER_VERSION_1 |
0x01 |
AES-256-GCM 12 bájtos nonce-szal, 16 bájtos hitelesítési címkével, a qub_id-hoz kötött AAD-vel |
v1 alapértelmezett |
| — | 0x02–0xFF |
Fenntartott | Jövőbeli |
A megjelenítőknek el KELL utasítaniuk az ismeretlen burkoló-verziókat egyértelmű hibával. A protokoll szándékosan szűken tartja a burkoló-verzióteret, amíg egy konkrét migrációs hajtóerő meg nem jelenik (pl. egy másik AEAD-et előnyben részesítő NIST-irányelv); egy 0x02 hely ugyanabban a felülvizsgálatban kerül kiosztásra, amely bevezeti az algoritmust.
13. Külső titkosító burkoló
13.1 Indoklás
A protokollrétegek (QubEnvelope → tlock → SealedQub) időzárolttá teszik a lezárt qubot: a törzs olvashatatlan az unlock_at-ig, és amíg a drand-kör aláírása közzétételre nem kerül. A feloldás után azonban a kör aláírása nyilvános, és a SealedQub kanonikus CBOR-alakja felismerhető, így egy gyűjtő, aki indexelte az állandó tárhelyű tranzakciókat, tömegesen visszafejthetné az egész qub-korpuszt.
A külső titkosító burkoló bezárja ezt a csatornát azáltal, hogy egy további szimmetrikus AEAD-réteget iktat be a kanonikus SealedQubCbor és az állandó tárhelyre írt bájtok közé. A 256 bites K kulcs kizárólag a kézbesítési URL fragmentjében és a felhasználói eszközökön él; a böngészők nem továbbítják az URL-fragmenteket a szervereknek, így a qub.social, minden tárolási átjáró és minden CDN bármelyikük előtt megfigyelhetően vak a K-ra. Az állandó tárhelyen lévő minden qub tehát átlátszatlan rejtjelezett szöveg, amelynek egyszerű szövege visszanyerhetetlen az alkotó által megosztani választott URL nélkül.
Nettó hatás:
- Felsorolás-immunitás alapértelmezetten. Az állandó tárhelyen lévő becsomagolt bájtok bájtszinten megkülönböztethetetlenek a tetszőleges rejtjelezett szövegtől. Egy „GraphQL-lekérdezés qub formájú feltöltésekre, tömeges visszafejtés nyilvános drand-aláírásokkal” gyűjtőstratégia nem végződik egyszerű szöveggel.
- Kripto-aprítási adatvédelmi tartás. A qub.social szó szerint nem tudja visszafejteni a saját korpuszát. Az idézések rejtjelezett szöveget érnek el, nem egyszerű szöveget.
- Kétszintű bizalmassági létra. Alapértelmezett = hivatkozás-vezérelt hozzáférés (ez a szakasz). A címzettnek titkosított privát qubok (fenntartott 2. fázisú funkció, még nincs specifikálva) a tetejére rétegződnek második szintként.
13.2 Rétegezés
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)
A lezárás és feloldás a protokollrétegen (§7, §8) változatlan a burkoló-határ alatt; a burkoló a seal() hívási helyén csatlakozik, és az unlock() hívási helyén válik le.
13.3 OuterWrapper adatstruktúra
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
}
Mező-invariánsok.
- A
versionmezőnek0x01-nek KELL lennie a v1.0 burkoló-bájtoknál. - A
qub_idmezőnek meg KELL egyeznie a kicsomagolás után visszanyert SealedQubqub_idmezőjével. A kicsomagolási lépés ezt nem érvényesíti közvetlenül (az AEAD AAD-kötés lehetetlenné teszi a bájtszintű hamisítást), de a feloldási réteg tranzitíven ellenőrzi a kapcsolatot: ha egy alkotó olyanSealedQubCbor-t csomagol be, amelynek belsőqub_id-ja nem egyezik a burkolóqub_id-jával, a §8 11. lépése meghiúsul. - A
noncemezőnek 96 bitnek (12 bájtnak) KELL lennie, frissen generálva egy CSPRNG által minden becsomagolási műveletnél. Egy nonce újrahasználata ugyanazon kulcs alatt lehetővé teszi az AEAD nonce-újrahasználati támadásokat, amelyek visszanyerik az egyszerű szöveget; az előállítóknak a (key,nonce) párokat egyszer használatosként KELL kezelniük. - A
ciphertextaz AES-256-GCM kimenete: a rejtjelezett szöveg bájtjai összefűzve a 16 bájtos hitelesítési címkével. Aciphertext.len() == SealedQubCbor.len() + 16pontosan.
CBOR-kódolás. Kanonikus CBOR a §3 szerint, ugyanazzal a kulcsrendezési szabállyal (kódolt bájthossz szerint növekvően rendezve, majd lexikografikusan). A négy kulcs:
| Kulcs | Kódolt bájtok | Sorrend |
|---|---|---|
nonce |
6 | 1 |
qub_id |
7 | 2 |
version |
8 | 3 |
ciphertext |
11 | 4 |
Az OuterWrapper CBOR első bájtja tehát egy 4 bejegyzéses térkép határozott hosszúságú térképfejléce (0xA4).
13.4 AAD-kötés a qub_id-hoz
A burkoló a qub_id-t AEAD kiegészítő hitelesített adatként köti. Ez a teherviselő szerkezeti védelem három támadásosztály ellen:
| Támadás | Védelem |
|---|---|
A rejtjelezett szöveg áthelyezése egy másik qub_id mező alá a burkolóban |
AAD-eltérés → az AEAD-hitelesítés meghiúsul |
| Az A qub URL-fragmentjének keverése a B qub állandó tárhelyű bájtjaival | AAD-eltérés → az AEAD-hitelesítés meghiúsul |
A burkoló qub_id mezőjének meghamisítása a feltöltés után |
AAD-eltérés → az AEAD-hitelesítés meghiúsul |
A qub_id burkoló egyszerű szövegében való hordozása nem gyengíti érdemben a felsorolás-immunitást — a qub_id maga is a §4.1 bemeneti kép SHA3-256 kivonata, a kivonatból nem visszanyerhető bemeneti képpel, és egy felsoroló, aki már begyűjtötte a burkoló bájtjait, semmi olyat nem tanul a látható qub_id-ból, amit ne tudna kikövetkeztetni magának a feltöltésnek a létezéséből.
13.5 Becsomagolási és kicsomagolási algoritmusok
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
Hibamód-összeomlás. A rossz K, a rossz nonce, az AAD-eltérés és a meghamisított rejtjelezett szöveg mind ugyanazt a DECRYPT_FAILED hibát eredményezi. Ez szándékos AEAD-tulajdonság: a hibamód megkülönböztetése oldalcsatornát hozna létre, amelyet egy távoli támadó hibás formátumú burkolók küldésével és a válasz időzítésével vizsgálhatna. A referencia-megvalósításoknak minden AEAD-hibát egyetlen hibaalakra KELL összeomlasztaniuk.
13.6 Kulcsanyag és terjesztés
A becsomagoló K kulcs egy 256 bites egyenletes véletlen érték, amelyet qubonként generál egy CSPRNG. A referencia-megvalósítások az alábbiakból nyerik:
- WASM alkotó:
getrandom(WebCrypto awasm_jsháttér alatt). - Worker szerveroldali lezárási útvonal:
crypto.getRandomValues.
Terjesztés: a K mezőt URL-biztonságos base64-ként KELL kódolni (RFC 4648 §5, kitöltés nélkül), és a kézbesítési URL-hez fragmentkomponensként hozzáfűzni:
delivery_url = <origin>/c/<arweave_tx_id>#<base64url(K)>
A fragmentet egy megfelelő böngésző soha nem továbbítja egyetlen szervernek sem. Azok a helyreállítási csatornák (szerveroldali előzményindex, választható e-mailes automatikus küldés), amelyek a teljes kézbesítési URL-t — beleértve a fragmentet — a felhasználó eszközén túl megőrzik, kifejezett kompromisszum az alapértelmezett kripto-aprítási tartással szemben, és kifejezett felhasználói beleegyezéshez KELL kötni őket.
Fragmentvesztés. Ha egy felhasználó elveszíti az URL-fragmentet, és nincs helyreállítási csatornája, a qub olvashatatlan. Ez a tervezés teherviselő kompromisszuma, és a lezárás idején KÖZÖLNI KELL a felhasználóval. Az MVP megerősíti a lezárás-idejű közlést kifejezett „mentse el ezt az URL-t” szöveggel és egy ellenőrzött e-mailes helyreállítási csatornával azoknak a felhasználóknak, akik ezt választják.
13.7 A szakasz hatókörén kívül
- A szerzőség aláírása (§9) változatlan: az aláírások a belső
QubEnvelope-on belül számítódnak ki, és a kicsomagolás → tlock-visszafejtés → CBOR-elemzés után kerülnek visszanyerésre. - A címzettnek titkosított privát qubok (fenntartott 2. fázisú funkció, még nincs specifikálva) e burkoló tetejére komponálódnak második bizalmassági szintként; mindkét szint egyidejűleg aktív lehet.
- A paktumok (§6, content_type
0x03) pontosan úgy csomagolódnak be, mint a szöveges qubok; a burkoló bájtvak a belső tartalomtípusra.
13.8 Nyilvános qubok (a burkoló elhagyása)
A külső burkoló a kézbesítési rétegen választható. Egy alkotó nyilvánosként is lepecsételhet egy qubot, amely esetben a kanonikus SealedQubCbor közvetlenül kerül az állandó tárhelyre, OuterWrapper réteg és K kulcs nélkül:
SealedQubCbor bytes ──(public)──▶ uploaded to permanent storage as-is
SealedQubCbor bytes ──(private)─▶ AES-256-GCM(K, …) ▶ OuterWrapper ▶ uploaded
Egy nyilvános qub időzárolt, de nincs hivatkozással kapuzva: olvashatatlan marad, amíg a drand-köre közzétételre nem kerül (a tlock-réteg változatlan), de a feloldás után bárki, akinek megvan az arweave_tx_id, vissza tudja fejteni — nincs szükség URL-fragmentre, mert nincs K. Ez a szándékos kompromisszum azokhoz a felületekhez, amelyeket a szervernek kell mozgatnia: a felfedés-értesítő e-mailek, a harmadik féltől származó beágyazások és a gazdagabb felfedés-utáni SEO mind olyan hivatkozást igényel, amely olyan titok nélkül működik, amelyet a szerver soha nem tart a kezében (§13.6).
Következmények, amelyekkel egy előállítónak SZÁMOLNIA KELL:
- Nincs felsorolás-immunitás. A nyilvános qubok konstrukciójukból adódóan lemondanak a §13.1 felsorolás-immunitási tulajdonságról. A referencia-feltöltési szolgáltatás
Visibility: publicállandó-tárhely címkével látja el őket (és csak őket), így szándékosan felfedezhetők; a privát qubok nem hordoznak ilyen címkét, és megőrzik a bájtszintű megkülönböztethetetlenségüket. - Egyszerű szöveges cím feltárva a lezárás idején. A §3.2
titlemező egyszerű szöveg aSealedQubCbor-on belül. A burkoló alatt rejtve marad, amíg egy megjelenítő nem szolgáltatja aK-t; a burkoló nélkül a feltöltés pillanatától, a feloldás előtt, az állandó tárhelyen mindenki számára olvasható. A megfelelő alkotó-alkalmazásoknak ezt a lezárás idején KÖZÖLNIÜK KELL. - A felismerés szerkezeti. Egy megfelelő megjelenítő/beágyazás elemzéssel különbözteti meg a két alakot: az
OuterWrapper-ként elemezhető bájtok aK-val-kicsomagolás útvonalát követik; a csupaszSealedQubCbor-ként elemezhető bájtok közvetlenül elfogadásra kerülnek. Nincs szükség wire-jelzőre, és aqub_idnem köti a láthatóságot — ugyanaz a tartalom aSealedQubrétegen bájtazonos, akár nyilvánosan, akár privátként lett lepecsételve.
A privát (becsomagolt) marad az alapértelmezett; a nyilvános kifejezett, qubonkénti alkotói választás.
14. Tesztvektorok
14.1 qub_id levezetése
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
Az implementációknak ehhez a bemenethez azonos body_hash és qub_id értékeket KELL előállítaniuk. Ezt a tesztvektort érdemes első egységtesztként megírni. A fenti kanonikus értékeket a referencia-implementáció számította ki, és bitről bitre egyezniük KELL. Korábbi preimage-elrendezések (indulás előtt — egyetlen élő qub sem függött ezektől): a 92 bájtos V1.0 qub_id 3d9fc2390eab043d38a1669ed3b71be76f9eefe872b9569ab1aaa027b88392b0 volt; a 100 bájtos V1.1 qub_id (az outcome_at_or_zero bekötése után) b0d032898ad629795150fdcb3f84e518f59ed05b7a2a82bc24ebdb87f52144ed volt. A V1.2 bevonja a drand_round mezőt, és a tartományelválasztót QUB_ID_V2-re emeli.
14.2 Feloldási kör leképezése
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 Kanonikus CBOR oda-vissza
A megvalósításoknak ellenőrizniük KELL, hogy a serialize(parse(serialize(qub))) == serialize(qub) minden érvényes bemenetre. Ez tulajdonságteszt, nem egyetlen vektor.
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)
A kanonikus CBOR-bájtokat és a SHA3-256 body_hash-t a referencia-megvalósítás számítja ki. A megvalósításoknak bájtazonos CBOR-t KELL előállítaniuk erre a bemenetre.
A megvalósításoknak emellett ellenőrizniük KELL, hogy a serialize(parse(serialize(pact))) == serialize(pact) minden érvényes PactTerms bemenetre (tulajdonságteszt).
14.5 Külső burkoló nyelvközi vektorok
A külső burkolónak (§13) külön kanonikus fixture-je van itt: crates/qub-core/tests/vectors/wrapper_v1.json. Minden eset egy (key, nonce, qub_id, sealed_cbor) rendezett ötöst rögzít átlátszatlan hexa-bemenetekként, és egy konkrét expected_wrapper_hex kimenetet állít. Mindkét referencia-megvalósítás ugyanazt a JSON-fájlt használja:
- Rust:
crates/qub-core/tests/wrapper_vectors.rs(cargo test -p qub-core --test wrapper_vectors). - TypeScript:
workers/api/src/crypto/__tests__/wrapper.test.ts(npm test).
A fixture jelenleg három esetet rögzít:
| Eset | Lefedettség |
|---|---|
basic-text-public |
A legkisebb realisztikus SealedQub alak; opcionális mezők nélkül. Megállapítja a kanonikus burkoló-alakot egy v1.0-tipikus qubhoz. |
with-recipient-pubkey |
SealedQub beállított recipient_pubkey-vel (2. fázis útvonal). Eltérő belső CBOR-kulcskészlet, eltérő qub_id. |
longer-body |
~4 KiB-os törzs — gyakorolja a többbájtos CBOR-hosszelőtagokat mind a belső borítékon, mind a külső rejtjelezett szövegen belül. |
A megvalósításoknak bájtazonos expected_wrapper_hex-et KELL előállítaniuk a rögzített bemenetekre. A fixture újragenerálása QUB_REGEN_VECTORS=1 cargo test -p qub-core --test wrapper_vectors parancsot igényel, és szándékos formátumváltoztatásokra van fenntartva.
15. Kriptográfiai profil kormányzása (jövőbeli)
Ez a szakasz informatív a v1-re, és normatívvá válik, amikor először lép be egy második algoritmus a qub kriptográfiai alapelemeinek bármelyikébe.
15.1 Jelenlegi tartás
A v1 protokoll alapelemenként pontosan egy algoritmust köt:
- Aláírás: ML-DSA-65 (
sig_alg = 0x01; 1952 bájtos nyilvános kulcs, 3309 bájtos aláírás) és aláíratlan (sig_alg = 0x00). A §9.2 nyilvántartás nem határoz meg más értékeket; egy v1-ellenőrzőnek el KELL utasítania minden{0x00, 0x01}halmazon kívülisig_algértéket. Egy jövőbeli Ed25519 bejegyzés várható (§15.3), de v1-ben nincs lefoglalva. - Időzár: csak drand quicknet — a lánckivonat, a nyilvános kulcs, a genesis-idő és a periódus rögzített hálózati paraméterek, amelyeket a referencia
DrandTimelockProvider::quicknet()(crates/qub-core/src/tlock.rs) és aconfig/drand-endpoints.jsonhordoz. - Külső burkoló: csak AES-256-GCM v1 (§13).
Az ellenőrzők jelenleg keményen kódolják a kulcs- és aláíráshosszakat alapelemenként. A wire-formátum nem tár fel agilitási felületet.
15.2 Tervezett alak
Amikor egy második algoritmus belép a protokollba, az ellenőrző egy elnevezett CryptoProfile-hoz (pl. ExqubV1) lesz konfigurálva, amely felsorolja az alapelemenként engedélyezett értékek pontos halmazát — sig_alg-ek, drand-láncok, burkoló-verziók, tartalomtípusok. A profil az ellenőrzés idején rögzül, soha nincs sávon belül egyeztetve. Az aktív profilon kívüli bármely érték elutasításra kerül.
Ez garantálja, hogy az ML-DSA-87 hozzáadása vagy az Ed25519 aktiválása nem gyengítheti visszamenőlegesen a meglévő ellenőrző-konfigurációkat: egy v1-ellenőrző v1-ellenőrző marad még egy v2-profil közzététele után is.
15.3 Kiváltó feltételek
Léptesse elő a §15-öt normatív státuszra, amikor az alábbiak bármelyike javaslatra kerül:
- Egy második
sig_algbájt (Ed25519 aktiválás, ML-DSA-87 vagy bármely új bejegyzés a §9 nyilvántartásban). - Egy második drand-lánc éles használatban.
- Egy második külső-burkoló verzió.
Addig a §15 helykitöltő, amely rögzíti a migrációs alakot, hogy a jövőbeli PR-ek ismert célpontra érkezzenek, ahelyett, hogy a tárgyalási felületet a nulláról újratárgyalnák.