qub प्रोटोकॉल विनिर्देश
qub क्रिप्टोग्राफिक कालिक प्रतिबद्धताओं के लिए एक प्रोटोकॉल है: एक प्रणाली जो शब्दों को भविष्य की तारीख पर मुहर लगाती है और जब वह तारीख आती है, तो ठीक-ठीक प्रमाणित करती है कि क्या कहा गया था और कब।
तीन आदिम तत्व इसे कार्यान्वित करते हैं। drand एक विकेन्द्रीकृत यादृच्छिकता बीकन है — प्रकटीकरण की तारीख भौतिकी द्वारा प्रवर्तनीय है, किसी पक्ष की सद्भावना से नहीं। स्थायी सार्वजनिक संग्रहण एक छेड़छाड़-रोधी सार्वजनिक भंडार है — एक बार मुहरबंद होने के बाद कोई भी पक्ष qub को संपादित या हटा नहीं सकता। ML-DSA-65 एक उत्तर-क्वांटम डिजिटल हस्ताक्षर है — प्रत्येक qub एक कुंजी जोड़े से बंधा है जिसकी गुप्त कुंजी कभी भी लेखक के डिवाइस को नहीं छोड़ती।
मिलकर ये आदिम तत्व एक ऐसा कथन बनाते हैं जो समय-बद्ध, छेड़छाड़-स्पष्ट और श्रेय-योग्य है — एक रसीद जिसका मूल्य तब बढ़ता है जब दुनिया की अतीत को गढ़ने की क्षमता में सुधार होता है।
इस दस्तावेज़ का शेष भाग अंतर-संचालनीय कार्यान्वयनों के लिए आवश्यक मानक विनिर्देशन है।
qub प्रोटोकॉल विनिर्देशन
| क्षेत्र | मान |
|---|---|
| संस्करण | 1.0 (प्रोटोकॉल संस्करण 0x01, बाहरी आवरण संस्करण 0x01) |
| तारीख | 2026-05-01 |
| स्थिति | मसौदा |
| समीक्षा-तिथि तक | 2026-05-01 |
यह दस्तावेज़ qub समयबद्ध प्रतिबद्धता प्रणाली के लिए मानक प्रोटोकॉल विनिर्देशन है। यह डेटा संरचनाओं, क्रमबद्धता नियमों, व्युत्पत्ति सूत्रों और सत्यापन प्रक्रियाओं को परिभाषित करता है जो अंतर-संचालनीय कार्यान्वयनों के लिए आवश्यक हैं।
कार्यक्षेत्र: प्रोटोकॉल परत जानबूझकर भाषा-तटस्थ है — qub का बॉडी अपारदर्शी प्लेनटेक्स्ट / मार्कडाउन / संधि बाइट्स है, और लोकेल-संवेदी रेंडरिंग दर्शक की जिम्मेदारी है (qub.social वेब ऐप, <qub-embed> iframe, MCP क्लाइंट, इत्यादि)।
1. संकेतन और परिपाटियाँ
| संकेतन | अर्थ |
|---|---|
u8, u64, i64 |
निर्दिष्ट बिट चौड़ाई के अहस्ताक्षरित/हस्ताक्षरित पूर्णांक |
[u8; N] |
N बाइट्स की स्थिर-लंबाई बाइट सरणी |
Vec<u8> |
परिवर्तनशील-लंबाई बाइट सरणी |
Option<T> |
प्रकार T का मान, या अनुपस्थित |
String |
UTF-8 टेक्स्ट स्ट्रिंग, NFC सामान्यीकृत |
| ` | |
SHA3-256(x) |
बाइट स्ट्रिंग x का NIST SHA3-256 हैश (FIPS 202) |
ceil(x) |
सीलिंग फलन: सबसे छोटा पूर्णांक ≥ x |
| CBOR | Concise Binary Object Representation (RFC 8949) |
| big-endian | सबसे महत्वपूर्ण बाइट पहले |
प्रीइमेज निर्माणों में सभी पूर्णांक big-endian स्थिर-चौड़ाई बाइट सरणियों के रूप में एन्कोड किए जाते हैं (i64 → 8 बाइट्स, u8 → 1 बाइट), जब तक अन्यथा निर्दिष्ट न हो।
सभी टाइमस्टैम्प UTC में Unix सेकंड हैं।
2. डेटा संरचनाएँ
2.1 ComposeQub (रचयिता की इन-मेमोरी स्थिति)
CBOR में क्रमबद्ध नहीं। स्थायी संग्रहण में नहीं लिखा गया। रचयिता ऐप के लिए स्थानीय।
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 (डिक्रिप्ट किया गया पेलोड)
कैनोनिकल CBOR (§3) का उपयोग करके क्रमबद्ध। SealedQub के अंदर एन्क्रिप्ट किया गया। यह वह संरचना है जो डिक्रिप्शन के बाद सामग्री अखंडता को प्रमाणित करती है।
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 — जब वास्तविकता निर्णय प्रदान करती है (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
}
आधार रेखा (अहस्ताक्षरित टेक्स्ट qub): version = 0x01, content_type = 0x01, sig_alg = 0x00, सभी Option क्षेत्र अनुपस्थित।
अन्य v1 कॉन्फ़िगरेशन: content_type = 0x03 (संधि बॉडी, देखें §6.1); sig_alg = 0x01 (ML-DSA-65) author_signature और author_pubkey मौजूद के साथ (देखें §9.3); सह-हस्ताक्षरित संधियों के लिए cosigner_pubkey और cosigner_signature एक साथ उपस्थित (देखें §9.7); उत्तर-शृंखला qubs के लिए reply_to मूल qub के qub_id पर सेट (हस्ताक्षर दायरे के निहितार्थ के लिए §9.3 देखें)।
2.3 SealedQub (कैनोनिकल वायर प्रारूप)
कैनोनिकल CBOR (§3) का उपयोग करके क्रमबद्ध। स्थायी संग्रहण में लिखा जाता है। यह ऑन-चेन कलाकृति है।
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 — प्रकट होने से पहले verdict-watch CTA पर
// प्रदर्शित; QubEnvelope.outcome_at का दर्पण;
// §4.1 प्रीइमेज के माध्यम से qub_id से बंधा।
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 (दर्शक एप्लिकेशन स्थिति)
CBOR में क्रमबद्ध नहीं। दर्शक ऐप के लिए स्थानीय। सफल डिक्रिप्शन और सत्यापन के बाद निर्मित।
RevealedQub {
qub_id: [u8; 32],
arweave_tx_id: String,
visibility: u8,
content_type: u8,
created_at: i64,
unlock_at: i64,
drand_chain_id: String,
drand_round: u64,
sender_label: Option<String>,
title: Option<String>, // Carried forward from SealedQub.title
reply_to: Option<[u8; 32]>,
body: Vec<u8>,
body_hash: [u8; 32],
body_hash_verified: bool,
author_signature: Option<Vec<u8>>,
author_pubkey: Option<Vec<u8>>,
signature_verified: Option<bool>,
cosigner_pubkey: Option<Vec<u8>>,
cosigner_signature: Option<Vec<u8>>,
cosigner_verified: Option<bool>,
}
3. कैनोनिकल CBOR प्रोफ़ाइल
सभी SealedQub और QubEnvelope क्रमबद्धता इस प्रोफ़ाइल के अनुरूप होनी MUST। दिए गए समान तार्किक संरचना के साथ दो कार्यान्वयन समान बाइट्स उत्पन्न करने MUST।
3.1 एन्कोडिंग नियम
| नियम | विनिर्देशन |
|---|---|
| मानक | RFC 8949 §4.2.1 (Core Deterministic Encoding Requirements) |
| मानचित्र कुंजी क्रम | पहले एन्कोडेड बाइट लंबाई से क्रमबद्ध (छोटे से लंबे), फिर शब्दकोश क्रम (समान-लंबाई एन्कोडिंग के लिए बाइट-दर-बाइट) |
| पूर्णांक एन्कोडिंग | सबसे छोटा रूप: 0–23 प्रारंभिक बाइट में; 24–255 2 बाइट्स में; 256–65535 3 बाइट्स में; आदि। |
| लंबाई एन्कोडिंग | केवल निश्चित लंबाई। कोई अनिश्चित-लंबाई सरणियाँ, मानचित्र, बाइट स्ट्रिंग, या टेक्स्ट स्ट्रिंग नहीं (additional info = 31 निषिद्ध है)। |
| टैग | कोई CBOR टैग नहीं (मेजर टाइप 6 निषिद्ध है)। |
| फ्लोटिंग-पॉइंट | कोई फ्लोट नहीं (मेजर टाइप 7 मान 0xF9–0xFB निषिद्ध हैं)। |
| टेक्स्ट स्ट्रिंग | UTF-8 एन्कोडेड, NFC सामान्यीकृत (Unicode Normalization Form C)। |
| बाइट स्ट्रिंग | कच्चे बाइट्स। CBOR परत पर कोई base64 एन्कोडिंग नहीं। |
| डुप्लिकेट कुंजियाँ | त्रुटि के साथ अस्वीकार करें। पार्सर्स डुप्लिकेट मानचित्र कुंजियों को चुपचाप स्वीकार MUST NOT करें। |
| सरल मान | केवल true (0xF5), false (0xF4), और null (0xF6) की अनुमति है। |
| वैकल्पिक क्षेत्र | अनुपस्थित वैकल्पिक क्षेत्र CBOR मानचित्र से पूरी तरह से छोड़ दिए जाते हैं (null के रूप में एन्कोड नहीं किए जाते)। उपस्थित वैकल्पिक क्षेत्र क्रमबद्ध कुंजी क्रम में शामिल किए जाते हैं। |
3.2 सत्यापित कैनोनिकल कुंजी क्रम
ये कुंजी क्रम मानक हैं। कार्यान्वयन ठीक इसी क्रम में कुंजियाँ उत्सर्जित करना MUST। डिबग दावे गैर-रिलीज़ बिल्ड्स में क्रमण को सत्यापित करना SHOULD।
QubEnvelope (संस्करण 0x01, अहस्ताक्षरित, सभी वैकल्पिक क्षेत्र अनुपस्थित):
"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 कुंजी क्रम व्युत्पत्ति: प्रत्येक कुंजी एक CBOR टेक्स्ट स्ट्रिंग है। एन्कोडेड लंबाई = 1 बाइट हेडर + स्ट्रिंग लंबाई (24 बाइट्स से कम की स्ट्रिंग के लिए)। पहले कुल एन्कोडेड लंबाई से क्रमबद्ध करें, फिर समान-लंबाई की कुंजियों के लिए शब्दकोश क्रम से।
SealedQub (संस्करण 0x01, सार्वजनिक, कोई प्राप्तकर्ता नहीं):
"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 (संधि बॉडी, 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 सरणी की पंक्ति):
"key" (4 encoded bytes)
"value" (6 encoded bytes)
PartyIdentifier (party_a / party_b मानचित्र):
"label" (6 encoded bytes)
"contact" (8 encoded bytes) ← only if present
3.3 बाइट एन्कोडिंग संदर्भ
| प्रकार | CBOR एन्कोडिंग | उदाहरण |
|---|---|---|
| SHA3-256 हैश (32 बाइट्स) | 0x58 0x20 + 32 बाइट्स |
body_hash, qub_id |
| टाइमस्टैम्प (i64) | मेजर टाइप 0 (धनात्मक) या 1 (ऋणात्मक), सबसे छोटा एन्कोडिंग | Unix सेकंड |
| संस्करण (u8, मान 1) | 0x01 (एकल बाइट) |
|
| सामग्री प्रकार (u8, मान 1) | 0x01 (एकल बाइट) |
|
| sig_alg (u8, मान 0) | 0x00 (एकल बाइट) |
|
| ML-DSA-65 हस्ताक्षर (3,309 बाइट्स) | 0x59 0x0C 0xED + 3,309 बाइट्स |
author_signature, cosigner_signature |
| ML-DSA-65 सार्वजनिक कुंजी (1,952 बाइट्स) | 0x59 0x07 0xA0 + 1,952 बाइट्स |
author_pubkey, cosigner_pubkey |
4. मानक व्युत्पत्तियाँ
4.1 qub_id
qub_id विशिष्ट रूप से एक qub की पहचान करता है और QubEnvelope को SealedQub से बांधता है। यह एनवेलप सामग्री से नियतात्मक रूप से व्युत्पन्न किया जाता है।
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
डोमेन विभाजक एन्कोडिंग: स्ट्रिंग "QUB_ID_V2" 9 ASCII बाइट्स है। संरेखण के लिए 10 बाइट्स तक पहुँचने के लिए एक 0x00 पैडिंग बाइट जोड़ा जाता है। कार्यान्वयन ठीक इन 10 बाइट्स का उपयोग करना MUST: [0x51, 0x55, 0x42, 0x5F, 0x49, 0x44, 0x5F, 0x56, 0x32, 0x00]।
outcome_at एन्कोडिंग: V1.1 ने वैकल्पिक outcome_at क्षेत्र को बंधन में मोड़ने के लिए प्रीइमेज को 92 से 100 बाइट्स तक बढ़ाया। अनुपस्थित outcome_at 8 शून्य बाइट्स के रूप में एन्कोड किया जाता है; प्रोटोकॉल सत्यापनकर्ता हर जगह outcome_at <= 0 को अस्वीकार करते हैं, इसलिए यह सेंटिनल किसी वैध मान से टकरा नहीं सकता। देखें §3.2 (वायर प्रारूप) और verdict तंत्र के लिए इन-ट्री tasks/verdict-uplift-plan.md जो इस क्षेत्र को प्रेरित करता है।
drand_round एन्कोडिंग: V1.2 ने drand_round (लक्ष्य drand राउंड, §4.3) को बंधन में मोड़ने के लिए प्रीइमेज को 100 से 108 बाइट्स तक बढ़ाया, और डोमेन विभाजक को QUB_ID_V2 तक बढ़ाया। यह टाइमलॉक राउंड को qub पहचान में बांधता है: एक गेटवे सिफरटेक्स्ट को प्रदर्शित unlock_at द्वारा निहित राउंड से भिन्न (उदा. पहले ही बीत चुके) राउंड से दोबारा नहीं बांध सकता। अनलॉक प्रक्रिया (§8) अतिरिक्त रूप से सत्यापित करती है कि tlock सिफरटेक्स्ट स्टैन्ज़ा में पकाया गया राउंड unlock_round(unlock_at) से मेल खाता है, इसलिए प्रदर्शित अनलॉक समय प्रमाण्य रूप से वही राउंड है जो डिक्रिप्शन को नियंत्रित करता है।
गुण:
- QubEnvelope में किसी भी क्षेत्र (बॉडी, टाइमस्टैम्प, सामग्री प्रकार, संस्करण) को बदलने पर एक अलग qub_id उत्पन्न होता है।
- qub_id एन्क्रिप्शन से पहले गणना की जाती है। QubEnvelope और SealedQub दोनों एक ही qub_id ले जाते हैं। दर्शक डिक्रिप्शन के बाद उनके मिलान को सत्यापित करता है।
- qub_id
sender_label,author_signature, याauthor_pubkeyपर निर्भर नहीं करता। इसका अर्थ है कि एक ही समय पर मुहरबंद की गई एक ही सामग्री वही qub_id उत्पन्न करती है, चाहे उस पर कोई भी हस्ताक्षर करे। - SealedQub
titleको बदलने (बाकी सब कुछ स्थिर रखते हुए) सेtitle_hashके माध्यम सेqub_idबदलता है। इसलिए एक गेटवे qub पहचान को अमान्य किए बिना उलटी गिनती पर प्रदर्शित प्लेनटेक्स्ट शीर्षक को बदल नहीं सकता। - SealedQub
outcome_atको बदलने (बाकी सब कुछ स्थिर रखते हुए) से प्रीइमेज के माध्यम सेqub_idबदलता है। एक गेटवे qub पहचान को अमान्य किए बिना उलटी गिनती पर प्रदर्शित प्रकटीकरण-पूर्व verdict-on तिथि को बदल नहीं सकता। drand_roundको बदलने (बाकी सब कुछ स्थिर रखते हुए) से प्रीइमेज के माध्यम सेqub_idबदलता है। एक गेटवे qub पहचान को अमान्य किए बिना टाइमलॉक सिफरटेक्स्ट को किसी भिन्न राउंड से दोबारा नहीं बांध सकता; §8 अनलॉक-समय स्टैन्ज़ा-राउंड जाँच के साथ मिलकर, प्रदर्शितunlock_atवही राउंड है जो वास्तव में डिक्रिप्शन को नियंत्रित करता है।
4.2 body_hash
body_hash = SHA3-256(body)
जहाँ body कच्चा Vec<u8> सामग्री पेलोड है। टेक्स्ट qubs के लिए, यह UTF-8 एन्कोडेड qub बॉडी है।
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
जहाँ title वैकल्पिक प्लेनटेक्स्ट शीर्षक है जो प्रकट करने से पहले दर्शक की उलटी गिनती पर सतह पर आता है (देखें §3.2)। NFC सामान्यीकरण हैश समय पर चलता है ताकि डाइजेस्ट दृश्य रूप से समकक्ष कोड-पॉइंट अनुक्रमों में स्थिर हो। सभी-शून्य सेंटीनेल अनुपस्थित मामले के लिए आरक्षित है; एक खाली स्ट्रिंग कैनोनिकल CBOR सीमा पर "अनुपस्थित" के गैर-कैनोनिकल एन्कोडिंग के रूप में अस्वीकार की जाती है (कैनोनिकल एन्कोडिंग क्षेत्र को पूरी तरह से छोड़ देता है)।
4.3 Unlock-Round मानचित्रण
drand_round = ceil((unlock_at - chain_genesis_time) / chain_period_seconds)
| पैरामीटर | स्रोत | उदाहरण |
|---|---|---|
unlock_at |
उपयोगकर्ता-चयनित Unix सेकंड UTC | 1735689600 (2025-01-01 00:00:00 UTC) |
chain_genesis_time |
drand चेन जानकारी (genesis_time) |
1595431050 |
chain_period_seconds |
drand चेन जानकारी (period) |
30 |
ceil() ऑपरेशन पहला drand राउंड चुनता है जिसका रिवील समय ≥ unlock_at है। यह सुनिश्चित करता है कि qub चुने गए अनलॉक समय से पहले डिक्रिप्ट करने योग्य नहीं होता।
किनारा मामला: यदि (unlock_at - chain_genesis_time) chain_period_seconds से ठीक विभाज्य है, तो परिणाम ठीक वह राउंड है — qub उस राउंड के रिवील समय पर ठीक-ठीक अनलॉक होता है।
सत्यापन: unlock_at मुहरबंदी के समय भविष्य में होना MUST। unlock_at created_at से 10 वर्षों से अधिक नहीं होना MUST NOT (लंबे-क्षितिज drand निर्भरता जोखिम को सीमित करने के लिए; UI को 2 वर्षों से अधिक अनलॉक तिथियों के लिए चेतावनी देनी SHOULD)।
5. वायर प्रारूप न्यूटाइप्स
वायर प्रारूप न्यूटाइप्स CBOR बाइट्स को JSON, कच्चे प्लेनटेक्स्ट, या अन्य बाइट एन्कोडिंग के साथ भ्रमित होने से कंपाइल-टाइम सुरक्षा प्रदान करते हैं।
| प्रकार | समाहित करता है | उत्पादित | उपभोग |
|---|---|---|---|
SealedQubCbor |
SealedQub का कैनोनिकल CBOR | serialize_sealed_qub() |
स्थायी-संग्रहण अपलोड, दर्शक फ़ेच |
QubEnvelopeCbor |
QubEnvelope का कैनोनिकल CBOR | serialize_qub_envelope() |
tlock एन्क्रिप्ट इनपुट, tlock डिक्रिप्ट आउटपुट |
5.1 निर्माण नियम
// 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 निर्माण पर सत्यापन
from_encoded() को सत्यापित करना SHOULD कि इनपुट एक मान्य CBOR मानचित्र हेडर से शुरू होता है। पूर्ण संरचनात्मक सत्यापन पार्स समय पर होता है, निर्माण समय पर नहीं, ताकि दोहरी-पार्सिंग से बचा जा सके।
6. सामग्री प्रकार रजिस्ट्री
| मान | प्रकार | अधिकतम बॉडी आकार | टिप्पणियाँ |
|---|---|---|---|
0x00 |
आरक्षित (अमान्य) | — | उपयोग MUST NOT |
0x01 |
सादा टेक्स्ट (UTF-8, प्रतिबंधित मार्कडाउन) | 50 KB सशुल्क / 10 KB मुफ़्त | रेंडरिंग नियमों के लिए §10 देखें। मुफ़्त / सशुल्क विभाजन अपलोड सेवा द्वारा लागू किया जाता है; प्रोटोकॉल-परत कठोर सीमा 50 KB है। |
0x02 |
आरक्षित (भविष्य) | — | भविष्य के सामग्री प्रकार के लिए आवंटित; v1 में मान्य नहीं। दर्शक नीचे दिए गए नियम के अनुसार इसे अस्वीकार करना MUST। |
0x03 |
संधि (द्विपक्षीय समझौता, CBOR बॉडी) | 100 KB | बॉडी कैनोनिकल CBOR PactTerms (§6.1) है। सह-हस्ताक्षर §9.7 के अनुसार। |
दर्शक अज्ञात सामग्री प्रकारों को एक स्पष्ट उपयोगकर्ता-दृश्य त्रुटि के साथ अस्वीकार करना MUST। दर्शक अज्ञात प्रकारों को टेक्स्ट के रूप में रेंडर करने का प्रयास MUST NOT।
6.1 संधि बॉडी (content_type = 0x03)
संधि बॉडी PactTerms मान का कैनोनिकल CBOR एन्कोडिंग है:
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)> }
तीनों मानचित्रों के लिए कैनोनिकल CBOR कुंजी क्रम §3.2 में दिए गए हैं। कुल क्रमबद्ध संधि CBOR 100 KB से अधिक MUST NOT (§6 से मेल खाता है)।
योजना विभेदक। structured/v1 संधि के लिए terms में पहली पंक्ति { key: "pact_schema", value: "structured/v1" } होनी MUST। इस मार्कर के बिना पंक्तियाँ "कस्टम" संधियाँ हैं और कोई संरचित सत्यापन या योजना-संवेदी रेंडरिंग प्राप्त नहीं करतीं।
स्थिर स्वीकृति स्लॉट। structured/v1 संधियाँ इन कुंजियों के अंतर्गत ठीक चार स्वीकृति पंक्तियाँ ले जाती हैं:
"initiator_standard_terms"
"initiator_capacity_terms"
"counterparty_standard_terms"
"counterparty_capacity_terms"
प्रत्येक के लिए value (role, kind) जोड़ी द्वारा चुनी गई आठ स्थिर अंग्रेज़ी स्ट्रिंग्स में से एक है, जहाँ role ∈ { seller, buyer, provider, client } और kind ∈ { standard, capacity }। स्ट्रिंग्स स्वयं मानक प्रोटोकॉल डेटा हैं — दोनों पक्षों के ML-DSA-65 हस्ताक्षर body_hash के माध्यम से सटीक बाइट्स के लिए प्रतिबद्ध होते हैं। उन्हें स्थानीयकृत नहीं किया जाता; हस्ताक्षरित बॉडी भाषा-तटस्थ है। किसी भी शब्दावली परिवर्तन के लिए एक नया योजना संस्करण (structured/v2) आवश्यक है।
आठ स्ट्रिंग्स, उनकी खोज (acknowledgement_for(role, kind)), और प्रत्येक के लिए तर्क संदर्भ कार्यान्वयन द्वारा पिन किए गए हैं। अनुरूप कार्यान्वयन बाइट-समान स्वीकृति मान उत्सर्जित करना MUST; सभी चार भूमिका संयोजनों को कवर करने वाले स्वर्ण-फ़िक्स्चर SHA3-256 बॉडी-हैश परीक्षण किसी भी विचलन को पकड़ते हैं।
दर्शक प्रदर्शन क्रम। स्वीकृति स्ट्रिंग्स में "described above" जैसे वाक्यांश होते हैं, जो मानते हैं कि विवरण / दायरा पंक्तियाँ स्वीकृतियों से पहले रेंडर होती हैं। दर्शक terms सरणी को CBOR क्रम में रेंडर करना MUST; पुनः क्रमबद्ध करने से प्रोज़ अर्थ-विज्ञान टूट जाता है।
प्रति-पक्ष संपर्क। जब पक्ष B का contact एक मान्य ईमेल पता होता है, तो qub अपलोड सेवा स्टेज समय पर एक समीक्षा / सह-हस्ताक्षर निमंत्रण ईमेल स्वतः-भेजती है और अंततः सह-हस्ताक्षर को उसी पते के सत्यापन से बांधती है (§9.7)। जिन संधियों में पक्ष B संपर्क अनुपस्थित है, उन पर अभी भी सह-हस्ताक्षर किए जा सकते हैं, लेकिन केवल बैंड-से-बाहर चैनल के माध्यम से — सेवा सह-हस्ताक्षर अनुरोधों को अस्वीकार करती है जो एक मेल खाते 15-मिनट के ईमेल-सत्यापन मार्कर का उत्पादन नहीं कर सकते।
6.2 फ़ैसला बॉडी (content_type = 0x04)
फ़ैसला बॉडी VerdictBody मान का कैनोनिकल CBOR एन्कोडिंग है:
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
}
कैनोनिकल CBOR कुंजी क्रम:
"outcome" (8 encoded bytes)
"reflection" (11 encoded bytes) ← only if present
"evidence_url" (13 encoded bytes) ← only if present
"verdict_version" (16 encoded bytes)
कुल क्रमबद्ध फ़ैसला CBOR 8 KB से अधिक MUST NOT (ऊपर दी गई रजिस्ट्री पंक्ति से मेल खाता है)।
परिणाम एनम। वायर बाइट इंटेंट-तटस्थ है; चार बकेट Right / Partial / Wrong / Unfalsifiable हर फ़ैसला-वहन करने वाले इंटेंट के परिणाम-अंतराल को कवर करते हैं। प्रति-इंटेंट लेबल (Right के लिए "सही कहा था" / "निभाया" / "जारी हुआ" / "पुष्टि हुई", आदि) एक दर्शक-पक्ष रेंडरिंग चिंता है जो मूल qub के इंटेंट के विरुद्ध हल की जाती है — वायर भाषा- और इंटेंट-तटस्थ रहती है। 1..=4 से बाहर के मान डिकोड पर अस्वीकार किए जाने MUST।
मूल संबंध। एक फ़ैसला qub अपनी बॉडी में मूल संदर्भ नहीं ले जाता। मूल qub की Arweave लेन-देन id अपलोड समय पर Parent-Tx-Id संग्रहण टैग के रूप में उत्सर्जित की जाती है (§7 संग्रहण-टैग परत)। यह बॉडी को स्व-आँकलन का एक स्व-निहित हस्ताक्षरित कथन रखता है; ऑडिट श्रृंखला ("किसके बारे में सही?") Arweave-टैग लुकअप के माध्यम से स्थापित होती है।
साक्ष्य URL सुरक्षा (मानक)। जब evidence_url उपस्थित होता है, सत्यापनकर्ता (कंपोज़-पक्ष, वायर-पक्ष, Worker एज) निम्न लागू करना MUST:
- केवल HTTPS। स्ट्रिंग बाइट अनुक्रम
https://से शुरू होनी MUST। कोई अन्य योजना —http,ftp,javascript,data,file, आदि — अस्वीकार की जाती है। - लंबाई सीमा। ≤ 2,048 बाइट्स (ब्राउज़र URL व्यावहारिक सीमा)।
- NFC + शत्रुतापूर्ण-कोडपॉइंट जाँच।
titleऔरreflectionके समान नियम — bidi-override / zero-width / tag-block / BOM / C0 / C1 कोडपॉइंट अस्वीकार किए जाते हैं। परिभाषा Rustcrate::handle::contains_hostile_text_codepointऔर TSworkers/api/src/utils/unicode.ts::isHostileCodepointसे मेल खाती है (लॉकस्टेप में रखें)। - कोई व्हाइटस्पेस नहीं, कोई ASCII नियंत्रण नहीं। URL में कहीं भी व्हाइटस्पेस / DEL / सब-
0x20बाइट्स अस्वीकार किए जाते हैं —\n/\tइंजेक्शन वेक्टर को बंद करता है जिसे bidi नियम कवर नहीं करता। - गैर-खाली होस्ट खंड।
https://और पहले/,?, या#के बीच सब कुछ गैर-खाली होना MUST।
कोई सर्वर-पक्ष फ़ेचिंग नहीं। Worker URL को प्रॉक्सी, फ़ेच, या प्रीव्यू MUST NOT। प्रोटोकॉल एक स्ट्रिंग संग्रहित करता है; रेंडरिंग दर्शक-पक्ष पर rel="nofollow noopener noreferrer" target="_blank" और लिंक टेक्स्ट के साथ प्रदर्शित एक दृश्य होस्ट के साथ होती है।
चिंतन। वैकल्पिक रचयिता-लिखित चिंतन टेक्स्ट ("क्या बदला, आपने क्या सीखा")। title के समान NFC + शत्रुतापूर्ण-कोडपॉइंट सत्यापन। खाली / केवल-व्हाइटस्पेस इनपुट निर्माण समय पर अनुपस्थित में मुड़ जाता है।
योजना संस्करण। v1 केवल verdict_version = 0x01 का समर्थन करता है। भविष्य की योजना संशोधन इस बाइट को बढ़ाते हैं और §12 के अनुसार एक नए प्रोटोकॉल संस्करण के साथ आते हैं।
7. मुहरबंदी प्रोटोकॉल
पूर्ण मुहरबंदी अनुक्रम। प्रत्येक चरण मानक है।
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.
संग्रहण टैग परत (बैंड-से-बाहर)। qub अपलोड सेवा रैप किए गए पेलोड के साथ संग्रहण लेन-देन टैग्स का जानबूझकर छोटा सेट संलग्न करती है। Content-Type=application/octet-stream मानक रूप से आवश्यक है। संदर्भ सेवा अतिरिक्त रूप से तीन वैकल्पिक टैग संलग्न करती है जब रचयिता उन्हें सतह पर लाना चुनता है: Intent (allowlist-सत्यापित compose intent — उदा. quote, reply, commitment), Author (रचयिता की §9.3 पबकी फ़िंगरप्रिंट 64-वर्ण लोअरकेस हेक्स के रूप में), और Parent-Tx-Id (उत्तर शृंखलाओं के लिए मूल qub का संग्रहण लेन-देन ID, 43-वर्ण base64url)।
Author टैग प्रति qub ऑप्ट-इन है: संदर्भ रचयिता ऐप इसे केवल तब संलग्न करता है जब उपयोगकर्ता मुहरबंदी समय पर स्पष्ट रूप से सार्वजनिक श्रेय सक्षम करता है। जब टॉगल बंद होता है — डिफ़ॉल्ट — कोई Author टैग नहीं लिखा जाता और qub चेन पर बिना श्रेय वाला होता है: स्थायी संग्रहण में कुछ भी अपलोड को किसी रचयिता के हैंडल, ईमेल, या अन्य qubs से नहीं जोड़ता। जब टॉगल चालू होता है, Author फ़िंगरप्रिंट §9.5 अनुप्रमाणन शृंखला के माध्यम से रचयिता के चुने हुए @handle से हल हो जाता है। उत्तर-शृंखला संबंध और Intent गैर-पहचानने वाले होते हैं। बाहरी आवरण (§13) सिफरटेक्स्ट सहसंबंध से आंतरिक बॉडी की रक्षा करता है — एक हार्वेस्टर को drand राउंड प्रकाशित होने के बाद qub-आकार के अपलोड को पहचानने और थोक-डिक्रिप्ट करने से रोकता है।
संदर्भ सेवा जानबूझकर App-Name, App-Version, या Type टैग संलग्न नहीं करती: किसी भी ऐसे एकल-मान फ़िल्टर से GraphQL क्वेरी को संपूर्ण qub कॉर्पस वापस मिल जाएगा, जो आवरण के बॉडी-केवल गोपनीयता दायरे के साथ असंगत है।
एक अनुरूप सत्यापनकर्ता §11 तृतीय-पक्ष सत्यापन के लिए किसी भी संग्रहण टैग पर निर्भर MUST NOT; बॉडी हैश / qub_id / हस्ताक्षर केवल आंतरिक CBOR के लिए प्रतिबद्ध होते हैं, टैग सेट के लिए कभी नहीं।
8. अनलॉक प्रोटोकॉल
पूर्ण अनलॉक अनुक्रम। प्रत्येक चरण मानक है।
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. लेखकत्व हस्ताक्षर
9.1 तर्क
qubs स्थायी संग्रहण में संग्रहीत किए जाते हैं। लेखकत्व हस्ताक्षरों को अनिश्चित काल तक अजेय बने रहना चाहिए, यही कारण है कि v1.0 शास्त्रीय योजना के बजाय उत्तर-क्वांटम ML-DSA-65 योजना (FIPS 204) का उपयोग करता है जिसकी सुरक्षा qub के स्थायी जीवनकाल के भीतर ख़राब हो सकती है।
9.2 एल्गोरिथम रजिस्ट्री
sig_alg |
योजना | कुंजी आकार | हस्ताक्षर आकार |
|---|---|---|---|
0x00 |
कोई हस्ताक्षर नहीं (अहस्ताक्षरित) | — | — |
0x01 |
ML-DSA-65 (FIPS 204) | 1,952 बाइट्स | 3,309 बाइट्स |
दर्शक अज्ञात sig_alg मानों को अस्वीकार करना MUST।
9.3 हस्ताक्षरित प्रीइमेज निर्माण
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)
डोमेन विभाजक: "QUB_AUTHOR_SIG_V1" 17 ASCII बाइट्स है: [0x51, 0x55, 0x42, 0x5F, 0x41, 0x55, 0x54, 0x48, 0x4F, 0x52, 0x5F, 0x53, 0x49, 0x47, 0x5F, 0x56, 0x31]। कोई पैडिंग नहीं।
ट्रेलिंग बाइट: 91वाँ प्रीइमेज बाइट 0x00 होना MUST। संदर्भ कार्यान्वयन इसे crates/qub-core/src/signing.rs में स्थिर ORG_ID_PRESENT_INDIVIDUAL = 0x00 के रूप में उजागर करता है; सत्यापन के लिए sig_input का पुनर्निर्माण करने वाले दर्शक उसी बाइट को उत्सर्जित करना MUST।
हस्ताक्षर दायरा — क्या कवर है और क्या नहीं। sig_input चार एनवेलप क्षेत्रों के लिए प्रतिबद्ध होता है: version, qub_id, body_hash, unlock_at (साथ ही स्थिर डोमेन विभाजक और org_id_present बाइट)। उन चार में से तीन संरचनात्मक अपरिवर्तनीय हैं: qub_id स्वयं §4.1 प्रीइमेज के माध्यम से version, content_type, created_at, unlock_at, outcome_at, drand_round, और body_hash से व्युत्पन्न होता है, इसलिए उन क्षेत्रों में कोई भी परिवर्तन एक अलग qub_id उत्पन्न करता है और सकर्मक रूप से हस्ताक्षर को अमान्य कर देता है। इसलिए सीधे-प्रमाणित सतह है:
| क्षेत्र | हस्ताक्षर द्वारा प्रमाणित | कैसे |
|---|---|---|
version |
✓ | sig_input के लिए सीधा इनपुट |
qub_id |
✓ | सीधा इनपुट |
body_hash |
✓ | सीधा इनपुट |
unlock_at |
✓ | सीधा इनपुट |
content_type |
✓ | सकर्मक रूप से, qub_id प्रीइमेज के माध्यम से |
created_at |
✓ | सकर्मक रूप से, qub_id प्रीइमेज के माध्यम से |
outcome_at |
✓ | सकर्मक रूप से, qub_id प्रीइमेज के माध्यम से |
drand_round |
✓ | सकर्मक रूप से, qub_id प्रीइमेज के माध्यम से (V1.2) |
body |
✓ | सकर्मक रूप से, body_hash = SHA3-256(body) के माध्यम से |
author_pubkey |
— (निहित) | हस्ताक्षर सत्यापित करने वाली कुंजी ही परिभाषा के अनुसार लेखक है |
sender_label |
✗ | केवल-प्रदर्शन टेक्स्ट; हस्ताक्षर भंग किए बिना परिवर्तनशील |
reply_to |
✗ | थ्रेडिंग पॉइंटर; हस्ताक्षर भंग किए बिना परिवर्तनशील |
cosigner_pubkey / cosigner_signature |
— | उसी sig_input पर स्वतंत्र रूप से हस्ताक्षरित (देखें §9.7) |
drand_chain_id, tlock_ciphertext, visibility |
— | बाहरी SealedQub क्षेत्र, एनवेलप के अंदर नहीं — अपने स्वयं के संरचनात्मक अपरिवर्तनीयों (राउंड / चेन संगति) द्वारा कवर, लेकिन लेखक हस्ताक्षर द्वारा नहीं। (drand_round अब qub_id प्रीइमेज के माध्यम से सकर्मक रूप से बंधा है — ऊपर देखें।) |
गैर-प्रमाणित क्षेत्रों के सुरक्षा निहितार्थ।
- संग्रहीत बाइट्स तक राइट एक्सेस वाला कोई पक्ष लेखक के हस्ताक्षर को अमान्य किए बिना
sender_label("ऐलिस" → "मैलोरी") को बदल सकता है। एनवेलप के अंदरauthor_pubkeyसच्चा पहचान लंगर बना रहता है — दर्शकsender_labelपर भरोसा करने के बजायauthor_pubkeyसे (§9.5 अनुप्रमाणन परत के माध्यम से) प्रदर्शन पहचान व्युत्पन्न करना MUST। reply_toक्षेत्र को भी हस्ताक्षर के बाद संपादित किया जा सकता है। चूँकिqub_idसामग्री-संबोधित है, एक हमलावरreply_toको एक गैर-मौजूद लक्ष्य पर इंगित नहीं कर सकता, लेकिन वे चुपचाप उत्तर को एक अलग मौजूदा qub के नीचे फिर से जोड़ सकते हैं।
जो कार्यान्वयन अंतिम उपयोगकर्ताओं को sender_label या reply_to प्रदर्शित करते हैं, उन्हें प्राथमिक पहचान संकेत के रूप में प्रमाणित पहचान (पबकी फ़िंगरप्रिंट, अनुप्रमाणन) को सतह पर लाना MUST, लेबल को नहीं।
9.4 सत्यापन प्रक्रिया
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."
हस्ताक्षर सत्यापन सबसे महंगा ऑपरेशन है (विशेष रूप से ML-DSA-65)। इसे सभी सस्ती जाँचों (हैश, qub_id, unlock_at) के पारित होने के बाद ही किया जाना SHOULD।
9.5 पहचान अनुप्रमाणन
पहचान अनुप्रमाणन — author_pubkey का मानव-पहचानने योग्य पहचान दावों जैसे qub हैंडल, ईमेल पता, सोशल हैंडल, या पासकी क्रेडेंशियल से मानचित्रण — एक दर्शक-पक्ष प्रगतिशील संवर्धन है और हस्ताक्षर सत्यापन के लिए आवश्यक नहीं है। प्रदर्शन पहचान के लिए अनुप्रमाणन हल करने वाले दर्शक वरीयता क्रम लागू करना MUST:
handle > email > social > fingerprint
फ़िंगरप्रिंट फ़ॉलबैक SHA3-256(author_pubkey) का लोअरकेस हेक्स है; यह किसी भी हस्ताक्षरित qub के लिए हमेशा उपलब्ध है। दर्शक प्रदर्शन के लिए इसे संक्षिप्त करना MAY — संदर्भ दर्शक qub: के बाद पहले और अंतिम चार बाइट्स (qub:<8 hex>…<8 hex>) रेंडर करता है।
एक अनुरूप सत्यापनकर्ता qub API से संपर्क किए बिना, स्थायी संग्रहण और drand से परे किसी भी नेटवर्क के बिना, और किसी भी सर्वर-साइड लुकअप के बिना §9.4 में हर जाँच पूरी कर सकता है। अनुप्रमाणन समाधान केवल हस्ताक्षर सत्यापन सफल होने के बाद किया गया एक अलग सर्वोत्तम-प्रयास चरण है।
9.6 आकार प्रभाव
| Ed25519 | ML-DSA-65 | |
|---|---|---|
| हस्ताक्षर | 64 बाइट्स | 3,309 बाइट्स |
| सार्वजनिक कुंजी | 32 बाइट्स | 1,952 बाइट्स |
| प्रति qub कुल | 96 बाइट्स | 5,261 बाइट्स |
| संग्रहण लागत अंतर (~$5/MB पर) | ~$0.0005 | ~$0.026 |
500–2,000 बाइट्स के टेक्स्ट qub के लिए, ML-DSA-65 लगभग संग्रहीत आकार को तिगुना कर देता है। निरपेक्ष लागत नगण्य है।
9.7 सह-हस्ताक्षरकर्ता सत्यापन (संधि द्विपक्षीय समझौते)
द्विपक्षीय समझौतों (content_type = 0x03) के लिए, एक दूसरी हस्ताक्षर परत प्रमाणित करती है कि दोनों पक्षों ने समान शर्तों के लिए सहमति दी।
एनवेलप क्षेत्र:
cosigner_pubkey: प्रति-हस्ताक्षरकर्ता (पक्ष B) की ML-DSA-65 सार्वजनिक कुंजी।cosigner_signature: लेखक के समानsig_inputपर हस्ताक्षर (§9.3)।
दोनों क्षेत्र एक साथ उपस्थित MUST या दोनों अनुपस्थित। यदि ठीक एक उपस्थित है, तो दर्शक अखंडता त्रुटि की रिपोर्ट करना MUST।
सत्यापन प्रक्रिया:
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."
गुण:
- सह-हस्ताक्षरकर्ता लेखक के समान
sig_inputपर हस्ताक्षर करता है — दोनों पक्ष समानqub_id,body_hash, औरunlock_atके लिए प्रतिबद्ध होते हैं। qub_idव्युत्पत्ति (§4.1) में सह-हस्ताक्षरकर्ता क्षेत्र शामिल नहीं हैं। मौजूदा एनवेलप में सह-हस्ताक्षरकर्ता जोड़ने सेqub_idनहीं बदलता।- एक संधि केवल लेखक-हस्ताक्षरित (एकतरफा प्रतिबद्धता), केवल सह-हस्ताक्षरकर्ता (असामान्य), या दोनों (पूर्ण द्विपक्षीय प्रमाण) हो सकती है।
ईमेल-बंधन गेट (परिचालन)। जब एक स्टेज की गई संधि एक पक्ष B ईमेल संपर्क (§6.1) ले जाती है, तो qub अपलोड सेवा सह-हस्ताक्षर अनुरोध को अस्वीकार करना MUST जब तक कि एक अल्पकालिक ईमेल-सत्यापन मार्कर मौजूद न हो जो स्टेजिंग id और उस संपर्क के सामान्यीकृत-ईमेल हैश दोनों से मेल खाता हो। मार्कर /api/v1/auth/verify द्वारा लिखा जाता है जब मैजिक-लिंक टोकन staging_id ले जाता है और सत्यापित पता SHA-256(normalise_email(party_b.contact)) से मेल खाता है — जहाँ normalise_email(addr) स्थानीय-भाग के केस को संरक्षित करता है और केवल डोमेन भाग को लोअरकेस करता है (RFC 5321 §2.3.11 के अनुसार), और SHA-256 यहाँ NIST FIPS 180-4 हैश है (§4 व्युत्पत्तियों में उपयोग किए जाने वाले SHA3-256 से अलग) — और जारी होने के 900 सेकंड (15 मिनट) बाद समाप्त हो जाता है। यह एक परिचालन प्रति-प्रतिरूपण गेट है, ऑन-चेन qub प्रमाण का हिस्सा NOT — एक तृतीय-पक्ष सत्यापनकर्ता जो §11 को रिप्ले कर रहा है, उसे केवल स्थायी संग्रहण और drand की आवश्यकता होती है, बिना किसी सर्वर-साइड लुकअप के। मार्कर केवल सर्वर-साइड मौजूद है और हस्ताक्षरित बॉडी का हिस्सा कभी नहीं होता।
आकार प्रभाव (ML-DSA-65 लेखक + सह-हस्ताक्षरकर्ता):
| घटक | आकार |
|---|---|
| लेखक हस्ताक्षर | 3,309 बाइट्स |
| लेखक सार्वजनिक कुंजी | 1,952 बाइट्स |
| सह-हस्ताक्षरकर्ता हस्ताक्षर | 3,309 बाइट्स |
| सह-हस्ताक्षरकर्ता सार्वजनिक कुंजी | 1,952 बाइट्स |
| कुल क्रिप्टो ओवरहेड | 10,522 बाइट्स |
| संग्रहण लागत अंतर | ~$0.05 |
10. मार्कडाउन रेंडरिंग और स्वच्छीकरण
यह अनुभाग सुरक्षा-गंभीर है। दर्शक एक प्रतिबंधित मार्कडाउन उपसमुच्चय का उपयोग करके टेक्स्ट qubs (content_type = 0x01) को रेंडर करता है।
10.1 अनुमत तत्व
- शीर्षक:
#से####तक (कोई#####या######नहीं) - ज़ोर: बोल्ड (
**), इटैलिक (*), स्ट्राइकथ्रू (~~) - सूचियाँ: क्रमबद्ध (
1.) और अक्रमबद्ध (-,*) - ब्लॉकउद्धरण (
>) - कोड: इनलाइन स्पैन (```) और बाड़ लगाए गए ब्लॉक (`````)
- क्षैतिज नियम (
---) - पंक्ति विराम (दो ट्रेलिंग रिक्त स्थान या रिक्त पंक्ति)
- अनुच्छेद
10.2 निषिद्ध तत्व
| तत्व | संभालन |
|---|---|
कच्चा HTML (<div>, <script>, इत्यादि) |
पूरी तरह से हटा दिया जाता है। कोई HTML पास नहीं होता। |
छवियाँ () |
हटा दी जाती हैं। आउटपुट से छवि सिंटैक्स हटा दिया जाता है। |
लिंक ([text](url)) |
URL दृश्यमान सादा टेक्स्ट के रूप में रेंडर किया जाता है। ऑटो-लिंक नहीं। स्पष्ट उपयोगकर्ता क्रिया के बिना क्लिक करने योग्य नहीं। |
| खतरनाक URL योजनाएँ | javascript:, data:, vbscript:, file: — हटा दिए जाते हैं। |
| Iframes, embeds, objects | हटा दिए जाते हैं। |
| HTML इकाइयाँ | केवल सुरक्षित होने पर प्रदर्शन वर्णों में डिकोड की जाती हैं। |
10.3 कार्यान्वयन
कार्यान्वयन एक सख्त अनुमति-सूची पार्सर का उपयोग करना MUST, अवरुद्ध-सूची का नहीं। अनुशंसित दृष्टिकोण:
pulldown-cmark(या समकक्ष) का उपयोग करके मार्कडाउन पार्स करें।- AST के माध्यम से चलें और अनुमति-सूची (§10.1) में नहीं किसी भी नोड को छोड़ दें।
- लिंक नोड्स के लिए: URL को दृश्यमान टेक्स्ट के रूप में उत्सर्जित करें, क्लिक करने योग्य
<a>तत्व के रूप में नहीं। - फ़िल्टर किए गए AST को एक टाइप्ड मध्यवर्ती प्रतिनिधित्व (उदा. केवल सुरक्षित वैरिएंट्स के साथ एक
MarkdownNodeenum) में परिवर्तित करें। इस IR में कच्चा HTML संरचनात्मक रूप से अप्रतिनिधित्व योग्य है। - टाइप्ड IR से लक्ष्य व्यू परत (उदा. प्रतिक्रियाशील व्यू घटक, DOM नोड्स) में रेंडर करें। किसी भी बिंदु पर कोई HTML स्ट्रिंग संयोजन या
innerHTMLनहीं।
अवरुद्ध-सूची दृष्टिकोण नाजुक हैं क्योंकि नए मार्कडाउन एक्सटेंशन या पार्सर विचित्रताएँ अनफ़िल्टर्ड तत्वों को पेश कर सकती हैं। टाइप्ड-AST दृष्टिकोण XSS को संरचनात्मक रूप से असंभव बनाता है — कोई वैरिएंट नहीं है जो मनमाने HTML को ले जा सके।
10.4 आकार और संरचना सीमाएँ
- अधिकतम रेंडर किया गया शीर्षक गहराई:
####(H4)।#####और गहरे बोल्ड टेक्स्ट के रूप में रेंडर किए जाते हैं। - अनुच्छेद गणना पर कोई सीमा नहीं (§6 में बॉडी आकार सीमाएँ बाधा हैं)।
- बाड़ लगाए गए कोड ब्लॉक: MVP में कोई सिंटैक्स हाइलाइटिंग नहीं। मोनोस्पेस पूर्व-प्रारूपित टेक्स्ट के रूप में रेंडर।
11. तृतीय-पक्ष सत्यापन
कोई भी तृतीय पक्ष qub सहयोग के बिना सार्वजनिक qub को सत्यापित कर सकता है। सत्यापन प्रक्रिया:
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.
सत्यापन क्या प्रमाणित करता है:
| प्रमाण | यह क्या स्थापित करता है |
|---|---|
| प्रतिबद्धता | संग्रहण ब्लॉक टाइमस्टैम्प द्वारा सिफरटेक्स्ट मौजूद था। |
| अखंडता | प्लेनटेक्स्ट बॉडी प्रतिबद्ध हैश से मेल खाती है और बदली नहीं गई है। |
| समय | सामग्री drand राउंड तक अपठनीय थी, जो चुने हुए अनलॉक समय (tlock और drand सुरक्षा धारणाओं के अधीन) से मेल खाती है। |
सत्यापन क्या प्रमाणित नहीं करता:
| गैर-प्रमाण | क्यों |
|---|---|
| लेखकत्व | sender_label सजावटी है। sig_alg ≥ 0x01 के बिना, कोई भी इस सामग्री को मुहरबंद कर सकता था। |
| इरादा | qub सामग्री और समय प्रमाणित करता है, यह नहीं कि रचयिता ने व्यक्तिपरक रूप से क्या मतलब किया। |
| पूर्व-घटना समय | संग्रहण ब्लॉक समावेशन वास्तविक अपलोड से मिनटों से पीछे हो सकता है। प्रतिबद्धता टाइमस्टैम्प ब्लॉक समय है, उस क्षण नहीं जब उपयोगकर्ता ने "मुहर लगाएँ" दबाया। |
12. संस्करण
12.1 प्रोटोकॉल संस्करण
SealedQub और QubEnvelope दोनों में version क्षेत्र (u8) मुख्य प्रोटोकॉल संस्करण की पहचान करता है।
- दर्शक एक स्पष्ट त्रुटि के साथ अज्ञात प्रमुख संस्करणों को अस्वीकार करना MUST।
- ज्ञात प्रमुख संस्करण अज्ञात वैकल्पिक क्षेत्रों को सहन MAY यदि फ़ॉरवर्ड संगतता नियम अनुमति देते हैं (कैनोनिकल कुंजी क्रम से अनुपस्थित वैकल्पिक क्षेत्र अनदेखे किए जाते हैं)।
- सामग्री प्रकार (
content_type) और हस्ताक्षर योजनाएँ (sig_alg) संस्करण-नियंत्रित हैं: नए मान केवल एक नए प्रोटोकॉल संस्करण या स्पष्ट रजिस्ट्री अद्यतन के साथ ही प्रस्तुत किए जा सकते हैं।
12.2 संस्करण इतिहास
| संस्करण | मान | विवरण |
|---|---|---|
| v1 | 0x01 |
सार्वजनिक टेक्स्ट qubs (content_type 0x01), संधि द्विपक्षीय समझौते (0x03, structured/v1 योजना, ML-DSA-65 लेखक + सह-हस्ताक्षरकर्ता), tlock, SHA3-256 |
12.3 फ़ॉरवर्ड संगति
एक v1 दर्शक जो अज्ञात वैकल्पिक CBOR मानचित्र कुंजियों (§3.2 कैनोनिकल क्रम में नहीं की कुंजियाँ) के साथ QubEnvelope का सामना करता है, उन कुंजियों को अनदेखा करना SHOULD और ज्ञात क्षेत्रों का उपयोग करके सत्यापन के साथ आगे बढ़ना SHOULD। यह भविष्य के छोटे जोड़ (उदा. नया मेटाडेटा) को बिना प्रमुख संस्करण उछाल की आवश्यकता के अनुमति देता है।
एक v1 दर्शक जो sig_alg = 0x01 (ML-DSA-65) का सामना करता है लेकिन ML-DSA-65 सत्यापन समर्थन की कमी है, qub सामग्री को "हस्ताक्षर उपस्थित लेकिन सत्यापन योग्य नहीं" सूचना के साथ प्रदर्शित करना SHOULD, qub को पूरी तरह से अस्वीकार नहीं करना। संदर्भ कार्यान्वयन आज 0x00 और 0x01 के अलावा हर sig_alg मान को अस्वीकार करता है क्योंकि v1 रजिस्ट्री में कोई अन्य मान्य एल्गोरिथम नहीं है — सख्त अस्वीकृति और सॉफ्ट-फ़ेल तब तक अवलोकनात्मक रूप से समान हैं जब तक कि एक तीसरा एल्गोरिथम पंजीकृत न हो। ऊपर का सॉफ्ट-फ़ेल व्यवहार तब भार-वहन करने वाला हो जाता है जब §9.2 एक नई प्रविष्टि स्वीकार करता है, और संदर्भ दर्शक उस बिंदु पर सॉफ्ट-फ़ेल करने के लिए अद्यतन किया जाएगा।
12.4 बाहरी आवरण संस्करण
§13 में वर्णित OuterWrapper अपना स्वयं का version बाइट ले जाता है, स्वतंत्र SealedQub.version और QubEnvelope.version से। दो संस्करण स्थान अलग-अलग विकसित होते हैं: एक भविष्य का उत्तर-क्वांटम-सुरक्षित सममित प्रतिस्थापन आंतरिक प्रोटोकॉल संस्करण को छुए बिना आवरण बाइट को उछालता है, और एक भविष्य का प्रोटोकॉल-परत जोड़ (उदा. एक नया एनवेलप क्षेत्र) आवरण बाइट को छुए बिना आंतरिक संस्करण को उछालता है।
OUTER_WRAPPER_VERSION_* |
मान | एल्गोरिथम | स्थिति |
|---|---|---|---|
OUTER_WRAPPER_VERSION_1 |
0x01 |
AES-256-GCM 12-बाइट nonce, 16-बाइट प्रमाणीकरण टैग, AAD qub_id से बंधा |
v1 डिफ़ॉल्ट |
| — | 0x02–0xFF |
आरक्षित | भविष्य |
दर्शक अज्ञात आवरण संस्करणों को एक स्पष्ट त्रुटि के साथ अस्वीकार करना MUST। प्रोटोकॉल जानबूझकर आवरण संस्करण स्थान को संकीर्ण रखता है जब तक कि एक ठोस माइग्रेशन चालक प्रकट नहीं होता (उदा. एक अलग AEAD के पक्ष में NIST मार्गदर्शन); एक 0x02 स्लॉट उसी संशोधन में आवंटित किया जाएगा जो एल्गोरिथम का परिचय देता है।
13. बाहरी एन्क्रिप्शन आवरण
13.1 तर्क
प्रोटोकॉल परतें (QubEnvelope → tlock → SealedQub) एक मुहरबंद qub को समय-बद्ध बनाती हैं: बॉडी unlock_at तक अपठनीय है और drand राउंड हस्ताक्षर प्रकाशित हो चुका है। हालाँकि, अनलॉक के बाद, राउंड हस्ताक्षर सार्वजनिक है और SealedQub का कैनोनिकल CBOR आकार पहचानने योग्य है, इसलिए एक हार्वेस्टर जिसने स्थायी-संग्रहण लेन-देन को अनुक्रमित किया है, संपूर्ण qub कॉर्पस को थोक-डिक्रिप्ट कर सकता है।
बाहरी एन्क्रिप्शन आवरण कैनोनिकल SealedQubCbor और स्थायी संग्रहण में लिखे गए बाइट्स के बीच एक अतिरिक्त सममित AEAD परत डालकर उस चैनल को बंद कर देता है। 256-बिट कुंजी K डिलीवरी URL के URL फ़्रैगमेंट में और उपयोगकर्ता डिवाइसों पर केवल रहती है; ब्राउज़र URL फ़्रैगमेंट सर्वर को संचारित नहीं करते, इसलिए qub.social, हर संग्रहण गेटवे, और दोनों के सामने हर CDN K के लिए अवलोकनात्मक रूप से अंधे हैं। स्थायी संग्रहण में हर qub इसलिए एक अपारदर्शी सिफरटेक्स्ट है जिसका प्लेनटेक्स्ट उस URL के बिना अप्राप्य है जिसे रचयिता ने साझा करने के लिए चुना।
शुद्ध प्रभाव:
- डिफ़ॉल्ट रूप से गणन प्रतिरक्षा। स्थायी संग्रहण में रैप किए गए बाइट्स मनमाने सिफरटेक्स्ट से बाइट-अप्रभेद्य हैं। "qub-आकार के अपलोड के लिए GraphQL-क्वेरी करें, सार्वजनिक drand हस्ताक्षरों के साथ थोक-डिक्रिप्ट करें" की एक हार्वेस्टर रणनीति प्लेनटेक्स्ट के साथ समाप्त नहीं होती।
- क्रिप्टो-श्रेडिंग गोपनीयता मुद्रा। qub.social शाब्दिक रूप से अपने स्वयं के कॉर्पस को डिक्रिप्ट नहीं कर सकता। सबपोएना सिफरटेक्स्ट तक पहुँचते हैं, प्लेनटेक्स्ट तक नहीं।
- दो-स्तरीय गोपनीयता सीढ़ी। डिफ़ॉल्ट = लिंक-नियंत्रित पहुँच (यह अनुभाग)। प्राप्तकर्ता-एन्क्रिप्टेड निजी qubs (एक आरक्षित Phase-2 सुविधा, अभी तक निर्दिष्ट नहीं) दूसरे स्तर के रूप में शीर्ष पर परत बनाते हैं।
13.2 परतीकरण
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)
प्रोटोकॉल परत (§7, §8) पर मुहरबंदी और अनलॉक आवरण सीमा के नीचे अपरिवर्तित हैं; आवरण seal() के कॉल साइट पर जुड़ता है और unlock() के कॉल साइट पर अलग होता है।
13.3 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
}
क्षेत्र अपरिवर्तनीय।
versionv1.0 आवरण बाइट्स के लिए0x01के बराबर होना MUST।qub_idअनरैपिंग के बाद पुनर्प्राप्त SealedQub केqub_idक्षेत्र के बराबर होना MUST। अनरैप चरण इसे सीधे लागू नहीं करता (AEAD AAD बंधन बाइट-स्तरीय छेड़छाड़ को असंभव बनाता है), लेकिन अनलॉक परत सकर्मक रूप से संबंध की जाँच करती है: यदि एक रचयिता एकSealedQubCborको रैप करता है जिसका आंतरिकqub_idआवरणqub_idसे मेल नहीं खाता, तो §8 चरण 11 विफल हो जाता है।nonce96 बिट (12 बाइट्स) होना MUST, प्रत्येक रैप ऑपरेशन के लिए एक CSPRNG द्वारा ताज़ा उत्पन्न किया गया। एक ही कुंजी के तहत एक nonce का पुन: उपयोग AEAD nonce-पुन: उपयोग हमलों की अनुमति देता है जो प्लेनटेक्स्ट को पुनर्प्राप्त करते हैं; उत्पादक (key,nonce) जोड़ों को एक-शॉट के रूप में मानना MUST।ciphertextAES-256-GCM आउटपुट है: 16-बाइट प्रमाणीकरण टैग के साथ संयोजित सिफरटेक्स्ट बाइट्स।ciphertext.len() == SealedQubCbor.len() + 16ठीक।
CBOR एन्कोडिंग। §3 के अनुसार कैनोनिकल CBOR, उसी कुंजी-क्रम नियम के साथ (एन्कोडेड बाइट लंबाई आरोही द्वारा क्रमबद्ध, फिर शब्दकोश)। चार कुंजियाँ हैं:
| कुंजी | एन्कोडेड बाइट्स | क्रम |
|---|---|---|
nonce |
6 | 1 |
qub_id |
7 | 2 |
version |
8 | 3 |
ciphertext |
11 | 4 |
OuterWrapper CBOR का पहला बाइट इसलिए 4-प्रविष्टि मानचित्र (0xA4) के लिए निश्चित-लंबाई मानचित्र हेडर है।
13.4 qub_id के लिए AAD बंधन
आवरण qub_id को AEAD अतिरिक्त प्रमाणित डेटा के रूप में बांधता है। यह तीन वर्ग के हमलों के विरुद्ध भार-वहन करने वाली संरचनात्मक रक्षा है:
| हमला | रक्षा |
|---|---|
आवरण में एक अलग qub_id क्षेत्र के तहत सिफरटेक्स्ट स्थानांतरित करें |
AAD बेमेल → AEAD प्रमाणीकरण विफल |
| qub A के URL फ़्रैगमेंट को qub B के स्थायी-संग्रहण बाइट्स के साथ मिलाएँ | AAD बेमेल → AEAD प्रमाणीकरण विफल |
अपलोड के बाद आवरण के qub_id क्षेत्र से छेड़छाड़ करें |
AAD बेमेल → AEAD प्रमाणीकरण विफल |
आवरण प्लेनटेक्स्ट में qub_id ले जाना गणन प्रतिरक्षा को सार्थक रूप से कमज़ोर नहीं करता — qub_id स्वयं §4.1 प्रीइमेज का SHA3-256 हैश है जिसमें डाइजेस्ट से कोई पुनर्प्राप्ति योग्य प्रीइमेज नहीं है, और एक गणक जिसने पहले से आवरण बाइट्स को काटा है, दृश्यमान qub_id से कुछ नहीं सीखता जो वे अपलोड के अस्तित्व से अनुमान नहीं लगा सकते।
13.5 रैप और अनरैप एल्गोरिथम
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
विफलता-मोड पतन। ग़लत K, ग़लत nonce, AAD बेमेल, और छेड़छाड़ किया गया सिफरटेक्स्ट सभी एक ही DECRYPT_FAILED त्रुटि उत्पन्न करते हैं। यह एक जानबूझकर AEAD गुण है: विफलता मोड को अलग करने से एक साइड चैनल बनेगा जिसे एक दूरस्थ हमलावर विकृत आवरण भेजकर और प्रतिक्रिया को समयित करके जाँच सकता है। संदर्भ कार्यान्वयन सभी AEAD विफलताओं को एकल त्रुटि आकार में संक्षेपित करना MUST।
13.6 कुंजी सामग्री और वितरण
रैपिंग कुंजी K एक प्रति-qub CSPRNG द्वारा उत्पन्न एक 256-बिट समान यादृच्छिक मान है। संदर्भ कार्यान्वयन इसे यहाँ से प्राप्त करते हैं:
- WASM रचयिता:
getrandom(wasm_jsबैकएंड के तहत WebCrypto)। - वर्कर सर्वर-साइड seal रूट:
crypto.getRandomValues।
वितरण: K को URL-सुरक्षित base64 (RFC 4648 §5, कोई पैडिंग नहीं) के रूप में एन्कोड किया जाना MUST और फ़्रैगमेंट घटक के रूप में डिलीवरी URL में जोड़ा जाना MUST:
delivery_url = <origin>/c/<arweave_tx_id>#<base64url(K)>
फ़्रैगमेंट को किसी भी सर्वर को एक अनुरूप ब्राउज़र द्वारा कभी संचारित नहीं किया जाता। पुनर्प्राप्ति चैनल (सर्वर-साइड इतिहास सूचकांक, ऑप्ट-इन ईमेल ऑटो-सेंड) जो उपयोगकर्ता डिवाइस से परे पूर्ण डिलीवरी URL — फ़्रैगमेंट सहित — को बनाए रखते हैं, डिफ़ॉल्ट क्रिप्टो-श्रेडिंग मुद्रा के विरुद्ध एक स्पष्ट व्यापार हैं और स्पष्ट उपयोगकर्ता सहमति पर गेट किए जाने MUST।
फ़्रैगमेंट हानि। यदि एक उपयोगकर्ता URL फ़्रैगमेंट खो देता है और कोई पुनर्प्राप्ति चैनल नहीं है, तो qub अपठनीय है। यह डिज़ाइन का भार-वहन करने वाला व्यापार है और मुहरबंदी समय पर उपयोगकर्ता को प्रकट किया जाना MUST। MVP मुहरबंदी-समय प्रकटीकरण को स्पष्ट "इस URL को सहेजें" प्रति और ऑप्ट-इन करने वाले उपयोगकर्ताओं के लिए एक सत्यापित-ईमेल पुनर्प्राप्ति चैनल के साथ मज़बूत करता है।
13.7 इस अनुभाग के लिए दायरे से बाहर
- लेखकत्व हस्ताक्षर (§9) अपरिवर्तित है: हस्ताक्षर आंतरिक
QubEnvelopeके अंदर गणना किए जाते हैं और अनरैप → tlock डिक्रिप्ट → CBOR पार्स के बाद पुनर्प्राप्त किए जाते हैं। - प्राप्तकर्ता-एन्क्रिप्टेड निजी qubs (एक आरक्षित Phase-2 सुविधा, अभी तक निर्दिष्ट नहीं) एक दूसरे गोपनीयता स्तर के रूप में इस आवरण के शीर्ष पर रचना करते हैं; दोनों स्तर एक साथ सक्रिय हो सकते हैं।
- संधियाँ (§6, content_type
0x03) टेक्स्ट qubs की तरह बिल्कुल रैप की जाती हैं; आवरण आंतरिक सामग्री प्रकार के लिए बाइट-अंधा है।
13.8 सार्वजनिक qubs (आवरण लोप)
बाहरी आवरण वितरण परत पर वैकल्पिक है। एक रचयिता एक qub को सार्वजनिक के रूप में मुहरबंद कर सकता है, जिस स्थिति में कैनोनिकल SealedQubCbor को स्थायी संग्रहण में सीधे लिखा जाता है, बिना किसी OuterWrapper परत और बिना कुंजी K के:
SealedQubCbor bytes ──(public)──▶ uploaded to permanent storage as-is
SealedQubCbor bytes ──(private)─▶ AES-256-GCM(K, …) ▶ OuterWrapper ▶ uploaded
एक सार्वजनिक qub समय-बद्ध है लेकिन लिंक-नियंत्रित नहीं: यह तब तक अपठनीय रहता है जब तक इसका drand राउंड प्रकाशित नहीं हो जाता (tlock परत अपरिवर्तित है), लेकिन अनलॉक के बाद कोई भी जिसके पास arweave_tx_id है इसे डिक्रिप्ट कर सकता है — किसी URL फ़्रैगमेंट की आवश्यकता नहीं, क्योंकि कोई K नहीं है। यह उन सतहों के लिए जानबूझकर किया गया व्यापार है जिन्हें सर्वर को चलाना MUST: प्रकट-समय अधिसूचना ईमेल, तृतीय-पक्ष एम्बेड, और समृद्ध प्रकट-के-बाद SEO सभी को एक ऐसे लिंक की आवश्यकता है जो उस रहस्य के बिना काम करे जिसे सर्वर कभी धारण नहीं करता (§13.6)।
परिणाम जिनके लिए एक उत्पादक को MUST हिसाब रखना:
- कोई गणन प्रतिरक्षा नहीं। सार्वजनिक qubs रचना द्वारा §13.1 गणन-प्रतिरक्षा गुण को त्याग देते हैं। संदर्भ अपलोड सेवा उन पर (और केवल उन पर) एक
Visibility: publicस्थायी-संग्रहण टैग मुद्रित करती है ताकि वे जानबूझकर खोजने योग्य हों; निजी qubs ऐसा कोई टैग नहीं ले जाते और अपनी बाइट-अप्रभेद्यता बनाए रखते हैं। - मुहरबंदी समय पर उजागर प्लेनटेक्स्ट शीर्षक। §3.2
titleक्षेत्रSealedQubCborके अंदर प्लेनटेक्स्ट है। आवरण के तहत यह तब तक छिपा रहता है जब तक एक दर्शकKप्रदान नहीं करता; आवरण के बिना यह स्थायी संग्रहण पर अपलोड के क्षण से, अनलॉक से पहले, विश्व-पठनीय है। अनुरूप रचयिता ऐप्स इसे मुहरबंदी समय पर प्रकट करना MUST। - पहचान संरचनात्मक है। एक अनुरूप दर्शक/एम्बेड दो आकृतियों को पार्स द्वारा अलग करता है: जो बाइट्स
OuterWrapperके रूप में पार्स होते हैं वेK-के-साथ-अनरैप पथ लेते हैं; जो बाइट्स एक नंगेSealedQubCborके रूप में पार्स होते हैं वे सीधे स्वीकार किए जाते हैं। किसी वायर फ़्लैग की आवश्यकता नहीं, औरqub_idदृश्यता को नहीं बांधता —SealedQubपरत पर वही सामग्री बाइट-समान है चाहे सार्वजनिक मुहरबंद हो या निजी।
निजी (रैप किया हुआ) डिफ़ॉल्ट बना रहता है; सार्वजनिक एक स्पष्ट प्रति-qub रचयिता विकल्प है।
14. परीक्षण सदिश
14.1 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
कार्यान्वयन इस इनपुट के लिए समान body_hash और qub_id मान उत्पन्न करना MUST। यह परीक्षण सदिश पहली यूनिट परीक्षण के रूप में लिखा जाना SHOULD। ऊपर कैनोनिकल मान संदर्भ कार्यान्वयन द्वारा गणना किए गए थे और बिट-दर-बिट मेल खाना MUST। ऐतिहासिक प्रीइमेज विन्यास (प्री-लॉन्च — कोई जीवित qubs इन पर निर्भर नहीं थे): 92-बाइट V1.0 qub_id 3d9fc2390eab043d38a1669ed3b71be76f9eefe872b9569ab1aaa027b88392b0 था; 100-बाइट V1.1 qub_id (outcome_at_or_zero मोड़ने के बाद) b0d032898ad629795150fdcb3f84e518f59ed05b7a2a82bc24ebdb87f52144ed था। V1.2 drand_round को मोड़ता है और डोमेन विभाजक को QUB_ID_V2 तक बढ़ाता है।
14.2 Unlock-Round मानचित्रण
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 कैनोनिकल CBOR राउंड-ट्रिप
कार्यान्वयन सत्यापित करना MUST कि सभी मान्य इनपुट्स के लिए serialize(parse(serialize(qub))) == serialize(qub)। यह एक गुण परीक्षण है, एकल सदिश नहीं।
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)
कैनोनिकल CBOR बाइट्स और SHA3-256 body_hash संदर्भ कार्यान्वयन द्वारा गणना किए जाते हैं। कार्यान्वयन इस इनपुट के लिए बाइट-समान CBOR उत्पन्न करना MUST।
कार्यान्वयन यह भी सत्यापित करना MUST कि सभी मान्य PactTerms इनपुट्स के लिए serialize(parse(serialize(pact))) == serialize(pact) (गुण परीक्षण)।
14.5 बाहरी आवरण क्रॉस-भाषा सदिश
बाहरी आवरण (§13) का crates/qub-core/tests/vectors/wrapper_v1.json पर एक अलग कैनोनिकल फ़िक्स्चर है। प्रत्येक मामला अपारदर्शी हेक्स इनपुट्स के रूप में एक (key, nonce, qub_id, sealed_cbor) टपल को स्थिर करता है और एक विशिष्ट expected_wrapper_hex आउटपुट पर ज़ोर देता है। दोनों संदर्भ कार्यान्वयन समान JSON फ़ाइल का उपभोग करते हैं:
- 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)।
फ़िक्स्चर वर्तमान में तीन मामलों को पिन करता है:
| मामला | कवरेज |
|---|---|
basic-text-public |
सबसे छोटा यथार्थवादी SealedQub आकार; कोई वैकल्पिक क्षेत्र नहीं। एक v1.0-विशिष्ट qub के लिए कैनोनिकल आवरण आकार स्थापित करता है। |
with-recipient-pubkey |
recipient_pubkey सेट के साथ SealedQub (चरण 2 पथ)। अलग आंतरिक CBOR कुंजी सेट, अलग qub_id। |
longer-body |
~4 KiB बॉडी — आंतरिक एनवेलप और बाहरी सिफरटेक्स्ट दोनों के अंदर मल्टी-बाइट CBOR लंबाई उपसर्ग का अभ्यास करता है। |
कार्यान्वयन रिकॉर्ड किए गए इनपुट्स के लिए बाइट-समान expected_wrapper_hex उत्पन्न करना MUST। फ़िक्स्चर का पुनर्जनन QUB_REGEN_VECTORS=1 cargo test -p qub-core --test wrapper_vectors की आवश्यकता है और जानबूझकर प्रारूप परिवर्तनों के लिए आरक्षित है।
15. क्रिप्टो प्रोफ़ाइल शासन (भविष्य)
यह अनुभाग v1 के लिए सूचनात्मक है और तब मानक बनता है जब पहली बार qub के किसी क्रिप्टोग्राफ़िक आदिम में दूसरा एल्गोरिथम प्रवेश करता है।
15.1 वर्तमान मुद्रा
प्रोटोकॉल v1 प्रति आदिम ठीक एक एल्गोरिथम बांधता है:
- हस्ताक्षर: ML-DSA-65 (
sig_alg = 0x01; 1952-बाइट सार्वजनिक कुंजी, 3309-बाइट हस्ताक्षर) और अहस्ताक्षरित (sig_alg = 0x00)। §9.2 रजिस्ट्री कोई अन्य मान परिभाषित नहीं करती; एक v1 सत्यापनकर्ता{0x00, 0x01}के बाहर हरsig_algको अस्वीकार करना MUST। भविष्य की Ed25519 प्रविष्टि अपेक्षित है (§15.3) लेकिन v1 में आवंटित नहीं है। - टाइमलॉक: केवल drand quicknet — चेन हैश, सार्वजनिक कुंजी, जेनेसिस समय और अवधि स्थिर नेटवर्क पैरामीटर हैं जो संदर्भ
DrandTimelockProvider::quicknet()(crates/qub-core/src/tlock.rs) औरconfig/drand-endpoints.jsonद्वारा वहन किए जाते हैं। - बाहरी आवरण: केवल AES-256-GCM v1 (§13)।
सत्यापनकर्ता वर्तमान में प्रति आदिम कुंजी और हस्ताक्षर लंबाइयों को हार्डकोड करते हैं। वायर प्रारूप द्वारा कोई चपलता सतह उजागर नहीं की गई है।
15.2 अभिप्रेत आकार
जब एक दूसरा एल्गोरिथम प्रोटोकॉल में प्रवेश करता है, तो सत्यापनकर्ता को एक नामित CryptoProfile (उदा. ExqubV1) के लिए कॉन्फ़िगर किया जाएगा जो प्रति आदिम अनुमत मानों के सटीक सेट को सूचीबद्ध करता है — sig_algs, drand चेन, आवरण संस्करण, सामग्री प्रकार। प्रोफ़ाइल सत्यापन समय पर तय की जाती है, कभी इन-बैंड बातचीत नहीं की जाती। सक्रिय प्रोफ़ाइल के बाहर का कोई भी मान अस्वीकार कर दिया जाता है।
यह सुनिश्चित करता है कि ML-DSA-87 जोड़ना या Ed25519 सक्रिय करना मौजूदा सत्यापनकर्ता कॉन्फ़िगरेशन को पीछे की ओर कमज़ोर नहीं कर सकता: एक v1 सत्यापनकर्ता एक v2 प्रोफ़ाइल प्रकाशित होने के बाद भी v1 सत्यापनकर्ता ही रहता है।
15.3 ट्रिगर शर्तें
§15 को मानक स्थिति में पदोन्नत करें जब निम्नलिखित में से कोई प्रस्तावित हो:
- एक दूसरा
sig_algबाइट (Ed25519 सक्रियण, ML-DSA-87, या §9 रजिस्ट्री में कोई नई प्रविष्टि)। - उत्पादन उपयोग में एक दूसरी drand चेन।
- एक दूसरा बाहरी-आवरण संस्करण।
तब तक §15 एक प्लेसहोल्डर है जो माइग्रेशन आकार को स्थिर करता है ताकि भविष्य के PRs बातचीत सतह को नए सिरे से पुनः-निर्धारित करने के बजाय एक ज्ञात लक्ष्य के विरुद्ध उतरें।