qub Protokol Spesifikasyonu
qub, kriptografik zamansal taahhütler için bir protokoldür: sözleri gelecekteki bir tarihe mühürlemek ve o tarih geldiğinde tam olarak ne söylendiğini ve ne zaman söylendiğini kanıtlamak için bir sistem.
Bunu mümkün kılan üç ilkel öğe vardır. drand, merkezsiz bir rastgelelik işaretçisidir — açıklama tarihi herhangi bir tarafın iyi niyetiyle değil, fizik tarafından uygulanır. Kalıcı herkese açık depolama, kurcalanamaz bir kamu deposudur — bir qub mühürlendikten sonra hiçbir taraf onu düzenleyemez veya silemez. ML-DSA-65, post-kuantum bir dijital imzadır — her qub, gizli anahtarı yazarın cihazından asla çıkmayan bir anahtar çiftine bağlıdır.
Bu ilkel öğeler birlikte, zamana kilitli, kurcalama kanıtlı ve atfedilebilir bir ifade oluşturur — dünyanın geçmişi uydurma yeteneği geliştikçe değeri artan bir makbuz.
Bu belgenin geri kalanı, birlikte çalışabilir uygulamalar için gerekli olan normatif spesifikasyondur.
qub Protokol Spesifikasyonu
| Alan | Değer |
|---|---|
| Sürüm | 1.0 (protokol sürümü 0x01, dış sarmalayıcı sürümü 0x01) |
| Tarih | 2026-05-01 |
| Durum | Taslak |
| İncelendiği tarih | 2026-05-01 |
Bu belge, qub zamanlı taahhüt sistemi için normatif protokol spesifikasyonudur. Birlikte çalışabilir uygulamalar için gerekli olan veri yapılarını, serileştirme kurallarını, türetme formüllerini ve doğrulama prosedürlerini tanımlar.
Kapsam: protokol katmanı kasıtlı olarak dilden bağımsızdır — qub gövdesi opak düz metin / markdown / pakt baytlarıdır ve yerel ayarlara duyarlı sunum izleyicinin sorumluluğundadır (qub.social web uygulaması, <qub-embed> iframe'i, MCP istemcileri, vb.).
1. Gösterim ve sözleşmeler
| Gösterim | Anlam |
|---|---|
u8, u64, i64 |
Belirtilen bit genişliğinde işaretsiz/işaretli tam sayılar |
[u8; N] |
N bayttan oluşan sabit uzunluklu bayt dizisi |
Vec<u8> |
Değişken uzunluklu bayt dizisi |
Option<T> |
T türünde değer veya yok |
String |
UTF-8 metin dizesi, NFC normalleştirilmiş |
| ` | |
SHA3-256(x) |
x bayt dizisinin NIST SHA3-256 özeti (FIPS 202) |
ceil(x) |
Tavan fonksiyonu: x'ten büyük veya eşit en küçük tam sayı |
| CBOR | Concise Binary Object Representation (RFC 8949) |
| big-endian | En anlamlı bayt önce |
Ön görüntü yapılarındaki tüm tam sayılar, aksi belirtilmedikçe big-endian sabit genişlikli bayt dizileri olarak kodlanır (i64 → 8 bayt, u8 → 1 bayt).
Tüm zaman damgaları UTC cinsinden Unix saniyeleridir.
2. Veri yapıları
2.1 ComposeQub (Yaratıcının bellek içi durumu)
CBOR'a serileştirilmez. Kalıcı depolamada saklanmaz. Yaratıcı uygulamasına yereldir.
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 (Şifresi çözülmüş yük)
Kanonik CBOR (§3) kullanılarak serileştirilir. SealedQub içinde şifrelenir. Bu, şifre çözüldükten sonra içerik bütünlüğünü kanıtlayan yapıdır.
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
}
Temel hat (imzasız metin qub): version = 0x01, content_type = 0x01, sig_alg = 0x00, tüm Option alanları yok.
Diğer v1 yapılandırmaları: content_type = 0x03 (pakt gövdesi, bkz. §6.1); author_signature ve author_pubkey mevcut olarak sig_alg = 0x01 (ML-DSA-65) (bkz. §9.3); birlikte imzalanan paktlar için cosigner_pubkey ve cosigner_signature birlikte mevcut (bkz. §9.7); yanıt zinciri qub'ları için reply_to, üst qub'un qub_id'sine ayarlanır (imza kapsamı sonuçları için bkz. §9.3).
2.3 SealedQub (Kanonik aktarım biçimi)
Kanonik CBOR (§3) kullanılarak serileştirilir. Kalıcı depolamaya yazılır. Bu, zincir üzerindeki artefakttır.
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 (İzleyici uygulama durumu)
CBOR'a serileştirilmez. İzleyici uygulamasına yereldir. Başarılı şifre çözme ve doğrulamadan sonra inşa edilir.
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 — QubEnvelope.outcome_at / SealedQub.outcome_at'tan taşınır; açıklama sayfasındaki karar-izleme bloğunu sürer (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. Kanonik CBOR profili
Tüm SealedQub ve QubEnvelope serileştirme bu profille uyumlu OLMALIDIR. Aynı mantıksal yapı verildiğinde iki uygulama aynı baytları üretmek ZORUNDADIR.
3.1 Kodlama kuralları
| Kural | Spesifikasyon |
|---|---|
| Standart | RFC 8949 §4.2.1 (Çekirdek Deterministik Kodlama Gereksinimleri) |
| Harita anahtarı sıralaması | Önce kodlanmış bayt uzunluğuna göre sıralanır (kısa olan önce gelir), sonra sözlüksel olarak (aynı uzunluktaki kodlamalar için bayt bayt) |
| Tam sayı kodlaması | En kısa biçim: ilk baytta 0–23; 2 baytta 24–255; 3 baytta 256–65535; vb. |
| Uzunluk kodlaması | Yalnızca kesin uzunluklar. Belirsiz uzunluklu diziler, haritalar, bayt dizileri veya metin dizeleri yoktur (ek bilgi = 31 yasaktır). |
| Etiketler | CBOR etiketi yoktur (ana tür 6 yasaktır). |
| Kayan nokta | Kayan nokta yoktur (ana tür 7, 0xF9–0xFB değerleri yasaktır). |
| Metin dizeleri | UTF-8 kodlamalı, NFC normalleştirilmiş (Unicode Normalleştirme Formu C). |
| Bayt dizeleri | Ham baytlar. CBOR katmanında base64 kodlaması yoktur. |
| Yinelenen anahtarlar | Hata ile reddet. Ayrıştırıcılar yinelenen harita anahtarlarını sessizce kabul ETMEMELİDİR. |
| Basit değerler | Yalnızca true (0xF5), false (0xF4) ve null (0xF6) izin verilir. |
| İsteğe bağlı alanlar | Mevcut olmayan isteğe bağlı alanlar CBOR haritasından tamamen çıkarılır (null olarak kodlanmaz). Mevcut isteğe bağlı alanlar sıralı anahtar düzeninde dahil edilir. |
3.2 Doğrulanmış kanonik anahtar sıraları
Bu anahtar sıraları normatiftir. Uygulamalar anahtarları tam olarak bu sırayla yaymak ZORUNDADIR. Hata ayıklama onaylamaları, üretim dışı yapılarda sıralamayı doğrulamalıdır (SHOULD).
QubEnvelope (sürüm 0x01, imzasız, tüm isteğe bağlı alanlar yok):
"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 anahtar sırası türetmesi: her anahtar bir CBOR metin dizesidir. Kodlanmış uzunluk = 1 baytlık başlık + dize uzunluğu (24 bayttan kısa dizeler için). Önce toplam kodlanmış uzunluğa göre, aynı uzunluktaki anahtarlar için sözlüksel olarak sıralayın.
SealedQub (sürüm 0x01, herkese açık, alıcı yok):
"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 (pakt gövdesi, 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 (terms dizisinin satırı):
"key" (4 encoded bytes)
"value" (6 encoded bytes)
PartyIdentifier (party_a / party_b haritası):
"label" (6 encoded bytes)
"contact" (8 encoded bytes) ← only if present
3.3 Bayt kodlama referansı
| Tür | CBOR kodlaması | Örnek |
|---|---|---|
| SHA3-256 özeti (32 bayt) | 0x58 0x20 + 32 bayt |
body_hash, qub_id |
| Zaman damgaları (i64) | Ana tür 0 (pozitif) veya 1 (negatif), en kısa kodlama | Unix saniyeleri |
| Sürüm (u8, değer 1) | 0x01 (tek bayt) |
|
| İçerik türü (u8, değer 1) | 0x01 (tek bayt) |
|
| sig_alg (u8, değer 0) | 0x00 (tek bayt) |
|
| ML-DSA-65 imzası (3.309 bayt) | 0x59 0x0C 0xED + 3.309 bayt |
author_signature, cosigner_signature |
| ML-DSA-65 açık anahtarı (1.952 bayt) | 0x59 0x07 0xA0 + 1.952 bayt |
author_pubkey, cosigner_pubkey |
4. Normatif türetmeler
4.1 qub_id
qub_id, bir qub'u benzersiz şekilde tanımlar ve QubEnvelope'u SealedQub'a bağlar. Zarf içeriğinden deterministik olarak türetilir.
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
Etki alanı ayırıcı kodlaması: "QUB_ID_V2" dizesi 9 ASCII bayttır. Hizalama için 10 bayta ulaşmak amacıyla tek bir 0x00 dolgu baytı eklenir. Uygulamalar tam olarak bu 10 baytı kullanmak ZORUNDADIR: [0x51, 0x55, 0x42, 0x5F, 0x49, 0x44, 0x5F, 0x56, 0x32, 0x00].
outcome_at kodlaması: V1.1, isteğe bağlı outcome_at alanını bağlamaya katmak için ön görüntüyü 92 bayttan 100 bayta genişletti. Yok olan outcome_at, 8 sıfır bayt olarak kodlanır; protokol doğrulayıcıları her yerde outcome_at <= 0 değerini reddeder, böylece bu nöbetçi değer meşru bir değerle çakışamaz. Bkz. §3.2 (aktarım biçimi) ve bu alanı motive eden hüküm mekaniği için ağaç içi tasks/verdict-uplift-plan.md.
drand_round kodlaması: V1.2, drand_round'u (hedef drand turu, §4.3) bağlamaya katmak için ön görüntüyü 100 bayttan 108 bayta genişletti ve etki alanı ayırıcısını QUB_ID_V2'ye yükseltti. Bu, zaman kilidi turunu qub kimliğine bağlar: bir ağ geçidi, şifreli metni gösterilen unlock_at'ın ima ettiğinden farklı bir tura (örneğin halihazırda geçmiş bir tura) yeniden bağlayamaz. Açılma yordamı (§8) ayrıca tlock şifreli metin stanzasına gömülü turun unlock_round(unlock_at) ile eşleştiğini doğrular, böylece gösterilen açılma zamanının, şifre çözmeyi kapılayan tur olduğu kanıtlanabilir.
Özellikler:
- QubEnvelope'daki herhangi bir alanı (gövde, zaman damgaları, içerik türü, sürüm) değiştirmek farklı bir qub_id üretir.
- qub_id, şifrelemeden önce hesaplanır. Hem QubEnvelope hem de SealedQub aynı qub_id'yi taşır. İzleyici, şifre çözmeden sonra eşleştiklerini doğrular.
- qub_id,
sender_label,author_signatureveyaauthor_pubkey'e bağlı değildir. Bu, aynı zamanda mühürlenen aynı içeriğin, onu kimin imzaladığına bakılmaksızın aynı qub_id'yi üreteceği anlamına gelir. - SealedQub
title'ını değiştirmek (diğer her şey sabit kalırken),title_hasharacılığıylaqub_id'yi değiştirir (§4.1). Bu nedenle bir ağ geçidi, qub kimliğini geçersiz kılmadan geri sayımda gösterilen düz metin başlığı değiştiremez. - SealedQub
outcome_at'ını değiştirmek (diğer her şey sabit kalırken), ön görüntü aracılığıylaqub_id'yi değiştirir. Bir ağ geçidi, qub kimliğini geçersiz kılmadan geri sayımda gösterilen açıklama öncesi hüküm tarihini değiştiremez. drand_round'u değiştirmek (diğer her şey sabit kalırken), ön görüntü aracılığıylaqub_id'yi değiştirir. Bir ağ geçidi, qub kimliğini geçersiz kılmadan zaman kilidi şifreli metnini farklı bir tura yeniden bağlayamaz; §8 açılma zamanı stanza-tur kontrolüyle birleştiğinde, gösterilenunlock_at, şifre çözmeyi gerçekten kapılayan turdur.
4.2 body_hash
body_hash = SHA3-256(body)
Burada body, ham Vec<u8> içerik yüküdür. Metin qub'ları için bu, UTF-8 kodlamalı qub gövdesidir.
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
Burada title, açıklama öncesinde izleyici geri sayımında gösterilen isteğe bağlı düz metin başlığıdır (bkz. §3.2). NFC normalleştirme, özetin görsel olarak eşdeğer kod-nokta dizileri arasında kararlı olması için özet zamanında çalışır. Tümü sıfır olan işaretçi, yok durumu için ayrılmıştır; boş bir dize, kanonik CBOR sınırında "yok"un kanonik olmayan kodlaması olarak reddedilir (kanonik kodlama alanı tamamen çıkarır).
4.3 Açılma turu eşleştirmesi
drand_round = ceil((unlock_at - chain_genesis_time) / chain_period_seconds)
| Parametre | Kaynak | Örnek |
|---|---|---|
unlock_at |
Kullanıcı tarafından seçilen UTC Unix saniyeleri | 1735689600 (2025-01-01 00:00:00 UTC) |
chain_genesis_time |
drand zincir bilgisi (genesis_time) |
1595431050 |
chain_period_seconds |
drand zincir bilgisi (period) |
30 |
ceil() işlemi, açıklama zamanı ≥ unlock_at olan ilk drand turunu seçer. Bu, qub'un seçilen açılma zamanından önce şifresinin çözülememesini sağlar.
Sınır durumu: (unlock_at - chain_genesis_time) tam olarak chain_period_seconds'a bölünebiliyorsa, sonuç tam olarak o turdur — qub o turun açıklama zamanında tam olarak açılır.
Doğrulama: unlock_at, mühürleme anında gelecekte olmak ZORUNDADIR. unlock_at, created_at'tan en fazla 10 yıl uzakta olmak ZORUNDADIR (uzun ufuklu drand bağımlılık riskini sınırlamak için; arayüz 2 yılın ötesindeki açılma tarihleri için uyarı vermelidir — SHOULD).
5. Aktarım biçimi yeni tipleri
Aktarım biçimi yeni tipleri (newtypes), CBOR baytlarını JSON, ham düz metin veya diğer bayt kodlamalarıyla karıştırmaya karşı derleme zamanı güvenliği sağlar.
| Tür | İçerir | Üreten | Tüketen |
|---|---|---|---|
SealedQubCbor |
SealedQub'ın kanonik CBOR'u | serialize_sealed_qub() |
Kalıcı depolama yüklemesi, izleyici alımı |
QubEnvelopeCbor |
QubEnvelope'un kanonik CBOR'u | serialize_qub_envelope() |
tlock şifreleme girdisi, tlock şifre çözme çıktısı |
5.1 İnşa kuralları
// 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 İnşada doğrulama
from_encoded(), çift ayrıştırmayı önlemek için girdinin geçerli bir CBOR harita başlığıyla başladığını doğrulamalıdır (SHOULD). Tam yapısal doğrulama inşa zamanında değil, ayrıştırma zamanında gerçekleşir.
6. İçerik türü kayıt defteri
| Değer | Tür | Maksimum gövde boyutu | Notlar |
|---|---|---|---|
0x00 |
Ayrılmış (geçersiz) | — | Kullanılmamalıdır (MUST NOT) |
0x01 |
Düz metin (UTF-8, kısıtlı Markdown) | 50 KB ücretli / 10 KB ücretsiz | Sunum kuralları için bkz. §10. Ücretsiz / ücretli ayrımı yükleme hizmeti tarafından uygulanır; protokol katmanı kesin tavanı 50 KB'dir. |
0x02 |
Ayrılmış (gelecek) | — | Gelecekteki bir içerik türü için ayrılmıştır; v1'de geçerli değildir. İzleyiciler aşağıdaki kural uyarınca reddetmek ZORUNDADIR. |
0x03 |
Pakt (ikili anlaşma, CBOR gövdesi) | 100 KB | Gövde kanonik CBOR PactTerms'tür (§6.1). §9.7 uyarınca birlikte imzalayan imzalama. |
0x04 |
Karar (yaratıcı öz-değerlendirmesi, CBOR gövdesi) | 8 KB | Gövde kanonik CBOR VerdictBody'dir (§6.2). Yalnızca sistem tarafı verdict niyeti tarafından yayılır. Üst ilişki, gövdede değil, Parent-Tx-Id Arweave etiketindedir. Bkz. verdict-uplift-plan §3.4. |
İzleyiciler bilinmeyen içerik türlerini açık bir kullanıcıya görünür hata ile reddetmek ZORUNDADIR. İzleyiciler bilinmeyen türleri metin olarak sunmaya çalışMAMALIDIR.
6.1 Pakt gövdesi (content_type = 0x03)
Bir pakt gövdesi, bir PactTerms değerinin kanonik CBOR kodlamasıdır:
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)> }
Üç harita için kanonik CBOR anahtar sıraları §3.2'de verilmiştir. Toplam serileştirilmiş pakt CBOR 100 KB'yi aşMAMALIDIR (§6 ile eşleşir).
Şema ayırt edicisi. Bir structured/v1 paktında terms'teki ilk satır { key: "pact_schema", value: "structured/v1" } OLMALIDIR. Bu işareti olmayan satırlar "özel" paktlardır ve yapılandırılmış doğrulama veya şemaya duyarlı sunum almazlar.
Donmuş onay yuvaları. structured/v1 paktları bu anahtarlar altında tam olarak dört onay satırı taşır:
"initiator_standard_terms"
"initiator_capacity_terms"
"counterparty_standard_terms"
"counterparty_capacity_terms"
Her birinin value'su, (role, kind) çifti ile seçilen sekiz donmuş İngilizce dizeden biridir; burada role ∈ { seller, buyer, provider, client } ve kind ∈ { standard, capacity }. Dizelerin kendisi normatif protokol verisidir — her iki tarafın ML-DSA-65 imzaları, body_hash aracılığıyla tam baytlara taahhüt eder. Bunlar yerelleştirilMEZ; imzalanan gövde dilden bağımsızdır. Herhangi bir ifade değişikliği yeni bir şema sürümü gerektirir (structured/v2).
Sekiz dize, aramaları (acknowledgement_for(role, kind)) ve her birinin gerekçesi referans uygulama tarafından sabitlenir. Uyumlu uygulamalar bayt-aynı onay değerleri yaymak ZORUNDADIR; dört rol kombinasyonunun tamamını kapsayan altın-fikstür SHA3-256 gövde-özeti testleri herhangi bir kaymayı yakalar.
İzleyici görüntüleme sırası. Onay dizeleri, açıklama / kapsam satırlarının onaylardan önce sunulduğunu varsayan "yukarıda açıklandığı gibi" ("described above") gibi ifadeler içerir. İzleyiciler terms dizisini CBOR sırasında sunmak ZORUNDADIR; yeniden sıralama metnin anlamsal bütünlüğünü bozar.
Karşı taraf iletişimi. Taraf B'nin contact bilgisi geçerli bir e-posta adresi olduğunda, qub yükleme hizmeti, hazırlama anında otomatik olarak bir inceleme / birlikte imzalama davet e-postası gönderir ve nihai birlikte imzayı aynı adresin doğrulamasına bağlar (§9.7). Taraf B iletişimi olmayan paktlar yine de birlikte imzalanabilir, ancak yalnızca bant dışı bir kanal aracılığıyla — hizmet, eşleşen bir 15 dakikalık e-posta doğrulama işaretçisi üretemeyen birlikte imzalama isteklerini reddeder.
6.2 Karar gövdesi (content_type = 0x04)
Bir karar gövdesi, bir VerdictBody değerinin kanonik CBOR kodlamasıdır:
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
}
Kanonik CBOR anahtar sırası:
"outcome" (8 encoded bytes)
"reflection" (11 encoded bytes) ← only if present
"evidence_url" (13 encoded bytes) ← only if present
"verdict_version" (16 encoded bytes)
Toplam serileştirilmiş karar CBOR'u 8 KB'yi aşMAMALIDIR (yukarıdaki kayıt defteri satırıyla eşleşir).
Sonuç sıralı türü (enum). Tel baytı niyetten bağımsızdır; dört kategori — Right / Partial / Wrong / Unfalsifiable — karar taşıyan her niyetin sonuç uzayını kapsar. Niyete özgü etiketler (Right için "Bildim" / "Tuttum" / "Yayımlandı" / "Doğrulandı" gibi) izleyici tarafı sunum işidir ve üst qub'un niyetine göre çözümlenir — tel, dilden ve niyetten bağımsız kalır. 1..=4 dışındaki değerler kod çözmede reddedilmek ZORUNDADIR.
Üst bağlantısı. Bir karar qub'u, üst referansını gövdesinde taşıMAZ. Üst qub'un Arweave işlem kimliği, yükleme anında Parent-Tx-Id depolama etiketi olarak yayılır (§7 depolama-etiketi katmanı). Bu, gövdeyi kendi kendine yeten, imzalı bir öz-değerlendirme bildirimi olarak tutar; denetim zinciri ("ne hakkında haklı?") Arweave-etiketi araması üzerinden kurulur.
Kanıt URL güvenliği (normatif). evidence_url mevcut olduğunda, doğrulayıcılar (hazırlama tarafı, tel tarafı, Worker kenarı) şunları uygulamak ZORUNDADIR:
- Yalnızca HTTPS. Dize,
https://bayt dizisiyle başlamak ZORUNDADIR. Başka herhangi bir şema —http,ftp,javascript,data,filevb. — reddedilir. - Uzunluk üst sınırı. ≤ 2.048 bayt (tarayıcı URL pratik sınırı).
- NFC + düşmanca kod noktası denetimi.
titlevereflectionile aynı kural — bidi-override / sıfır genişlik / etiket bloğu / BOM / C0 / C1 kod noktaları reddedilir. Tanım, Rustcrate::handle::contains_hostile_text_codepointve TSworkers/api/src/utils/unicode.ts::isHostileCodepointile eşleşir (üçü birlikte ilerletilmek ZORUNDADIR). - Boşluk yok, ASCII denetim karakteri yok. URL'nin herhangi bir yerindeki boşluk / DEL /
0x20altındaki baytlar reddedilir — bidi kuralının kapsamadığı\n/\tenjeksiyon vektörünü kapatır. - Boş olmayan ana bilgisayar bölümü.
https://ile ilk/,?veya#arasındaki her şey boş olmayan ZORUNDADIR.
Sunucu tarafında getirme yok. Worker, URL'yi vekille çekMEMELİ, getirMEMELİ ya da önizleMEMELİDİR. Protokol bir dize saklar; sunum, rel="nofollow noopener noreferrer" target="_blank" ile izleyici tarafında gerçekleşir ve bağlantı metniyle birlikte görünür bir ana bilgisayar gösterilir.
Düşünce. İsteğe bağlı, yaratıcının yazdığı düşünce metni ("ne değişti, ne öğrendin"). title ile aynı NFC + düşmanca kod noktası doğrulaması. Boş / yalnızca boşluk içeren girdi, oluşturma anında yok sayılır.
Şema sürümü. v1 yalnızca verdict_version = 0x01'i destekler. Gelecekteki şema güncellemeleri bu baytı artırır ve §12 uyarınca yeni bir protokol sürümüyle birlikte iner.
7. Mühürleme protokolü
Tam mühürleme dizisi. Her adım normatiftir.
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.
Depolama etiket katmanı (bant dışı). qub yükleme hizmeti, sarmalanmış yüke ek olarak kasıtlı olarak küçük bir depolama işlem etiketi seti ekler. Content-Type=application/octet-stream normatif olarak gereklidir. Referans hizmet ayrıca, yaratıcı bunları yüzeye çıkarmayı seçtiğinde üç isteğe bağlı etiket ekler: Intent (izin listesi doğrulamalı oluşturma niyeti — örneğin quote, reply, commitment), Author (yaratıcının §9.3 açık anahtar parmak izi 64 karakterli küçük harf onaltılık olarak) ve Parent-Tx-Id (yanıt zincirleri için üst qub'un depolama işlem kimliği, 43 karakterli base64url).
Author etiketi qub başına opsiyoneldir: referans yaratıcı uygulaması bunu yalnızca kullanıcı mühürleme anında kamu atıfını açıkça etkinleştirdiğinde ekler. Geçiş kapalıyken — varsayılan — hiçbir Author etiketi yazılmaz ve qub zincirde atfedilmemiştir: kalıcı depolamadaki hiçbir şey yüklemeyi bir yaratıcının kullanıcı adına, e-postasına veya diğer qub'larına bağlamaz. Geçiş açıkken, Author parmak izi §9.5 onay zinciri aracılığıyla yaratıcının seçtiği @handle'a çözümlenir. Yanıt zinciri ilişkileri ve Intent tanımlayıcı değildir. Dış sarmalayıcı (§13), iç gövdeyi şifreli metin korelasyonundan korur — bir hasatçının drand turu yayınlandıktan sonra qub-şekilli yüklemeleri tanımasını ve toplu olarak şifresini çözmesini engeller.
Referans hizmet kasıtlı olarak App-Name, App-Version veya Type etiketlerini eklemez: bu tür herhangi bir tek değerli filtre, bir GraphQL sorgusuna tüm qub corpus'unu döndürür ki bu, sarmalayıcının yalnızca-gövde gizlilik kapsamıyla tutarsızdır.
Uyumlu bir doğrulayıcı, §11 üçüncü taraf doğrulaması için herhangi bir depolama etiketine bağımlı olMAMALIDIR; gövde özeti / qub_id / imza yalnızca iç CBOR'a taahhüt eder, asla etiket setine değil.
8. Açma protokolü
Tam açma dizisi. Her adım normatiftir.
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. Yazarlık imzalama
9.1 Gerekçe
qub'lar kalıcı depolamada saklanır. Yazarlık imzaları süresiz olarak sahteciliğe karşı dirençli kalmalıdır, bu nedenle v1.0, güvenliği qub'un kalıcı yaşam süresi içinde bozulabilecek klasik bir şema yerine post-kuantum ML-DSA-65 şemasını (FIPS 204) kullanır.
9.2 Algoritma kayıt defteri
sig_alg |
Şema | Anahtar boyutu | İmza boyutu |
|---|---|---|---|
0x00 |
İmza yok (imzasız) | — | — |
0x01 |
ML-DSA-65 (FIPS 204) | 1.952 bayt | 3.309 bayt |
İzleyiciler bilinmeyen sig_alg değerlerini reddetmek ZORUNDADIR.
9.3 İmzalı ön görüntü inşası
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)
Etki alanı ayırıcı: "QUB_AUTHOR_SIG_V1" 17 ASCII bayttır: [0x51, 0x55, 0x42, 0x5F, 0x41, 0x55, 0x54, 0x48, 0x4F, 0x52, 0x5F, 0x53, 0x49, 0x47, 0x5F, 0x56, 0x31]. Dolgu yok.
Son bayt: 91. ön görüntü baytı 0x00 OLMALIDIR. Referans uygulama bunu crates/qub-core/src/signing.rs içinde ORG_ID_PRESENT_INDIVIDUAL = 0x00 sabiti olarak sunar; doğrulama için sig_input'u yeniden oluşturan izleyiciler aynı baytı yaymak ZORUNDADIR.
İmza kapsamı — neyi kapsar ve neyi kapsamaz. sig_input, dört zarf alanına taahhüt eder: version, qub_id, body_hash, unlock_at (artı sabit etki alanı ayırıcısı ve org_id_present baytı). Bu dördünden üçü yapısal değişmezlerdir: qub_id'nin kendisi §4.1 ön görüntüsü aracılığıyla version, content_type, created_at, unlock_at, outcome_at, drand_round ve body_hash'ten türetilir, bu nedenle bu alanlarda yapılan herhangi bir değişiklik farklı bir qub_id üretir ve imzayı geçişli olarak geçersiz kılar. Bu nedenle doğrudan kimliği doğrulanmış yüzey şudur:
| Alan | İmza ile kimliği doğrulanır | Nasıl |
|---|---|---|
version |
✓ | sig_input'a doğrudan girdi |
qub_id |
✓ | Doğrudan girdi |
body_hash |
✓ | Doğrudan girdi |
unlock_at |
✓ | Doğrudan girdi |
content_type |
✓ | qub_id ön görüntüsü aracılığıyla geçişli olarak |
created_at |
✓ | qub_id ön görüntüsü aracılığıyla geçişli olarak |
outcome_at |
✓ | qub_id ön görüntüsü aracılığıyla geçişli olarak |
drand_round |
✓ | qub_id ön görüntüsü aracılığıyla geçişli olarak (V1.2) |
body |
✓ | body_hash = SHA3-256(body) aracılığıyla geçişli olarak |
author_pubkey |
— (örtük) | İmzayı doğrulayan anahtar, tanım gereği yazardır |
sender_label |
✗ | Yalnızca görüntüleme metni; imza bozulmadan değiştirilebilir |
reply_to |
✗ | İş parçacığı işaretçisi; imza bozulmadan değiştirilebilir |
cosigner_pubkey / cosigner_signature |
— | Aynı sig_input üzerinde bağımsız olarak imzalanır (bkz. §9.7) |
drand_chain_id, tlock_ciphertext, visibility |
— | Dış SealedQub alanları, zarfın içinde değil — kendi yapısal değişmezleri (tur / zincir tutarlılığı) tarafından kapsanır ancak yazar imzası tarafından kapsanmaz. (drand_round artık qub_id ön görüntüsü aracılığıyla geçişli olarak bağlanır — yukarıya bakın.) |
Kimliği doğrulanmamış alanların güvenlik etkileri.
- Depolanan baytlara yazma erişimi olan bir taraf, yazar imzasını geçersiz kılmadan
sender_label'ı ("Alice" → "Mallory") değiştirebilir. Zarftakiauthor_pubkey, gerçek kimlik dayanağı olarak kalır — izleyiciler görüntüleme kimliğinisender_label'a güvenmek yerineauthor_pubkey'den (§9.5 onay katmanı aracılığıyla) türetmek ZORUNDADIR. - Bir
reply_toalanı da imzalamadan sonra benzer şekilde düzenlenebilir.qub_idiçerik adresli olduğundan, bir saldırganreply_to'yu var olmayan bir hedefe yönlendiremez, ancak bir yanıtı sessizce farklı bir mevcut qub'a yeniden bağlayabilirler.
sender_label veya reply_to'yu son kullanıcılara gösteren uygulamalar, kimliği doğrulanmış kimliği (açık anahtar parmak izi, onay) etiket yerine birincil kimlik sinyali olarak yüzeye çıkarmak ZORUNDADIR.
9.4 Doğrulama prosedürü
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."
İmza doğrulama en pahalı işlemdir (özellikle ML-DSA-65). Daha ucuz tüm kontroller (özet, qub_id, unlock_at) geçtikten sonra yapılmalıdır (SHOULD).
9.5 Kimlik onayları
Kimlik onayları — author_pubkey'in qub kullanıcı adı, e-posta adresi, sosyal kullanıcı adı veya parola anahtarı kimlik bilgisi gibi insan tarafından tanınabilen kimlik iddialarına eşlenmesi — izleyici tarafında aşamalı bir geliştirmedir ve imza doğrulaması için gerekli değildir. Onayları bir görüntüleme kimliğine çözen izleyiciler şu önceliği uygulamak ZORUNDADIR:
handle > email > social > fingerprint
Parmak izi yedeği, SHA3-256(author_pubkey)'in küçük harf onaltılığıdır; herhangi bir imzalı qub için her zaman kullanılabilir. İzleyiciler bunu görüntüleme için kısaltABİLİR — referans izleyici, qub: ardından ilk ve son dört baytı sunar (qub:<8 hex>…<8 hex>).
Uyumlu bir doğrulayıcı, qub API'sine başvurmadan, kalıcı depolama ve drand'in ötesinde herhangi bir ağ olmadan ve herhangi bir sunucu tarafı araması olmadan §9.4'teki her kontrolü tamamlayabilir. Onay çözümleme, yalnızca imza doğrulaması başarılı olduktan sonra gerçekleştirilen ayrı bir en iyi çaba adımıdır.
9.6 Boyut etkisi
| Ed25519 | ML-DSA-65 | |
|---|---|---|
| İmza | 64 bayt | 3.309 bayt |
| Açık anahtar | 32 bayt | 1.952 bayt |
| qub başına toplam | 96 bayt | 5.261 bayt |
| Depolama maliyet farkı (~5$/MB ile) | ~0,0005$ | ~0,026$ |
500–2.000 bayt'lık bir metin qub için ML-DSA-65 depolanan boyutu kabaca üç katına çıkarır. Mutlak maliyet ihmal edilebilir düzeydedir.
9.7 Birlikte imzalayan doğrulaması (Pakt ikili anlaşmaları)
İkili anlaşmalar için (content_type = 0x03), ikinci bir imza katmanı her iki tarafın da aynı koşullara onay verdiğini kanıtlar.
Zarf alanları:
cosigner_pubkey: Karşı imzalayanın (Taraf B) ML-DSA-65 açık anahtarı.cosigner_signature: Yazarla aynısig_inputüzerindeki imza (§9.3).
Her iki alan da birlikte mevcut olmak veya her ikisi de yok olmak ZORUNDADIR. Yalnızca biri mevcutsa, izleyiciler bir bütünlük hatası bildirmek ZORUNDADIR.
Doğrulama prosedürü:
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."
Özellikler:
- Birlikte imzalayan, yazarla aynı
sig_input'u imzalar — her iki taraf da aynıqub_id,body_hashveunlock_at'a taahhüt eder. qub_idtüretmesi (§4.1) birlikte imzalayan alanlarını İÇERMEZ. Mevcut bir zarfa bir birlikte imzalayan eklemekqub_id'yi değiştirmez.- Bir pakt yalnızca yazar tarafından imzalanmış (tek taraflı taahhüt), yalnızca birlikte imzalayan (alışılmadık) veya her ikisi (tam ikili kanıt) olabilir.
E-posta bağlama kapısı (operasyonel). Hazırlanan bir pakt bir Taraf B e-posta iletişimi taşıdığında (§6.1), qub yükleme hizmeti, hem hazırlama kimliği hem de bu iletişimin normalleştirilmiş e-posta özeti ile eşleşen kısa ömürlü bir e-posta doğrulama işaretçisi mevcut olmadıkça birlikte imzalama isteğini reddetmek ZORUNDADIR. İşaretçi, sihirli bağlantı belirteci bir staging_id taşıdığında ve doğrulanmış adres SHA-256(normalise_email(party_b.contact)) ile eşleştiğinde /api/v1/auth/verify tarafından yazılır — burada normalise_email(addr) yerel bölümün büyük/küçük harfini korur ve yalnızca etki alanı bölümünü küçük harfe çevirir (RFC 5321 §2.3.11 uyarınca) ve buradaki SHA-256, NIST FIPS 180-4 özetidir (§4 türetmelerinde kullanılan SHA3-256'dan farklı) — ve verildikten 900 saniye (15 dakika) sonra sona erer. Bu operasyonel bir kimlik taklidine karşı kapıdır, zincir üzerindeki qub kanıtının bir parçası DEĞİLDİR — §11'i yeniden oynayan üçüncü taraf bir doğrulayıcının yalnızca kalıcı depolama ve drand'a ihtiyacı vardır, herhangi bir sunucu tarafı araması olmadan. İşaretçi yalnızca sunucu tarafında bulunur ve asla imzalanmış gövdenin bir parçası değildir.
Boyut etkisi (ML-DSA-65 yazar + birlikte imzalayan):
| Bileşen | Boyut |
|---|---|
| Yazar imzası | 3.309 bayt |
| Yazar açık anahtarı | 1.952 bayt |
| Birlikte imzalayan imzası | 3.309 bayt |
| Birlikte imzalayan açık anahtarı | 1.952 bayt |
| Toplam kripto ek yükü | 10.522 bayt |
| Depolama maliyet farkı | ~0,05$ |
10. Markdown sunumu ve temizleme
Bu bölüm güvenlik açısından kritiktir. İzleyici, metin qub'larını (content_type = 0x01) kısıtlı bir Markdown alt kümesi kullanarak sunar.
10.1 İzin verilen öğeler
- Başlıklar:
#'tan####'a (#####veya######yok) - Vurgu: kalın (
**), italik (*), üstü çizili (~~) - Listeler: sıralı (
1.) ve sırasız (-,*) - Alıntı blokları (
>) - Kod: satır içi aralıklar (```) ve çitlenmiş bloklar (`````)
- Yatay çizgiler (
---) - Satır sonları (iki sondaki boşluk veya boş satır)
- Paragraflar
10.2 Yasaklanan öğeler
| Öğe | İşleme |
|---|---|
Ham HTML (<div>, <script>, vb.) |
Tamamen çıkarılır. HTML'den hiçbiri geçmez. |
Görseller () |
Çıkarılır. Görsel söz dizimi çıktıdan kaldırılır. |
Bağlantılar ([text](url)) |
URL görünür düz metin olarak sunulur. Otomatik bağlantılanmaz. Açık kullanıcı eylemi olmadan tıklanabilir değildir. |
| Tehlikeli URL şemaları | javascript:, data:, vbscript:, file: — çıkarılır. |
| iframe'ler, gömülenler, nesneler | Çıkarılır. |
| HTML varlıkları | Yalnızca güvenliyse görüntüleme karakterlerine kod çözülür. |
10.3 Uygulama
Uygulamalar bir kara liste değil, katı bir izin listesi ayrıştırıcısı kullanmak ZORUNDADIR. Önerilen yaklaşım:
- Markdown'ı
pulldown-cmark(veya eşdeğeri) kullanarak ayrıştırın. - AST'de gezinin ve izin listesinde olmayan herhangi bir düğümü atın (§10.1).
- Bağlantı düğümleri için: URL'yi tıklanabilir bir
<a>öğesi olarak değil, görünür metin olarak yayın. - Filtrelenmiş AST'yi tipli bir ara temsile dönüştürün (örneğin, yalnızca güvenli varyantları olan bir
MarkdownNodeenum'u). Bu IR'de ham HTML yapısal olarak temsil edilemez. - Tipli IR'den hedef görünüm katmanına (örneğin, reaktif görünüm bileşenleri, DOM düğümleri) sunum yapın. Hiçbir noktada HTML dize birleştirme veya
innerHTMLkullanılmaz.
Kara liste yaklaşımları kırılgandır çünkü yeni Markdown uzantıları veya ayrıştırıcı tuhaflıkları filtrelenmemiş öğeler getirebilir. Tipli AST yaklaşımı, XSS'yi yapısal olarak imkansız hale getirir — keyfi HTML taşıyabilecek bir varyant yoktur.
10.4 Boyut ve yapı sınırları
- Maksimum sunulan başlık derinliği:
####(H4).#####ve daha derin olanlar kalın metin olarak sunulur. - Paragraf sayısında sınır yoktur (gövde boyutu sınırları §6'da kısıtlamadır).
- Çitlenmiş kod blokları: MVP'de söz dizimi vurgulama yok. Monospace önceden biçimlendirilmiş metin olarak sunulur.
11. Üçüncü taraf doğrulaması
Herhangi bir üçüncü taraf, qub işbirliği olmadan bir kamu qub'unu doğrulayabilir. Doğrulama prosedürü:
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.
Doğrulamanın kanıtladıkları:
| Kanıt | Ne kurar |
|---|---|
| Taahhüt | Şifreli metin depolama blok zaman damgasına kadar var olmuştur. |
| Bütünlük | Düz metin gövdesi taahhüt edilen özetle eşleşir ve değiştirilmemiştir. |
| Zamanlama | İçerik, seçilen açılma zamanına karşılık gelen drand turuna kadar okunamazdı (tlock ve drand güvenlik varsayımlarına tabidir). |
Doğrulamanın kanıtlaMADIKLARI:
| Kanıtlanamayan | Neden |
|---|---|
| Yazarlık | sender_label dekoratiftir. sig_alg ≥ 0x01 olmadan, bu içeriği herhangi biri mühürlemiş olabilir. |
| Niyet | qub içeriği ve zamanlamayı kanıtlar, yaratıcının öznel olarak ne demek istediğini değil. |
| Olay öncesi zamanlama | Depolama blok dahil edilmesi gerçek yüklemeden dakikalarca gecikebilir. Taahhüt zaman damgası blok zamanıdır, kullanıcının "mühürle"ye bastığı an değildir. |
12. Sürümleme
12.1 Protokol sürümü
Hem SealedQub hem de QubEnvelope içindeki version alanı (u8), birincil protokol sürümünü tanımlar.
- İzleyiciler bilinmeyen birincil sürümleri açık bir hata ile reddetmek ZORUNDADIR.
- Bilinen birincil sürümler, ileriye dönük uyumluluk kuralları izin verirse bilinmeyen isteğe bağlı alanları tolere edebilir (kanonik anahtar sırasında bulunmayan isteğe bağlı alanlar yok sayılır) (MAY).
- İçerik türleri (
content_type) ve imza şemaları (sig_alg) sürüm kapılıdır: yeni değerler yalnızca yeni bir protokol sürümü veya açık kayıt defteri güncellemesi ile birlikte tanıtılabilir.
12.2 Sürüm geçmişi
| Sürüm | Değer | Açıklama |
|---|---|---|
| v1 | 0x01 |
Kamu metin qub'ları (content_type 0x01), pakt ikili anlaşmaları (0x03, structured/v1 şeması, ML-DSA-65 yazar + birlikte imzalayan), tlock, SHA3-256 |
12.3 İleriye dönük uyumluluk
Bilinmeyen isteğe bağlı CBOR harita anahtarlarına (§3.2 kanonik sırasında olmayan anahtarlar) sahip bir QubEnvelope ile karşılaşan bir v1 izleyicisi, bu anahtarları yok saymalı ve bilinen alanları kullanarak doğrulamaya devam etmelidir (SHOULD). Bu, büyük sürüm yükseltmesi gerektirmeden gelecekteki küçük eklemelere (örneğin yeni meta veriler) izin verir.
sig_alg = 0x01 (ML-DSA-65) ile karşılaşan ancak ML-DSA-65 doğrulama desteğinden yoksun bir v1 izleyicisi, qub'u tamamen reddetmek yerine "imza mevcut ancak doğrulanamaz" notu ile qub içeriğini görüntülemelidir (SHOULD). Bugünkü referans uygulama, 0x00 ve 0x01 dışındaki her sig_alg değerini reddeder çünkü v1 kayıt defterinde başka geçerli algoritma yoktur — üçüncü bir algoritma kaydedilene kadar katı reddetme ve yumuşak hata gözlemsel olarak aynıdır. Yukarıdaki yumuşak hata davranışı, §9.2 yeni bir giriş kabul ettikten sonra yük taşır hale gelir ve referans izleyici o noktada yumuşak hataya güncellenecektir.
12.4 Dış sarmalayıcı sürümü
§13'te açıklanan OuterWrapper, SealedQub.version ve QubEnvelope.version'dan bağımsız olarak kendi version baytını taşır. İki sürüm alanı ayrı ayrı evrimleşir: gelecekteki post-kuantum-güvenli bir simetrik değiştirme, iç protokol sürümüne dokunmadan sarmalayıcı baytını yükseltir ve gelecekteki bir protokol katmanı eklemesi (örneğin yeni bir zarf alanı), sarmalayıcı baytına dokunmadan iç sürümü yükseltir.
OUTER_WRAPPER_VERSION_* |
Değer | Algoritma | Durum |
|---|---|---|---|
OUTER_WRAPPER_VERSION_1 |
0x01 |
12-baytlık nonce, 16-baytlık kimlik doğrulama etiketi, qub_id'ye bağlı AAD ile AES-256-GCM |
v1 varsayılan |
| — | 0x02–0xFF |
Ayrılmış | Gelecek |
İzleyiciler bilinmeyen sarmalayıcı sürümlerini açık bir hata ile reddetmek ZORUNDADIR. Protokol, somut bir geçiş itici gücü ortaya çıkana kadar (örneğin farklı bir AEAD'yi destekleyen NIST kılavuzu) sarmalayıcı sürüm alanını kasıtlı olarak dar tutar; bir 0x02 yuvası, algoritmayı tanıtan aynı revizyonda tahsis edilecektir.
13. Dış şifreleme sarmalayıcısı
13.1 Gerekçe
Protokol katmanları (QubEnvelope → tlock → SealedQub) mühürlü bir qub'u zamana kilitli yapar: gövde unlock_at'a ve drand tur imzası yayınlanana kadar okunamaz. Ancak açılmadan sonra, tur imzası kamuya açıktır ve SealedQub'un kanonik CBOR şekli tanınabilirdir, bu nedenle kalıcı depolama işlemlerini indeksleyen bir hasatçı, tüm qub corpus'unu toplu olarak şifresini çözebilir.
Dış şifreleme sarmalayıcısı, kanonik SealedQubCbor ile kalıcı depolamaya yazılan baytlar arasına ek bir simetrik AEAD katmanı yerleştirerek bu kanalı kapatır. 256-bitlik anahtar K, yalnızca teslim URL'sinin URL parçasında ve kullanıcı cihazlarında bulunur; tarayıcılar URL parçalarını sunuculara iletmez, bu nedenle qub.social, her depolama ağ geçidi ve her ikisinin önündeki her CDN, K'ye gözlemsel olarak kördür. Bu nedenle kalıcı depolamadaki her qub, düz metni yaratıcının paylaşmayı seçtiği URL olmadan kurtarılamayan opak bir şifreli metindir.
Net etki:
- Varsayılan olarak numaralandırma bağışıklığı. Kalıcı depolamadaki sarmalanmış baytlar, keyfi şifreli metinden bayt olarak ayırt edilemez. "qub-şekilli yüklemeler için GraphQL sorgusu yap, kamu drand imzalarıyla toplu şifre çöz" şeklindeki bir hasatçı stratejisi düz metinle sonlanmaz.
- Kripto-parçalama gizlilik duruşu. qub.social, kendi corpus'unun şifresini kelimenin tam anlamıyla çözemez. Mahkeme celpleri şifreli metne ulaşır, düz metne değil.
- İki katmanlı gizlilik merdiveni. Varsayılan = bağlantı kontrollü erişim (bu bölüm). Alıcıyla şifrelenmiş özel qub'lar (Faz 2 için ayrılmış, henüz tanımlanmamış bir özellik), ikinci katman olarak üstte katmanlanır.
13.2 Katmanlama
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)
Protokol katmanındaki mühürleme ve açma (§7, §8) sarmalayıcı sınırının altında değişmez; sarmalayıcı seal()'ın çağrı yerinde takılır ve unlock()'ın çağrı yerinde çıkarılır.
13.3 OuterWrapper veri yapısı
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
}
Alan değişmezleri.
version, v1.0 sarmalayıcı baytları için0x01'e eşit OLMALIDIR.qub_id, sarmalama açıldıktan sonra kurtarılan SealedQub'unqub_idalanına eşit OLMALIDIR. Sarmalama açma adımı bunu doğrudan zorlamaz (AEAD AAD bağlama, bayt düzeyinde kurcalamayı imkansız kılar), ancak açma katmanı ilişkiyi geçişli olarak kontrol eder: bir yaratıcı, içqub_id'si sarmalayıcıqub_id'siyle eşleşmeyen birSealedQubCbor'u sararsa, §8 adım 11 başarısız olur.nonce, 96 bit (12 bayt) OLMALIDIR, her sarmalama işlemi için bir CSPRNG tarafından taze olarak üretilir. Aynı anahtar altında bir nonce'u yeniden kullanmak, düz metni kurtaran AEAD nonce-yeniden kullanım saldırılarına izin verir; üreticiler (key,nonce) çiftlerini tek atışlık olarak işlemek ZORUNDADIR.ciphertext, AES-256-GCM çıktısıdır: 16 bayt kimlik doğrulama etiketi ile birleştirilmiş şifreli metin baytları.ciphertext.len() == SealedQubCbor.len() + 16tam olarak.
CBOR kodlaması. §3 uyarınca kanonik CBOR, aynı anahtar sıralama kuralıyla (artan kodlanmış bayt uzunluğuna göre sıralı, sonra sözlüksel olarak). Dört anahtar şudur:
| Anahtar | Kodlanmış baytlar | Sıra |
|---|---|---|
nonce |
6 | 1 |
qub_id |
7 | 2 |
version |
8 | 3 |
ciphertext |
11 | 4 |
Bu nedenle OuterWrapper CBOR'unun ilk baytı, 4-girişli bir harita için kesin uzunluklu harita başlığıdır (0xA4).
13.4 qub_id'ye AAD bağlama
Sarmalayıcı, qub_id'yi AEAD ek kimliği doğrulanmış veri olarak bağlar. Bu, üç sınıf saldırıya karşı yük taşıyan yapısal savunmadır:
| Saldırı | Savunma |
|---|---|
Şifreli metni sarmalayıcıdaki farklı bir qub_id alanı altında taşımak |
AAD uyuşmazlığı → AEAD kimlik doğrulaması başarısız olur |
| qub A'nın URL parçasını qub B'nin depolama baytları ile karıştırmak | AAD uyuşmazlığı → AEAD kimlik doğrulaması başarısız olur |
Yüklemeden sonra sarmalayıcının qub_id alanını kurcalamak |
AAD uyuşmazlığı → AEAD kimlik doğrulaması başarısız olur |
qub_id'yi sarmalayıcı düz metninde taşımak, numaralandırma bağışıklığını anlamlı ölçüde zayıflatmaz — qub_id'nin kendisi §4.1 ön görüntüsünün özetten kurtarılamayan ön görüntüsüz bir SHA3-256 özetidir ve sarmalayıcı baytlarını zaten toplayan bir numaralandırıcı, görünür qub_id'den yüklemenin varlığından çıkarabileceğinden daha fazla bir şey öğrenmez.
13.5 Sarmalama ve sarmalama açma algoritmaları
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
Hata modu çöküşü. Yanlış K, yanlış nonce, AAD uyuşmazlığı ve kurcalanmış şifreli metin, hepsi aynı DECRYPT_FAILED hatasını üretir. Bu, kasıtlı bir AEAD özelliğidir: hata modunu ayırt etmek, uzaktan bir saldırganın hatalı biçimlendirilmiş sarmalayıcılar göndererek ve yanıtı zamanlayarak araştırabileceği bir yan kanal oluşturur. Referans uygulamalar tüm AEAD hatalarını tek bir hata şekline daraltmak ZORUNDADIR.
13.6 Anahtar materyali ve dağıtım
Sarmalama anahtarı K, bir CSPRNG tarafından qub başına üretilen 256-bitlik tek tip rastgele bir değerdir. Referans uygulamalar bunu şuradan alır:
- WASM yaratıcısı:
getrandom(wasm_jsarka ucu altında WebCrypto). - Worker sunucu tarafı mühürleme rotası:
crypto.getRandomValues.
Dağıtım: K, URL-güvenli base64 (RFC 4648 §5, dolgu yok) olarak kodlanmak ve teslim URL'sine parça bileşeni olarak eklenmek ZORUNDADIR:
delivery_url = <origin>/c/<arweave_tx_id>#<base64url(K)>
Parça, uyumlu bir tarayıcı tarafından hiçbir sunucuya iletilmez. Tam teslim URL'sini — parça dahil — kullanıcının cihazının ötesinde kalıcı kılan kurtarma kanalları (sunucu tarafı geçmiş dizini, opt-in e-posta otomatik gönderme), varsayılan kripto-parçalama duruşuna karşı açık bir takastır ve açık kullanıcı onayına kapılı olmak ZORUNDADIR.
Parça kaybı. Bir kullanıcı URL parçasını kaybeder ve kurtarma kanalı yoksa, qub okunamaz. Bu, tasarımın yük taşıyan takasıdır ve mühürleme anında kullanıcıya açıklanmak ZORUNDADIR. MVP, mühürleme anı açıklamasını açık "bu URL'yi kaydedin" metni ve opt-in yapan kullanıcılar için doğrulanmış-e-posta kurtarma kanalı ile güçlendirir.
13.7 Bu bölümün kapsamı dışında
- Yazarlık imzalama (§9) değişmez: imzalar iç
QubEnvelopeiçinde hesaplanır ve sarmalama açma → tlock şifre çözme → CBOR ayrıştırma sonrasında kurtarılır. - Alıcıyla şifrelenmiş özel qub'lar (Faz 2 için ayrılmış, henüz tanımlanmamış bir özellik) bu sarmalayıcının üzerine ikinci bir gizlilik katmanı olarak oluşturulur; her iki katman aynı anda etkin olabilir.
- Paktlar (§6, content_type
0x03) tam olarak metin qub'ları gibi sarmalanır; sarmalayıcı iç içerik türüne bayt olarak kördür.
13.8 Kamu qub'ları (sarmalayıcı atlanması)
Dış sarmalayıcı, teslim katmanında isteğe bağlıdır. Bir yaratıcı bir qub'u kamu olarak mühürleyebilir; bu durumda kanonik SealedQubCbor, OuterWrapper katmanı ve K anahtarı olmadan kalıcı depolamaya doğrudan yazılır:
SealedQubCbor bytes ──(public)──▶ uploaded to permanent storage as-is
SealedQubCbor bytes ──(private)─▶ AES-256-GCM(K, …) ▶ OuterWrapper ▶ uploaded
Bir kamu qub'u zamana kilitlidir ancak bağlantı kontrollü değildir: drand turu yayınlanana kadar okunamaz durumda kalır (tlock katmanı değişmez), ancak açılmadan sonra arweave_tx_id'ye sahip olan herkes onun şifresini çözebilir — hiçbir URL parçası gerekmez, çünkü bir K yoktur. Bu, sunucunun yürütmesi gereken yüzeyler için kasıtlı bir takastır: açılma bildirimi e-postaları, üçüncü taraf gömme öğeleri ve daha zengin açılma sonrası SEO'nun tümü, sunucunun asla elinde tutmadığı bir gizli değer olmadan çalışan bir bağlantıya ihtiyaç duyar (§13.6).
Bir üreticinin hesaba katmak ZORUNDA olduğu sonuçlar:
- Numaralandırma bağışıklığı yok. Kamu qub'ları, yapısı gereği §13.1 numaralandırma bağışıklığı özelliğinden vazgeçer. Referans yükleme hizmeti, bunlara (ve yalnızca bunlara) bir
Visibility: publickalıcı depolama etiketi basar, böylece kasıtlı olarak keşfedilebilirler; özel qub'lar böyle bir etiket taşımaz ve bayt olarak ayırt edilemezliklerini korur. - Mühürleme anında açığa çıkan düz metin başlık. §3.2
titlealanı,SealedQubCboriçinde düz metindir. Sarmalayıcının altında, bir izleyiciKsağlayana kadar gizlidir; sarmalayıcı olmadan, açılmadan önce yükleme anından itibaren kalıcı depolamada herkes tarafından okunabilir. Uyumlu yaratıcı uygulamaları bunu mühürleme anında açıklamak ZORUNDADIR. - Tespit yapısaldır. Uyumlu bir izleyici/gömme öğesi, iki şekli ayrıştırarak ayırt eder:
OuterWrapperolarak ayrıştırılan baytlarKile sarmalama açma yolunu izler; çıplak birSealedQubCborolarak ayrıştırılan baytlar doğrudan kabul edilir. Hiçbir kablo bayrağı gerekmez vequb_idgörünürlüğe bağlanmaz — aynı içerik, kamu olarak mı yoksa özel olarak mı mühürlendiğine bakılmaksızınSealedQubkatmanında bayt olarak özdeştir.
Özel (sarmalanmış) varsayılan olarak kalır; kamu, açık bir qub-başına yaratıcı seçimidir.
14. Test vektörleri
14.1 qub_id türetmesi
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
Uygulamalar bu girdi için aynı body_hash ve qub_id değerlerini üretmek ZORUNDADIR. Bu test vektörü yazılan ilk birim testi olmalıdır (SHOULD). Yukarıdaki kanonik değerler referans uygulama tarafından hesaplanmıştır ve bit-bit eşleşmek ZORUNDADIR. Tarihsel ön görüntü düzenleri (lansman öncesi — bu değerlere bağlı canlı qub yoktu): 92 baytlık V1.0 qub_id şuydu: 3d9fc2390eab043d38a1669ed3b71be76f9eefe872b9569ab1aaa027b88392b0; 100 baytlık V1.1 qub_id (outcome_at_or_zero katlandıktan sonra) şuydu: b0d032898ad629795150fdcb3f84e518f59ed05b7a2a82bc24ebdb87f52144ed. V1.2, drand_round'u katlar ve etki alanı ayırıcısını QUB_ID_V2'ye yükseltir.
14.2 Açılma turu eşleştirmesi
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 Kanonik CBOR gidiş-dönüşü
Uygulamalar, tüm geçerli girdiler için serialize(parse(serialize(qub))) == serialize(qub) olduğunu doğrulamak ZORUNDADIR. Bu tek bir vektör değil, bir özellik testidir.
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)
Kanonik CBOR baytları ve SHA3-256 body_hash, referans uygulama tarafından hesaplanır. Uygulamalar bu girdi için bayt-aynı CBOR üretmek ZORUNDADIR.
Uygulamalar ayrıca, tüm geçerli PactTerms girdileri için serialize(parse(serialize(pact))) == serialize(pact) olduğunu doğrulamak ZORUNDADIR (özellik testi).
14.5 Dış sarmalayıcı diller arası vektörler
Dış sarmalayıcı (§13), crates/qub-core/tests/vectors/wrapper_v1.json konumunda ayrı bir kanonik fikstüre sahiptir. Her vaka, opak onaltılık girdiler olarak bir (key, nonce, qub_id, sealed_cbor) demetini sabitler ve belirli bir expected_wrapper_hex çıktısını onaylar. Her iki referans uygulama da aynı JSON dosyasını tüketir:
- 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).
Fikstür şu anda üç vakayı sabitler:
| Vaka | Kapsam |
|---|---|
basic-text-public |
En küçük gerçekçi SealedQub şekli; isteğe bağlı alan yok. v1.0-tipik bir qub için kanonik sarmalayıcı şeklini kurar. |
with-recipient-pubkey |
recipient_pubkey ayarlı SealedQub (Faz 2 yolu). Farklı iç CBOR anahtar seti, farklı qub_id. |
longer-body |
~4 KiB gövde — hem iç zarfta hem de dış şifreli metinde çok baytlı CBOR uzunluk öneklerini sınar. |
Uygulamalar, kaydedilen girdiler için bayt-aynı expected_wrapper_hex üretmek ZORUNDADIR. Fikstürü yeniden oluşturmak QUB_REGEN_VECTORS=1 cargo test -p qub-core --test wrapper_vectors gerektirir ve kasıtlı biçim değişiklikleri için ayrılmıştır.
15. Kripto profil yönetişimi (Gelecek)
Bu bölüm v1 için bilgilendiricidir ve qub'un kriptografik ilkellerinden herhangi birine ikinci bir algoritma girdiği ilk anda normatif hale gelir.
15.1 Mevcut duruş
Protokol v1, ilkel başına tam olarak bir algoritmaya bağlanır:
- İmza: ML-DSA-65 (
sig_alg = 0x01; 1952 baytlık açık anahtar, 3309 baytlık imza) ve imzasız (sig_alg = 0x00). §9.2 kayıt defteri başka hiçbir değer tanımlamaz; v1 doğrulayıcısı{0x00, 0x01}dışındaki hersig_algdeğerini reddetmek ZORUNDADIR. Gelecekte bir Ed25519 girişi öngörülmektedir (§15.3) ancak v1'de ayrılmamıştır. - Zaman kilidi: yalnızca drand quicknet — zincir özeti, açık anahtar, doğuş zamanı ve periyot, referans
DrandTimelockProvider::quicknet()(crates/qub-core/src/tlock.rs) veconfig/drand-endpoints.jsontarafından taşınan sabit ağ parametreleridir. - Dış sarmalayıcı: yalnızca AES-256-GCM v1 (§13).
Doğrulayıcılar şu anda ilkel başına anahtar ve imza uzunluklarını sabit kodlar. Aktarım biçimi tarafından çeviklik yüzeyi sunulmaz.
15.2 Hedeflenen şekil
Protokole ikinci bir algoritma girdiğinde, doğrulayıcı, ilkel başına izin verilen değerlerin tam setini — sig_alg'ler, drand zincirleri, sarmalayıcı sürümleri, içerik türleri — listeleyen adlandırılmış bir CryptoProfile (örneğin ExqubV1) için yapılandırılacaktır. Profil doğrulama zamanında sabitlenir, asla bant içinde müzakere edilmez. Aktif profilin dışındaki herhangi bir değer reddedilir.
Bu, ML-DSA-87 eklemenin veya Ed25519'u etkinleştirmenin mevcut doğrulayıcı yapılandırmalarını geriye dönük olarak zayıflatamamasını garanti eder: bir v1 doğrulayıcısı, bir v2 profili yayınlandıktan sonra bile bir v1 doğrulayıcısı olarak kalır.
15.3 Tetikleyici koşullar
§15'i şunlardan herhangi biri önerildiğinde normatif duruma yükseltin:
- İkinci bir
sig_algbaytı (Ed25519 etkinleştirmesi, ML-DSA-87 veya §9 kayıt defterindeki herhangi bir yeni giriş). - Üretimde kullanılan ikinci bir drand zinciri.
- İkinci bir dış sarmalayıcı sürümü.
O zamana kadar §15, gelecekteki PR'ların müzakere yüzeyini sıfırdan yeniden tartışmak yerine bilinen bir hedefe karşı inmesi için geçiş şeklini sabitleyen bir yer tutucudur.