Προδιαγραφή Πρωτοκόλλου qub
qub είναι ένα πρωτόκολλο για κρυπτογραφικές χρονικές δεσμεύσεις: ένα σύστημα για τη σφράγιση λέξεων σε μια μελλοντική ημερομηνία και την απόδειξη, όταν αυτή η ημερομηνία φτάσει, του τι ακριβώς ειπώθηκε και πότε.
Τρία πρωτεύοντα στοιχεία το κάνουν να λειτουργεί. drand είναι ένας αποκεντρωμένος φάρος τυχαιότητας — η ημερομηνία αποκάλυψης επιβάλλεται από τη φυσική, όχι από την καλή πίστη οποιουδήποτε μέρους. Η μόνιμη δημόσια αποθήκευση είναι ένα ανθεκτικό σε παραποίηση δημόσιο κατάστιχο — κανένα μέρος δεν μπορεί να επεξεργαστεί ή να διαγράψει ένα qub αφού αυτό σφραγιστεί. ML-DSA-65 είναι μια μετα-κβαντική ψηφιακή υπογραφή — κάθε qub συνδέεται με ένα ζεύγος κλειδιών του οποίου το μυστικό δεν εγκαταλείπει ποτέ τη συσκευή του συντάκτη.
Μαζί, αυτά τα πρωτεύοντα στοιχεία παράγουν μια δήλωση που είναι χρονοκλειδωμένη, ανθεκτική σε παραποίηση και αποδιδόμενη — μια απόδειξη της οποίας η αξία αυξάνεται καθώς βελτιώνεται η ικανότητα του κόσμου να κατασκευάζει το παρελθόν.
Το υπόλοιπο αυτού του εγγράφου είναι η κανονιστική προδιαγραφή που απαιτείται για διαλειτουργικές υλοποιήσεις.
Προδιαγραφή Πρωτοκόλλου qub
| Πεδίο | Τιμή |
|---|---|
| Έκδοση | 1.0 (έκδοση πρωτοκόλλου 0x01, έκδοση εξωτερικού περιτυλίγματος 0x01) |
| Ημερομηνία | 2026-05-01 |
| Κατάσταση | Προσχέδιο |
| Αναθεωρημένο μέχρι | 2026-05-01 |
Το παρόν έγγραφο είναι η κανονιστική προδιαγραφή πρωτοκόλλου για το σύστημα χρονικής δέσμευσης qub. Καθορίζει δομές δεδομένων, κανόνες σειριοποίησης, τύπους παραγωγής και διαδικασίες επαλήθευσης που απαιτούνται για διαλειτουργικές υλοποιήσεις.
Εμβέλεια: το επίπεδο του πρωτοκόλλου είναι σκόπιμα γλωσσικά ουδέτερο — το σώμα του qub είναι αδιαφανές απλό κείμενο / markdown / bytes συμφώνου, και η απόδοση με συναίσθηση τοπικότητας είναι ευθύνη του θεατή (εφαρμογή web qub.social, iframe <qub-embed>, πελάτες MCP, κ.λπ.).
1. Σύμβαση και Συμβολισμοί
| Συμβολισμός | Σημασία |
|---|---|
u8, u64, i64 |
Μη προσημασμένοι/προσημασμένοι ακέραιοι καθορισμένου εύρους bit |
[u8; N] |
Πίνακας bytes σταθερού μήκους N bytes |
Vec<u8> |
Πίνακας bytes μεταβλητού μήκους |
Option<T> |
Τιμή τύπου T, ή απούσα |
String |
Συμβολοσειρά κειμένου UTF-8, κανονικοποιημένη σε NFC |
| ` | |
SHA3-256(x) |
Κατακερματισμός NIST SHA3-256 της συμβολοσειράς bytes x (FIPS 202) |
ceil(x) |
Συνάρτηση οροφής: μικρότερος ακέραιος ≥ x |
| CBOR | Concise Binary Object Representation (RFC 8949) |
| big-endian | Πρώτα το πιο σημαντικό byte |
Όλοι οι ακέραιοι σε κατασκευές προεικόνας κωδικοποιούνται ως πίνακες bytes σταθερού εύρους big-endian (i64 → 8 bytes, u8 → 1 byte) εκτός αν προδιαγράφεται διαφορετικά.
Όλες οι χρονοσημάνσεις είναι δευτερόλεπτα Unix σε UTC.
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)· reply_to ορισμένο στο qub_id του γονικού qub για qubs αλυσίδας απάντησης (βλέπε §9.3 για τις επιπτώσεις στην εμβέλεια υπογραφής).
2.3 SealedQub (Κανονικό Μορφότυπο Σύρματος)
Σειριοποιείται με κανονικό CBOR (§3). Εγγράφεται σε μόνιμη αποθήκευση. Αυτό είναι το αντικείμενο on-chain.
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 — εμφανίζεται στο CTA παρακολούθησης ετυμηγορίας
// πριν την αποκάλυψη· καθρεφτίζει το QubEnvelope.outcome_at·
// δεσμεύεται στο qub_id μέσω της προεικόνας §4.1.
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,
outcome_at: Option<i64>, // V1.1 — μεταφέρεται από το QubEnvelope.outcome_at / SealedQub.outcome_at· τροφοδοτεί το μπλοκ παρακολούθησης ετυμηγορίας στη σελίδα αποκάλυψης (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. Προφίλ Κανονικού CBOR
Όλη η σειριοποίηση SealedQub και QubEnvelope ΠΡΕΠΕΙ να συμμορφώνεται με αυτό το προφίλ. Δύο υλοποιήσεις δοθείσας της ίδιας λογικής δομής ΠΡΕΠΕΙ να παράγουν πανομοιότυπα bytes.
3.1 Κανόνες Κωδικοποίησης
| Κανόνας | Προδιαγραφή |
|---|---|
| Πρότυπο | RFC 8949 §4.2.1 (Core Deterministic Encoding Requirements) |
| Διάταξη κλειδιών χάρτη | Ταξινόμηση κατά κωδικοποιημένο μήκος bytes πρώτα (μικρότερο πριν το μεγαλύτερο), μετά λεξικογραφικά (byte-προς-byte για κωδικοποιήσεις του ίδιου μήκους) |
| Κωδικοποίηση ακεραίων | Συντομότερη μορφή: 0–23 στο αρχικό byte· 24–255 σε 2 bytes· 256–65535 σε 3 bytes· κ.λπ. |
| Κωδικοποίηση μήκους | Μόνο καθορισμένα μήκη. Όχι πίνακες, χάρτες, συμβολοσειρές bytes ή συμβολοσειρές κειμένου αόριστου μήκους (επιπλέον πληροφορία = 31 απαγορεύεται). |
| Ετικέτες | Όχι ετικέτες CBOR (κύριος τύπος 6 απαγορεύεται). |
| Κινητής υποδιαστολής | Όχι floats (τιμές κύριου τύπου 7 0xF9–0xFB απαγορεύονται). |
| Συμβολοσειρές κειμένου | Κωδικοποιημένες σε UTF-8, κανονικοποιημένες σε NFC (Unicode Normalization Form C). |
| Συμβολοσειρές bytes | Ακατέργαστα bytes. Όχι κωδικοποίηση base64 στο επίπεδο CBOR. |
| Διπλά κλειδιά | Απόρριψη με σφάλμα. Οι αναλυτές ΔΕΝ ΠΡΕΠΕΙ να αποδέχονται σιωπηρά διπλά κλειδιά χάρτη. |
| Άγνωστα κλειδιά | Απόρριψη με σφάλμα. Οι αναλυτές ΔΕΝ ΠΡΕΠΕΙ να ανέχονται κλειδιά χάρτη εκτός του κανονικού συνόλου κλειδιών του τύπου — δύο διαφορετικές κανονικές συμβολοσειρές bytes δεν πρέπει ποτέ να αποκωδικοποιούνται στην ίδια τιμή (encode(decode(x)) == x), και για υπογεγραμμένα ωφέλιμα φορτία ένα επιπλέον κλειδί θα ήταν κρυφό περιεχόμενο στο οποίο δεσμεύονται και οι δύο υπογραφές. Η εξέλιξη σχήματος γίνεται μέσω του version, ποτέ μέσω επιπλέον κλειδιών. |
| Απλές τιμές | Επιτρέπονται μόνο true (0xF5), false (0xF4) και null (0xF6). |
| Προαιρετικά πεδία | Τα απόντα προαιρετικά πεδία παραλείπονται εξ ολοκλήρου από τον χάρτη CBOR (δεν κωδικοποιούνται ως null). Τα παρόντα προαιρετικά πεδία περιλαμβάνονται με την ταξινομημένη σειρά κλειδιών. |
3.2 Επαληθευμένες Κανονικές Σειρές Κλειδιών
Αυτές οι σειρές κλειδιών είναι κανονιστικές. Οι υλοποιήσεις ΠΡΕΠΕΙ να εκπέμπουν κλειδιά ακριβώς με αυτή τη σειρά. Οι ισχυρισμοί εντοπισμού σφαλμάτων ΘΑ ΕΠΡΕΠΕ να επαληθεύουν την ταξινόμηση σε μη-εκδόσεις παραγωγής.
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) ← μόνο εάν είναι παρόν (μηχανισμός ετυμηγορίας V1.1)
"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 byte κεφαλίδα + μήκος συμβολοσειράς (για συμβολοσειρές κάτω των 24 bytes). Ταξινομήστε πρώτα κατά συνολικό κωδικοποιημένο μήκος, μετά λεξικογραφικά για κλειδιά ίδιου μήκους.
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) ← μόνο εάν είναι παρόν (μηχανισμός ετυμηγορίας V1.1)
"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 Αναφορά Κωδικοποίησης Bytes
| Τύπος | Κωδικοποίηση CBOR | Παράδειγμα |
|---|---|---|
| Κατακερματισμός SHA3-256 (32 bytes) | 0x58 0x20 + 32 bytes |
body_hash, qub_id |
| Χρονοσημάνσεις (i64) | Κύριος τύπος 0 (θετικός) ή 1 (αρνητικός), συντομότερη κωδικοποίηση | Δευτερόλεπτα Unix |
| Έκδοση (u8, τιμή 1) | 0x01 (ένα byte) |
|
| Τύπος περιεχομένου (u8, τιμή 1) | 0x01 (ένα byte) |
|
| sig_alg (u8, τιμή 0) | 0x00 (ένα byte) |
|
| Υπογραφή ML-DSA-65 (3.309 bytes) | 0x59 0x0C 0xED + 3.309 bytes |
author_signature, cosigner_signature |
| Δημόσιο κλειδί ML-DSA-65 (1.952 bytes) | 0x59 0x07 0xA0 + 1.952 bytes |
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 bytes. Ένα μοναδικό byte γεμίσματος 0x00 προστίθεται για να φτάσει τα 10 bytes για ευθυγράμμιση. Οι υλοποιήσεις ΠΡΕΠΕΙ να χρησιμοποιούν ακριβώς αυτά τα 10 bytes: [0x51, 0x55, 0x42, 0x5F, 0x49, 0x44, 0x5F, 0x56, 0x32, 0x00].
Κωδικοποίηση outcome_at: Η V1.1 επέκτεινε την προεικόνα από 92 σε 100 bytes ώστε να ενσωματώσει το προαιρετικό πεδίο outcome_at στη δέσμευση. Το απόν outcome_at κωδικοποιείται ως 8 μηδενικά bytes· οι επικυρωτές του πρωτοκόλλου απορρίπτουν outcome_at <= 0 παντού, ώστε αυτή η ένδειξη να μην μπορεί να συγκρουστεί με νόμιμη τιμή. Βλέπε §3.2 (μορφότυπο σύρματος) και το ενσωματωμένο tasks/verdict-uplift-plan.md για τον μηχανισμό ετυμηγορίας που υποκινεί αυτό το πεδίο.
Κωδικοποίηση drand_round: Η V1.2 επέκτεινε την προεικόνα από 100 σε 108 bytes ώστε να ενσωματώσει το drand_round (τον γύρο-στόχο drand, §4.3) στη δέσμευση, και αναβάθμισε τον διαχωριστή πεδίου σε QUB_ID_V2. Αυτό δεσμεύει τον γύρο χρονοκλειδώματος στην ταυτότητα του qub: μια πύλη δεν μπορεί να επαναδεσμεύσει το κρυπτογραφημένο κείμενο σε διαφορετικό (π.χ. ήδη παρελθόντα) γύρο από αυτόν που υπονοεί το εμφανιζόμενο unlock_at. Η διαδικασία ξεκλειδώματος (§8) επιπλέον επαληθεύει ότι ο γύρος που είναι ψημένος μέσα στη στροφή (stanza) του κρυπτογραφημένου κειμένου tlock ταιριάζει με το unlock_round(unlock_at), οπότε ο εμφανιζόμενος χρόνος ξεκλειδώματος είναι αποδεδειγμένα ο γύρος που ελέγχει την αποκρυπτογράφηση.
Ιδιότητες:
- Η αλλαγή οποιουδήποτε πεδίου στο QubEnvelope (body, χρονοσημάνσεις, τύπος περιεχομένου, έκδοση) παράγει διαφορετικό qub_id.
- Το qub_id υπολογίζεται πριν την κρυπτογράφηση. Τόσο το QubEnvelope όσο και το SealedQub φέρουν το ίδιο qub_id. Ο θεατής επαληθεύει ότι ταιριάζουν μετά την αποκρυπτογράφηση.
- Το qub_id δεν εξαρτάται από το
sender_label, τηνauthor_signatureή τοauthor_pubkey. Αυτό σημαίνει ότι το ίδιο περιεχόμενο σφραγισμένο την ίδια στιγμή παράγει το ίδιο qub_id ανεξάρτητα από το ποιος το υπογράφει. - Η αλλαγή του
titleτου SealedQub (με όλα τα άλλα σταθερά) αλλάζει τοqub_idμέσω τουtitle_hash. Μια πύλη επομένως δεν μπορεί να εναλλάξει τον τίτλο απλού κειμένου που εμφανίζεται στην αντίστροφη μέτρηση χωρίς να ακυρώσει την ταυτότητα του qub. - Η αλλαγή του
outcome_atτου SealedQub (με όλα τα άλλα σταθερά) αλλάζει τοqub_idμέσω της προεικόνας. Μια πύλη δεν μπορεί να εναλλάξει την προ-αποκάλυψης ημερομηνία ετυμηγορίας που εμφανίζεται στην αντίστροφη μέτρηση χωρίς να ακυρώσει την ταυτότητα του qub. - Η αλλαγή του
drand_round(με όλα τα άλλα σταθερά) αλλάζει τοqub_idμέσω της προεικόνας. Μια πύλη δεν μπορεί να επαναδεσμεύσει το κρυπτογραφημένο κείμενο χρονοκλειδώματος σε διαφορετικό γύρο χωρίς να ακυρώσει την ταυτότητα του qub· σε συνδυασμό με τον έλεγχο γύρου-στροφής (stanza) κατά τον χρόνο ξεκλειδώματος της §8, το εμφανιζόμενοunlock_atείναι ο γύρος που πραγματικά ελέγχει την αποκρυπτογράφηση.
4.2 body_hash
body_hash = SHA3-256(body)
Όπου body είναι το ακατέργαστο ωφέλιμο φορτίο περιεχομένου Vec<u8>. Για qubs κειμένου, αυτό είναι το σώμα του qub κωδικοποιημένο σε UTF-8.
4.2.1 title_hash
title_hash = SHA3-256(NFC(title).utf8_bytes) if title is present
title_hash = [0u8; 32] if title is absent
Όπου title είναι ο προαιρετικός τίτλος απλού κειμένου που εμφανίζεται στην αντίστροφη μέτρηση του θεατή πριν την αποκάλυψη (βλέπε §3.2). Η κανονικοποίηση NFC εκτελείται κατά τον χρόνο κατακερματισμού ώστε η σύνοψη να είναι σταθερή σε οπτικά ισοδύναμες ακολουθίες κωδικοσημείων. Η ένδειξη απουσίας με όλα μηδενικά διατηρείται για την περίπτωση απουσίας· μια κενή συμβολοσειρά απορρίπτεται στο όριο κανονικού CBOR ως μη-κανονική κωδικοποίηση του "απών" (η κανονική κωδικοποίηση παραλείπει το πεδίο εξ ολοκλήρου).
4.3 Αντιστοίχιση Γύρου Ξεκλειδώματος
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 ΠΡΕΠΕΙ να είναι στο μέλλον κατά τον χρόνο σφράγισης. Το unlock_at ΔΕΝ ΠΡΕΠΕΙ να είναι περισσότερο από 10 χρόνια από το created_at (για τον περιορισμό του κινδύνου εξάρτησης drand σε μακρύ ορίζοντα· η διεπαφή χρήστη ΘΑ ΕΠΡΕΠΕ να προειδοποιεί για ημερομηνίες ξεκλειδώματος πέρα από 2 χρόνια).
5. Newtypes Μορφότυπου Σύρματος
Τα newtypes μορφότυπου σύρματος παρέχουν ασφάλεια κατά τον χρόνο μεταγλώττισης ενάντια στη σύγχυση των bytes CBOR με JSON, ακατέργαστο απλό κείμενο ή άλλες κωδικοποιήσεις bytes.
| Τύπος | Περιέχει | Παράγεται από | Καταναλώνεται από |
|---|---|---|---|
SealedQubCbor |
Κανονικό CBOR του SealedQub | serialize_sealed_qub() |
Ανέβασμα σε μόνιμη αποθήκευση, λήψη από θεατή |
QubEnvelopeCbor |
Κανονικό CBOR του QubEnvelope | 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() ΘΑ ΕΠΡΕΠΕ να επαληθεύει ότι η είσοδος ξεκινά με έγκυρη κεφαλίδα χάρτη CBOR. Η πλήρης δομική επαλήθευση συμβαίνει στον χρόνο ανάλυσης, όχι στον χρόνο κατασκευής, για να αποφευχθεί η διπλή ανάλυση.
6. Μητρώο Τύπων Περιεχομένου
| Τιμή | Τύπος | Μέγιστο Μέγεθος Σώματος | Σημειώσεις |
|---|---|---|---|
0x00 |
Δεσμευμένο (μη έγκυρο) | — | ΔΕΝ ΠΡΕΠΕΙ να χρησιμοποιηθεί |
0x01 |
Απλό κείμενο (UTF-8, περιορισμένο Markdown) | 50 KB επί πληρωμή / 10 KB δωρεάν | Βλέπε §10 για κανόνες απόδοσης. Ο διαχωρισμός δωρεάν / επί πληρωμή επιβάλλεται από την υπηρεσία ανεβάσματος· το αυστηρό ανώτατο όριο επιπέδου πρωτοκόλλου είναι 50 KB. |
0x02 |
Δεσμευμένο (μελλοντικό) | — | Κατανεμημένο για έναν μελλοντικό τύπο περιεχομένου· μη έγκυρο στην v1. Οι θεατές ΠΡΕΠΕΙ να το απορρίπτουν σύμφωνα με τον παρακάτω κανόνα. |
0x03 |
Σύμφωνο (διμερής συμφωνία, σώμα CBOR) | 100 KB | Το σώμα είναι κανονικό CBOR PactTerms (§6.1). Συν-υπογραφή ανά §9.7. |
0x04 |
Ετυμηγορία (αυτο-αξιολόγηση δημιουργού, σώμα CBOR) | 8 KB | Το σώμα είναι κανονικό CBOR VerdictBody (§6.2). Εκπέμπεται μόνο από την πρόθεση verdict της πλευράς του συστήματος. Η γονική σχέση βρίσκεται στην ετικέτα Arweave Parent-Tx-Id, όχι στο σώμα. Βλέπε verdict-uplift-plan §3.4. |
Οι θεατές ΠΡΕΠΕΙ να απορρίπτουν άγνωστους τύπους περιεχομένου με σαφές μήνυμα σφάλματος ορατό στον χρήστη. Οι θεατές ΔΕΝ ΠΡΕΠΕΙ να επιχειρούν να αποδώσουν άγνωστους τύπους ως κείμενο.
6.1 Σώμα Συμφώνου (content_type = 0x03)
Ένα σώμα συμφώνου είναι η κανονική κωδικοποίηση CBOR μιας τιμής PactTerms:
PactTerms {
pact_version: u8, // 0x01 for structured/v1
title: String, // ≤ 200 bytes, NFC
terms: Vec<PactTerm>, // ≤ 20 rows
party_a: PartyIdentifier, // initiator
party_b: PartyIdentifier, // counter-signer
notes: Option<String>, // ≤ 5,000 bytes, NFC; absent key if none
}
PactTerm { key: String (≤ 100), value: String (≤ 2,000) } // NFC on both sides
PartyIdentifier{ label: String (≤ 100), contact: Option<String (≤ 320)> }
Οι κανονικές σειρές κλειδιών CBOR και για τους τρεις χάρτες δίνονται στην §3.2. Το συνολικό σειριοποιημένο CBOR του συμφώνου ΔΕΝ ΠΡΕΠΕΙ να υπερβαίνει τα 100 KB (ταιριάζει με την §6).
Διακριτής σχήματος. Η πρώτη γραμμή στα terms για ένα σύμφωνο structured/v1 ΠΡΕΠΕΙ να είναι { key: "pact_schema", value: "structured/v1" }. Οι γραμμές χωρίς αυτό το σήμα είναι "προσαρμοσμένα" σύμφωνα και δεν λαμβάνουν δομημένη επικύρωση ή απόδοση που γνωρίζει το σχήμα.
Παγωμένες υποδοχές αναγνώρισης. Τα σύμφωνα 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 και των δύο μερών δεσμεύονται στα ακριβή bytes μέσω του body_hash. ΔΕΝ είναι τοπικοποιημένες· το υπογεγραμμένο σώμα είναι γλωσσικά ουδέτερο. Οποιαδήποτε αλλαγή διατύπωσης απαιτεί νέα έκδοση σχήματος (structured/v2).
Οι οκτώ συμβολοσειρές, η αναζήτησή τους (acknowledgement_for(role, kind)) και η λογική για κάθε μία είναι καρφιτσωμένες από την υλοποίηση αναφοράς. Οι συμμορφούμενες υλοποιήσεις ΠΡΕΠΕΙ να εκπέμπουν byte-πανομοιότυπες τιμές αναγνώρισης· τα golden-fixture τεστ SHA3-256 body-hash που καλύπτουν και τους τέσσερις συνδυασμούς ρόλων εντοπίζουν οποιαδήποτε απόκλιση.
Σειρά εμφάνισης θεατή. Οι συμβολοσειρές αναγνώρισης περιέχουν φράσεις όπως "described above", οι οποίες προϋποθέτουν ότι οι γραμμές περιγραφής / εμβέλειας αποδίδονται πριν τις αναγνωρίσεις. Οι θεατές ΠΡΕΠΕΙ να αποδίδουν τον πίνακα terms με τη σειρά CBOR· η αναδιάταξη σπάει τη σημασιολογία του πεζού λόγου.
Επικοινωνία αντισυμβαλλόμενου. Όταν το contact του Party B είναι μια έγκυρη διεύθυνση email, η υπηρεσία ανεβάσματος qub αποστέλλει αυτόματα ένα email πρόσκλησης ανασκόπησης / συν-υπογραφής κατά τον χρόνο προετοιμασίας και δεσμεύει την τελική συν-υπογραφή στην επαλήθευση αυτής της ίδιας διεύθυνσης (§9.7). Τα σύμφωνα των οποίων η επικοινωνία Party B απουσιάζει μπορούν ακόμα να συν-υπογραφούν, αλλά μόνο μέσω εξωτερικού καναλιού — η υπηρεσία αρνείται αιτήματα συν-υπογραφής που δεν μπορούν να παράγουν ταιριαστό δείκτη επαλήθευσης email 15 λεπτών.
6.2 Σώμα Ετυμηγορίας (content_type = 0x04)
Ένα σώμα ετυμηγορίας είναι η κανονική κωδικοποίηση CBOR μιας τιμής VerdictBody:
VerdictBody {
verdict_version: u8, // 0x01 for structured/v1
outcome: u8, // 1=Right · 2=Partial · 3=Wrong · 4=Unfalsifiable
reflection: Option<String>, // ≤ 2,000 bytes NFC; "what changed, what did you learn"
evidence_url: Option<String>, // ≤ 2,048 bytes; HTTPS only; absent key when omitted
}
Κανονική σειρά κλειδιών 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 (ταιριάζει με τη γραμμή του μητρώου παραπάνω).
Απαρίθμηση έκβασης. Το byte του πρωτοκόλλου είναι ουδέτερο ως προς την πρόθεση· οι τέσσερις επιλογές Right / Partial / Wrong / Unfalsifiable καλύπτουν τον χώρο εκβάσεων κάθε πρόθεσης που φέρει ετυμηγορία. Οι ετικέτες ανά πρόθεση («Το προέβλεψα σωστά» / «Την τήρησα» / «Παραδόθηκε» / «Επιβεβαιώθηκε» για το Right, κ.ο.κ.) είναι ζήτημα απόδοσης από την πλευρά του θεατή, που επιλύεται έναντι της πρόθεσης του γονικού qub — το πρωτόκολλο παραμένει ουδέτερο ως προς τη γλώσσα και την πρόθεση. Τιμές εκτός του 1..=4 ΠΡΕΠΕΙ να απορρίπτονται κατά την αποκωδικοποίηση.
Γονική σύνδεση. Ένα qub ετυμηγορίας ΔΕΝ μεταφέρει τη γονική αναφορά στο σώμα του. Το αναγνωριστικό συναλλαγής Arweave του γονικού qub εκπέμπεται ως η ετικέτα αποθήκευσης Parent-Tx-Id κατά τον χρόνο ανεβάσματος (§7, επίπεδο ετικετών αποθήκευσης). Αυτό κρατά το σώμα ως αυτοτελή υπογεγραμμένη δήλωση αυτο-αξιολόγησης· η αλυσίδα ελέγχου («σωστά για το τι;») θεμελιώνεται μέσω της αναζήτησης ετικετών Arweave.
Ασφάλεια του URL τεκμηρίωσης (κανονιστική). Όταν το evidence_url είναι παρόν, οι επικυρωτές (πλευρά σύνθεσης, πλευρά πρωτοκόλλου, άκρο Worker) ΠΡΕΠΕΙ να επιβάλλουν:
- Μόνο HTTPS. Η συμβολοσειρά ΠΡΕΠΕΙ να ξεκινά με την ακολουθία bytes
https://. Κάθε άλλο σχήμα —http,ftp,javascript,data,fileκ.λπ. — απορρίπτεται. - Ανώτατο όριο μήκους. ≤ 2.048 bytes (πρακτικό όριο URL περιηγητή).
- Έλεγχος NFC + εχθρικών κωδικών. Ο ίδιος κανόνας με το
titleκαι τοreflection— κωδικοί παράκαμψης κατεύθυνσης (bidi) / μηδενικού πλάτους / μπλοκ ετικετών / BOM / C0 / C1 απορρίπτονται. Ο ορισμός ταιριάζει με το Rustcrate::handle::contains_hostile_text_codepointκαι το TSworkers/api/src/utils/unicode.ts::isHostileCodepoint(διατηρούνται σε βηματισμό). - Χωρίς κενά, χωρίς χαρακτήρες ελέγχου ASCII. Κενά / DEL / bytes κάτω από
0x20οπουδήποτε στο URL απορρίπτονται — κλείνει τον φορέα έγχυσης\n/\tπου ο κανόνας bidi δεν καλύπτει. - Μη κενό τμήμα κεντρικού υπολογιστή. Όλα όσα βρίσκονται μεταξύ του
https://και του πρώτου/,?ή#ΠΡΕΠΕΙ να είναι μη κενά.
Καμία ανάκτηση από την πλευρά του διακομιστή. Ο Worker ΔΕΝ ΠΡΕΠΕΙ να διαμεσολαβεί, να ανακτά ή να προεπισκοπεί το URL. Το πρωτόκολλο αποθηκεύει μια συμβολοσειρά· η απόδοση συμβαίνει από την πλευρά του θεατή με rel="nofollow noopener noreferrer" target="_blank" και ορατό όνομα κεντρικού υπολογιστή που εμφανίζεται δίπλα στο κείμενο του συνδέσμου.
Αναστοχασμός. Προαιρετικό κείμενο αναστοχασμού γραμμένο από τον δημιουργό («τι άλλαξε, τι μάθατε»). Ίδια επικύρωση NFC + εχθρικών κωδικών με το title. Κενή είσοδος ή είσοδος μόνο με κενά συμπτύσσεται σε απουσία κατά τον χρόνο κατασκευής.
Έκδοση σχήματος. Η v1 υποστηρίζει μόνο verdict_version = 0x01. Μελλοντικές αναθεωρήσεις σχήματος αυξάνουν αυτό το byte και προσγειώνονται μαζί με μια νέα έκδοση πρωτοκόλλου ανά §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 — π.χ., quote, reply, commitment), Author (αποτύπωμα δημόσιου κλειδιού του δημιουργού §9.3 ως 64-χαρακτήρων μικρών γραμμάτων hex) και Parent-Tx-Id (αναγνωριστικό συναλλαγής αποθήκευσης του γονικού qub για αλυσίδες απάντησης, 43-χαρακτήρων base64url).
Η ετικέτα Author είναι opt-in ανά qub: η εφαρμογή δημιουργού αναφοράς την επισυνάπτει μόνο όταν ο χρήστης ενεργοποιεί ρητά τη δημόσια απόδοση κατά τον χρόνο σφράγισης. Όταν ο διακόπτης είναι απενεργοποιημένος — η προεπιλογή — δεν γράφεται ετικέτα Author και το qub είναι μη-αποδιδόμενο στην αλυσίδα: τίποτα στη μόνιμη αποθήκευση δεν συνδέει το ανέβασμα με το handle ενός δημιουργού, email ή άλλα qubs. Όταν ο διακόπτης είναι ενεργοποιημένος, το αποτύπωμα Author αναλύεται στο επιλεγμένο @handle του δημιουργού μέσω της αλυσίδας πιστοποίησης §9.5. Οι σχέσεις αλυσίδας απάντησης και το Intent δεν είναι αναγνωριστικά. Το εξωτερικό περιτύλιγμα (§13) προστατεύει το εσωτερικό σώμα από τη συσχέτιση κρυπτογραφημένου κειμένου — αποτρέποντας έναν συλλέκτη από το να αναγνωρίσει και να αποκρυπτογραφήσει μαζικά ανεβάσματα σχήματος qub αφού δημοσιευθεί ο γύρος drand τους.
Η υπηρεσία αναφοράς σκόπιμα ΔΕΝ επισυνάπτει ετικέτες App-Name, App-Version ή Type: οποιοδήποτε τέτοιο φίλτρο μονής τιμής θα επέστρεφε το σύνολο του σώματος qubs σε ένα ερώτημα GraphQL, το οποίο είναι ασύμβατο με την εμβέλεια εμπιστευτικότητας μόνο-σώματος του περιτυλίγματος.
Ένας συμμορφούμενος επαληθευτής ΔΕΝ ΠΡΕΠΕΙ να εξαρτάται από οποιαδήποτε ετικέτα αποθήκευσης για την §11 επαλήθευση τρίτου μέρους· ο κατακερματισμός σώματος / 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 bytes | 3.309 bytes |
Οι θεατές ΠΡΕΠΕΙ να απορρίπτουν άγνωστες τιμές sig_alg.
9.3 Κατασκευή Υπογεγραμμένης Προεικόνας
Έχουν υπάρξει δύο εκδόσεις προεικόνας. Όλες οι υπογραφές ΠΡΕΠΕΙ να χρησιμοποιούν την V2, και οι επαληθευτές ΠΡΕΠΕΙ να αποδέχονται μόνο την V2. Η παλαιού τύπου προεικόνα V1 (τεκμηριώνεται παρακάτω για ιστορικούς λόγους) γινόταν αποδεκτή ως εφεδρική διαδρομή μόνο για επαλήθευση κατά τη μετάβαση στην V2· αυτή η εφεδρική διαδρομή έχει αποσυρθεί και μια υπογραφή μόνο-V1 πλέον απορρίπτεται.
V2 (τρέχουσα — παράγεται από κάθε νέα υπογραφή συγγραφέα, καθώς και από αμφότερες τις υπογραφές της ροής προετοιμασίας / συν-υπογραφής συμφώνου):
sig_input = SHA3-256(
"QUB_AUTHOR_SIG_V2" || // domain separator (17 bytes)
version || // u8 (1 byte)
qub_id || // [u8; 32] (32 bytes)
body_hash || // [u8; 32] (32 bytes)
unlock_at || // i64 big-endian (8 bytes)
0x00 || // u8 (1 byte): MUST be 0x00 in v1.x
sender_label_hash || // [u8; 32]: SHA3-256(NFC(sender_label)),
// or 32 zero bytes when absent
reply_to_or_zero // [u8; 32]: parent qub_id, or 32 zero
// bytes when absent
)
// Total preimage: 155 bytes → 32-byte hash
signature = Sign(author_secret_key, sig_input)
Το sender_label_hash ακολουθεί την ίδια σύμβαση απόντος-φρουρού με το title_hash (§4.2.1): 32 μηδενικά bytes δεν αποτελούν έγκυρη έξοδο SHA3-256, οπότε η «απουσία» δεν μπορεί ποτέ να συγκρουστεί με μια παρούσα ετικέτα. Όλα τα πεδία έχουν σταθερό πλάτος, οπότε η προεικόνα είναι μονοσήμαντη χωρίς προθέματα μήκους.
V1 (παλαιού τύπου — ΑΠΟΣΥΡΘΗΚΕ· δεν παράγεται πλέον και δεν γίνεται πλέον αποδεκτή κατά την επαλήθευση):
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
Η προεικόνα V1 παρέλειπε τα sender_label και reply_to. Γινόταν αποδεκτή ως εφεδρική διαδρομή μόνο για επαλήθευση κατά τη μετάβαση στην V2· αυτή η εφεδρική διαδρομή έκτοτε έχει αποσυρθεί — οι επαληθευτές ΠΡΕΠΕΙ να αποδέχονται μόνο την προεικόνα V2. Ο ορισμός διατηρείται εδώ για ιστορικούς λόγους και για να εξηγήσει τον διαχωριστή πεδίου παρακάτω. Μια υπογραφή που επαληθεύεται μόνο έναντι της V1 ΠΡΕΠΕΙ να αντιμετωπίζεται ως αποτυχία επαλήθευσης.
Διαχωριστές πεδίου: τα "QUB_AUTHOR_SIG_V1" / "QUB_AUTHOR_SIG_V2" είναι 17 ASCII bytes το καθένα ([0x51, 0x55, 0x42, 0x5F, 0x41, 0x55, 0x54, 0x48, 0x4F, 0x52, 0x5F, 0x53, 0x49, 0x47, 0x5F, 0x56, 0x31/0x32]). Χωρίς γέμισμα. Ο διαφορετικός διαχωριστής διαχωρίζει τα δύο κατασκευάσματα ως προς τον τομέα, οπότε μια υπογραφή πάνω στη μία προεικόνα δεν μπορεί ποτέ να επαληθευτεί ως η άλλη.
Το byte org_id_present: το byte που ακολουθεί το unlock_at ΠΡΕΠΕΙ να είναι 0x00. Η υλοποίηση αναφοράς εκθέτει αυτό ως τη σταθερά ORG_ID_PRESENT_INDIVIDUAL = 0x00 στο crates/qub-core/src/signing.rs· οι θεατές που ανακατασκευάζουν το sig_input για επαλήθευση ΠΡΕΠΕΙ να εκπέμπουν το ίδιο byte.
Εμβέλεια υπογραφής — τι καλύπτεται και τι όχι. Το sig_input της V2 δεσμεύεται άμεσα στα version, qub_id, body_hash, unlock_at, sender_label και reply_to (συν τον σταθερό διαχωριστή πεδίου και το byte org_id_present). Το ίδιο το qub_id παράγεται από τα version, content_type, created_at, unlock_at, outcome_at, drand_round και body_hash μέσω της προεικόνας §4.1, οπότε οποιαδήποτε αλλαγή σε αυτά τα πεδία παράγει διαφορετικό qub_id και ακυρώνει μεταβατικά την υπογραφή. Η πιστοποιημένη επιφάνεια είναι επομένως:
| Πεδίο | Πιστοποιημένο από υπογραφή | Πώς |
|---|---|---|
version |
✓ | Άμεση είσοδος στο sig_input |
qub_id |
✓ | Άμεση είσοδος |
body_hash |
✓ | Άμεση είσοδος |
unlock_at |
✓ | Άμεση είσοδος |
sender_label |
✓ | Άμεση είσοδος μέσω του sender_label_hash (προεικόνα V2 — η μόνη αποδεκτή μορφή) |
reply_to |
✓ | Άμεση είσοδος μέσω του reply_to_or_zero (προεικόνα V2 — η μόνη αποδεκτή μορφή) |
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 |
— (έμμεσα) | Το κλειδί που επαλήθευσε την υπογραφή είναι ο συγγραφέας, εξ ορισμού |
cosigner_pubkey / cosigner_signature |
— | Υπογράφονται ανεξάρτητα πάνω στο ίδιο sig_input (βλέπε §9.7) |
drand_chain_id, tlock_ciphertext, visibility |
— | Εξωτερικά πεδία του SealedQub, όχι μέσα στον φάκελο — καλύπτονται από τις δικές τους δομικές αναλλοιότητες (συνέπεια γύρου / αλυσίδας) αλλά όχι από την υπογραφή του συγγραφέα. (Το drand_round δεσμεύεται πλέον μεταβατικά μέσω της προεικόνας qub_id — βλέπε παραπάνω.) |
Γιατί η V2 είναι η μόνη αποδεκτή προεικόνα.
- Υπό την αποσυρμένη προεικόνα V1, ένα μέρος με δικαίωμα εγγραφής στα αποθηκευμένα bytes θα μπορούσε να αντικαταστήσει το
sender_label(«Alice» → «Mallory») ή να επανα-γονιοποιήσει τοreply_to— και να επανακρυπτογραφήσει μετά τον γύρο — χωρίς να ακυρώσει την υπογραφή του συγγραφέα, επειδή κανένα από τα δύο πεδία δεν βρισκόταν στην υπογεγραμμένη προεικόνα. Η V2 καλύπτει και τα δύο, οπότε οποιαδήποτε αλλαγή σε οποιοδήποτε από τα δύο πεδία μετατρέπει την επαλήθευση σε «αποτυχία». Επειδή οι επαληθευτές αποδέχονται πλέον μόνο την V2, αυτή η αντικατάσταση αποκλείεται για κάθε υπογραφή: μια υπογραφή που δεν δεσμεύει κανένα από τα δύο πεδία (δηλαδή επαληθεύεται μόνο έναντι της V1) απορρίπτεται εξ ολοκλήρου αντί να γίνεται αποδεκτή ως υποβαθμισμένη. - Το
author_pubkeyμέσα στον φάκελο παραμένει η αληθινή άγκυρα ταυτότητας — οι θεατές ΠΡΕΠΕΙ να εξάγουν την ταυτότητα εμφάνισης από τοauthor_pubkey(μέσω του επιπέδου πιστοποίησης §9.5) και όχι να εμπιστεύονται τοsender_label.
Οι υλοποιήσεις που εμφανίζουν sender_label ή reply_to σε τελικούς χρήστες ΠΡΕΠΕΙ να εμφανίζουν την πιστοποιημένη ταυτότητα (αποτύπωμα δημόσιου κλειδιού, πιστοποίηση) ως το κύριο σήμα ταυτότητας, όχι την ετικέτα.
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 (V2 formula, §9.3).
6. Verify(author_pubkey, sig_input, author_signature). The V2 preimage is the
only accepted form — the legacy V1 fallback is retired (§9.3), so a
signature that does not verify against V2 fails, full stop.
7. If verification succeeds → display "signed by [key fingerprint]."
8. If verification fails → display "signature verification failed."
Η επαλήθευση υπογραφής είναι η πιο δαπανηρή λειτουργία (ειδικά το ML-DSA-65). ΘΑ ΕΠΡΕΠΕ να εκτελείται αφού έχουν περάσει όλοι οι φθηνότεροι έλεγχοι (κατακερματισμός, qub_id, unlock_at).
9.5 Πιστοποιήσεις Ταυτότητας
Οι πιστοποιήσεις ταυτότητας — η αντιστοίχιση του author_pubkey σε αξιώσεις ταυτότητας αναγνωρίσιμες από ανθρώπους όπως ένα handle qub, διεύθυνση email, κοινωνικό handle ή διαπιστευτήριο passkey — είναι μια προοδευτική ενίσχυση από την πλευρά του θεατή και δεν απαιτούνται για την επαλήθευση της υπογραφής. Οι θεατές που αναλύουν πιστοποιήσεις σε ταυτότητα εμφάνισης ΠΡΕΠΕΙ να εφαρμόζουν την προτεραιότητα:
handle > email > social > fingerprint
Το εφεδρικό αποτύπωμα είναι το hex μικρών γραμμάτων του SHA3-256(author_pubkey)· είναι πάντα διαθέσιμο για οποιοδήποτε υπογεγραμμένο qub. Οι θεατές ΜΠΟΡΟΥΝ να το συντομεύουν για εμφάνιση — ο θεατής αναφοράς αποδίδει qub: ακολουθούμενο από τα πρώτα και τα τελευταία τέσσερα bytes (qub:<8 hex>…<8 hex>).
Ένας συμμορφούμενος επαληθευτής μπορεί να ολοκληρώσει κάθε έλεγχο της §9.4 χωρίς να επικοινωνήσει με το API του qub, χωρίς κανένα δίκτυο πέραν της μόνιμης αποθήκευσης και drand και χωρίς αναζήτηση από την πλευρά του διακομιστή. Η ανάλυση πιστοποίησης είναι ένα ξεχωριστό βήμα μέγιστης προσπάθειας που εκτελείται μόνο μετά την επιτυχή επαλήθευση της υπογραφής.
9.6 Επίπτωση Μεγέθους
| Ed25519 | ML-DSA-65 | |
|---|---|---|
| Υπογραφή | 64 bytes | 3.309 bytes |
| Δημόσιο κλειδί | 32 bytes | 1.952 bytes |
| Σύνολο ανά qub | 96 bytes | 5.261 bytes |
| Επίπτωση κόστους αποθήκευσης (στα ~$5/MB) | ~$0,0005 | ~$0,026 |
Για ένα qub κειμένου 500–2.000 bytes, το ML-DSA-65 περίπου τριπλασιάζει το αποθηκευμένο μέγεθος. Το απόλυτο κόστος είναι αμελητέο.
9.7 Επαλήθευση Συν-υπογραφέα (Διμερείς Συμφωνίες Συμφώνου)
Για διμερείς συμφωνίες (content_type = 0x03), ένα δεύτερο επίπεδο υπογραφής αποδεικνύει ότι και τα δύο μέρη συναίνεσαν στους ίδιους όρους.
Πεδία φακέλου:
cosigner_pubkey: Δημόσιο κλειδί ML-DSA-65 του αντι-υπογραφέα (Party B).cosigner_signature: Υπογραφή πάνω στο ίδιοsig_inputμε τον συγγραφέα (§9.3).
Και τα δύο πεδία ΠΡΕΠΕΙ να είναι παρόντα μαζί ή και τα δύο απόντα. Εάν ακριβώς ένα είναι παρόν, οι θεατές ΠΡΕΠΕΙ να αναφέρουν σφάλμα ακεραιότητας.
Διαδικασία επαλήθευσης:
1. If cosigner_pubkey absent and cosigner_signature absent → no cosigner. Done.
2. If exactly one is present → integrity error.
3. Verify cosigner_pubkey != author_pubkey (prevent self-cosigning).
Fail → display "cosigner pubkey must differ from author."
4. Reconstruct sig_input using the same formula as §9.3 (V2 only — the
legacy V1 fallback is retired; all pact clients produce V2 signatures).
5. Verify(cosigner_pubkey, sig_input, cosigner_signature).
6. Success → display "co-signed by [cosigner fingerprint]."
7. Failure → display "co-signature verification failed."
Ιδιότητες:
- Ο συν-υπογραφέας υπογράφει το πανομοιότυπο
sig_inputμε τον συγγραφέα — και τα δύο μέρη δεσμεύονται στο ίδιοqub_id,body_hashκαιunlock_at(και, υπό την V2, στο ίδιοsender_label_hashκαιreply_to_or_zero). - Για να μπορέσει ο αντι-υπογραφέας να ανακατασκευάσει την προεικόνα V2 χωρίς πρόσβαση στα ακατέργαστα bytes του φακέλου, η υπηρεσία προετοιμασίας επιβάλλει κατά τον χρόνο προετοιμασίας ότι το
sender_labelενός φακέλου συμφώνου ισούται με τοpact_terms.party_a.labelκαι ότι τοreply_toαπουσιάζει. Και τα δύο ισχύουν για κάθε σύμφωνο πελάτη αναφοράς· οι φάκελοι που τα παραβιάζουν απορρίπτονται κατά την προετοιμασία. - Η παραγωγή του
qub_id(§4.1) ΔΕΝ περιλαμβάνει πεδία συν-υπογραφέα. Η προσθήκη συν-υπογραφέα σε υπάρχοντα φάκελο δεν αλλάζει τοqub_id. - Ένα σύμφωνο μπορεί να είναι μόνο υπογεγραμμένο από τον συγγραφέα (μονόπλευρη δέσμευση), μόνο συν-υπογραφέα (ασυνήθιστο) ή και τα δύο (πλήρης διμερής απόδειξη).
Πύλη δέσμευσης email (επιχειρησιακή). Όταν ένα προετοιμασμένο σύμφωνο φέρει επικοινωνία email του Party B (§6.1), η υπηρεσία ανεβάσματος qub ΠΡΕΠΕΙ να αρνηθεί το αίτημα συν-υπογραφής εκτός αν υπάρχει βραχύβιος δείκτης επαλήθευσης email που ταιριάζει τόσο το staging id όσο και τον κατακερματισμό κανονικοποιημένου-email αυτής της επικοινωνίας. Ο δείκτης γράφεται από το /api/v1/auth/verify όταν το token magic-link φέρει staging_id και η επαληθευμένη διεύθυνση ταιριάζει με SHA-256(normalise_email(party_b.contact)) — όπου το normalise_email(addr) διατηρεί τη γραμματοσειρά του τοπικού μέρους και μετατρέπει σε μικρά μόνο το τμήμα τομέα (κατά RFC 5321 §2.3.11), και το SHA-256 εδώ είναι ο κατακερματισμός NIST FIPS 180-4 (διακριτός από το SHA3-256 που χρησιμοποιείται στις παραγωγές §4) — και λήγει 900 δευτερόλεπτα (15 λεπτά) μετά την έκδοση. Αυτή είναι μια επιχειρησιακή πύλη anti-πλαστοπροσωπίας, ΟΧΙ μέρος της απόδειξης qub on-chain — ένας τρίτος επαληθευτής που επαναλαμβάνει την §11 χρειάζεται μόνο μόνιμη αποθήκευση και drand, χωρίς αναζήτηση από την πλευρά του διακομιστή. Ο δείκτης υπάρχει μόνο από την πλευρά του διακομιστή και δεν είναι ποτέ μέρος του υπογεγραμμένου σώματος.
Επίπτωση μεγέθους (συγγραφέας ML-DSA-65 + συν-υπογραφέας):
| Συστατικό | Μέγεθος |
|---|---|
| Υπογραφή συγγραφέα | 3.309 bytes |
| Δημόσιο κλειδί συγγραφέα | 1.952 bytes |
| Υπογραφή συν-υπογραφέα | 3.309 bytes |
| Δημόσιο κλειδί συν-υπογραφέα | 1.952 bytes |
| Συνολικό κρυπτογραφικό overhead | 10.522 bytes |
| Επίπτωση κόστους αποθήκευσης | ~$0,05 |
10. Απόδοση και Καθαρισμός Markdown
Αυτή η ενότητα είναι κρίσιμη για την ασφάλεια. Ο θεατής αποδίδει qubs κειμένου (content_type = 0x01) χρησιμοποιώντας ένα περιορισμένο υποσύνολο Markdown.
10.1 Επιτρεπόμενα Στοιχεία
- Επικεφαλίδες:
#έως####(όχι#####ή######) - Έμφαση: έντονη (
**), πλάγια (*), διακεκομμένη (~~) - Λίστες: ταξινομημένες (
1.) και μη-ταξινομημένες (-,*) - Παραθέσεις (
>) - Κώδικας: εμβόλιμα διαστήματα (```) και περιφραγμένα μπλοκ (`````)
- Οριζόντιοι κανόνες (
---) - Αλλαγές γραμμής (δύο τελικοί χώροι ή κενή γραμμή)
- Παράγραφοι
10.2 Απαγορευμένα Στοιχεία
| Στοιχείο | Χειρισμός |
|---|---|
Ακατέργαστο HTML (<div>, <script>, κ.λπ.) |
Αφαιρείται εξ ολοκλήρου. Κανένα HTML δεν περνά. |
Εικόνες () |
Αφαιρούνται. Η σύνταξη εικόνας αφαιρείται από την έξοδο. |
Σύνδεσμοι ([text](url)) |
Η διεύθυνση URL αποδίδεται ως ορατό απλό κείμενο. Δεν συνδέεται αυτόματα. Δεν είναι κλικαρίσιμη χωρίς ρητή ενέργεια του χρήστη. |
| Επικίνδυνα σχήματα URL | javascript:, data:, vbscript:, file: — αφαιρούνται. |
| Iframes, embeds, objects | Αφαιρούνται. |
| Οντότητες HTML | Αποκωδικοποιούνται σε χαρακτήρες εμφάνισης μόνο εάν είναι ασφαλείς. |
10.3 Υλοποίηση
Οι υλοποιήσεις ΠΡΕΠΕΙ να χρησιμοποιούν έναν αυστηρό αναλυτή allowlist, όχι blocklist. Η προτεινόμενη προσέγγιση:
- Ανάλυση Markdown με χρήση
pulldown-cmark(ή ισοδύναμου). - Διάσχιση του AST και απόρριψη οποιουδήποτε κόμβου δεν είναι στο allowlist (§10.1).
- Για κόμβους συνδέσμων: εκπομπή της διεύθυνσης URL ως ορατό κείμενο, όχι ως κλικαρίσιμο στοιχείο
<a>. - Μετατροπή του φιλτραρισμένου AST σε τυποποιημένη ενδιάμεση αναπαράσταση (π.χ., enum
MarkdownNodeμε μόνο ασφαλείς παραλλαγές). Το ακατέργαστο HTML είναι δομικά μη αναπαραστάσιμο σε αυτό το IR. - Απόδοση από το τυποποιημένο IR στο επίπεδο προβολής στόχου (π.χ., αντιδραστικά στοιχεία προβολής, κόμβοι DOM). Καμία συνένωση συμβολοσειρών HTML ή
innerHTMLσε κανένα σημείο.
Οι προσεγγίσεις blocklist είναι εύθραυστες επειδή νέες επεκτάσεις Markdown ή ιδιοτροπίες αναλυτή μπορούν να εισάγουν μη-φιλτραρισμένα στοιχεία. Η προσέγγιση τυποποιημένου 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 Έκδοση Πρωτοκόλλου
Το πεδίο version (u8) και στο SealedQub και στο QubEnvelope αναγνωρίζει την κύρια έκδοση του πρωτοκόλλου.
- Οι θεατές ΠΡΕΠΕΙ να απορρίπτουν άγνωστες κύριες εκδόσεις με σαφές σφάλμα.
- Εντός μιας γνωστής κύριας έκδοσης, οι αποκωδικοποιητές ΠΡΕΠΕΙ να απορρίπτουν άγνωστα κλειδιά χάρτη (§3.1) — η εξέλιξη σχήματος γίνεται με την εισαγωγή νέου
version, όχι με την προσθήκη κλειδιών που οι υπάρχοντες αποκωδικοποιητές θα παρέβλεπαν. (Προηγούμενες αναθεωρήσεις αυτής της προδιαγραφής επέτρεπαν την ανοχή άγνωστων προαιρετικών πεδίων· η ρήτρα αυτή αποσύρεται — καθιστούσε τοencode(decode(x))μη ένα-προς-ένα και άνοιγε έναν φορέα κρυφού υπογεγραμμένου περιεχομένου στα ωφέλιμα φορτία συμφώνων.) - Οι τύποι περιεχομένου (
content_type) και τα σχήματα υπογραφής (sig_alg) είναι ελεγχόμενα από έκδοση: νέες τιμές μπορούν να εισαχθούν μόνο μαζί με νέα έκδοση πρωτοκόλλου ή ρητή ενημέρωση μητρώου.
12.2 Ιστορικό Εκδόσεων
| Έκδοση | Τιμή | Περιγραφή |
|---|---|---|
| v1 | 0x01 |
Δημόσια qubs κειμένου (content_type 0x01), διμερείς συμφωνίες συμφώνου (0x03, σχήμα structured/v1, συγγραφέας + συν-υπογραφέας ML-DSA-65), tlock, SHA3-256 |
12.3 Συμβατότητα προς τα εμπρός
Ένας θεατής v1 που συναντά QubEnvelope με άγνωστα κλειδιά χάρτη CBOR (κλειδιά που δεν είναι στην κανονική σειρά §3.2) ΠΡΕΠΕΙ να το απορρίπτει με σφάλμα αποκωδικοποίησης (§3.1). Η συμβατότητα προς τα εμπρός στηρίζεται στο πεδίο version, όχι στην ανοχή κλειδιών: μελλοντικές προσθήκες — ακόμη και μικρά μεταδεδομένα — παραδίδονται με νέα τιμή version, την οποία ένας θεατής v1 απορρίπτει με σαφές σφάλμα «νεότερο πρωτόκολλο» αντί να παραλείπει σιωπηρά περιεχόμενο στο οποίο δεσμεύονται οι υπογραφές.
Ένας θεατής v1 που συναντά sig_alg = 0x01 (ML-DSA-65) αλλά χωρίς υποστήριξη επαλήθευσης ML-DSA-65 ΘΑ ΕΠΡΕΠΕ να εμφανίσει το περιεχόμενο του qub με μια ειδοποίηση "η υπογραφή υπάρχει αλλά δεν είναι επαληθεύσιμη", και όχι να απορρίψει το qub εξ ολοκλήρου. Η σημερινή υλοποίηση αναφοράς απορρίπτει κάθε τιμή sig_alg εκτός από 0x00 και 0x01 επειδή το μητρώο v1 δεν περιέχει άλλο έγκυρο αλγόριθμο — η αυστηρή απόρριψη και το soft-fail είναι παρατηρητικά ταυτόσημα μέχρι να εγγραφεί τρίτος αλγόριθμος. Η παραπάνω συμπεριφορά soft-fail γίνεται κρίσιμη μόλις η §9.2 δεχθεί νέα εγγραφή, και ο θεατής αναφοράς θα ενημερωθεί ώστε να κάνει soft-fail σε εκείνο το σημείο.
12.4 Έκδοση Εξωτερικού Περιτυλίγματος
Το OuterWrapper που περιγράφεται στην §13 φέρει το δικό του byte version, ανεξάρτητο από τα SealedQub.version και QubEnvelope.version. Οι δύο χώροι έκδοσης εξελίσσονται ξεχωριστά: μια μελλοντική μετα-κβαντικά ασφαλής συμμετρική αντικατάσταση αυξάνει το byte περιτυλίγματος χωρίς να αγγίξει την εσωτερική έκδοση πρωτοκόλλου, και μια μελλοντική προσθήκη στο επίπεδο πρωτοκόλλου (π.χ., νέο πεδίο φακέλου) αυξάνει την εσωτερική έκδοση χωρίς να αγγίξει το byte περιτυλίγματος.
OUTER_WRAPPER_VERSION_* |
Τιμή | Αλγόριθμος | Κατάσταση |
|---|---|---|---|
OUTER_WRAPPER_VERSION_1 |
0x01 |
AES-256-GCM με 12-byte nonce, 16-byte ετικέτα πιστοποίησης, AAD δεσμευμένο στο qub_id |
Προεπιλογή v1 |
| — | 0x02–0xFF |
Δεσμευμένο | Μελλοντικό |
Οι θεατές ΠΡΕΠΕΙ να απορρίπτουν άγνωστες εκδόσεις περιτυλίγματος με σαφές σφάλμα. Το πρωτόκολλο σκόπιμα διατηρεί τον χώρο εκδόσεων περιτυλίγματος στενό μέχρι να εμφανιστεί συγκεκριμένος οδηγός μετάβασης (π.χ., οδηγία NIST που ευνοεί διαφορετικό AEAD)· μια θέση 0x02 θα κατανεμηθεί στην ίδια αναθεώρηση που εισάγει τον αλγόριθμο.
13. Εξωτερικό Περιτύλιγμα Κρυπτογράφησης
13.1 Λογική
Τα επίπεδα πρωτοκόλλου (QubEnvelope → tlock → SealedQub) κάνουν ένα σφραγισμένο qub χρονοκλειδωμένο: το σώμα είναι μη αναγνώσιμο μέχρι το unlock_at και τη δημοσίευση της υπογραφής γύρου drand. Μετά το ξεκλείδωμα, ωστόσο, η υπογραφή γύρου είναι δημόσια και το κανονικό σχήμα CBOR του SealedQub είναι αναγνωρίσιμο, οπότε ένας συλλέκτης που έχει ευρετηριάσει συναλλαγές μόνιμης αποθήκευσης θα μπορούσε να αποκρυπτογραφήσει μαζικά ολόκληρο το σώμα qubs.
Το εξωτερικό περιτύλιγμα κρυπτογράφησης κλείνει αυτό το κανάλι παρεμβάλλοντας ένα επιπλέον συμμετρικό επίπεδο AEAD μεταξύ του κανονικού SealedQubCbor και των bytes που εγγράφονται στη μόνιμη αποθήκευση. Το κλειδί 256-bit K ζει μόνο στο τμήμα fragment της URL παράδοσης και στις συσκευές των χρηστών· οι περιηγητές δεν μεταδίδουν τμήματα URL fragment σε διακομιστές, οπότε το qub.social, κάθε πύλη αποθήκευσης και κάθε CDN μπροστά από οποιοδήποτε από αυτά είναι παρατηρητικά τυφλά στο K. Κάθε qub στη μόνιμη αποθήκευση είναι επομένως ένα αδιαφανές κρυπτογραφημένο κείμενο του οποίου το απλό κείμενο είναι μη ανακτήσιμο χωρίς την URL που ο δημιουργός επέλεξε να μοιραστεί.
Καθαρό αποτέλεσμα:
- Ανοσία απαρίθμησης από προεπιλογή. Τα περιτυλιγμένα bytes στη μόνιμη αποθήκευση είναι byte-μη-διακριτά από αυθαίρετο κρυπτογραφημένο κείμενο. Μια στρατηγική συλλέκτη «GraphQL-ερώτημα για ανεβάσματα σχήματος qub, μαζική αποκρυπτογράφηση με δημόσιες υπογραφές drand» δεν καταλήγει σε απλό κείμενο.
- Κρυπτο-τεμαχιστική θέση απορρήτου. Το qub.social κυριολεκτικά δεν μπορεί να αποκρυπτογραφήσει το δικό του σώμα. Οι κλητεύσεις φτάνουν στο κρυπτογραφημένο κείμενο, όχι στο απλό κείμενο.
- Σκάλα εμπιστευτικότητας δύο επιπέδων. Προεπιλογή = πρόσβαση ελεγχόμενη από σύνδεσμο (αυτή η ενότητα). Τα ιδιωτικά qubs κρυπτογραφημένα στον παραλήπτη (δεσμευμένη λειτουργία της Φάσης 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
}
Αναλλοίωτα πεδίων.
- Το
versionΠΡΕΠΕΙ να ισούται με0x01για bytes περιτυλίγματος v1.0. - Το
qub_idΠΡΕΠΕΙ να ισούται με το πεδίοqub_idτου SealedQub που ανακτάται μετά το ξεπεριτύλιγμα. Το βήμα ξεπεριτυλίγματος δεν το επιβάλλει αυτό άμεσα (η δέσμευση AEAD AAD κάνει την αλλοίωση σε επίπεδο byte αδύνατη), αλλά το επίπεδο ξεκλειδώματος ελέγχει τη σχέση μεταβατικά: εάν ένας δημιουργός περιτυλίγει έναSealedQubCborτου οποίου το εσωτερικόqub_idδεν ταιριάζει με τοqub_idτου περιτυλίγματος, η §8 βήμα 11 αποτυγχάνει. - Το
nonceΠΡΕΠΕΙ να είναι 96 bits (12 bytes), παραγόμενο φρέσκο από ένα CSPRNG για κάθε λειτουργία περιτυλίγματος. Η επαναχρησιμοποίηση ενός nonce υπό το ίδιο κλειδί επιτρέπει επιθέσεις επαναχρησιμοποίησης AEAD nonce που ανακτούν το απλό κείμενο· οι παραγωγοί ΠΡΕΠΕΙ να αντιμετωπίζουν τα ζεύγη (key,nonce) ως μίας χρήσης. - Το
ciphertextείναι η έξοδος AES-256-GCM: bytes κρυπτογραφημένου κειμένου συνενωμένα με την 16-byte ετικέτα πιστοποίησης.ciphertext.len() == SealedQubCbor.len() + 16ακριβώς.
Κωδικοποίηση CBOR. Κανονικό CBOR ανά §3, με τον ίδιο κανόνα ταξινόμησης κλειδιών (ταξινόμηση κατά κωδικοποιημένο μήκος bytes σε αύξουσα σειρά, μετά λεξικογραφικά). Τα τέσσερα κλειδιά είναι:
| Κλειδί | Κωδικοποιημένα bytes | Σειρά |
|---|---|---|
nonce |
6 | 1 |
qub_id |
7 | 2 |
version |
8 | 3 |
ciphertext |
11 | 4 |
Το πρώτο byte του CBOR OuterWrapper είναι επομένως η κεφαλίδα χάρτη καθορισμένου μήκους για χάρτη 4 εισόδων (0xA4).
13.4 Δέσμευση AAD στο qub_id
Το περιτύλιγμα δεσμεύει το qub_id ως πρόσθετα πιστοποιημένα δεδομένα AEAD. Αυτή είναι η κρίσιμη δομική άμυνα έναντι τριών κατηγοριών επίθεσης:
| Επίθεση | Άμυνα |
|---|---|
Μετακίνηση κρυπτογραφημένου κειμένου κάτω από διαφορετικό πεδίο qub_id στο περιτύλιγμα |
Αναντιστοιχία AAD → αποτυγχάνει η πιστοποίηση AEAD |
| Ανάμιξη του τμήματος URL του qub A με τα bytes μόνιμης αποθήκευσης του qub B | Αναντιστοιχία AAD → αποτυγχάνει η πιστοποίηση AEAD |
Αλλοίωση του πεδίου qub_id του περιτυλίγματος μετά το ανέβασμα |
Αναντιστοιχία AAD → αποτυγχάνει η πιστοποίηση AEAD |
Η μεταφορά του qub_id στο απλό κείμενο του περιτυλίγματος δεν αποδυναμώνει ουσιαστικά την ανοσία απαρίθμησης — το qub_id το ίδιο είναι κατακερματισμός SHA3-256 της προεικόνας §4.1 χωρίς ανακτήσιμη προεικόνα από τη σύνοψη, και ένας απαριθμητής που έχει ήδη συλλέξει τα bytes του περιτυλίγματος δεν μαθαίνει τίποτα από το ορατό 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 σε ένα μόνο σχήμα σφάλματος.
13.6 Υλικό Κλειδιού και Διανομή
Το κλειδί περιτυλίγματος K είναι μια 256-bit ομοιόμορφη τυχαία τιμή που παράγεται ανά-qub από ένα CSPRNG. Οι υλοποιήσεις αναφοράς το πηγάζουν από:
- Δημιουργός WASM:
getrandom(WebCrypto υπό το backendwasm_js). - Καλών του API σφράγισης από την πλευρά διακομιστή: το τοπικό του CSPRNG· ο καλών παρέχει και διατηρεί το
Kωςwrapper_key_b64url. Ο Worker χρησιμοποιεί τοKστη μνήμη για το περιτύλιγμα αλλά ΔΕΝ ΠΡΕΠΕΙ να το διατηρεί. Αυτό επιτρέπει σε μια ταυτοδύναμη (idempotent) επανάληψη να ανακτήσει μια λογοκριμένη απόκριση χρησιμοποιώντας τη διατηρημένη δυνατότητα του καλούντος αντί να εξαρτάται από ένα μυστικό μίας χρήσης παραγόμενο από τον διακομιστή.
Διανομή: το K ΠΡΕΠΕΙ να κωδικοποιείται ως URL-safe base64 (RFC 4648 §5, χωρίς γέμισμα) και να προσαρτάται στην URL παράδοσης ως το συστατικό fragment:
delivery_url = <origin>/c/<arweave_tx_id>#<base64url(K)>
Το τμήμα fragment δεν μεταδίδεται ποτέ σε κανέναν διακομιστή από συμμορφούμενο περιηγητή. Τα κανάλια ανάκτησης (ευρετήριο ιστορικού από την πλευρά του διακομιστή, opt-in αυτόματη αποστολή email) που διατηρούν την πλήρη URL παράδοσης — συμπεριλαμβανομένου του τμήματος fragment — πέραν της συσκευής του χρήστη είναι ρητός συμβιβασμός έναντι της προεπιλεγμένης κρυπτο-τεμαχιστικής θέσης και ΠΡΕΠΕΙ να ελέγχονται από ρητή συγκατάθεση του χρήστη.
Απώλεια τμήματος fragment. Εάν ένας χρήστης χάσει το τμήμα fragment της URL και δεν έχει κανάλι ανάκτησης, το qub είναι μη αναγνώσιμο. Αυτός είναι ο κρίσιμος συμβιβασμός του σχεδιασμού και ΠΡΕΠΕΙ να αποκαλύπτεται στον χρήστη κατά τον χρόνο σφράγισης. Το MVP ενισχύει την αποκάλυψη χρόνου σφράγισης με ρητό κείμενο «αποθηκεύστε αυτή τη URL» και κανάλι ανάκτησης με επαληθευμένο email για χρήστες που επιλέγουν.
13.7 Εκτός Εμβέλειας για αυτή την Ενότητα
- Η υπογραφή συγγραφής (§9) δεν αλλάζει: οι υπογραφές υπολογίζονται μέσα στον εσωτερικό
QubEnvelopeκαι ανακτώνται μετά το ξεπεριτύλιγμα → αποκρυπτογράφηση tlock → ανάλυση CBOR. - Τα ιδιωτικά qubs κρυπτογραφημένα στον παραλήπτη (δεσμευμένη λειτουργία της Φάσης 2, δεν έχει ακόμη προδιαγραφεί) συντίθενται πάνω από αυτό το περιτύλιγμα ως δεύτερο επίπεδο εμπιστευτικότητας· και τα δύο επίπεδα μπορούν να είναι ενεργά ταυτόχρονα.
- Τα σύμφωνα (§6, content_type
0x03) περιτυλίγονται ακριβώς όπως τα qubs κειμένου· το περιτύλιγμα είναι byte-τυφλό στον εσωτερικό τύπο περιεχομένου.
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 μπορεί να το αποκρυπτογραφήσει — δεν απαιτείται τμήμα fragment της URL, επειδή δεν υπάρχει K. Αυτός είναι ο σκόπιμος συμβιβασμός για επιφάνειες που πρέπει να καθοδηγεί ο διακομιστής: τα email ειδοποίησης αποκάλυψης, οι ενσωματώσεις τρίτων και ο πλουσιότερος SEO μετά την αποκάλυψη χρειάζονται όλα έναν σύνδεσμο που λειτουργεί χωρίς ένα μυστικό που ο διακομιστής δεν κατέχει ποτέ (§13.6).
Συνέπειες που ένας παραγωγός ΠΡΕΠΕΙ να λάβει υπόψη:
- Καμία ανοσία απαρίθμησης. Τα δημόσια qubs εγκαταλείπουν εκ κατασκευής την ιδιότητα ανοσίας απαρίθμησης της §13.1. Η υπηρεσία ανεβάσματος αναφοράς τους επισημαίνει με μια ετικέτα μόνιμης αποθήκευσης
Visibility: public(και μόνο αυτά) ώστε να είναι σκόπιμα ανιχνεύσιμα· τα ιδιωτικά qubs δεν φέρουν τέτοια ετικέτα και διατηρούν τη byte-μη-διακριτότητά τους. - Τίτλος απλού κειμένου εκτεθειμένος κατά τον χρόνο σφράγισης. Το πεδίο
titleτης §3.2 είναι απλό κείμενο μέσα στοSealedQubCbor. Κάτω από το περιτύλιγμα είναι κρυμμένο μέχρι ένας θεατής να παράσχει τοK· χωρίς το περιτύλιγμα είναι αναγνώσιμο από όλους στη μόνιμη αποθήκευση από τη στιγμή του ανεβάσματος, πριν το ξεκλείδωμα. Οι συμμορφούμενες εφαρμογές δημιουργού ΠΡΕΠΕΙ να το αποκαλύπτουν κατά τον χρόνο σφράγισης. - Η ανίχνευση είναι δομική. Ένας συμμορφούμενος θεατής/ενσωμάτωση διακρίνει τα δύο σχήματα με ανάλυση: τα bytes που αναλύονται ως
OuterWrapperακολουθούν τη διαδρομή ξεπεριτυλίγματος-με-K· τα bytes που αναλύονται ως γυμνόSealedQubCborγίνονται δεκτά απευθείας. Δεν απαιτείται καμία ένδειξη στα bytes, και τοqub_idδεν δεσμεύει την ορατότητα — το ίδιο περιεχόμενο είναι byte-πανομοιότυπο στο επίπεδο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 για αυτή την είσοδο. Αυτό το δοκιμαστικό διάνυσμα ΘΑ ΕΠΡΕΠΕ να είναι το πρώτο unit test που γράφεται. Οι κανονικές τιμές παραπάνω υπολογίστηκαν από την υλοποίηση αναφοράς και ΠΡΕΠΕΙ να ταιριάζουν bit-προς-bit. Ιστορικές διατάξεις προεικόνας (προ της εκκίνησης — κανένα ζωντανό qub δεν εξαρτιόταν από αυτές): το qub_id της V1.0 με προεικόνα 92 bytes ήταν 3d9fc2390eab043d38a1669ed3b71be76f9eefe872b9569ab1aaa027b88392b0· το qub_id της V1.1 με προεικόνα 100 bytes (μετά την ενσωμάτωση του outcome_at_or_zero) ήταν b0d032898ad629795150fdcb3f84e518f59ed05b7a2a82bc24ebdb87f52144ed. Η V1.2 ενσωματώνει το drand_round και αναβαθμίζει τον διαχωριστή πεδίου σε QUB_ID_V2.
14.2 Αντιστοίχιση Γύρου Ξεκλειδώματος
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 Round-Trip
Οι υλοποιήσεις ΠΡΕΠΕΙ να επαληθεύουν ότι serialize(parse(serialize(qub))) == serialize(qub) για όλες τις έγκυρες εισόδους. Αυτό είναι ένα property test, όχι ένα μεμονωμένο διάνυσμα.
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)
Τα κανονικά bytes CBOR και ο SHA3-256 body_hash υπολογίζονται από την υλοποίηση αναφοράς. Οι υλοποιήσεις ΠΡΕΠΕΙ να παράγουν byte-πανομοιότυπο CBOR για αυτή την είσοδο.
Οι υλοποιήσεις ΠΡΕΠΕΙ επίσης να επαληθεύουν ότι serialize(parse(serialize(pact))) == serialize(pact) για όλες τις έγκυρες εισόδους PactTerms (property test).
14.5 Διανύσματα Εξωτερικού Περιτυλίγματος Πολλαπλών Γλωσσών
Το εξωτερικό περιτύλιγμα (§13) έχει ξεχωριστό κανονικό fixture στο crates/qub-core/tests/vectors/wrapper_v1.json. Κάθε περίπτωση καρφιτσώνει μια τετράδα (key, nonce, qub_id, sealed_cbor) ως αδιαφανείς εισόδους hex και ισχυρίζεται μια συγκεκριμένη έξοδο 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).
Το fixture αυτή τη στιγμή καρφιτσώνει τρεις περιπτώσεις:
| Περίπτωση | Κάλυψη |
|---|---|
basic-text-public |
Μικρότερο ρεαλιστικό σχήμα SealedQub· χωρίς προαιρετικά πεδία. Καθιερώνει το κανονικό σχήμα περιτυλίγματος για ένα τυπικό qub v1.0. |
with-recipient-pubkey |
SealedQub με recipient_pubkey ορισμένο (μονοπάτι Phase 2). Διαφορετικό σύνολο εσωτερικών κλειδιών CBOR, διαφορετικό qub_id. |
longer-body |
Σώμα ~4 KiB — εξασκεί προθέματα μήκους CBOR πολλαπλών bytes τόσο μέσα στον εσωτερικό φάκελο όσο και στο εξωτερικό κρυπτογραφημένο κείμενο. |
Οι υλοποιήσεις ΠΡΕΠΕΙ να παράγουν byte-πανομοιότυπο expected_wrapper_hex για τις καταγεγραμμένες εισόδους. Η αναγέννηση του fixture απαιτεί 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-byte, υπογραφή 3309-byte) και χωρίς υπογραφή (sig_alg = 0x00). Το μητρώο της §9.2 δεν ορίζει καμία άλλη τιμή· ένας επαληθευτής v1 ΠΡΕΠΕΙ να απορρίπτει κάθεsig_algεκτός του{0x00, 0x01}. Μια μελλοντική καταχώριση 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, εκδόσεις περιτυλίγματος, τύπους περιεχομένου. Το προφίλ είναι σταθερό κατά τον χρόνο επαλήθευσης, ποτέ διαπραγματεύσιμο in-band. Οποιαδήποτε τιμή εκτός του ενεργού προφίλ απορρίπτεται.
Αυτό εγγυάται ότι η προσθήκη ML-DSA-87 ή η ενεργοποίηση του Ed25519 δεν μπορεί να αποδυναμώσει αναδρομικά υπάρχουσες διαμορφώσεις επαληθευτή: ένας επαληθευτής v1 παραμένει επαληθευτής v1 ακόμη και αφού δημοσιευθεί ένα προφίλ v2.
15.3 Συνθήκες Ενεργοποίησης
Προωθήστε την §15 σε κανονιστική κατάσταση όταν προταθεί οποιοδήποτε από τα ακόλουθα:
- Ένα δεύτερο byte
sig_alg(ενεργοποίηση Ed25519, ML-DSA-87, ή οποιαδήποτε νέα εγγραφή στο μητρώο §9). - Μια δεύτερη αλυσίδα drand σε παραγωγική χρήση.
- Μια δεύτερη έκδοση εξωτερικού περιτυλίγματος.
Μέχρι τότε η §15 είναι ένα placeholder που σταθεροποιεί το σχήμα μετάβασης ώστε μελλοντικά PRs να προσγειώνονται σε γνωστό στόχο αντί να επανα-διαπραγματεύονται την επιφάνεια διαπραγμάτευσης από την αρχή.
16. Αρχείο Διαφάνειας και Βαθμίδες Αντοχής (Σχεδίαση — η αναθεώρηση ολοκληρώθηκε)
Κατάσταση. Αυτή η ενότητα είναι μια προδιαγραφή σχεδίασης. Τα μορφότυπα σύρματος, ο κατακερματισμός και το μοντέλο εμπιστοσύνης παρακάτω είναι κανονιστικά για την υλοποίηση, αλλά κανένας κώδικας αρχείου διαφάνειας δεν έχει ακόμη παραδοθεί. Η εξωτερική αναθεώρηση W5 έχει ολοκληρωθεί: η §16.15 καταγράφει τις επιλυμένες αποφάσεις και τους δεσμευτικούς περιορισμούς εκκίνησης που προέκυψαν από αυτήν. Η υλοποίηση μπορεί να προχωρήσει υπό αυτούς τους περιορισμούς. Η §16 παραμένει μελλοντοστρεφής με την ίδια έννοια όπως η §15 — σταθεροποιεί τον στόχο ώστε η υλοποίηση να προσγειωθεί σε μια καθορισμένη σχεδίαση αντί να επανα-παράγει το μοντέλο εμπιστοσύνης κατά την αναθεώρηση κώδικα. Είναι αυστηρά προσθετική — κάθε υπάρχον qub διατηρεί την ατομική του συναλλαγή Arweave και δεν υπάρχει καμία αλλαγή στο μορφότυπο σύρματος
SealedQub/QubEnvelope.
16.1 Λογική και Βαθμίδες Αντοχής
Σήμερα η αντοχή ενός qub και η χρονική του δέσμευση στηρίζονται και οι δύο σε μία μόνο συναλλαγή Arweave ανά qub (§11). Αυτό συνδέει την καθυστέρηση σφράγισης με την οριστικοποίηση του Arweave, καθιστά το ανέβασμα ανά qub ένα ανώτατο όριο κόστους προϊόντος (ARWEAVE_DAILY_CEILING), και δεν δίνει καμία διάταξη ανθεκτική σε αλλοίωση μεταξύ των qubs. Το αρχείο διαφάνειας προσθέτει δύο επίπεδα κάτω και γύρω από αυτή τη μοναδική βαθμίδα:
| Βαθμίδα | Όνομα | Εγγύηση | Πότε |
|---|---|---|---|
| T1 | Σύγχρονη επιβεβαίωση με R2 πρώτα | Δάπεδο αντοχής — τα σφραγισμένα bytes εγγράφονται σε ανθεκτική αποθήκευση πριν επιστρέψει η σφράγιση (< 300 ms p95). |
Κάθε qub, σύγχρονα (§16.10). |
| T2 | Συμπερίληψη στο αρχείο διαφάνειας ανά παρτίδα | Καθολική δέσμευση μόνο-προσάρτησης, ανθεκτική σε αλλοίωση + ολική διάταξη, αγκυρωμένη στο Arweave. | Κάθε qub, αναβεβλημένα + σε παρτίδες (§16.5–16.7). |
| T3 | Μονιμότητα Arweave ανά qub | Μια ατομική συναλλαγή Arweave για το qub. | Επί πληρωμή αναβάθμιση, και η εφεδρεία μη-διαθεσιμότητας Arweave (§16.8). |
Το T2 κάνει το Arweave ανά qub μια επιλογή (T3) αντί για τη μοναδική διαδρομή αντοχής. Το ARWEAVE_DAILY_CEILING αποσύρεται ως ανώτατο όριο προϊόντος και υποβιβάζεται σε διακόπτη κυκλώματος μόνο για το αποκλειστικό πορτοφόλι αγκύρωσης (§16.7)· οι σφραγίσεις των χρηστών δεν απορρίπτονται ποτέ επειδή το υπερβαίνουν.
Εντιμότητα αντοχής (επιλύθηκε — §16.15 Q6). Η αντοχή δεν οπισθοχωρεί: η εγγραφή T1 στο R2 είναι σύγχρονη και άπαξ-εγγραφής, οπότε ένα qub δωρεάν βαθμίδας που δεν αγόρασε T3 είναι πλήρως ανθεκτικό τη στιγμή που επιστρέφει η σφράγιση. Αυτό που χονδραίνει είναι ο αποδείξιμος χρόνος δέσμευσης ανώτατου ορίου: για ένα δωρεάν qub γίνεται ο χρόνος μπλοκ αγκύρωσης αντί για τον χρόνο μπλοκ μιας συναλλαγής ανά qub. Σε χαμηλό όγκο — η ρεαλιστική κατάσταση πρώιμης εκκίνησης και εκτός αιχμής — η πλήρης ημερήσια συχνότητα είναι το τυπικό δάπεδο, όχι μια σπάνια ακραία περίπτωση. Η διατύπωση του προϊόντος είναι επομένως ένα ανώτατο όριο με καμία δεσμευμένη αριθμητική καθυστέρηση — «σφραγισμένο και ανθεκτικό τώρα· μια ανεξάρτητη δημόσια χρονοσήμανση προστίθεται στην επόμενη αγκύρωση αρχείου (τυπικά ημερησίως)» — και η απόδειξη δέσμευσης ακριβούς ώρας είναι μια ιδιότητα T3 επί πληρωμή, αποκαλυπτόμενη στην επιφάνεια σύγκρισης βαθμίδων και στους όρους (§16.11, §16.15 Q6). Οποιοδήποτε χρονικό όριο είναι αποκλειστικά ένα εσωτερικό SLO, ποτέ ένα προωθούμενο SLA.
16.2 Δομή LogLeaf (δύο δεσμευμένα σχήματα)
Μια εγγραφή αρχείου είναι ένα LogLeaf, κωδικοποιημένο ως χειρόγραφο κανονικό CBOR υπό το προφίλ §3.1 (καθορισμένου μήκους, χωρίς ετικέτες, χωρίς floats, ακέραιοι συντομότερης μορφής, κείμενο NFC, προαιρετικά πεδία που παραλείπονται όταν απουσιάζουν, κλειδιά ταξινομημένα κατά κωδικοποιημένο μήκος bytes σε αύξουσα σειρά και μετά λεξικογραφικά). Ο κανονικός φρουρός §3.1 parse → re-encode → compare εφαρμόζεται στη διαδρομή κωδικοποίησης πριν τον κατακερματισμό (όχι μόνο στην αποκωδικοποίηση), ώστε δύο υλοποιήσεις να μην μπορούν να διαφωνήσουν για τα bytes του φύλλου μέσω διαφοράς πλάτους ακεραίου ή σειράς κλειδιών. Όλοι οι ακέραιοι είναι u8 / u64 / i64· όλες οι συνόψεις είναι 32-byte byte strings (bstr[32]). Ένα αποθηκευμένο id συναλλαγής Arweave είναι μια ακατέργαστη 32-byte σύνοψη SHA-256 που μεταφέρεται ως bstr[32], ποτέ ως κείμενο base64url (ταιριάζει με την §3.3).
Το φύλλο έχει δύο σχήματα που επιλέγονται από ένα byte kind, επειδή στην προεπιλεγμένη διαδρομή ανεβάσματος ο Worker είναι byte-τυφλός: το POST /api/v1/upload λαμβάνει μόνο qub_id και unlock_at ως μη έμπιστους ισχυρισμούς πελάτη — τα body_hash, drand_round, created_at και drand_chain_version είναι όλα σφραγισμένα μέσα στο εξωτερικό περιτύλιγμα §13, του οποίου το κλειδί ο Worker δεν κατέχει ποτέ. Μόνο η διαδρομή σφράγισης διακομιστή (POST /api/v1/seal) παράγει body_hash / drand_round από το απλό κείμενο. Ένα μοναδικό σχήμα φύλλου που μεταφέρει body_hash + drand_round θα δέσμευε επομένως τιμές που ο χειριστής δεν επαλήθευσε ποτέ για την πλειονότητα των πραγματικών qubs. Ο διαχωρισμός κρατά κάθε δεσμευμένη τιμή έντιμη:
| Κλειδί | Κωδ. μήκος | Τύπος | Παρουσία | Σημασία |
|---|---|---|---|---|
seq |
4 | u64 |
υποχρεωτικό | Καθολικός δείκτης φύλλου με βάση το 0· η θέση που δεσμεύει η απόδειξη συμπερίληψης. |
kind |
5 | u8 |
υποχρεωτικό | 0x01 πιστοποιημένο (σφράγιση διακομιστή) ή 0x02 ισχυριζόμενο (σφράγιση πελάτη / byte-τυφλό ανέβασμα). |
ref |
4 | bstr[32] |
υποχρεωτικό | Id αναφοράς φύλλου. Πιστοποιημένο → ακατέργαστο qub_id. Ισχυριζόμενο → το τυφλοποιημένο id SHA3-256(qub_id ‖ log_blind_secret) (§16.2.1). |
chash |
6 | bstr[32] |
υποχρεωτικό | Διεύθυνση περιεχομένου SHA3-256(stored_bytes) — ο μοναδικός δεσμός περιεχομένου που ο Worker μπορεί πάντα να υπολογίσει έντιμα, και στις δύο διαδρομές. |
unlock_at |
10 | i64 |
υποχρεωτικό | Αντιγραμμένο (πιστοποιημένο) ή ισχυριζόμενο (ισχυριζόμενο)· επικυρωμένο > 0 πριν εισέλθει στο φύλλο. |
received_at |
12 | i64 |
υποχρεωτικό | Ρολόι τοίχου του Worker κατά την επιβεβαίωση R2. Μη αποδεικτικό (ισχυριζόμενο από τον χειριστή· §16.6). Παρόν για αυτο-περιγραφή, ποτέ απόδειξη. Επικυρωμένο > 0. |
body_hash |
10 | bstr[32] |
μόνο kind=0x01 |
Παραλείπεται στο 0x02 — ο Worker δεν το διαθέτει υπό την §13. |
drand_round |
12 | u64 |
μόνο kind=0x01 |
Παραλείπεται στο 0x02. |
Ένα φύλλο kind=0x02 σκόπιμα δεν δεσμεύει ούτε body_hash ούτε drand_round: πιστοποιεί τη δέσμευση και τη διάταξη ενός αδιαφανούς κρυπτογραφημένου κειμένου στη διεύθυνση περιεχομένου chash, ισχυριζόμενο qub_id και unlock_at — όχι το απλό κείμενο ή τον γύρο του. Τα σκέλη απλού κειμένου/γύρου για ένα ισχυριζόμενο qub προέρχονται από την υπάρχουσα επαλήθευση δέσμης .qub της §11, όχι από το αρχείο (§16.11). Το drand_chain_version δεν είναι στο φύλλο (βρίσκεται μέσα στο περιτύλιγμα στην προεπιλεγμένη διαδρομή)· η ανάλυση αλυσίδας ζει στην αγκύρωση (§16.7). Πειθαρχία κωδικοποιητή: απόρριψη ενός ref ή chash με όλα μηδενικά, και απόρριψη μη-θετικού unlock_at / received_at, αντικατοπτρίζοντας τον φρουρό σεντινέλας outcome_at > 0 στο cbor.rs.
16.2.1 Τυφλοποίηση ιδιωτικού qub
Το αρχείο δεν πρέπει να γίνει το μαντείο απαρίθμησης που το εξωτερικό περιτύλιγμα §13 υπάρχει για να αποτρέψει (§13.1). Για ένα ιδιωτικό (περιτυλιγμένο) qub το asserted φύλλο δεσμεύει το τυφλοποιημένο αναγνωριστικό SHA3-256(qub_id ‖ log_blind_secret), όπου το log_blind_secret είναι ένα μυστικό που κατέχει ο διακομιστής, και παραλείπει το body_hash. Ένα τρίτο μέρος δεν μπορεί να συνδέσει ένα τέτοιο φύλλο με ένα συγκεκριμένο qub_id· ο κάτοχος του qub, που έχει την URL παράδοσης και επομένως το qub_id, μπορεί να επανυπολογίσει την τυφλοποίηση για να επιβεβαιώσει τη δική του συμπερίληψη. Ένα δημόσιο qub (ήδη απαριθμήσιμο, ήδη φέροντας την ετικέτα Arweave Visibility: public ανά §13.8) δεσμεύει το ακατέργαστο qub_id. Αυτό είναι το ένα σημείο όπου η αυτόνομη επαληθευσιμότητα σκόπιμα υποχωρεί σε ένα φέρον αναλλοίωτο απορρήτου· ο αυτόνομος δεσμός για τα ιδιωτικά qubs είναι το chash (§16.9).
Φύλαξη του log_blind_secret (επιλύθηκε — §16.15 Q4). Η τυφλοποίηση προστατεύει τη μη-συνδεσιμότητα φύλλων, όχι την εμπιστευτικότητα απλού κειμένου (το περιτύλιγμα §13 την κρατά ανεξάρτητα). Σε μια παραβίαση του log_blind_secret, για οποιοδήποτε qub_id που ο αντίπαλος ήδη κατέχει ή μπορεί να ανακατασκευάσει (κάθε qub του οποίου τη δέσμη/URL έχει, συν οποιοδήποτε qub_id χαμηλής εντροπίας ή δημόσιο) επανυπολογίζει το ref του φύλλου σε έναν κατακερματισμό και το συνδέει — αυτό είναι άμεση σύνδεση ενός γνωστού πληθυσμού, όχι αναζήτηση ωμής βίας σε άγνωστο χώρο. Ταξινομήστε το log_blind_secret ως μυστικό βαθμίδας συσχέτισης/Sybil στην ίδια βαθμίδα φύλαξης με άλλα μυστικά διακομιστή, και κάντε ανανέωση μόνο προς τα εμπρός (μια ανανέωση τυφλοποιεί εκ νέου τα μελλοντικά φύλλα· δεν μπορεί να αποσυνδέσει αναδρομικά τα ήδη αγκυρωμένα).
16.3 Κατακερματισμός Φύλλων και Κόμβων
Κατακερματισμός με διαχωρισμό πεδίου RFC 6962 §2.1 με το SHA-256 αντικατεστημένο από SHA3-256:
leaf_hash = SHA3-256(0x00 || canonical_cbor(LogLeaf))
node_hash(l,r) = SHA3-256(0x01 || l || r)
empty tree = SHA3-256("") // defined but never anchored
Τα bytes προθέματος πεδίου 0x02 (αλυσίδα εγγραφών, §16.4) και 0x03 (κατακερματισμός STH, §16.6) είναι δεσμευμένα και ξένα προς αυτά. Είναι μεμονωμένα bytes και επομένως δεν μπορούν να συγκρουστούν με τους υπάρχοντες 10-byte ASCII διαχωριστές πεδίου (QUB_ID_V2, κ.λπ.). Το δέντρο είναι το RFC 6962 αριστερά-πλήρες μη-ισορροπημένο δέντρο (κάθε εσωτερικός διαχωρισμός στη μεγαλύτερη δύναμη του δύο αυστηρά μικρότερη από τον αριθμό φύλλων του υποδέντρου), που επιτρέπει στις αποδείξεις συμπερίληψης και συνέπειας να μοιράζονται έναν αλγόριθμο διαδρομής ελέγχου. Η προδιαγραφή αναφοράς φέρει ρητό ψευδοκώδικα παραγωγής αριστερά/δεξιά και καρφιτσώνει ένα δοκιμαστικό διάνυσμα μη-δύναμης-του-δύο (5 φύλλων) ώστε να εξασκείται η περίπτωση προαγωγής δεξιού άκρου — που ένα διάνυσμα 4 φύλλων κρύβει.
16.4 Αλυσίδωση Κατακερματισμού (εσωτερική)
Το LogDO διατηρεί μια εσωτερική αλυσίδα εγγραφών μόνο για συνέπεια έναντι καταρρεύσεων. Δεν δημοσιεύεται ποτέ και δεν είναι ποτέ ορατή στον επαληθευτή:
entry_chain[seq] = SHA3-256(0x02 || entry_chain[seq-1] || leaf_hash[seq])
entry_chain[-1] = SHA3-256("QUB_TLOG_GENESIS_V1")
Η δημοσιευμένη αρχή μόνο-προσάρτησης είναι η σωρευτική ρίζα Merkle + η αγκύρωσή της (§16.5–16.6), ποτέ η ακατέργαστη σειρά με την οποία ο χειριστής τυχαίνει να σερβίρει τα φύλλα: η αλυσίδα επανυπολογίζεται για οποιαδήποτε σερβιρισμένη σειρά, οπότε μόνο η αγκυρωμένη ρίζα καρφιτσώνει την κανονική θέση.
16.5 Σωρευτικό Δέντρο Merkle και Ομαδοποίηση σε Παρτίδες
Υπάρχει ένα διαρκώς αυξανόμενο δέντρο RFC 6962 πάνω από όλα τα φύλλα σε σειρά seq — όχι απομονωμένα δέντρα ανά παρτίδα. (Μια κατασκευή ανά παρτίδα με αλυσίδωση φύλλου-μεταφοράς απορρίφθηκε: δεν είναι μια αληθινή σχέση προθέματος, οπότε οι «αποδείξεις συνέπειάς» της είναι μη ορθές.) Το σωρευτικό δέντρο δίνει γνήσιες αποδείξεις συνέπειας RFC 9162 και επιτρέπει σε μία μόνο πρόσφατη αγκύρωση να αποδείξει τη συμπερίληψη οποιουδήποτε παλαιότερου qub.
Το Durable Object LogDO είναι ο μοναδικός εγγραφέας (blockConcurrencyWhile, αντικατοπτρίζοντας τα QuotaDO / EntitlementDO) — η προσάρτηση σε ένα κοινόχρηστο αρχείο είναι ανάγνωση-τροποποίηση-εγγραφή σε κοινή κατάσταση και επομένως ΠΡΕΠΕΙ να περνά μέσω ενός DO, ποτέ KV. Αποθηκεύει στην προσωρινή μνήμη το σύνορο δεξιού άκρου του δέντρου (O(log n) κατακερματισμοί) ώστε το κλείσιμο μιας παρτίδας να είναι O(batch). Μια παρτίδα είναι το σύνολο των φύλλων που αγκυρώνονται μαζί· οι σκανδαλισμοί της είναι διαμορφώσιμοι, όχι σταθεροποιημένοι από το πρωτόκολλο: μια προώθηση tree_size τουλάχιστον κατά LOG_BATCH_MAX_LEAVES (προεπιλογή 4096), ή ηλικία που φτάνει τη συχνότητα αγκύρωσης, ή μια εξαναγκασμένη εκκένωση όταν προσγειώνεται μια σφράγιση T3 επί πληρωμή. Το root_i είναι ο σωρευτικός Κατακερματισμός Δέντρου Merkle πάνω από τα φύλλα 0 .. tree_size_i.
16.6 Υπογεγραμμένη Κεφαλή Δέντρου μέσω Αγκύρωσης Arweave
Η συναλλαγή αγκύρωσης Arweave είναι η Υπογεγραμμένη Κεφαλή Δέντρου και αντικαθιστά μια υπογραφή χειριστή για την ίδια την κεφαλή δέντρου: η ημερήσια αγκύρωση δεν χρειάζεται κλειδί qub επειδή ο owner της συναλλαγής Arweave είναι η υπογραφή. Η θέση του moat ισχύει — το αμετάβλητο υπόστρωμα, όχι ένα μυστικό που κατέχει το qub, είναι το φέρον στοιχείο για την αγκυρωμένη ρίζα.
Υπάρχει ακριβώς ένα ζεστό κλειδί υπογραφής qub στη σχεδίαση, και είναι καρφιτσωμένο: το κλειδί απόδειξης παραλαβής ανά σφράγιση (§16.10). Το δημόσιο κλειδί του είναι δεσμευμένο στο LogProfile (διανέμεται με τον επαληθευτή) και συν-υπογεγραμμένο από το anchor_owner, ώστε ένας επαληθευτής να επικυρώνει μια απόδειξη παραλαβής έναντι της ίδιας καρφιτσωμένης ρίζας όπως η αγκύρωση. Αυτή είναι η επίλυση του §16.15 Q2 — ένα μη-καρφιτσωμένο, εναλλάξιμο από τον χειριστή κλειδί απόδειξης παραλαβής θα ήταν αποκηρύξιμο (ο χειριστής θα μπορούσε να αρνηθεί ότι το κλειδί ήταν δικό του), που θα ακύρωνε την αξία λογοδοσίας της απόδειξης έναντι του αντιπάλου επιπέδου-χειριστή που η απόδειξη υπάρχει για να αποτρέψει. Άρα: το qub δεν κατέχει κανένα μη-καρφιτσωμένο κλειδί υπογραφής αρχείου· το κλειδί απόδειξης παραλαβής είναι καρφιτσωμένο και συν-υπογεγραμμένο από το anchor_owner.
Το SignedTreeHead είναι κανονικό CBOR (κλειδιά κατά κωδικοποιημένο μήκος): size:u64, root:bstr[32], batch:u64, prev:bstr[32] (προηγούμενο sth_hash· γένεση = 32 μηδενικά bytes), log_id:bstr[32], first_seq:u64, anchored_at:i64. Ο κατακερματισμός του είναι sth_hash = SHA3-256(0x03 || canonical_cbor(SignedTreeHead)).
Καρφιτσωμένη ρίζα εμπιστοσύνης. log_id = SHA3-256("QUB_TLOG_V1" || anchor_owner_address). Ένας συμμορφούμενος επαληθευτής ΠΡΕΠΕΙ να απαιτεί anchor_tx.owner == LogProfile.anchor_owner, όπου το anchor_owner (και το δημόσιο κλειδί απόδειξης παραλαβής) είναι ενσωματωμένο στο qub_core ως το LogProfile — μαζί με τις σταθερές quicknet που υπάρχουν ήδη στο DrandTimelockProvider::quicknet() — και διανέμεται με το δυαδικό του επαληθευτή. Ο επαληθευτής ΠΡΕΠΕΙ επίσης να επαληθεύει τη δέσμευση data → tx_id της συναλλαγής Arweave τοπικά αντί να εμπιστεύεται μια απάντηση /raw/ πύλης. Αυτό κλείνει την τρύπα ασάφειας του απατεώνα πορτοφολιού: το «αγκυρωμένο στο Arweave» είναι ανούσιο μέχρι ο επαληθευτής να καρφιτσώσει ποιο πορτοφόλι.
Η ανανέωση είναι μια επέκταση διακυβέρνησης §15, όχι επαναχρησιμοποίηση (επιλύθηκε — §16.15 Q3). Η επιφάνεια προφίλ της §15.2 αυτή τη στιγμή απαριθμεί μόνο sig_algs / αλυσίδες drand / εκδόσεις περιτυλίγματος / τύπους περιεχομένου, και οι σκανδαλισμοί της §15.3 δεν αναφέρουν κανέναν από αυτούς — το LogProfile / anchor_owner δεν βρίσκεται ακόμη στην επιφάνεια της §15. Η διακυβέρνηση ανανέωσης πρέπει επομένως να χτιστεί: η §15.3 επεκτείνεται (παρακάτω) ώστε να προστεθεί ο σκανδαλισμός LogProfile, και μια ανανέωση είναι μια υπογεγραμμένη προώθηση LogProfile που παραδίδεται σε μια ενημέρωση επαληθευτή. Μια προγραμματισμένη ανανέωση φέρει μια συν-υπογραφή εξερχόμενου → εισερχόμενου· μια οδηγούμενη από παραβίαση ανανέωση δεν μπορεί (το εξερχόμενο κλειδί είναι μη έμπιστο/μη διαθέσιμο ακριβώς τότε) και καταφεύγει στην προώθηση που διέπεται από την §15, με τον έλεγχο διακλάδωσης prev-anchor (παρακάτω) να οριοθετεί τη ζημιά στο ενδιάμεσο.
Παράθυρο ασάφειας (παράμετρος εμπιστοσύνης πρώτης τάξης). Ένα φύλλο είναι ανθεκτικό σε ασάφεια μόνο μόλις η καλύπτουσα αγκύρωσή του είναι Arweave-επιβεβαιωμένη. Το παράθυρο είναι received_at → επιβεβαίωση αγκύρωσης (≤ συχνότητα + οριστικοποίηση Arweave). Εντός του, οι μόνες εγγυήσεις είναι η καρφιτσωμένη απόδειξη παραλαβής σφράγισης (§16.10) και η λειτουργική ακεραιότητα του qub. Τρία τεχνουργήματα λογοδοσίας κάνουν αυτό έντιμο αντί για χειρονομία (το μοντέλο μάρτυρα είναι η επίλυση του §16.15 Q2):
- Καρφιτσωμένη υπογεγραμμένη απόδειξη παραλαβής σφράγισης — το ανάλογο SCT που επιστρέφεται στην απάντηση ανεβάσματος (§16.10), υπογεγραμμένο από το καρφιτσωμένο, συν-υπογεγραμμένο από το
anchor_ownerκλειδί απόδειξης παραλαβής. Ένα φύλλο που ρίχνεται πριν την αγκύρωσή του αφήνει στο θύμα μια μη-αποκηρύξιμη απόδειξη παραλαβής προς δημοσίευση, κλείνοντας την τρύπα σιωπηρής παράλειψης. - Δημοσιευμένη μεθοδολογία παρακολούθησης + διάσχιση αλυσίδας prev — η αλυσίδα
prevτης αγκύρωσης διασχίζεται από την κεφαλή προς τη γένεση· μια διακλάδωση (δύο αγκυρώσεις στο ίδιοsizeμε διαφορετικήroot, ή μια σπασμένηprev) είναι δημοσιεύσιμη απόδειξη παραπτώματος. Η ανίχνευση ασάφειας είναι μια δηλωμένη λειτουργική δέσμευση, όχι μια σιωπηρή παραδοχή. - Διπλές αυτο-δημοσιευμένες κεφαλές — κάθε νέα κεφαλή
{sth_hash, tree_size}αναρτάται σε ένα αποκλειστικό δημόσιο, μόνο-προσάρτησης αποθετήριο GitHub που ανήκει στο qub (το φέρον σκέλος αυτο-δημοσίευσης ανθεκτικής σε αλλοίωση), με μια ανάρτηση στα κοινωνικά δίκτυα ως επιβεβαίωση βέλτιστης προσπάθειας μόνο. Μια αποτυχημένη ανάρτηση ΠΡΕΠΕΙ να ειδοποιεί (όχι να αποτυγχάνει σιωπηλά).
Όριο εντιμότητας (δεσμευτικός περιορισμός). Επειδή το qub ελέγχει και τις δύο επιφάνειες ανάρτησης, αυτό είναι αυτο-δημοσιευμένο, όχι ανεξάρτητα μαρτυρημένο. Καμία επιφάνεια προϊόντος, μάρκετινγκ ή νομική δεν μπορεί να ισχυριστεί ότι το αρχείο «μαρτυρείται ανεξάρτητα»· ο επιτρεπόμενος ισχυρισμός είναι ότι η ασάφεια είναι ανιχνεύσιμη και αφήνει μια μη-αποκηρύξιμη απόδειξη παραλαβής. Ένας αληθινός ανεξάρτητος μάρτυρας τρίτου μέρους αναβάλλεται για μια μελλοντική προώθηση διακυβέρνησης §15.
Το received_at είναι ισχυριζόμενο από τον χειριστή και κανένας ισχυρισμός δεν μπορεί να στηριχθεί σε αυτό — δεν επιφανειοποιείται ποτέ ως απόδειξη ή ως επιβεβαίωση διαφωνίας σε καμία επιφάνεια προϊόντος / νομική / API / απόδοσης απόδειξης. Ο χρόνος μπλοκ αγκύρωσης Arweave T είναι η μόνη χρονοσήμανση χωρίς εμπιστοσύνη (ένα ανώτατο όριο στο «καταγράφηκε έως»). Οποιοσδήποτε έλεγχος λογικής παρακολούθησης στο received_at ΠΡΕΠΕΙ να συγκρίνεται έναντι του T, όχι έναντι του ελεγχόμενου από τον χειριστή πεδίου anchored_at του STH· ένας τέτοιος έλεγχος είναι ένας φρουρός μόνο έναντι σφάλματος ρολογιού ενός έντιμου χειριστή, όχι ένας έλεγχος λογοδοσίας έναντι ενός κακόβουλου χειριστή (§16.15 Q5).
16.7 Μορφότυπο Συναλλαγής Αγκύρωσης και Συχνότητα
Το AnchorBundle είναι το σώμα συναλλαγής Arweave σε κανονικό CBOR, που εγγράφεται μέσω του bundler της §16.8: ver:u8, sth:bstr (κανονικά bytes SignedTreeHead), prev_anchor:bstr (id συναλλαγής προηγούμενης αγκύρωσης ως ακατέργαστα bytes· παραλείπεται στη γένεση), chain_hash:tstr (η αλυσίδα drand σε ισχύ — quicknet), και το ρεύμα leaf-CBOR της παρτίδας σε σειρά seq ώστε η αγκύρωση να είναι αυτοτελής: ένας παρακολουθητής επαναπαράγει τη root από το σώμα με μηδενική εξάρτηση από το qub. (Εάν το ρεύμα φύλλων γίνει μεγάλο σε υψηλό όγκο, μια μελλοντική αναθεώρηση μπορεί να δεσμεύσει μόνο ένα εύρος φύλλων κατά αναφορά· σημειώνεται, δεν υιοθετήθηκε στην v1.)
Οι ετικέτες Arweave είναι σκόπιμα απαριθμήσιμες — το αρχείο προορίζεται να βρεθεί, σε αντίθεση με τα ιδιωτικά qubs: App-Name: qub-tlog, Anchor-Format: 1, Log-Id: <hex>, Batch: <n>, Tree-Size: <n>, Root: <hex>, Prev-Anchor: <tx>, Content-Type: application/cbor. Οι ετικέτες είναι μη έμπιστες υποδείξεις· το σώμα CBOR είναι η μοναδική αρχή.
Συχνότητα: ημερήσια από προεπιλογή, αναθεωρούμενη με τον όγκο (ο σκανδαλισμός μεγέθους συντομεύει αυτόματα την πραγματική συχνότητα υπό φορτίο)· μια σφράγιση T3 επί πληρωμή εξαναγκάζει μια αγκύρωση ώστε οι πελάτες που πληρώνουν να μην περιμένουν ποτέ μια μέρα. Το πορτοφόλι αγκύρωσης είναι αποκλειστικό και χαμηλής ταχύτητας, ξεχωριστό από το πορτοφόλι ανεβάσματος — ΠΡΕΠΕΙ να είναι το δικό του JWK (ένα διακριτό κλειδί, όχι ένας λογικός ρόλος στο πορτοφόλι ανεβάσματος) ώστε μια παραβίαση του πορτοφολιού ανεβάσματος να μην μπορεί να πλαστογραφήσει αγκυρώσεις — με έναν σκληρό ημερήσιο προϋπολογισμό συναλλαγών αγκύρωσης (το υποβιβασμένο ARWEAVE_DAILY_CEILING). Η θέση φύλαξης δηλώνεται ξεκάθαρα: ένα ζεστό κλειδί στενής εμβέλειας με σφιχτό διακόπτη κυκλώματος και χαμηλό υπόλοιπο, όχι «ψυχρό» — ένα πορτοφόλι που αυτο-υπογράφει ημερησίως δεν μπορεί να είναι ψυχρό, και η προδιαγραφή δεν προσποιείται το αντίθετο.
16.8 Bundler ANS-104
Ένας εσωτερικός κωδικοποιητής DataItem ANS-104 και υπογραφέας deep-hash, περίπου 300 γραμμές, μόνο Web Crypto, μηδέν εξαρτήσεις npm (και τα δύο Turbo SDKs αποτυγχάνουν στον φρουρό εφοδιαστικής αλυσίδας npm ci --ignore-scripts). Διάταξη bytes DataItem:
signatureType (2, LE) || raw_signature || owner || target(flag+0|32) || anchor(flag+0|32) || num_tags(8, LE) || tags_len(8, LE) || avro_tags || data
Η υπογραφή είναι το Arweave deepHash — μια αναδρομική σύνοψη SHA-384 (απαίτηση σύρματος του Arweave, crypto.subtle.digest("SHA-384")) πάνω από ["dataitem", "1", sig_type, owner, target, anchor, encoded_tags, data] — και μετά RSA-PSS πάνω από τον deep hash με το JWK του πορτοφολιού μέσω crypto.subtle· id = base64url(SHA-256(signature)). Το SHA-384 εδώ είναι απομονωμένο ως πρωτεύον μόνο-σύρματος-Arweave, ποτέ ως πρωτεύον εμπιστοσύνης qub (η §15 καταγράφει το φράγμα· ο κατακερματισμός εμπιστοσύνης του qub είναι SHA3-256 παντού).
Μία διαδρομή κώδικα εξυπηρετεί τρεις καταναλωτές: μονιμότητα ανά qub T3 επί πληρωμή, την εφεδρεία μη-διαθεσιμότητας Arweave (βάλε το DataItem σε ουρά, επίστρεψε την επιβεβαίωση R2-πρώτα ανεξάρτητα — αυτό κλείνει το τρέχον αδιέξοδο 503 ARWEAVE_UNAVAILABLE), και την εγγραφή του AnchorBundle. Σχήμα υπογραφής (επιλύθηκε — §16.15 Q8): η v1 υπογράφει με RSA-PSS (τύπος υπογραφής 1) επαναχρησιμοποιώντας τον υπάρχοντα μηχανισμό JWK του πορτοφολιού Arweave (μηδενική νέα φύλαξη μακρόβιου κλειδιού, εξυπηρετώντας τη θέση «ένα μυστικό λιγότερο»)· το Ed25519 αναβάλλεται για τη διαδρομή PQ-μετάβασης της §15.
Ο χειρόγραφος deep hash είναι ο κώδικας υψηλότερου κινδύνου, χαμηλότερης φυσικής κάλυψης στο W5, οπότε η οριοθέτησή του είναι μη διαπραγματεύσιμη (§16.15 Q8):
- Το fixture πολλαπλών γλωσσών
tlog_v1.json(Rust + TS, το μοτίβοwrapper_v1.jsonτης §14.5) καλύπτει deep-hash, bytes + id DataItem, κατακερματισμούς φύλλων, μια ρίζα 5 φύλλων + διαδρομή ελέγχου, έναν κατακερματισμό STH, μια απόδειξη συμπερίληψης και μια απόδειξη συνέπειας — και στις δύο κατευθύνσεις υπογραφής και επαλήθευσης (η κατεύθυνση επαλήθευσης έχει σημασία επειδή ο τοπικός έλεγχος tx → tx_id της §16.6 τραβά τον deep hash σε κάθε αυτόνομο επαληθευτή, όχι μόνο στον εγγραφέα). - Ένα εφάπαξ round-trip διαλειτουργικότητας μέσω ενός bundler ANS-104 αναφοράς, που καταναλώνεται ως στατικά δοκιμαστικά δεδομένα μόνο — ποτέ ως εξάρτηση χρόνου εκτέλεσης npm (η θέση μόνο-Web-Crypto / χωρίς install-scripts ισχύει).
- Η διαδρομή deep-hash + RSA-PSS πρέπει να κάνει round-trip μέσω των ίδιων πρωτευόντων
crypto.subtleπου χρησιμοποιεί η παραγωγή, ώστε ο εσωτερικός κωδικοποιητής να είναι byte-συμβατός. - Ένας συνεχής παρακολουθητής αποδοχής μετά τη δέσμη επιβεβαιώνει ότι κάθε DataItem αγκύρωσης / εφεδρείας επιτυγχάνει όντως αποδοχή από το Arweave, με συναγερμό + διακόπτη κυκλώματος — επειδή ο deep hash εξυπηρετεί επίσης την ουρά εφεδρείας μη-διαθεσιμότητας Arweave, οπότε μια σιωπηρή οπισθοχώρηση θα γέμιζε εκείνη την ουρά με στοιχεία απορριφθέντα από το δίκτυο κατά την ακριβή διακοπή που υπάρχει για να καλύψει.
16.9 Αποδείξεις Συμπερίληψης και Συνέπειας
Και οι δύο είναι RFC 9162, SHA3-256, σερβιρισμένες ως κανονικό CBOR.
InclusionProof — GET /api/v1/qub/:tx_id/proof: ver:u8, leaf:bstr (το ακριβές CBOR φύλλου — ο επαληθευτής επανυπολογίζει το leaf_hash ο ίδιος και δεν εμπιστεύεται ποτέ έναν παρεχόμενο κατακερματισμό), index:u64, size:u64, audit:[bstr[32]], root:bstr[32], anchor:{ txid:bstr[32], batch:u64, sth:bstr[32], log_id:bstr[32], block_height?:u64, anchored_at?:i64 }.
ConsistencyProof — GET /api/v1/log/consistency?first=<size_a>&second=<size_b>: ver:u8, first_size:u64, second_size:u64, first_root:bstr[32], second_root:bstr[32], nodes:[bstr[32]], first_anchor, second_anchor. Μία μονοσήμαντη λίστα κλειδιών, καρφιτσωμένη από δοκιμαστικό διάνυσμα.
Αυτόνομη επαλήθευση (χωρίς διακομιστή qub, επεκτείνει την §11):
1. Parse .qub bundle → SealedQub; recompute qub_id (§4.1).
2. Read leaf.kind.
3a. kind=0x01 (attested):
assert leaf.ref == qub_id
assert leaf.body_hash == SHA3-256(body)
assert leaf.drand_round == unlock_round(unlock_at)
3b. kind=0x02 (asserted):
assert leaf.ref == SHA3-256(qub_id || blind) // holder supplies blind
OR treat ref as opaque and bind via leaf.chash == SHA3-256(stored_bytes)
4. Recompute leaf_hash = SHA3-256(0x00 || leaf); fold `audit` per RFC 6962
using index/size; require derived root == proof.root.
5. Fetch anchor.txid from any gateway; verify the tx data → tx_id binding
(do not trust a gateway /raw/ response); REQUIRE anchor_tx.owner ==
LogProfile.anchor_owner.
6. Parse AnchorBundle; require committed root == proof.root and size ==
proof.size; read the Arweave block time T.
7. Emit the claim scoped by leaf.kind (§16.11).
Η αποθήκευση σερβιρίσματος αποδείξεων ΠΡΕΠΕΙ να είναι με κλειδί συντεταγμένης (επιλύθηκε — §16.15 Q7, μπλοκάρουσα προϋπόθεση). Η παραγωγή απόδειξης ψυχρού φύλλου είναι ουδέτερη ως προς την ορθότητα μόνο εάν το υλικό ελέγχου R2 είναι ένα μόνιμο κατάστημα κόμβων Merkle με κλειδί την απόλυτη συντεταγμένη δέντρου (level, index) — όχι deltas κόμβων ανά batch. Με ένα κατάστημα με κλειδί συντεταγμένης, οποιαδήποτε διαδρομή ελέγχου (leaf i, size N) είναι ένα σύνολο O(log N) άμεσων R2 GET χωρίς επανυπολογισμό πέρα από τα όρια παρτίδας· με ένα κατάστημα με κλειδί παρτίδας δεν είναι, που είναι το κενό διάταξης αποθήκευσης που κλείνει αυτή η επίλυση. Τα σώματα των φύλλων είναι ομοίως διευθυνσιοδοτήσιμα κατά περιεχόμενο μέσω seq. Ένα δοκιμαστικό διάνυσμα W5 ΠΡΕΠΕΙ να αποδείξει ένα ψυχρό φύλλο εποχής γένεσης έναντι μιας πολύ μεταγενέστερης ρίζας χρησιμοποιώντας μόνο R2 + Arweave με την αποθήκευση του LogDO σβησμένη, ώστε ο ισχυρισμός ασφάλειας ανάκτησης στην §16.13 να είναι τεκμηριωμένος αντί για ισχυρισμένος. Τα O(log N) διαδοχικά R2 GET ανήκουν μόνο στο ασύγχρονο σημείο απόληξης απόδειξης — ποτέ στη ζεστή διαδρομή σφράγισης (§16.10) ή σε ένα cron ανά κύκλο.
16.10 Διάταξη Επιβεβαίωσης με R2 Πρώτα
Η ακολουθία του POST /api/v1/upload γίνεται:
- Φρουροί πρώτου ημίσεος (έλεγχος ταυτότητας, επικύρωση, κλειδί τμήματος idempotency) — αμετάβλητοι.
- Σύγχρονα
await QUB_CACHE.put(qub-cache/<tx_id>, wrappedBytes)— το δάπεδο αντοχής· κλείνει επίσης τον αγώνα προ-προσωρινής μνήμης του W1 (παλαιότερα έναctx.waitUntilμετά την υποβολή Arweave). - Σύγχρονα
await LogDO.append(leaf)— μία RPC DO εντός-colo· ο μοναδικός εγγραφέας αναθέτειseq, επεκτείνει την αλυσίδα εγγραφών και ενημερώνει το σύνορο. (RMW σε κοινή κατάσταση → DO, ποτέ KV.) Η RPCappendκάνει μόνο αυτό· η εργασία κλεισίματος παρτίδας MerkleO(batch)εκτελείται εκτός αυτής της RPC στον συναγερμό του LogDO, αλλιώς το p95 της προσάρτησης εκτινάσσεται σε κάθεLOG_BATCH_MAX_LEAVES-οστή σφράγιση. - Επίστρεψε την επιβεβαίωση τώρα — με την απόδειξη παραλαβής σφράγισης (υπογεγραμμένη από το καρφιτσωμένο κλειδί απόδειξης παραλαβής, §16.6) και
{ tx_id, log_seq, anchor_status: "pending" }. Η πολυδευτερόλεπτη διασπορά Arweave αφαιρείται από την κρίσιμη διαδρομή. - Ένα
ctx.waitUntilβάζει σε ουρά την αναβεβλημένη εργασία: την υποβολή Arweave ανά qub (τώρα βέλτιστης προσπάθειας / επί πληρωμή· σε αποτυχία δρομολογείται στην ουρά εφεδρείας του bundler αντί να επιστρέφει 503 στον χρήστη) συν τις υπάρχουσες προσωρινές εγγραφές μεταδεδομένων. Το κλείσιμο παρτίδας και η αγκύρωση εκτελούνται ανεξάρτητα από τον συναγερμό του LogDO και το ημερήσιο cron αγκύρωσης. Κανέναctx.waitUntilμέσα σε βρόχο· το υπάρχον κλειδί τμήματος idempotency διατηρείται.
Προϋπολογισμός καθυστέρησης (επιλύθηκε — §16.15 Q7). Ο στόχος < 300 ms p95 είναι μια μετρημένη πύλη εκκίνησης, όχι μια παραδοχή. Η έντιμη κρίσιμη διαδρομή είναι οι αναγνώσεις KV πρώτου ημίσεος + ένα R2 PUT + δύο σειριοποιημένα Durable Objects — η υπάρχουσα χρέωση ποσόστωσης σφράγισης QuotaDO και η νέα προσάρτηση LogDO — οπότε ο προϋπολογισμός πρέπει να λογαριάζει δύο γύρους DO εντός-colo, όχι έναν. Παράδωσε έναν συναγερμό καθυστέρησης LogDO που αντικατοπτρίζει αυτόν του QuotaDO και αντιμετώπισε μια οπισθοχώρηση p95 ως μπλοκάρουσα έκδοσης.
16.11 Μοντέλο Εμπιστοσύνης — ο ακριβής ισχυρισμός, οριοθετημένος ανά είδος φύλλου
Για kind=0x01 (πιστοποιημένο): «Αυτό το περιεχόμενο — σώμα που ταιριάζει με το body_hash, αναγνωρισμένο από το qub_id — δεσμεύτηκε στο αρχείο μόνο-προσάρτησης του qub στη θέση seq και υπήρχε όχι αργότερα από τον χρόνο μπλοκ Arweave T· ήταν κρυπτογραφικά μη αναγνώσιμο μέχρι τον γύρο drand R = unlock_round(unlock_at).» Αυτή είναι η πλήρης τριάδα {δέσμευση γύρου tlock + συμπερίληψη Merkle + αγκυρωμένη ρίζα}.
Για kind=0x02 (ισχυριζόμενο, η προεπιλογή): «Ένα αδιαφανές κρυπτογραφημένο κείμενο με διεύθυνση περιεχομένου chash, ισχυριζόμενο qub_id και unlock_at, δεσμεύτηκε στο αρχείο μόνο-προσάρτησης στη θέση seq και υπήρχε όχι αργότερα από τον χρόνο μπλοκ Arweave T.» Τα σκέλη γύρου και σώματος παρέχονται από την υπάρχουσα επαλήθευση δέσμης .qub της §11 (qub_core::unlock), όχι από το αρχείο· αυτό που προσθέτει το αρχείο πέρα από μια γυμνή συναλλαγή ανά qub είναι διάταξη ανθεκτική σε αλλοίωση, ένας χρόνος δέσμευσης ανώτατου ορίου χωρίς εμπιστοσύνη, και αντοχή σε ασάφεια.
Και οι δύο ισχυρισμοί εξαιρούν, ανά §11: συγγραφή χωρίς sig_alg ≥ 0x01, πρόθεση, και χρονισμό υπο-αγκύρωσης ανάλυσης. Κανένας δεν επιτρέπει σε κανέναν ισχυρισμό να στηριχθεί στο received_at.
Ανώτατο όριο ισχυρισμού (δεσμευτικός περιορισμός εκκίνησης — επιλύθηκε §16.15 Q1). Για δωρεάν / προεπιλεγμένα (kind=0x02) qubs, ο οριοθετημένος ισχυρισμός kind=0x02 παραπάνω είναι το ανώτατο όριο για το τι μπορεί να ισχυριστεί οποιαδήποτε επιφάνεια προϊόντος, μάρκετινγκ, όρων ή απόδοσης απόδειξης. Καμία επιφάνεια δεν μπορεί να δηλώσει ή να υπαινιχθεί ότι το αρχείο αποδεικνύει το περιεχόμενο ή τον γύρο ξεκλειδώματος ενός προεπιλεγμένου qub — το αρχείο αποδεικνύει διάταξη + έναν χρόνο δέσμευσης ανώτατου ορίου ενός αδιαφανούς κρυπτογραφημένου κειμένου χωρίς εμπιστοσύνη. Η απόδειξη περιεχομένου και γύρου προέρχεται αποκλειστικά από την υπάρχουσα επαλήθευση δέσμης .qub της §11, που είναι ανεξάρτητη του αρχείου. Αυτή είναι μια σκληρή μπλοκάρουσα εκκίνησης στο κείμενο, όχι μια στυλιστική προτίμηση· είναι η επίλυση που κρατά έντιμη την προεπιλεγμένη byte-τυφλή διαδρομή.
16.12 Διαχείριση Εκδόσεων και Συντονισμός W3
Δεν υπάρχει καμία αύξηση σύρματος SealedQub και επομένως καμία αύξηση έκδοσης πρωτοκόλλου (§12.1): το αρχείο είναι ένα sidecar που δεσμεύεται σε υπάρχοντα πεδία και bytes, οπότε δεν εισέρχεται στο ιστορικό έκδοσης πρωτοκόλλου της §12.2. Το προαιρετικό drand_chain_version του W3 παραμένει ανέγγιχτο και παραμένει το μόνο προαιρετικό πεδίο SealedQub. Το αρχείο εισάγει αντ' αυτού τους δικούς του ανεξάρτητους χώρους έκδοσης — LOG_VERSION_1, ANCHOR_FORMAT_1, InclusionProof.ver — αντικατοπτρίζοντας την ανεξαρτησία έκδοσης περιτυλίγματος της §12.4 (το περιτύλιγμα φέρει ένα byte έκδοσης ανεξάρτητο από την έκδοση πρωτοκόλλου, και οι εκδόσεις του αρχείου ακολουθούν τον ίδιο διαχωρισμό).
Η παράδοση απόδειξης ανακτάται από προεπιλογή, με μια προαιρετική συνεπιβίβαση. Μια απόδειξη δεν μπορεί να υπάρχει κατά τον χρόνο σφράγισης (η αγκύρωση δεν έχει ακόμη γραφτεί), οπότε η δέσμη .qub του χρόνου σφράγισης παραμένει χωρίς απόδειξη. Ο επαληθευτής του W7 ανακτά το GET …/proof μία φορά, ή σε πλήρως-εκτός-σύνδεσης λειτουργία ανακατασκευάζει την απόδειξη από το δημόσιο AnchorBundle μέσω ενός ερωτήματος Arweave στο Log-Id. Η δέσμη .qub (W7) δεσμεύει ένα προαιρετικό μέλος inclusion_proof — απόν κατά τη σφράγιση, συμπληρωμένο από μια επανεξαγωγή μετά την αγκύρωση για ψυχρή αρχειοθέτηση — ακολουθώντας το ίδιο μοτίβο «προαιρετικό, παραλειπόμενο από προεπιλογή, προσθετικό» όπως το drand_chain_version του W3.
16.13 Διατήρηση
Τα παράθυρα διατήρησης για την ανοιχτή ουρά του LogDO, το υπόστρωμα σερβιρίσματος αποδείξεων R2, τους μετρητές διακόπτη κυκλώματος αγκύρωσης, και την ουρά εφεδρείας του bundler προσδιορίζονται στο docs/DATA-RETENTION.md. Αρχή: η ζεστή αποθήκευση ανά εγγραφή του αρχείου (LogDO) είναι ανακτήσιμη μετά την αγκύρωση· το υλικό ελέγχου του — το κατάστημα κόμβων Merkle με κλειδί συντεταγμένης (level, index) + τα σώματα φύλλων διευθυνσιοδοτημένα κατά seq (§16.9) + οι αγκυρώσεις Arweave — είναι μόνιμο. Η ανάκτηση ενός ψυχρού φύλλου από το DO δεν ακυρώνει ποτέ μια εκδοθείσα απόδειξη, επειδή μια απόδειξη επιλύεται έναντι αυτού του μόνιμου καταστήματος κόμβων R2 και της αγκύρωσης Arweave, όχι του DO (και το δοκιμαστικό διάνυσμα σβησμένου-DO της §16.9 το αποδεικνύει).
16.14 Δοκιμαστικά Διανύσματα
Το W5 παραδίδει το fixture πολλαπλών γλωσσών tlog_v1.json (§16.8) συν επεξεργασμένα διανύσματα: ένα φύλλο kind=0x01 και ένα kind=0x02 → leaf_hash· τη σωρευτική ρίζα 5 φύλλων· μία απόδειξη συμπερίληψης· μία απόδειξη συνέπειας· ένα AnchorBundle· και ένα id DataItem. Αυτά ζουν δίπλα στα διανύσματα εξωτερικού περιτυλίγματος της §14.5 και εξασκούνται και από τις δύο υλοποιήσεις, Rust (qub-core) και TypeScript (Worker).
16.15 Αποφάσεις Αναθεώρησης (W5 — επιλυμένες)
Η εξωτερική αναθεώρηση W5 (ένα αντιπαλικό πέρασμα σχεδίασης + έγκριση κατόχου) έχει ολοκληρωθεί. Κάθε απόφαση παρακάτω είναι διευθετημένη και αντικατοπτρίζεται στο κείμενο της §16 παραπάνω· οι δεσμευτικοί περιορισμοί εκκίνησης επαναδιατυπώνονται στο τέλος. Η υλοποίηση μπορεί να προχωρήσει υπό αυτούς.
- Εντιμότητα φύλλου προεπιλεγμένης διαδρομής (
kind=0x02) — ΕΠΙΛΥΘΗΚΕ. Παράδωσε τον διαχωρισμό δύο ειδών φύλλου όπως προδιαγράφεται: τοkind=0x02δεν δεσμεύει ούτεbody_hashούτεdrand_round. Κανένα πεδίο*_body_hashστη byte-τυφλή διαδρομή (θα ήταν το πιο ευανάγνωστο ψευδές σήμα «επαληθευμένου» για τους ολοκληρωτές και είναι μια ευκολία που η §11 ήδη παρέχει από τη δέσμη). Μην απαιτείς σφράγιση διακομιστή για qubs με πιστοποίηση αρχείου (αυτό θα εξανάγκαζε το απλό κείμενο μέσα από τον Worker και θα κατέστρεφε το moat κρυπτο-τεμαχισμού). Οποιαδήποτε αυτο-περιγραφική παράκαμψη ανήκει στη δέσμη.qub/ στον φάκελο απόδειξης ως πεδίο επανυπολογισμένο από τον επαληθευτή, ποτέ ως πεδίο φύλλου. Ανώτατο όριο ισχυρισμού επιβεβαιωμένο από τον κάτοχο: §16.11. - Λογοδοσία ασάφειας / παράλειψης — ΕΠΙΛΥΘΗΚΕ. Το κλειδί απόδειξης παραλαβής σφράγισης είναι καρφιτσωμένο στο
LogProfile+ συν-υπογεγραμμένο από τοanchor_owner(κλείνοντας την προηγούμενη αντίφαση «κανένα κλειδί υπογραφής»· §16.6). Μοντέλο μάρτυρα εκκίνησης: καρφιτσωμένη απόδειξη παραλαβής + μεθοδολογία παρακολούθησης + διάσχιση αλυσίδας prev + διπλές αυτο-δημοσιευμένες κεφαλές (δημόσιο αποθετήριο GitHub που ανήκει στο qub, κοινωνικά βέλτιστης προσπάθειας), προωθούμενο ως ανιχνεύσιμο + με απόδειξη παραλαβής, ποτέ ανεξάρτητα μαρτυρημένο. Ένας αληθινός μάρτυρας τρίτου μέρους αναβάλλεται για μια προώθηση διακυβέρνησης §15. - Καρφιτσωμένη ρίζα εμπιστοσύνης anchor-owner + ανανέωση — ΕΠΙΛΥΘΗΚΕ. Υιοθέτησε το καρφίτσωμα
LogProfile(§16.6)· ο επαληθευτής ελέγχειanchor_tx.owner == anchor_ownerκαι επαληθεύει τη δέσμευση data → tx_id της συναλλαγής τοπικά. Η διακυβέρνηση ανανέωσης είναι μια προς κατασκευή επέκταση §15 (προστέθηκε σκανδαλισμός §15.3), όχι επαναχρησιμοποίηση· οι προγραμματισμένες ανανεώσεις συν-υπογράφουν, οι οδηγούμενες από παραβίαση καταφεύγουν στην προώθηση §15 με τον έλεγχο διακλάδωσης να οριοθετεί τη ζημιά. - Τυφλοποίηση φύλλου ιδιωτικού qub — ΕΠΙΛΥΘΗΚΕ. Διατήρησε την τυφλοποίηση για τα ιδιωτικά qubs (
ref = SHA3-256(qub_id ‖ log_blind_secret)), ακατέργαστοqub_idγια τα δημόσια qubs (ήδη §16.2.1),chashως τον αυτόνομο δεσμό. Τοlog_blind_secretείναι ένα μυστικό βαθμίδας συσχέτισης/Sybil, ανανέωση μόνο προς τα εμπρός (§16.2.1). received_at— ΕΠΙΛΥΘΗΚΕ. Διατήρησέ το στο φύλλο, δεσμευμένο αλλά ρητά μη αποδεικτικό· ποτέ μη επιφανειοποιημένο ως απόδειξη ή επιβεβαίωση διαφωνίας σε καμία επιφάνεια. Οποιοσδήποτε έλεγχος λογικής παρακολούθησης συγκρίνεται έναντι του χρόνου μπλοκ ArweaveT, όχι έναντι του ελεγχόμενου από τον χειριστήanchored_at(§16.6).- Αποδείξιμος χρονισμός δωρεάν βαθμίδας — ΕΠΙΛΥΘΗΚΕ (έγκριση κατόχου). Η αντοχή δεν οπισθοχωρεί· μόνο ο αποδείξιμος χρόνος δέσμευσης ανώτατου ορίου χονδραίνει στον χρόνο μπλοκ αγκύρωσης. Το κείμενο δωρεάν βαθμίδας δεν χρησιμοποιεί κανένα αριθμητικό SLA («…προστίθεται στην επόμενη αγκύρωση αρχείου, τυπικά ημερησίως»)· η απόδειξη ακριβούς ώρας είναι μια ιδιότητα T3 επί πληρωμή, αποκαλυπτόμενη στην επιφάνεια σύγκρισης βαθμίδων + στους όρους (§16.1).
- Σωρευτικό δέντρο στους Workers — ΕΠΙΛΥΘΗΚΕ. Ενιαίο σωρευτικό δέντρο RFC 9162 + LogDO μοναδικού εγγραφέα με προσωρινή μνήμη συνόρου (άνετο περιθώριο έναντι του ορίου ~1k εγγραφών/δευτ. του DO· αναβολή του διαμοιρασμού Merkle-of-shard-roots μέχρι κοντά σε αυτό). Μπλοκάρουσα προϋπόθεση: κατάστημα κόμβων R2 με κλειδί συντεταγμένης
(level, index)+ το δοκιμαστικό διάνυσμα ψυχρού-φύλλου σβησμένου-DO (§16.9)· το< 300 msείναι μια μετρημένη πύλη εκκίνησης πάνω από δύο σειριοποιημένα DO (§16.10). - Σχήμα υπογραφής ANS-104 + deep-hash — ΕΠΙΛΥΘΗΚΕ. RSA-PSS (τύπος υπογραφής 1, επαναχρησιμοποιώντας το αποκλειστικό JWK πορτοφολιού αγκύρωσης)· το Ed25519 αναβλήθηκε για τη διαδρομή PQ της §15. Ο χειρόγραφος deep hash SHA-384 οριοθετείται από το fixture πολλαπλών υλοποιήσεων και των δύο κατευθύνσεων, έναν έλεγχο διαλειτουργικότητας bundler αναφοράς μόνο-στατικό, το round-trip κοινού
crypto.subtle, και τον παρακολουθητή αποδοχής Arweave μετά τη δέσμη (§16.8).
Δεσμευτικοί περιορισμοί εκκίνησης (μεταφέρονται στην υλοποίηση + στην αναθεώρηση προϊόντος/νομική):
- Ανώτατο όριο ισχυρισμού (Q1/Q6). Καμία επιφάνεια δεν μπορεί να πει ότι το αρχείο αποδεικνύει το περιεχόμενο ή τον γύρο ξεκλειδώματος ενός προεπιλεγμένου qub· ο επιτρεπόμενος ισχυρισμός είναι διατεταγμένο, με τρόπο ανθεκτικό σε αλλοίωση, με έναν χρόνο δέσμευσης ανώτατου ορίου χωρίς εμπιστοσύνη. Το κείμενο χρονοσήμανσης δωρεάν βαθμίδας δεν φέρει αριθμητική καθυστέρηση· η απόδειξη ακριβούς ώρας είναι μόνο T3 επί πληρωμή.
- Εντιμότητα μάρτυρα (Q2). Προώθησε την ασάφεια ως ανιχνεύσιμη + με απόδειξη παραλαβής, ποτέ ανεξάρτητα μαρτυρημένη.
- Κλειδιά απόδειξης παραλαβής + αγκύρωσης (Q2/Q8). Το κλειδί απόδειξης παραλαβής είναι καρφιτσωμένο + συν-υπογεγραμμένο· το πορτοφόλι αγκύρωσης είναι το δικό του JWK διακριτό από το πορτοφόλι ανεβάσματος.
- Πύλη deep-hash (Q8). Καμία αγκύρωση ή συναλλαγή T3 δεν παραδίδεται μέχρι να περάσουν το fixture και των δύο κατευθύνσεων + ο έλεγχος διαλειτουργικότητας· ο παρακολουθητής αποδοχής ειδοποιεί σε αποτυχία.
- Προϋπόθεση αποθήκευσης (Q7). Το κατάστημα κόμβων με κλειδί συντεταγμένης + το διάνυσμα ψυχρού-φύλλου σβησμένου-DO είναι προαπαιτούμενα για την εγγύηση «η ανάκτηση δεν ακυρώνει ποτέ μια απόδειξη».