Spesifikasi Protokol qub
qub ialah protokol untuk komitmen temporal kriptografi: satu sistem untuk memeterai kata-kata kepada tarikh akan datang dan membuktikan, apabila tarikh itu tiba, apa sebenarnya yang telah dikatakan dan bila.
Tiga primitif menjadikannya berfungsi. drand ialah suar kerawakan ternyahpusat — tarikh pendedahan boleh dikuatkuasakan oleh fizik, bukan oleh niat baik mana-mana pihak. Storan awam kekal ialah simpanan awam tahan-usik — tiada pihak boleh menyunting atau memadam qub setelah ia dimeterai. ML-DSA-65 ialah tandatangan digital pasca-kuantum — setiap qub diikat kepada satu pasangan kunci yang rahsianya tidak pernah meninggalkan peranti pengarang.
Bersama-sama primitif ini menghasilkan satu kenyataan yang terkunci waktu, kalis usik, dan boleh dikaitkan — satu resit yang nilainya bertambah selari dengan kemampuan dunia untuk memalsukan masa lalu.
Sebahagian dokumen yang tinggal ialah spesifikasi normatif yang diperlukan untuk implementasi yang saling kendali.
Spesifikasi Protokol qub
| Medan | Nilai |
|---|---|
| Versi | 1.0 (versi protokol 0x01, versi pembungkus luar 0x01) |
| Tarikh | 2026-05-01 |
| Status | Draf |
| Disemak sehingga | 2026-05-01 |
Dokumen ini ialah spesifikasi protokol normatif untuk sistem komitmen berwaktu qub. Ia mentakrifkan struktur data, peraturan pensirian, formula derivasi, dan prosedur pengesahan yang diperlukan untuk implementasi yang saling kendali.
Skop: lapisan protokol secara sengaja bersifat neutral-bahasa — badan qub ialah bait teks biasa / markdown / perjanjian yang legap, dan pemaparan mengikut lokal ialah tanggungjawab pembaca (aplikasi web qub.social, iframe <qub-embed>, klien MCP, dsb.).
1. Notasi dan Konvensi
| Notasi | Maksud |
|---|---|
u8, u64, i64 |
Integer tanpa tanda/bertanda dengan lebar bit yang ditetapkan |
[u8; N] |
Tatasusunan bait panjang tetap sebanyak N bait |
Vec<u8> |
Tatasusunan bait panjang berubah |
Option<T> |
Nilai jenis T, atau tiada |
String |
Rentetan teks UTF-8, dinormalkan NFC |
| ` | |
SHA3-256(x) |
Cincang NIST SHA3-256 bagi rentetan bait x (FIPS 202) |
ceil(x) |
Fungsi siling: integer terkecil ≥ x |
| CBOR | Concise Binary Object Representation (RFC 8949) |
| big-endian | Bait paling signifikan didahulukan |
Semua integer dalam pembinaan praimej dikodkan sebagai tatasusunan bait lebar tetap big-endian (i64 → 8 bait, u8 → 1 bait) melainkan dinyatakan sebaliknya.
Semua cap masa ialah saat Unix dalam UTC.
2. Struktur Data
2.1 ComposeQub (Keadaan Dalam-Memori Pencipta)
Tidak disirikan kepada CBOR. Tidak ditulis ke storan kekal. Tempatan pada aplikasi pencipta.
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 (Muatan Ternyahsulit)
Disirikan menggunakan CBOR berkanun (§3). Disulitkan di dalam SealedQub. Inilah struktur yang membuktikan integriti kandungan selepas penyahsulitan.
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
}
Asas (qub teks tanpa tandatangan): version = 0x01, content_type = 0x01, sig_alg = 0x00, semua medan Option tiada.
Konfigurasi v1 yang lain: content_type = 0x03 (badan perjanjian, lihat §6.1); sig_alg = 0x01 (ML-DSA-65) dengan author_signature dan author_pubkey hadir (lihat §9.3); cosigner_pubkey dan cosigner_signature hadir bersama-sama untuk perjanjian yang ditandatangani bersama (lihat §9.7); reply_to ditetapkan kepada qub_id qub induk untuk qub rantai balas (lihat §9.3 untuk implikasi skop tandatangan).
2.3 SealedQub (Format Wayar Berkanun)
Disirikan menggunakan CBOR berkanun (§3). Ditulis ke storan kekal. Inilah artifak atas-rantai.
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 (Keadaan Aplikasi Pembaca)
Tidak disirikan kepada CBOR. Tempatan pada aplikasi pembaca. Dibina selepas penyahsulitan dan pengesahan berjaya.
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 — dibawa ke hadapan daripada QubEnvelope.outcome_at / SealedQub.outcome_at; memacu blok pemerhatian-keputusan halaman pendedahan (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. Profil CBOR Berkanun
Semua pensirian SealedQub dan QubEnvelope MUST mematuhi profil ini. Dua implementasi yang diberikan struktur logik yang sama MUST menghasilkan bait yang serupa.
3.1 Peraturan Pengekodan
| Peraturan | Spesifikasi |
|---|---|
| Piawai | RFC 8949 §4.2.1 (Core Deterministic Encoding Requirements) |
| Susunan kunci peta | Diisih mengikut panjang bait terkod dahulu (yang lebih pendek didahulukan), kemudian secara leksikografi (bait demi bait untuk pengekodan panjang yang sama) |
| Pengekodan integer | Bentuk terpendek: 0–23 dalam bait awal; 24–255 dalam 2 bait; 256–65535 dalam 3 bait; dsb. |
| Pengekodan panjang | Panjang tentu sahaja. Tiada tatasusunan, peta, rentetan bait, atau rentetan teks panjang tak tentu (maklumat tambahan = 31 adalah dilarang). |
| Tag | Tiada tag CBOR (jenis utama 6 adalah dilarang). |
| Titik apungan | Tiada apungan (nilai jenis utama 7 0xF9–0xFB adalah dilarang). |
| Rentetan teks | Dikod UTF-8, dinormalkan NFC (Unicode Normalization Form C). |
| Rentetan bait | Bait mentah. Tiada pengekodan base64 pada lapisan CBOR. |
| Kunci pendua | Tolak dengan ralat. Penghurai MUST NOT menerima kunci peta pendua secara senyap. |
| Nilai mudah | Hanya true (0xF5), false (0xF4), dan null (0xF6) dibenarkan. |
| Medan pilihan | Medan pilihan yang tiada diabaikan daripada peta CBOR sepenuhnya (tidak dikodkan sebagai null). Medan pilihan yang hadir dimasukkan mengikut susunan kunci yang diisih. |
3.2 Susunan Kunci Berkanun yang Disahkan
Susunan kunci ini bersifat normatif. Implementasi MUST mengeluarkan kunci dalam susunan yang tepat ini. Penegasan nyahpepijat SHOULD mengesahkan susunan dalam binaan bukan-keluaran.
QubEnvelope (versi 0x01, tanpa tandatangan, semua medan pilihan tiada):
"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)
Derivasi susunan kunci QubEnvelope: setiap kunci ialah rentetan teks CBOR. Panjang terkod = 1 bait pengepala + panjang rentetan (untuk rentetan di bawah 24 bait). Diisih mengikut jumlah panjang terkod dahulu, kemudian secara leksikografi bagi kunci panjang yang sama.
SealedQub (versi 0x01, awam, tiada penerima):
"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 (badan perjanjian, 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 (baris tatasusunan terms):
"key" (4 encoded bytes)
"value" (6 encoded bytes)
PartyIdentifier (peta party_a / party_b):
"label" (6 encoded bytes)
"contact" (8 encoded bytes) ← only if present
3.3 Rujukan Pengekodan Bait
| Jenis | Pengekodan CBOR | Contoh |
|---|---|---|
| Cincang SHA3-256 (32 bait) | 0x58 0x20 + 32 bait |
body_hash, qub_id |
| Cap masa (i64) | Jenis utama 0 (positif) atau 1 (negatif), pengekodan terpendek | saat Unix |
| Versi (u8, nilai 1) | 0x01 (bait tunggal) |
|
| Jenis kandungan (u8, nilai 1) | 0x01 (bait tunggal) |
|
| sig_alg (u8, nilai 0) | 0x00 (bait tunggal) |
|
| Tandatangan ML-DSA-65 (3,309 bait) | 0x59 0x0C 0xED + 3,309 bait |
author_signature, cosigner_signature |
| Kunci awam ML-DSA-65 (1,952 bait) | 0x59 0x07 0xA0 + 1,952 bait |
author_pubkey, cosigner_pubkey |
4. Derivasi Normatif
4.1 qub_id
qub_id mengenal pasti qub secara unik dan mengikat QubEnvelope kepada SealedQub. Ia diterbitkan secara deterministik daripada kandungan envelope.
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
Pengekodan pemisah domain: Rentetan "QUB_ID_V2" ialah 9 bait ASCII. Satu bait pelapik 0x00 ditambah untuk mencapai 10 bait bagi penjajaran. Implementasi MUST menggunakan tepat 10 bait ini: [0x51, 0x55, 0x42, 0x5F, 0x49, 0x44, 0x5F, 0x56, 0x32, 0x00].
Pengekodan outcome_at: V1.1 melanjutkan praimej daripada 92 kepada 100 bait untuk melipat medan outcome_at pilihan ke dalam ikatan. outcome_at yang tiada dikod sebagai 8 bait sifar; pengesah protokol menolak outcome_at <= 0 di mana-mana sahaja, jadi sentinel ini tidak boleh berlanggar dengan nilai yang sah. Lihat §3.2 (format wayar) dan tasks/verdict-uplift-plan.md dalam pokok untuk mekanik verdik yang mendorong medan ini.
Pengekodan drand_round: V1.2 melanjutkan praimej daripada 100 kepada 108 bait untuk melipat drand_round (pusingan drand sasaran, §4.3) ke dalam ikatan, dan menaikkan pemisah domain kepada QUB_ID_V2. Ini mengikat pusingan timelock ke dalam identiti qub: pintu masuk tidak boleh mengikat semula siferteks kepada pusingan yang berbeza (cth., yang sudah berlalu) daripada apa yang disiratkan oleh unlock_at yang dipaparkan. Prosedur buka kunci (§8) selanjutnya mengesahkan bahawa pusingan yang dibakar ke dalam stanza siferteks tlock sepadan dengan unlock_round(unlock_at), jadi masa buka kunci yang dipaparkan terbukti ialah pusingan yang mengawal penyahsulitan.
Sifat:
- Mengubah mana-mana medan dalam QubEnvelope (badan, cap masa, jenis kandungan, versi) menghasilkan qub_id yang berbeza.
- qub_id dikira sebelum penyulitan. Kedua-dua QubEnvelope dan SealedQub membawa qub_id yang sama. Pembaca mengesahkan ia sepadan selepas penyahsulitan.
- qub_id tidak bergantung pada
sender_label,author_signature, atauauthor_pubkey. Ini bermakna kandungan yang sama yang dimeterai pada masa yang sama menghasilkan qub_id yang sama tanpa mengira siapa yang menandatanganinya. - Mengubah
titleSealedQub (dengan segala-galanya tetap) mengubahqub_idmelaluititle_hash. Oleh itu, pintu masuk tidak boleh menukar tajuk teks biasa yang dipaparkan pada hitung mundur tanpa membatalkan identiti qub. - Mengubah
outcome_atSealedQub (dengan segala-galanya tetap) mengubahqub_idmelalui praimej. Pintu masuk tidak boleh menukar tarikh verdik-pada pra-pendedahan yang dipaparkan pada hitung mundur tanpa membatalkan identiti qub. - Mengubah
drand_round(dengan segala-galanya tetap) mengubahqub_idmelalui praimej. Pintu masuk tidak boleh mengikat semula siferteks timelock kepada pusingan yang berbeza tanpa membatalkan identiti qub; digabungkan dengan semakan stanza-pusingan masa-buka-kunci §8,unlock_atyang dipaparkan ialah pusingan yang sebenarnya mengawal penyahsulitan.
4.2 body_hash
body_hash = SHA3-256(body)
Di mana body ialah muatan kandungan Vec<u8> mentah. Untuk qub teks, ini ialah badan qub yang dikod UTF-8.
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
Di mana title ialah tajuk teks biasa pilihan yang dipaparkan pada hitung mundur pembaca sebelum pendedahan (lihat §3.2). Penormalan NFC dijalankan pada masa pencincangan supaya cernaan stabil merentas urutan titik kod yang setara secara visual. Sentinel sifar-semua dikhaskan untuk kes tiada; rentetan kosong ditolak pada sempadan CBOR berkanun sebagai pengekodan bukan-berkanun bagi "tiada" (pengekodan berkanun mengabaikan medan sepenuhnya).
4.3 Pemetaan Pusingan-Buka-Kunci
drand_round = ceil((unlock_at - chain_genesis_time) / chain_period_seconds)
| Parameter | Sumber | Contoh |
|---|---|---|
unlock_at |
Saat Unix UTC yang dipilih pengguna | 1735689600 (2025-01-01 00:00:00 UTC) |
chain_genesis_time |
maklumat rantai drand (genesis_time) |
1595431050 |
chain_period_seconds |
maklumat rantai drand (period) |
30 |
Operasi ceil() memilih pusingan drand pertama yang masa pendedahannya ≥ unlock_at. Ini memastikan qub tidak menjadi boleh dinyahsulit sebelum masa buka kunci yang dipilih.
Kes pinggir: jika (unlock_at - chain_genesis_time) boleh dibahagikan tepat dengan chain_period_seconds, hasilnya ialah pusingan tepat itu — qub buka kunci tepat pada masa pendedahan pusingan itu.
Pengesahan: unlock_at MUST berada pada masa hadapan pada masa pemeteraian. unlock_at MUST NOT lebih daripada 10 tahun daripada created_at (untuk mengehadkan risiko kebergantungan drand jangka panjang; UI SHOULD memberi amaran untuk tarikh buka kunci melebihi 2 tahun).
5. Jenis Baharu Format Wayar
Jenis baharu format wayar menyediakan keselamatan masa-kompilasi terhadap mengelirukan bait CBOR dengan JSON, teks biasa mentah, atau pengekodan bait lain.
| Jenis | Mengandungi | Dihasilkan Oleh | Digunakan Oleh |
|---|---|---|---|
SealedQubCbor |
CBOR berkanun bagi SealedQub | serialize_sealed_qub() |
Muat naik storan kekal, ambilan pembaca |
QubEnvelopeCbor |
CBOR berkanun bagi QubEnvelope | serialize_qub_envelope() |
Input penyulitan tlock, output penyahsulitan tlock |
5.1 Peraturan Pembinaan
// 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 Pengesahan pada Pembinaan
from_encoded() SHOULD mengesahkan bahawa input bermula dengan pengepala peta CBOR yang sah. Pengesahan struktur penuh berlaku pada masa hurai, bukan masa pembinaan, untuk mengelakkan hurai-dua-kali.
6. Pendaftaran Jenis Kandungan
| Nilai | Jenis | Saiz Badan Maks | Nota |
|---|---|---|---|
0x00 |
Dikhaskan (tidak sah) | — | MUST NOT digunakan |
0x01 |
Teks biasa (UTF-8, Markdown terhad) | 50 KB berbayar / 10 KB percuma | Lihat §10 untuk peraturan pemaparan. Pemisahan percuma / berbayar dikuatkuasakan oleh perkhidmatan muat naik; siling keras lapisan protokol ialah 50 KB. |
0x02 |
Dikhaskan (masa depan) | — | Diperuntukkan untuk jenis kandungan masa depan; tidak sah dalam v1. Pembaca MUST menolak mengikut peraturan di bawah. |
0x03 |
Perjanjian (perjanjian dwihala, badan CBOR) | 100 KB | Badan ialah CBOR berkanun PactTerms (§6.1). Tandatangan bersama mengikut §9.7. |
0x04 |
Keputusan (penilaian-diri pencipta, badan CBOR) | 8 KB | Badan ialah CBOR berkanun VerdictBody (§6.2). Dikeluarkan hanya oleh hasrat sisi-sistem verdict. Hubungan induk berada pada tag Arweave Parent-Tx-Id, bukan pada badan. Lihat verdict-uplift-plan §3.4. |
Pembaca MUST menolak jenis kandungan yang tidak dikenali dengan ralat yang jelas kelihatan kepada pengguna. Pembaca MUST NOT cuba memaparkan jenis yang tidak dikenali sebagai teks.
6.1 Badan Perjanjian (content_type = 0x03)
Badan perjanjian ialah pengekodan CBOR berkanun bagi nilai PactTerms:
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)> }
Susunan kunci CBOR berkanun untuk ketiga-tiga peta diberikan dalam §3.2. Jumlah CBOR perjanjian yang disirikan MUST NOT melebihi 100 KB (sepadan dengan §6).
Pembeza skema. Baris pertama dalam terms untuk perjanjian structured/v1 MUST ialah { key: "pact_schema", value: "structured/v1" }. Baris tanpa penanda ini ialah perjanjian "tersuai" dan tidak menerima pengesahan berstruktur atau pemaparan sedar-skema.
Slot pengakuan yang dibekukan. Perjanjian structured/v1 membawa tepat empat baris pengakuan di bawah kunci berikut:
"initiator_standard_terms"
"initiator_capacity_terms"
"counterparty_standard_terms"
"counterparty_capacity_terms"
Nilai value bagi setiap satu ialah salah satu daripada lapan rentetan Inggeris dibekukan yang dipilih oleh pasangan (role, kind), di mana role ∈ { seller, buyer, provider, client } dan kind ∈ { standard, capacity }. Rentetan itu sendiri ialah data protokol normatif — tandatangan ML-DSA-65 kedua-dua pihak komited kepada bait yang tepat melalui body_hash. Ia TIDAK dilokalkan; badan yang ditandatangani bersifat neutral-bahasa. Apa-apa perubahan kata-kata memerlukan versi skema baharu (structured/v2).
Lapan rentetan, carian (acknowledgement_for(role, kind)), dan rasional bagi setiap satu disematkan oleh implementasi rujukan. Implementasi yang mematuhi MUST mengeluarkan nilai pengakuan yang serupa bait-demi-bait; ujian body-cincangan SHA3-256 lekapan-emas yang meliputi keempat-empat kombinasi peranan menangkap apa-apa hanyutan.
Susunan paparan pembaca. Rentetan pengakuan mengandungi frasa seperti "described above", yang menganggap baris penerangan / skop dipaparkan sebelum pengakuan. Pembaca MUST memaparkan tatasusunan terms dalam susunan CBOR; menyusun semula merosakkan semantik prosa.
Hubungan Pihak Lawan. Apabila contact Pihak B ialah alamat e-mel yang sah, perkhidmatan muat naik qub menghantar e-mel jemputan semakan / tandatangan bersama secara automatik pada masa pementasan dan mengikat tandatangan bersama akhirnya kepada pengesahan alamat yang sama itu (§9.7). Perjanjian yang contact Pihak B-nya tiada masih boleh ditandatangani bersama, tetapi hanya melalui saluran luar-jalur — perkhidmatan menolak permintaan tandatangan bersama yang tidak boleh menghasilkan penanda pengesahan-e-mel 15 minit yang sepadan.
6.2 Badan Keputusan (content_type = 0x04)
Badan keputusan ialah pengekodan CBOR berkanun bagi nilai VerdictBody:
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
}
Susunan kunci CBOR berkanun:
"outcome" (8 encoded bytes)
"reflection" (11 encoded bytes) ← only if present
"evidence_url" (13 encoded bytes) ← only if present
"verdict_version" (16 encoded bytes)
Jumlah CBOR keputusan yang disirikan MUST NOT melebihi 8 KB (sepadan dengan baris pendaftaran di atas).
Enum keputusan. Bait wayar bersifat hasrat-neutral; keempat-empat kategori Right / Partial / Wrong / Unfalsifiable meliputi ruang keputusan setiap hasrat yang membawa keputusan. Label setiap-hasrat ("Tepat sasaran" / "Saya menunaikannya" / "Dikeluarkan" / "Disahkan" untuk Right, dsb.) ialah kebimbangan pemaparan sisi-pembaca yang diselesaikan terhadap hasrat qub induk — wayar kekal neutral-bahasa dan neutral-hasrat. Nilai di luar 1..=4 MUST ditolak pada penyahkodan.
Pautan induk. Sebuah qub keputusan TIDAK membawa rujukan induk dalam badannya. Id transaksi Arweave qub induk dikeluarkan sebagai tag storan Parent-Tx-Id pada masa muat naik (§7 lapisan tag storan). Ini mengekalkan badan sebagai pernyataan penilaian-diri yang ditandatangani dan serba lengkap; rantai audit ("betul tentang apa?") ditubuhkan melalui carian tag Arweave.
Keselamatan URL bukti (normatif). Apabila evidence_url hadir, pengesah (sisi-karang, sisi-wayar, edge Worker) MUST menguatkuasakan:
- HTTPS sahaja. Rentetan MUST bermula dengan urutan bait
https://. Apa-apa skema lain —http,ftp,javascript,data,file, dsb. — ditolak. - Had panjang. ≤ 2,048 bait (had praktikal URL pelayar).
- Pemeriksaan NFC + kod-titik bermusuhan. Peraturan yang sama seperti
titledanreflection— kod-titik bidi-override / lebar-sifar / blok-tag / BOM / C0 / C1 ditolak. Definisi sepadan dengan Rustcrate::handle::contains_hostile_text_codepointdan TSworkers/api/src/utils/unicode.ts::isHostileCodepoint(kekalkan selari). - Tiada ruang putih, tiada kawalan ASCII. Ruang putih / DEL / bait di bawah
0x20di mana-mana dalam URL ditolak — menutup vektor suntikan\n/\tyang tidak diliputi peraturan bidi. - Segmen hos tidak kosong. Semua yang berada di antara
https://dan/,?, atau#yang pertama MUST tidak kosong.
Tiada pengambilan sisi-pelayan. Worker MUST NOT memproksi, mengambil, atau pratonton URL. Protokol menyimpan rentetan; pemaparan berlaku sisi-pembaca dengan rel="nofollow noopener noreferrer" target="_blank" dan hos yang kelihatan dipaparkan bersebelahan teks pautan.
Refleksi. Teks refleksi tulisan-pencipta pilihan ("apa yang berubah, apa yang anda pelajari"). Pengesahan NFC + kod-titik bermusuhan yang sama seperti title. Input kosong / hanya ruang putih menguncup kepada tiada pada masa pembinaan.
Versi skema. v1 menyokong verdict_version = 0x01 sahaja. Semakan skema masa depan menaikkan bait ini dan tiba bersama versi protokol baharu mengikut §12.
7. Protokol Meterai
Urutan pemeteraian lengkap. Setiap langkah bersifat normatif.
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.
Lapisan tag storan (luar-jalur). Perkhidmatan muat naik qub melampirkan satu set tag transaksi storan yang sengaja kecil di sebelah muatan terbalut. Content-Type=application/octet-stream diperlukan secara normatif. Perkhidmatan rujukan juga melampirkan tiga tag pilihan apabila pencipta memilih untuk memaparkannya: Intent (niat penggubahan disahkan-senarai dibenarkan — cth., quote, reply, commitment), Author (cap jari kunci awam §9.3 pencipta sebagai heks huruf kecil 64-aksara), dan Parent-Tx-Id (ID transaksi storan qub induk untuk rantai balas, base64url 43-aksara).
Tag Author adalah pilih-masuk setiap qub: aplikasi pencipta rujukan melampirkannya hanya apabila pengguna mendayakan atribusi awam secara eksplisit pada masa pemeteraian. Apabila togol mati — lalai — tiada tag Author ditulis dan qub tidak dikaitkan pada rantai: tiada apa-apa dalam storan kekal yang menghubungkan muat naik kepada pemegang, e-mel, atau qub lain pencipta. Apabila togol hidup, cap jari Author menyelesaikan kepada @handle yang dipilih pencipta melalui rantai pengesahan §9.5. Hubungan rantai-balas dan Intent tidak mengenal pasti. Pembungkus luar (§13) melindungi badan dalaman daripada korelasi siferteks — menghalang penuai daripada mengenali dan menyahsulit secara pukal muat naik berbentuk qub selepas pusingan drand mereka diterbitkan.
Perkhidmatan rujukan sengaja TIDAK melampirkan tag App-Name, App-Version, atau Type: apa-apa penapis bernilai-tunggal sebegini akan mengembalikan keseluruhan korpus qub kepada pertanyaan GraphQL, yang tidak konsisten dengan skop kerahsiaan badan-sahaja pembungkus.
Pengesah yang mematuhi MUST NOT bergantung pada apa-apa tag storan untuk pengesahan pihak-ketiga §11; cincang badan / qub_id / tandatangan komited hanya kepada CBOR dalaman, tidak pernah kepada set tag.
8. Protokol Buka Kunci
Urutan buka kunci lengkap. Setiap langkah bersifat normatif.
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. Tandatangan Pengarang
9.1 Rasional
qub disimpan dalam storan kekal. Tandatangan pengarang mesti kekal tidak boleh dipalsukan selama-lamanya, sebab itulah v1.0 menggunakan skema ML-DSA-65 pasca-kuantum (FIPS 204) berbanding skema klasik yang keselamatannya boleh merosot dalam hayat kekal qub.
9.2 Pendaftaran Algoritma
sig_alg |
Skema | Saiz Kunci | Saiz Tandatangan |
|---|---|---|---|
0x00 |
Tiada tandatangan (tanpa tandatangan) | — | — |
0x01 |
ML-DSA-65 (FIPS 204) | 1,952 bait | 3,309 bait |
Pembaca MUST menolak nilai sig_alg yang tidak dikenali.
9.3 Pembinaan Praimej Bertandatangan
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)
Pemisah domain: "QUB_AUTHOR_SIG_V1" ialah 17 bait ASCII: [0x51, 0x55, 0x42, 0x5F, 0x41, 0x55, 0x54, 0x48, 0x4F, 0x52, 0x5F, 0x53, 0x49, 0x47, 0x5F, 0x56, 0x31]. Tiada pelapik.
Bait belakang: bait praimej ke-91 MUST ialah 0x00. Implementasi rujukan mendedahkan ini sebagai pemalar ORG_ID_PRESENT_INDIVIDUAL = 0x00 dalam crates/qub-core/src/signing.rs; pembaca yang membina semula sig_input untuk pengesahan MUST mengeluarkan bait yang sama.
Skop tandatangan — apa yang diliputi dan apa yang tidak. sig_input komited kepada empat medan envelope: version, qub_id, body_hash, unlock_at (tambah pemisah domain tetap dan bait org_id_present). Tiga daripada empat itu ialah invarian struktur: qub_id itu sendiri diterbitkan daripada version, content_type, created_at, unlock_at, outcome_at, drand_round, dan body_hash melalui praimej §4.1, jadi apa-apa perubahan kepada medan-medan itu menghasilkan qub_id yang berbeza dan membatalkan tandatangan secara transitif. Permukaan yang disahkan secara langsung dengan itu ialah:
| Medan | Disahkan oleh tandatangan | Bagaimana |
|---|---|---|
version |
✓ | Input langsung kepada sig_input |
qub_id |
✓ | Input langsung |
body_hash |
✓ | Input langsung |
unlock_at |
✓ | Input langsung |
content_type |
✓ | Secara transitif, melalui praimej qub_id |
created_at |
✓ | Secara transitif, melalui praimej qub_id |
outcome_at |
✓ | Secara transitif, melalui praimej qub_id |
drand_round |
✓ | Secara transitif, melalui praimej qub_id (V1.2) |
body |
✓ | Secara transitif, melalui body_hash = SHA3-256(body) |
author_pubkey |
— (tersirat) | Kunci yang mengesahkan tandatangan ialah pengarang, secara takrif |
sender_label |
✗ | Teks paparan-sahaja; boleh diubah tanpa kerosakan tandatangan |
reply_to |
✗ | Penunjuk benang; boleh diubah tanpa kerosakan tandatangan |
cosigner_pubkey / cosigner_signature |
— | Ditandatangani secara bebas pada sig_input yang sama (lihat §9.7) |
drand_chain_id, tlock_ciphertext, visibility |
— | Medan SealedQub luaran, bukan di dalam envelope — diliputi oleh invarian struktur mereka sendiri (konsistensi pusingan / rantai) tetapi bukan oleh tandatangan pengarang. (drand_round kini diikat secara transitif melalui praimej qub_id — lihat di atas.) |
Implikasi keselamatan medan tidak-disahkan.
- Pihak yang mempunyai akses tulis kepada bait yang disimpan boleh menukar
sender_label("Alice" → "Mallory") tanpa membatalkan tandatangan pengarang.author_pubkeydi dalam envelope kekal sebagai sauh identiti sebenar — pembaca MUST menerbitkan identiti paparan daripadaauthor_pubkey(melalui lapisan pengesahan §9.5) bukannya mempercayaisender_label. - Medan
reply_tojuga boleh disunting selepas-tandatangan. Oleh sebabqub_idialah dialamatkan-kandungan, penyerang tidak boleh menunjukreply_tokepada sasaran yang tidak wujud, tetapi mereka boleh secara senyap mengubah induk balasan kepada qub sedia ada yang berbeza.
Implementasi yang memaparkan sender_label atau reply_to kepada pengguna akhir MUST mempamerkan identiti yang disahkan (cap jari kunci awam, pengesahan) sebagai isyarat identiti utama, bukan label.
9.4 Prosedur Pengesahan
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."
Pengesahan tandatangan ialah operasi yang paling mahal (terutamanya ML-DSA-65). Ia SHOULD dilakukan selepas semua pemeriksaan yang lebih murah (cincang, qub_id, unlock_at) telah lulus.
9.5 Pengesahan Identiti
Pengesahan identiti — pemetaan author_pubkey kepada tuntutan identiti yang boleh dikenali manusia seperti pemegang qub, alamat e-mel, pemegang sosial, atau kelayakan passkey — ialah peningkatan progresif sisi-pembaca dan tidak diperlukan untuk pengesahan tandatangan. Pembaca yang menyelesaikan pengesahan kepada identiti paparan MUST menggunakan kekananan:
handle > email > social > fingerprint
Sandaran cap jari ialah heks huruf kecil bagi SHA3-256(author_pubkey); ia sentiasa tersedia untuk mana-mana qub bertandatangan. Pembaca MAY meringkaskannya untuk paparan — pembaca rujukan memaparkan qub: diikuti oleh empat bait pertama dan terakhir (qub:<8 hex>…<8 hex>).
Pengesah yang mematuhi boleh melengkapkan setiap pemeriksaan dalam §9.4 tanpa menghubungi API qub, tanpa apa-apa rangkaian melebihi storan kekal dan drand, dan tanpa apa-apa carian sisi-pelayan. Penyelesaian pengesahan ialah langkah terbaik-cuba yang berasingan yang dilakukan hanya selepas pengesahan tandatangan berjaya.
9.6 Kesan Saiz
| Ed25519 | ML-DSA-65 | |
|---|---|---|
| Tandatangan | 64 bait | 3,309 bait |
| Kunci awam | 32 bait | 1,952 bait |
| Jumlah setiap qub | 96 bait | 5,261 bait |
| Delta kos storan (pada ~$5/MB) | ~$0.0005 | ~$0.026 |
Untuk qub teks 500–2,000 bait, ML-DSA-65 kira-kira menggandakan tiga kali ganda saiz yang disimpan. Kos mutlak adalah boleh diabaikan.
9.7 Pengesahan Penandatangan Bersama (Perjanjian Dwihala Pakta)
Untuk perjanjian dwihala (content_type = 0x03), lapisan tandatangan kedua membuktikan kedua-dua pihak bersetuju dengan terma yang sama.
Medan envelope:
cosigner_pubkey: Kunci awam ML-DSA-65 penandatangan-balas (Pihak B).cosigner_signature: Tandatangan atassig_inputyang sama seperti pengarang (§9.3).
Kedua-dua medan MUST hadir bersama-sama atau kedua-duanya tiada. Jika tepat satu hadir, pembaca MUST melaporkan ralat integriti.
Prosedur pengesahan:
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."
Sifat:
- Penandatangan bersama menandatangani
sig_inputyang sama seperti pengarang — kedua-dua pihak komited kepadaqub_id,body_hash, danunlock_atyang sama. - Derivasi
qub_id(§4.1) TIDAK termasuk medan penandatangan bersama. Menambah penandatangan bersama kepada envelope sedia ada tidak mengubahqub_id. - Perjanjian boleh ditandatangani-pengarang sahaja (komitmen sebelah), penandatangan bersama sahaja (luar biasa), atau kedua-duanya (bukti dwihala penuh).
Pintu pengikatan-e-mel (operasi). Apabila perjanjian yang dipentaskan membawa hubungan e-mel Pihak B (§6.1), perkhidmatan muat naik qub MUST menolak permintaan tandatangan bersama melainkan penanda pengesahan-e-mel jangka pendek wujud yang sepadan dengan kedua-dua id pementasan dan cincang e-mel ternormal hubungan tersebut. Penanda itu ditulis oleh /api/v1/auth/verify apabila token pautan-ajaib membawa staging_id dan alamat yang disahkan sepadan dengan SHA-256(normalise_email(party_b.contact)) — di mana normalise_email(addr) mengekalkan kes bahagian-tempatan dan menurunkan huruf kecil hanya bahagian domain (mengikut RFC 5321 §2.3.11), dan SHA-256 di sini ialah cincang NIST FIPS 180-4 (berbeza daripada SHA3-256 yang digunakan dalam derivasi §4) — dan tamat tempoh 900 saat (15 minit) selepas dikeluarkan. Ini ialah pintu anti-penyamaran operasi, BUKAN sebahagian daripada bukti qub atas-rantai — pengesah pihak-ketiga yang memainkan semula §11 hanya memerlukan storan kekal dan drand, tanpa apa-apa carian sisi-pelayan. Penanda wujud sisi-pelayan sahaja dan tidak pernah menjadi sebahagian daripada badan yang ditandatangani.
Kesan saiz (pengarang ML-DSA-65 + penandatangan bersama):
| Komponen | Saiz |
|---|---|
| Tandatangan pengarang | 3,309 bait |
| Kunci awam pengarang | 1,952 bait |
| Tandatangan penandatangan bersama | 3,309 bait |
| Kunci awam penandatangan bersama | 1,952 bait |
| Jumlah overhed kripto | 10,522 bait |
| Delta kos storan | ~$0.05 |
10. Pemaparan dan Sanitasi Markdown
Bahagian ini kritikal keselamatan. Pembaca memaparkan qub teks (content_type = 0x01) menggunakan subset Markdown yang terhad.
10.1 Elemen Dibenarkan
- Pengepala:
#hingga####(tiada#####atau######) - Penekanan: tebal (
**), italik (*), garis-coret (~~) - Senarai: bertertib (
1.) dan tidak bertertib (-,*) - Petikan blok (
>) - Kod: rentang sebaris (```) dan blok berpagar (`````)
- Pemisah mendatar (
---) - Pemecah baris (dua ruang belakang atau baris kosong)
- Perenggan
10.2 Elemen Dilarang
| Elemen | Pengendalian |
|---|---|
HTML mentah (<div>, <script>, dsb.) |
Dibuang sepenuhnya. Tiada HTML melepasi. |
Imej () |
Dibuang. Sintaks imej dialih keluar daripada output. |
Pautan ([text](url)) |
URL dipaparkan sebagai teks biasa yang kelihatan. Tidak auto-pautkan. Tidak boleh diklik tanpa tindakan pengguna yang eksplisit. |
| Skema URL berbahaya | javascript:, data:, vbscript:, file: — dibuang. |
| Iframe, embed, objek | Dibuang. |
| Entiti HTML | Dinyahkod kepada aksara paparan hanya jika selamat. |
10.3 Implementasi
Implementasi MUST menggunakan penghurai senarai dibenarkan ketat, bukan senarai disekat. Pendekatan yang disyorkan:
- Hurai Markdown menggunakan
pulldown-cmark(atau setara). - Susuri AST dan buang mana-mana nod yang tidak dalam senarai dibenarkan (§10.1).
- Untuk nod pautan: keluarkan URL sebagai teks yang kelihatan, bukan sebagai elemen
<a>yang boleh diklik. - Tukarkan AST yang ditapis kepada perwakilan perantaraan bertaip (cth., enum
MarkdownNodedengan hanya varian selamat). HTML mentah tidak boleh diwakili secara struktur dalam IR ini. - Paparkan daripada IR bertaip kepada lapisan pandangan sasaran (cth., komponen pandangan reaktif, nod DOM). Tiada penyambungan rentetan HTML atau
innerHTMLpada bila-bila masa.
Pendekatan senarai disekat adalah rapuh kerana sambungan Markdown baharu atau keanehan penghurai boleh memperkenalkan elemen yang tidak ditapis. Pendekatan AST bertaip menjadikan XSS mustahil secara struktur — tiada varian yang boleh membawa HTML sewenang-wenangnya.
10.4 Had Saiz dan Struktur
- Kedalaman pengepala maksimum yang dipaparkan:
####(H4).#####dan lebih dalam dipaparkan sebagai teks tebal. - Tiada had bilangan perenggan (had saiz badan dalam §6 ialah kekangan).
- Blok kod berpagar: tiada penonjolan sintaks dalam MVP. Dipaparkan sebagai teks praformat monospace.
11. Pengesahan Pihak Ketiga
Mana-mana pihak ketiga boleh mengesahkan qub awam tanpa kerjasama qub. Prosedur pengesahan:
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.
Apa yang dibuktikan oleh pengesahan:
| Bukti | Apa yang ia tetapkan |
|---|---|
| Komitmen | Siferteks wujud menjelang cap masa blok storan. |
| Integriti | Badan teks biasa sepadan dengan cincang yang dikomited dan tidak diubah. |
| Pemasaan | Kandungan tidak boleh dibaca sehingga pusingan drand, yang sepadan dengan masa buka kunci yang dipilih (tertakluk kepada andaian keselamatan tlock dan drand). |
Apa yang TIDAK dibuktikan oleh pengesahan:
| Bukan-bukti | Mengapa |
|---|---|
| Pengarangan | sender_label bersifat hiasan. Tanpa sig_alg ≥ 0x01, sesiapa sahaja boleh meterai kandungan ini. |
| Niat | qub membuktikan kandungan dan pemasaan, bukan apa yang dimaksudkan pencipta secara subjektif. |
| Pemasaan pra-peristiwa | Kemasukan blok storan mungkin lewat muat naik sebenar dengan beberapa minit. Cap masa komitmen ialah masa blok, bukan saat pengguna menekan "meterai." |
12. Versi
12.1 Versi Protokol
Medan version (u8) dalam kedua-dua SealedQub dan QubEnvelope mengenal pasti versi protokol utama.
- Pembaca MUST menolak versi utama yang tidak dikenali dengan ralat yang jelas.
- Versi utama yang dikenali MAY bertolak ansur dengan medan pilihan yang tidak dikenali jika peraturan keserasian ke hadapan membenarkan (medan pilihan yang tiada daripada susunan kunci berkanun diabaikan).
- Jenis kandungan (
content_type) dan skema tandatangan (sig_alg) bersifat versi-berpintu: nilai baharu hanya boleh diperkenalkan bersama versi protokol baharu atau kemas kini pendaftaran yang eksplisit.
12.2 Sejarah Versi
| Versi | Nilai | Penerangan |
|---|---|---|
| v1 | 0x01 |
qub teks awam (content_type 0x01), badan perjanjian dwihala (0x03, skema structured/v1, pengarang + penandatangan bersama ML-DSA-65), tlock, SHA3-256 |
12.3 Keserasian Ke Hadapan
Pembaca v1 yang menjumpai QubEnvelope dengan kunci peta CBOR pilihan yang tidak dikenali (kunci yang tiada dalam susunan berkanun §3.2) SHOULD mengabaikan kunci tersebut dan teruskan dengan pengesahan menggunakan medan yang dikenali. Ini membolehkan penambahan kecil di masa hadapan (cth., metadata baharu) tanpa memerlukan tolakan versi utama.
Pembaca v1 yang menjumpai sig_alg = 0x01 (ML-DSA-65) tetapi kekurangan sokongan pengesahan ML-DSA-65 SHOULD memaparkan kandungan qub dengan notis "tandatangan hadir tetapi tidak boleh disahkan", bukannya menolak qub sepenuhnya. Implementasi rujukan hari ini menolak setiap nilai sig_alg selain daripada 0x00 dan 0x01 kerana pendaftaran v1 tidak mengandungi algoritma sah lain — penolakan ketat dan gagal-lembut adalah serupa dari segi pemerhatian sehingga algoritma ketiga didaftarkan. Tingkah laku gagal-lembut di atas menjadi memikul-beban sebaik sahaja §9.2 menerima entri baharu, dan pembaca rujukan akan dikemas kini kepada gagal-lembut pada ketika itu.
12.4 Versi Pembungkus Luar
OuterWrapper yang diterangkan dalam §13 membawa bait version-nya sendiri, bebas daripada SealedQub.version dan QubEnvelope.version. Kedua-dua ruang versi berkembang secara berasingan: penggantian simetrik selamat-pasca-kuantum pada masa hadapan menolak bait pembungkus tanpa menyentuh versi protokol dalaman, dan penambahan lapisan protokol pada masa hadapan (cth., medan envelope baharu) menolak versi dalaman tanpa menyentuh bait pembungkus.
OUTER_WRAPPER_VERSION_* |
Nilai | Algoritma | Status |
|---|---|---|---|
OUTER_WRAPPER_VERSION_1 |
0x01 |
AES-256-GCM dengan nonce 12-bait, tag pengesahan 16-bait, AAD terikat kepada qub_id |
lalai v1 |
| — | 0x02–0xFF |
Dikhaskan | Masa Hadapan |
Pembaca MUST menolak versi pembungkus yang tidak dikenali dengan ralat yang jelas. Protokol sengaja mengekalkan ruang versi pembungkus yang sempit sehingga pemacu migrasi konkrit muncul (cth., panduan NIST yang mengutamakan AEAD yang berbeza); slot 0x02 akan diperuntukkan dalam semakan yang sama yang memperkenalkan algoritma.
13. Pembungkus Penyulitan Luar
13.1 Rasional
Lapisan protokol (QubEnvelope → tlock → SealedQub) menjadikan qub yang dimeterai terkunci-waktu: badan tidak boleh dibaca sehingga unlock_at dan tandatangan pusingan drand telah diterbitkan. Walau bagaimanapun, selepas buka kunci, tandatangan pusingan adalah awam dan bentuk CBOR berkanun SealedQub boleh dikenali, jadi penuai yang mengindeks transaksi storan kekal boleh menyahsulit korpus qub keseluruhan secara pukal.
Pembungkus penyulitan luar menutup saluran itu dengan menyelitkan lapisan AEAD simetrik tambahan antara SealedQubCbor berkanun dan bait yang ditulis ke storan kekal. Kunci 256-bit K wujud hanya dalam fragmen URL pautan penghantaran dan pada peranti pengguna; pelayar tidak menghantar fragmen URL kepada pelayan, jadi qub.social, setiap pintu masuk storan, dan setiap CDN di hadapan kedua-duanya adalah buta dari segi pemerhatian terhadap K. Oleh itu, setiap qub dalam storan kekal ialah siferteks legap yang teks biasanya tidak boleh dipulihkan tanpa URL yang dipilih pencipta untuk dikongsi.
Kesan bersih:
- Imuniti penghitungan secara lalai. Bait terbungkus dalam storan kekal tidak boleh dibezakan bait-demi-bait daripada siferteks sewenang-wenangnya. Strategi penuai "pertanyaan-GraphQL untuk muat naik berbentuk-qub, nyahsulit pukal dengan tandatangan drand awam" tidak berakhir dengan teks biasa.
- Postur privasi kripto-pemusnahan. qub.social secara harfiah tidak boleh menyahsulit korpusnya sendiri. Sepina mencapai siferteks, bukan teks biasa.
- Tangga kerahsiaan dua-tahap. Lalai = akses dikawal-pautan (bahagian ini). qub peribadi yang disulitkan-penerima (ciri Fasa-2 yang dikhaskan, belum dispesifikasikan) berlapis di atas sebagai tahap kedua.
13.2 Berlapis
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)
Meterai dan buka kunci pada lapisan protokol (§7, §8) tidak berubah di bawah sempadan pembungkus; pembungkus dilekatkan pada laman panggilan seal() dan ditanggalkan pada laman panggilan unlock().
13.3 Struktur Data OuterWrapper
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
}
Invarian medan.
versionMUST bersamaan0x01untuk bait pembungkus v1.0.qub_idMUST bersamaan medanqub_idSealedQub yang dipulihkan selepas penyahbungkusan. Langkah penyahbungkusan tidak menguatkuasakan ini secara langsung (pengikatan AEAD AAD menjadikan usikan tahap-bait mustahil), tetapi lapisan buka kunci menyemak hubungan secara transitif: jika pencipta membungkusSealedQubCboryangqub_iddalamannya tidak sepadan denganqub_idpembungkus, §8 langkah 11 gagal.nonceMUST ialah 96 bit (12 bait), dihasilkan baharu oleh CSPRNG untuk setiap operasi pembungkusan. Menggunakan semula nonce di bawah kunci yang sama membenarkan serangan guna-semula-nonce AEAD yang memulihkan teks biasa; pengeluar MUST melayan pasangan (key,nonce) sebagai sekali-guna.ciphertextialah output AES-256-GCM: bait siferteks digabungkan dengan tag pengesahan 16-bait.ciphertext.len() == SealedQubCbor.len() + 16tepat.
Pengekodan CBOR. CBOR berkanun mengikut §3, dengan peraturan susunan-kunci yang sama (diisih mengikut panjang bait terkod menaik, kemudian secara leksikografi). Empat kunci tersebut ialah:
| Kunci | Bait terkod | Susunan |
|---|---|---|
nonce |
6 | 1 |
qub_id |
7 | 2 |
version |
8 | 3 |
ciphertext |
11 | 4 |
Bait pertama OuterWrapper CBOR oleh itu ialah pengepala peta panjang-tentu untuk peta 4-entri (0xA4).
13.4 Pengikatan AAD kepada qub_id
Pembungkus mengikat qub_id sebagai data pengesahan tambahan AEAD. Ini ialah pertahanan struktur yang memikul beban terhadap tiga kelas serangan:
| Serangan | Pertahanan |
|---|---|
Alih siferteks di bawah medan qub_id yang berbeza dalam pembungkus |
Ketidakpadanan AAD → pengesahan AEAD gagal |
| Campurkan fragmen URL qub A dengan bait storan kekal qub B | Ketidakpadanan AAD → pengesahan AEAD gagal |
Usik medan qub_id pembungkus selepas muat naik |
Ketidakpadanan AAD → pengesahan AEAD gagal |
Membawa qub_id dalam teks biasa pembungkus tidak melemahkan imuniti penghitungan dengan ketara — qub_id itu sendiri ialah cincang SHA3-256 bagi praimej §4.1 tanpa praimej boleh-pulih daripada cernaan, dan penghitung yang telah menuai bait pembungkus tidak belajar apa-apa daripada qub_id yang kelihatan yang tidak boleh disimpulkan daripada kewujudan muat naik itu sendiri.
13.5 Algoritma Bungkus dan Nyahbungkus
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
Keruntuhan mod-kegagalan. K yang salah, nonce yang salah, ketidakpadanan AAD, dan siferteks yang diusik semuanya menghasilkan ralat DECRYPT_FAILED yang sama. Ini ialah sifat AEAD yang disengajakan: membezakan mod kegagalan akan mencipta saluran sampingan yang penyerang jauh boleh siasat dengan menghantar pembungkus cacat dan mengetik tindak balas. Implementasi rujukan MUST meruntuhkan semua kegagalan AEAD kepada satu bentuk ralat.
13.6 Bahan Kunci dan Pengedaran
Kunci pembungkusan K ialah nilai rawak seragam 256-bit yang dihasilkan setiap-qub oleh CSPRNG. Implementasi rujukan mendapatkannya daripada:
- Pencipta WASM:
getrandom(WebCrypto di bawah belakangwasm_js). - Laluan meterai sisi-pelayan Worker:
crypto.getRandomValues.
Pengedaran: K MUST dikodkan sebagai base64 URL-selamat (RFC 4648 §5, tanpa pelapik) dan ditambah kepada pautan penghantaran sebagai komponen fragmen:
delivery_url = <origin>/c/<arweave_tx_id>#<base64url(K)>
Fragmen tidak pernah dihantar kepada mana-mana pelayan oleh pelayar yang mematuhi. Saluran pemulihan (indeks sejarah sisi-pelayan, hantar-auto e-mel pilih-masuk) yang mengekalkan pautan penghantaran penuh — termasuk fragmen — di luar peranti pengguna ialah pertukaran eksplisit terhadap postur kripto-pemusnahan lalai dan MUST dipintu pada persetujuan eksplisit pengguna.
Kehilangan fragmen. Jika pengguna kehilangan fragmen URL dan tiada saluran pemulihan, qub tidak boleh dibaca. Inilah pertukaran memikul-beban reka bentuk dan MUST didedahkan kepada pengguna pada masa pemeteraian. MVP mengukuhkan pendedahan masa-pemeteraian dengan salinan eksplisit "simpan URL ini" dan saluran pemulihan e-mel disahkan untuk pengguna yang pilih-masuk.
13.7 Di Luar Skop bagi Bahagian Ini
- Tandatangan pengarang (§9) tidak berubah: tandatangan dikira di dalam
QubEnvelopedalaman dan dipulihkan selepas nyahbungkus → nyahsulit tlock → hurai CBOR. - qub peribadi yang disulitkan-penerima (ciri Fasa-2 yang dikhaskan, belum dispesifikasikan) digubah di atas pembungkus ini sebagai tahap kerahsiaan kedua; kedua-dua tahap boleh aktif serentak.
- Perjanjian (§6, content_type
0x03) dibungkus dengan tepat seperti qub teks; pembungkus adalah buta-bait kepada jenis kandungan dalaman.
13.8 qub awam (peninggalan pembungkus)
Pembungkus luar bersifat pilihan pada lapisan penghantaran. Seorang pencipta boleh memeterai qub sebagai awam, dan dalam kes itu SealedQubCbor berkanun ditulis ke storan kekal secara langsung, tanpa lapisan OuterWrapper dan tanpa kunci K:
SealedQubCbor bytes ──(public)──▶ uploaded to permanent storage as-is
SealedQubCbor bytes ──(private)─▶ AES-256-GCM(K, …) ▶ OuterWrapper ▶ uploaded
Sebuah qub awam terkunci-waktu tetapi tidak berpintu-pautan: ia kekal tidak boleh dibaca sehingga pusingan drandnya diterbitkan (lapisan tlock tidak berubah), tetapi selepas buka kunci sesiapa sahaja yang mempunyai arweave_tx_id boleh menyahsulitnya — tiada fragmen URL diperlukan, kerana tiada K. Inilah pertukaran yang disengajakan untuk permukaan yang pelayan mesti pacu: e-mel pemberitahuan-pendedahan, sematan pihak-ketiga, dan SEO pasca-pendedahan yang lebih kaya semuanya memerlukan pautan yang berfungsi tanpa rahsia yang pelayan tidak pernah pegang (§13.6).
Akibat yang pengeluar MUST ambil kira:
- Tiada imuniti penghitungan. qub awam mengetepikan sifat imuniti-penghitungan §13.1 secara reka bentuk. Perkhidmatan muat naik rujukan mencap tag storan-kekal
Visibility: publicpadanya (dan hanya padanya) supaya ia sengaja boleh ditemui; qub peribadi tidak membawa tag sedemikian dan mengekalkan ketakbolehbezaan baitnya. - Tajuk teks biasa terdedah pada masa pemeteraian. Medan
title§3.2 ialah teks biasa di dalamSealedQubCbor. Di bawah pembungkus ia tersembunyi sehingga pembaca membekalkanK; tanpa pembungkus ia boleh dibaca seluruh dunia pada storan kekal dari saat muat naik, sebelum buka kunci. Aplikasi pencipta yang mematuhi MUST mendedahkan ini pada masa pemeteraian. - Pengesanan bersifat struktur. Pembaca/sematan yang mematuhi membezakan kedua-dua bentuk melalui hurai: bait yang dihurai sebagai
OuterWrappermengambil laluan nyahbungkus-dengan-K; bait yang dihurai sebagaiSealedQubCbortelanjang diterima secara langsung. Tiada bendera wayar diperlukan, danqub_idtidak mengikat keterlihatan — kandungan yang sama adalah serupa bait-demi-bait pada lapisanSealedQubsama ada dimeterai awam atau peribadi.
Peribadi (terbungkus) kekal sebagai lalai; awam ialah pilihan pencipta setiap-qub yang eksplisit.
14. Vektor Ujian
14.1 Derivasi qub_id
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
Implementasi MUST menghasilkan nilai body_hash dan qub_id yang serupa untuk input ini. Vektor ujian ini SHOULD menjadi ujian unit pertama yang ditulis. Nilai berkanun di atas dikira oleh implementasi rujukan dan MUST sepadan bit-demi-bit. Susun atur praimej sejarah (pra-pelancaran — tiada qub langsung bergantung pada nilai ini): qub_id V1.0 92-bait ialah 3d9fc2390eab043d38a1669ed3b71be76f9eefe872b9569ab1aaa027b88392b0; qub_id V1.1 100-bait (selepas melipat outcome_at_or_zero) ialah b0d032898ad629795150fdcb3f84e518f59ed05b7a2a82bc24ebdb87f52144ed. V1.2 melipat drand_round ke dalam dan menaikkan pemisah domain kepada QUB_ID_V2.
14.2 Pemetaan Pusingan-Buka-Kunci
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 Pergi-Balik CBOR Berkanun
Implementasi MUST mengesahkan bahawa serialize(parse(serialize(qub))) == serialize(qub) untuk semua input yang sah. Ini ialah ujian sifat, bukan vektor tunggal.
14.4 CBOR PactTerms (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)
Bait CBOR berkanun dan body_hash SHA3-256 dikira oleh implementasi rujukan. Implementasi MUST menghasilkan CBOR yang serupa bait-demi-bait untuk input ini.
Implementasi juga MUST mengesahkan bahawa serialize(parse(serialize(pact))) == serialize(pact) untuk semua input PactTerms yang sah (ujian sifat).
14.5 Vektor Silang-Bahasa Pembungkus Luar
Pembungkus luar (§13) mempunyai lekapan berkanun yang berasingan di crates/qub-core/tests/vectors/wrapper_v1.json. Setiap kes menetapkan tupel (key, nonce, qub_id, sealed_cbor) sebagai input heks legap dan menegaskan output expected_wrapper_hex tertentu. Kedua-dua implementasi rujukan menggunakan fail JSON yang sama:
- 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).
Lekapan tersebut kini menyemat tiga kes:
| Kes | Liputan |
|---|---|
basic-text-public |
Bentuk SealedQub realistik terkecil; tiada medan pilihan. Menetapkan bentuk pembungkus berkanun untuk qub tipikal-v1.0. |
with-recipient-pubkey |
SealedQub dengan recipient_pubkey ditetapkan (laluan Fasa 2). Set kunci CBOR dalaman yang berbeza, qub_id yang berbeza. |
longer-body |
Badan ~4 KiB — melatih awalan panjang CBOR pelbagai bait dalam kedua-dua envelope dalaman dan siferteks luar. |
Implementasi MUST menghasilkan expected_wrapper_hex yang serupa bait-demi-bait untuk input yang direkodkan. Penjanaan semula lekapan memerlukan QUB_REGEN_VECTORS=1 cargo test -p qub-core --test wrapper_vectors dan dikhaskan untuk perubahan format yang disengajakan.
15. Tadbir Urus Profil Kripto (Masa Hadapan)
Bahagian ini bersifat informatif untuk v1 dan menjadi normatif kali pertama algoritma kedua memasuki mana-mana primitif kriptografi qub.
15.1 Postur Semasa
Protokol v1 mengikat tepat satu algoritma setiap primitif:
- Tandatangan: ML-DSA-65 (
sig_alg = 0x01; kunci awam 1952-bait, tandatangan 3309-bait) dan tidak bertandatangan (sig_alg = 0x00). Pendaftaran §9.2 tidak menakrifkan nilai lain; pengesah v1 MUST menolak setiapsig_algdi luar{0x00, 0x01}. Entri Ed25519 masa depan dijangka (§15.3) tetapi tidak diperuntukkan dalam v1. - Kunci masa: quicknet drand sahaja — cincang rantai, kunci awam, masa genesis, dan tempoh ialah parameter rangkaian tetap yang dibawa oleh rujukan
DrandTimelockProvider::quicknet()(crates/qub-core/src/tlock.rs) danconfig/drand-endpoints.json. - Pembungkus luar: AES-256-GCM v1 sahaja (§13).
Pengesah kini mengekodkan-keras panjang kunci dan tandatangan setiap primitif. Tiada permukaan kelincahan didedahkan oleh format wayar.
15.2 Bentuk yang Dimaksudkan
Apabila algoritma kedua memasuki protokol, pengesah akan dikonfigurasi untuk CryptoProfile bernama (cth., ExqubV1) yang menyenaraikan set tepat nilai dibenarkan setiap primitif — sig_alg, rantai drand, versi pembungkus, jenis kandungan. Profil ditetapkan pada masa pengesahan, tidak pernah dirunding dalam-jalur. Apa-apa nilai di luar profil aktif ditolak.
Ini menjamin bahawa menambah ML-DSA-87 atau mengaktifkan Ed25519 tidak boleh secara retroaktif melemahkan konfigurasi pengesah sedia ada: pengesah v1 kekal sebagai pengesah v1 walaupun selepas profil v2 diterbitkan.
15.3 Syarat Pencetus
Naikkan §15 kepada status normatif apabila mana-mana yang berikut dicadangkan:
- Bait
sig_algkedua (pengaktifan Ed25519, ML-DSA-87, atau apa-apa entri baharu dalam pendaftaran §9). - Rantai drand kedua dalam penggunaan pengeluaran.
- Versi pembungkus-luar kedua.
Sehingga itu §15 ialah pemegang tempat yang menetapkan bentuk migrasi supaya PR masa hadapan mendarat terhadap sasaran yang diketahui dan bukannya bertikai semula permukaan rundingan dari awal.