Προδιαγραφή Πρωτοκόλλου 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. |
| Διπλά κλειδιά | Απόρριψη με σφάλμα. Οι αναλυτές ΔΕΝ ΠΡΕΠΕΙ να αποδέχονται σιωπηρά διπλά κλειδιά χάρτη. |
| Απλές τιμές | Επιτρέπονται μόνο 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 Κατασκευή Υπογεγραμμένης Προεικόνας
sig_input = SHA3-256(
"QUB_AUTHOR_SIG_V1" || // domain separator (17 bytes)
version || // u8 (1 byte)
qub_id || // [u8; 32] (32 bytes)
body_hash || // [u8; 32] (32 bytes)
unlock_at || // i64 big-endian (8 bytes)
0x00 // u8 (1 byte): MUST be 0x00 in v1.0
)
// Total preimage: 91 bytes → 32-byte hash
signature = Sign(author_secret_key, sig_input)
Διαχωριστής πεδίου: το "QUB_AUTHOR_SIG_V1" είναι 17 ASCII bytes: [0x51, 0x55, 0x42, 0x5F, 0x41, 0x55, 0x54, 0x48, 0x4F, 0x52, 0x5F, 0x53, 0x49, 0x47, 0x5F, 0x56, 0x31]. Χωρίς γέμισμα.
Τελευταίο byte: το 91ο byte της προεικόνας ΠΡΕΠΕΙ να είναι 0x00. Η υλοποίηση αναφοράς εκθέτει αυτό ως τη σταθερά ORG_ID_PRESENT_INDIVIDUAL = 0x00 στο crates/qub-core/src/signing.rs· οι θεατές που ανακατασκευάζουν το sig_input για επαλήθευση ΠΡΕΠΕΙ να εκπέμπουν το ίδιο byte.
Εμβέλεια υπογραφής — τι καλύπτεται και τι όχι. Το sig_input δεσμεύεται σε τέσσερα πεδία του φακέλου: version, qub_id, body_hash, unlock_at (συν τον σταθερό διαχωριστή πεδίου και το 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 |
✓ | Άμεση είσοδος |
content_type |
✓ | Μεταβατικά, μέσω της προεικόνας qub_id |
created_at |
✓ | Μεταβατικά, μέσω της προεικόνας qub_id |
outcome_at |
✓ | Μεταβατικά, μέσω της προεικόνας qub_id |
drand_round |
✓ | Μεταβατικά, μέσω της προεικόνας qub_id (V1.2) |
body |
✓ | Μεταβατικά, μέσω του body_hash = SHA3-256(body) |
author_pubkey |
— (έμμεσα) | Το κλειδί που επαλήθευσε την υπογραφή είναι ο συγγραφέας, εξ ορισμού |
sender_label |
✗ | Κείμενο μόνο για εμφάνιση· μεταβλητό χωρίς σπάσιμο υπογραφής |
reply_to |
✗ | Δείκτης νηματοποίησης· μεταβλητό χωρίς σπάσιμο υπογραφής |
cosigner_pubkey / cosigner_signature |
— | Υπογράφονται ανεξάρτητα πάνω στο ίδιο sig_input (βλέπε §9.7) |
drand_chain_id, tlock_ciphertext, visibility |
— | Εξωτερικά πεδία του SealedQub, όχι μέσα στον φάκελο — καλύπτονται από τις δικές τους δομικές αναλλοιότητες (συνέπεια γύρου / αλυσίδας) αλλά όχι από την υπογραφή του συγγραφέα. (Το drand_round δεσμεύεται πλέον μεταβατικά μέσω της προεικόνας qub_id — βλέπε παραπάνω.) |
Επιπτώσεις ασφαλείας μη-πιστοποιημένων πεδίων.
- Ένα μέρος με δικαίωμα εγγραφής στα αποθηκευμένα bytes θα μπορούσε να εναλλάξει το
sender_label("Alice" → "Mallory") χωρίς να ακυρώσει την υπογραφή του συγγραφέα. Τοauthor_pubkeyμέσα στον φάκελο παραμένει η αληθινή άγκυρα ταυτότητας — οι θεατές ΠΡΕΠΕΙ να εξάγουν την ταυτότητα εμφάνισης από τοauthor_pubkey(μέσω του επιπέδου πιστοποίησης §9.5) και όχι να εμπιστεύονται τοsender_label. - Ένα πεδίο
reply_toμπορεί επίσης να επεξεργαστεί μετά την υπογραφή. Επειδή τοqub_idείναι διευθυνσιοδοτημένο από περιεχόμενο, ένας επιτιθέμενος δεν μπορεί να κατευθύνει τοreply_toσε μη-υπαρκτό στόχο, αλλά μπορεί σιωπηρά να επανα-γονιοποιήσει μια απάντηση σε διαφορετικό υπάρχον qub.
Οι υλοποιήσεις που εμφανίζουν 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 (same formula as §9.3).
6. Verify(author_pubkey, sig_input, author_signature).
7. If verification succeeds → display "signed by [key fingerprint]."
8. If verification fails → display "signature verification failed."
Η επαλήθευση υπογραφής είναι η πιο δαπανηρή λειτουργία (ειδικά το ML-DSA-65). ΘΑ ΕΠΡΕΠΕ να εκτελείται αφού έχουν περάσει όλοι οι φθηνότεροι έλεγχοι (κατακερματισμός, qub_id, unlock_at).
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.
5. Verify(cosigner_pubkey, sig_input, cosigner_signature).
6. Success → display "co-signed by [cosigner fingerprint]."
7. Failure → display "co-signature verification failed."
Ιδιότητες:
- Ο συν-υπογραφέας υπογράφει το πανομοιότυπο
sig_inputμε τον συγγραφέα — και τα δύο μέρη δεσμεύονται στο ίδιοqub_id,body_hashκαιunlock_at. - Η παραγωγή του
qub_id(§4.1) ΔΕΝ περιλαμβάνει πεδία συν-υπογραφέα. Η προσθήκη συν-υπογραφέα σε υπάρχοντα φάκελο δεν αλλάζει τοqub_id. - Ένα σύμφωνο μπορεί να είναι μόνο υπογεγραμμένο από τον συγγραφέα (μονόπλευρη δέσμευση), μόνο συν-υπογραφέα (ασυνήθιστο) ή και τα δύο (πλήρης διμερής απόδειξη).
Πύλη δέσμευσης 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 αναγνωρίζει την κύρια έκδοση του πρωτοκόλλου.
- Οι θεατές ΠΡΕΠΕΙ να απορρίπτουν άγνωστες κύριες εκδόσεις με σαφές σφάλμα.
- Οι γνωστές κύριες εκδόσεις ΜΠΟΡΕΙ να ανέχονται άγνωστα προαιρετικά πεδία εάν οι κανόνες προς-τα-εμπρός συμβατότητας το επιτρέπουν (τα προαιρετικά πεδία που απουσιάζουν από την κανονική σειρά κλειδιών αγνοούνται).
- Οι τύποι περιεχομένου (
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) ΘΑ ΕΠΡΕΠΕ να αγνοεί αυτά τα κλειδιά και να προχωρά στην επαλήθευση χρησιμοποιώντας τα γνωστά πεδία. Αυτό επιτρέπει μελλοντικές μικρές προσθήκες (π.χ., νέα μεταδεδομένα) χωρίς να απαιτείται αύξηση κύριας έκδοσης.
Ένας θεατής 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). - Διαδρομή σφράγισης διακομιστή Worker:
crypto.getRandomValues.
Διανομή: το 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 να προσγειώνονται σε γνωστό στόχο αντί να επανα-διαπραγματεύονται την επιφάνεια διαπραγμάτευσης από την αρχή.