Đặc tả giao thức qub

qub là một giao thức cho các cam kết thời gian mật mã: một hệ thống để đóng dấu các từ vào một ngày trong tương lai và sau đó xác minh chính xác những gì đã được đóng dấu, trong đó drand điều phối thời gian phát hành của nó, và—khi một giao dịch lưu trữ hoặc bằng chứng nhật ký minh bạch có sẵn—một mốc thời gian độc lập xác định giới hạn trên về thời điểm bản mã được cam kết.

Ba nguyên thủy làm nó hoạt động. drand là một ngọn hải đăng ngẫu nhiên phi tập trung—ngày tiết lộ được thực thi bằng mật mã thay vì dựa vào thiện chí của qub. Lưu trữ bền bảo quản các byte đã được xác nhận niêm phong trong khi các đường dẫn xuất bản hiện tại lên lịch các giao dịch lưu trữ lâu dài riêng lẻ; các bản ghi tải lên chung thành công cũng có thể tham gia vào các cam kết theo lô đã được neo. ML-DSA-65 là một chữ ký số hậu lượng tử—khi quyền tác giả được bật, qub được gắn với một cặp khóa mà bí mật của nó không bao giờ rời khỏi thiết bị của tác giả.

Cùng nhau, những nguyên thủy này tạo ra một tuyên bố được khóa theo thời gian và có khả năng phát hiện sự gian lận, có thể xác định được tùy chọn, và có thể đánh dấu thời gian một cách độc lập—một biên nhận mà giá trị của nó tăng lên khi khả năng tạo dựng lại quá khứ của thế giới được cải thiện.

Phần còn lại của tài liệu này là đặc tả chuẩn mực được yêu cầu cho các triển khai có thể tương tác lẫn nhau.


Đặc tả giao thức qub

Cánh đồng Giá trị
Phát hành tài liệu 1.0.0 (protocol-v1.0.0)
Giao thức truyền dẫn 0x01
Lớp vỏ ngoài 0x01
Ngày có hiệu lực 23-09-2026
Trạng thái Hiện tại
Đã được xem xét 23-09-2026

Tài liệu này là đặc tả giao thức quy phạm cho hệ thống cam kết theo thời gian qub. Nó định nghĩa các cấu trúc dữ liệu, các quy tắc tuần tự hóa, các công thức suy dẫn và các quy trình xác minh cần thiết cho các triển khai có thể tương tác.

Phạm vi: lớp giao thức được cố ý làm trung lập về ngôn ngữ — phần thân của qub là các byte văn bản thuần / markdown / giao ước không rõ ràng, và việc hiển thị có nhận biết ngôn ngữ là trách nhiệm của người xem (ứng dụng web qub.social, iframe <qub-embed>, các trình khách MCP, v.v.).


1. Ký hiệu và quy ước

Ký hiệu Ý nghĩa
u8, u64, i64 Số nguyên không dấu/có dấu với độ rộng bit được chỉ định
[u8; N] Mảng byte có độ dài cố định N byte
Vec<u8> Mảng byte có độ dài thay đổi
Option<T> Giá trị kiểu T, hoặc vắng mặt
String Chuỗi văn bản UTF-8, đã chuẩn hóa NFC
`
SHA3-256(x) Hàm băm NIST SHA3-256 của chuỗi byte x (FIPS 202)
ceil(x) Hàm trần: số nguyên nhỏ nhất ≥ x
CBOR Biểu diễn đối tượng nhị phân súc tích (RFC 8949)
big-endian Byte có ý nghĩa nhất đứng trước

Tất cả các số nguyên trong các cấu trúc tiền ảnh được mã hóa thành mảng byte có độ rộng cố định big-endian (i64 → 8 byte, u8 → 1 byte) trừ khi có quy định khác.

Tất cả các dấu thời gian là giây Unix theo UTC.


2. Cấu trúc dữ liệu

2.1 ComposeQub (trạng thái trong bộ nhớ của người tạo)

Không tuần tự hóa thành CBOR. Không ghi vào nơi lưu trữ vĩnh viễn. Cục bộ trong ứng dụng của người tạo.

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,              // 0x00 = private; 0x01 = public
    content_type:   u8,              // 0x01 text; 0x03 pact; 0x04 verdict
    plaintext:      Vec<u8>,         // Raw body bytes (UTF-8 for text)
    sender_label:   Option<String>,  // Display name; V2-signed when authorship is enabled
    title:          Option<String>,  // Plaintext countdown title; bound via title_hash
    reply_to:       Option<[u8; 32]>,// Parent qub_id; V2-signed when authorship is enabled
    outcome_at:     Option<i64>,     // Optional future judgment time; bound to qub_id
    status:         DraftStatus,     // Composing | Sealed | Uploaded | Failed
}

2.2 QubEnvelope (tải trọng đã giải mã)

Tuần tự hóa bằng CBOR chuẩn (§3). Được mã hóa bên trong SealedQub. Đây là cấu trúc chứng minh tính toàn vẹn của nội dung sau khi giải mã.

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>,     // When reality renders judgment; bound to qub_id
    sender_label:        Option<String>,  // Not in qub_id; V2-signed when authorship is enabled
    reply_to:            Option<[u8; 32]>,// Parent qub_id; not in qub_id; V2-signed when present
    body:                Vec<u8>,         // UTF-8 text or canonical CBOR pact/verdict body
    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
}

Đường cơ sở (văn bản qub chưa ký): version = 0x01, content_type = 0x01, sig_alg = 0x00; các trường chữ ký và người bảo lãnh không có. Các trường siêu dữ liệu tùy chọn khác có thể có.

Các cấu hình v1 khác: content_type = 0x03 (thân giao ước, xem §6.1); sig_alg = 0x01 (ML-DSA-65) với author_signature và author_pubkey hiện diện (xem §9.3); cosigner_pubkey và cosigner_signature hiện diện cùng nhau cho các giao ước đồng ký (xem §9.7); reply_to được đặt thành qub_id của qub cha cho các qub chuỗi trả lời (xem §9.3 để biết các hệ quả về phạm vi chữ ký).

2.3 SealedQub (định dạng wire chuẩn)

Được tuần tự hóa bằng CBOR chuẩn (§3). Đây là hiện vật bên trong dây: giao hàng công cộng lưu trữ các byte này một cách trần, trong khi giao hàng riêng tư bao bọc chúng OuterWrapper trước khi lưu trữ (§13).

SealedQub {
    version:           u8,              // Protocol major version (0x01 for v1)
    qub_id:            [u8; 32],        // Same as QubEnvelope.qub_id
    visibility:        u8,              // 0x00 = private/wrapped; 0x01 = public/bare
    unlock_at:         i64,             // Unix seconds UTC
    outcome_at:        Option<i64>,     // Surfaced on the verdict-watch CTA
                                        //   before reveal; mirrors QubEnvelope.outcome_at;
                                        //   bound to qub_id via the §4.1 preimage.
    drand_chain_id:    String,          // drand chain hash (hex string)
    drand_round:       u64,             // Target drand round number
    drand_chain_version: Option<u8>,    // W3 — chain-migration version. Absent / 0 = quicknet
                                        //   (the only chain today). Lets a future chain swap
                                        //   be expressed on the wire without a breaking format
                                        //   change. NOT part of the §4.1 qub_id preimage, so its
                                        //   addition never alters an existing qub's identity.
    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 hostile/control code points.
}

2.4 RevealedQub (trạng thái ứng dụng của người xem)

Không tuần tự hóa thành CBOR. Cục bộ trong ứng dụng của người xem. Được xây dựng sau khi giải mã và xác minh thành công.

RevealedQub {
    qub_id:              [u8; 32],
    arweave_tx_id:       String,
    visibility:          u8,
    content_type:        u8,
    created_at:          i64,
    unlock_at:           i64,
    outcome_at:          Option<i64>,       // Carried from both wire layers; drives the verdict-watch block
    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. Hồ sơ CBOR chuẩn

Tất cả việc tuần tự hóa SealedQub và QubEnvelope PHẢI tuân thủ hồ sơ này. Hai triển khai khi nhận cùng một cấu trúc logic PHẢI tạo ra các byte giống hệt nhau.

3.1 Quy tắc mã hóa

Quy tắc Đặc tả
Chuẩn RFC 8949 §4.2.1 (Yêu cầu mã hóa xác định cốt lõi)
Thứ tự khóa của map Sắp xếp theo độ dài byte đã mã hóa trước (ngắn hơn trước dài hơn), sau đó theo từ điển (từng byte đối với các mã hóa cùng độ dài)
Mã hóa số nguyên Dạng ngắn nhất: 0–23 trong byte đầu; 24–255 trong 2 byte; 256–65535 trong 3 byte; v.v.
Mã hóa độ dài Chỉ độ dài xác định. Không có mảng, map, chuỗi byte hoặc chuỗi văn bản độ dài không xác định (thông tin bổ sung = 31 bị cấm).
Tags Không có tags CBOR (kiểu chính 6 bị cấm).
Dấu phẩy động Không có float (kiểu chính 7 giá trị 0xF9–0xFB bị cấm).
Chuỗi văn bản Mã hóa UTF-8, đã chuẩn hóa NFC (Unicode Normalization Form C).
Chuỗi byte Byte thô. Không có mã hóa base64 ở lớp CBOR.
Khóa trùng lặp Từ chối kèm lỗi. Các bộ phân tích cú pháp KHÔNG ĐƯỢC chấp nhận thầm lặng các khóa map trùng lặp.
Khóa không xác định Từ chối kèm lỗi. Các bộ phân tích cú pháp KHÔNG ĐƯỢC chấp nhận các khóa map nằm ngoài tập khóa chuẩn của kiểu — hai chuỗi byte chuẩn khác nhau không bao giờ được giải mã về cùng một giá trị (encode(decode(x)) == x), và đối với các tải trọng đã ký, một khóa bổ sung sẽ là nội dung ẩn mà cả hai chữ ký đều cam kết. Việc tiến hóa schema đi qua version, không bao giờ qua các khóa bổ sung.
Giá trị đơn Chỉ true (0xF5), false (0xF4) và null (0xF6) được cho phép.
Trường tùy chọn Các trường tùy chọn vắng mặt bị bỏ qua hoàn toàn khỏi map CBOR (không được mã hóa thành null). Các trường tùy chọn hiện diện được bao gồm theo thứ tự khóa đã sắp xếp.

3.2 Thứ tự khóa chuẩn đã xác minh

Các thứ tự khóa này là quy phạm. Các triển khai PHẢI phát các khóa chính xác theo thứ tự này. Các khẳng định debug NÊN xác minh thứ tự trong các bản dựng không phải release.

QubEnvelope (phiên bản 0x01, không ký, tất cả các trường tùy chọn vắng mặt):

"body"                (5 encoded bytes)
"qub_id"              (7 encoded bytes)
"sig_alg"             (8 encoded bytes)
"version"             (8 encoded bytes)
"reply_to"            (9 encoded bytes)   ← only if present (reply chains)
"body_hash"           (10 encoded bytes)
"unlock_at"           (10 encoded bytes)
"created_at"          (11 encoded bytes)
"outcome_at"          (11 encoded bytes)  ← only if present (verdict mechanic)
"content_type"        (13 encoded bytes)
"sender_label"        (13 encoded bytes)  ← only if present
"author_pubkey"       (14 encoded bytes)  ← only if present
"cosigner_pubkey"     (16 encoded bytes)  ← only if present (pact cosign)
"author_signature"    (17 encoded bytes)  ← only if present
"cosigner_signature"  (19 encoded bytes)  ← only if present (pact cosign)

Suy dẫn thứ tự khóa QubEnvelope: mỗi khóa là một chuỗi văn bản CBOR. Độ dài đã mã hóa = 1 byte header + độ dài chuỗi (cho các chuỗi dưới 24 byte). Sắp xếp theo tổng độ dài đã mã hóa trước, sau đó theo từ điển cho các khóa cùng độ dài.

SealedQub (phiên bản 0x01, công khai, không người nhận):

"title"             (6 encoded bytes)   ← only if present
"qub_id"            (7 encoded bytes)
"version"           (8 encoded bytes)
"unlock_at"         (10 encoded bytes)
"outcome_at"        (11 encoded bytes)  ← only if present (verdict mechanic)
"visibility"        (11 encoded bytes)
"drand_round"       (12 encoded bytes)
"drand_chain_id"    (15 encoded bytes)
"recipient_pubkey"  (17 encoded bytes)  ← only if present
"tlock_ciphertext"  (17 encoded bytes)
"drand_chain_version" (20 encoded bytes) ← only if present (W3; absent = quicknet)

PactTerms (thân giao ước, 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 (hàng của mảng terms):

"key"    (4 encoded bytes)
"value"  (6 encoded bytes)

PartyIdentifier (map party_a / party_b):

"label"    (6 encoded bytes)
"contact"  (8 encoded bytes)  ← only if present

3.3 Tham chiếu mã hóa byte

Kiểu Mã hóa CBOR Ví dụ
Hàm băm SHA3-256 (32 byte) 0x58 0x20 + 32 byte body_hash, qub_id
Dấu thời gian (i64) Kiểu chính 0 (dương) hoặc 1 (âm), mã hóa ngắn nhất giây Unix
Phiên bản (u8, giá trị 1) 0x01 (một byte)
Loại nội dung (u8, giá trị 1) 0x01 (một byte)
sig_alg (u8, giá trị 0) 0x00 (một byte)
Chữ ký ML-DSA-65 (3.309 byte) 0x59 0x0C 0xED + 3.309 byte author_signature, cosigner_signature
Khóa công khai ML-DSA-65 (1.952 byte) 0x59 0x07 0xA0 + 1.952 byte author_pubkey, cosigner_pubkey

4. Các suy dẫn quy phạm

4.1 qub_id

qub_id xác định duy nhất một qub và liên kết QubEnvelope với SealedQub. Nó được suy dẫn một cách xác định từ nội dung của envelope.

qub_id = SHA3-256(
    "QUB_ID_V2"          ||  // domain separator: ASCII bytes [0x51 0x55 0x42 0x5F 0x49 0x44 0x5F 0x56 0x32] (9 bytes) + 0x00 padding (1 byte) = 10 bytes
    version              ||  // u8 (1 byte)
    content_type         ||  // u8 (1 byte)
    created_at           ||  // i64 big-endian (8 bytes)
    unlock_at            ||  // i64 big-endian (8 bytes)
    outcome_at_or_zero   ||  // i64 big-endian (8 bytes; 0 when outcome_at is absent)
    drand_round          ||  // u64 big-endian (8 bytes)
    body_hash            ||  // [u8; 32] (32 bytes)
    title_hash               // [u8; 32] (32 bytes; absent-sentinel = [0u8; 32])
)
// Total preimage: 108 bytes → 32-byte output

Mã hóa dấu phân cách miền: Chuỗi "QUB_ID_V2" là 9 byte ASCII. Một byte đệm 0x00 đơn được nối thêm để đạt 10 byte cho việc căn chỉnh. Các triển khai PHẢI sử dụng chính xác 10 byte này: [0x51, 0x55, 0x42, 0x5F, 0x49, 0x44, 0x5F, 0x56, 0x32, 0x00].

outcome_at mã hóa: Một phiên bản sửa đổi triển khai trước khi phát hành đã mở rộng tiền ảnh từ 92 lên 100 byte để gộp tùy chọn outcome_at trường vào phần ràng buộc. Vắng mặt outcome_at được mã hóa dưới dạng 8 byte số không; các bộ xác thực giao thức từ chối outcome_at <= 0 mọi nơi để người gác này không thể va chạm với một giá trị hợp lệ. Xem §3.2 (định dạng dây) và cây nội bộ tasks/verdict-uplift-plan.md cho cơ chế phán quyết tạo động lực cho lĩnh vực này.

drand_round mã hóa: Một phiên bản triển khai trước khi phát hành sau đó đã mở rộng tiền ảnh từ 100 lên 108 byte để gập drand_round (vòng drand mục tiêu, §4.3) vào binding, và tăng bộ phân tách miền lên QUB_ID_V2. Điều này gắn vòng khóa thời gian vào định danh qub: một cổng không thể liên kết lại văn bản được mã hóa với một vòng khác (ví dụ: đã qua) với vòng được hiển thị unlock_at ngụ ý. Thủ tục mở khóa (§8) còn xác minh rằng vòng được mã hóa trong câu stanza ciphertext tlock khớp với unlock_round(unlock_at), vì vậy thời gian mở khóa hiển thị chứng minh được là vòng mà cổng giải mã.

Tính chất:

4.2 body_hash

body_hash = SHA3-256(body)

Trong đó body là tải trọng nội dung Vec<u8> thô. Đối với các qub văn bản, đây là thân qub được mã hóa 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

Trong đó title là tiêu đề văn bản thuần tùy chọn được hiển thị trên đồng hồ đếm ngược của người xem trước khi công bố (xem §3.2). Chuẩn hóa NFC chạy tại thời điểm băm để bản tóm tắt ổn định trên các chuỗi điểm mã tương đương về mặt thị giác. Trị canh gác toàn số 0 được dành riêng cho trường hợp vắng mặt; một chuỗi rỗng bị từ chối ở ranh giới CBOR chuẩn như một mã hóa không chuẩn của "vắng mặt" (mã hóa chuẩn loại bỏ hoàn toàn trường này).

4.3 Bản đồ Giải khóa-Vòng

drand_round = floor((unlock_at - chain_genesis_time) / chain_period_seconds) + 1
Tham số Nguồn Ví dụ
unlock_at Giây Unix theo UTC do người dùng chọn 1735689600 (2025-01-01 00:00:00 UTC)
chain_genesis_time thông tin chuỗi drand (genesis_time) 1595431050
chain_period_seconds thông tin chuỗi drand (period) 30

Đây là ánh xạ tlock tham chiếu (của drand) CurrentRound). drand xuất bản vòng N tại chain_genesis_time + (N - 1) * chain_period_seconds, vì vậy công thức chọn dòng điện tròn tại unlock_at — vòng mà chữ ký của nó là chữ ký đầu tiên mà người xem đến unlock_at có thể sử dụng.

Thuộc tính căn chỉnh (trường hợp quan trọng trong thực tế): khi (unlock_at - chain_genesis_time) chia hết cho chain_period_seconds, chữ ký của vòng được chọn được công bố chính xác vào unlock_at, chưa bao giờ trước đây. Điều này luôn đúng đối với triển khai tham chiếu: thời gian khai sinh của quicknet (1692803367) chia hết cho chu kỳ 3 giây của nó, và các ứng dụng tham chiếu khóa thời gian mở khóa theo phút. Đối với một thời điểm không căn chỉnh unlock_at, chữ ký của vòng được chọn được công bố ít hơn một kỳ hạn trước unlock_at — độ chính xác về thời gian của cam kết là một khoảng thời gian của beacon.

Bản đồ trước phát hành kế thừa và độ dung sai phía mở khóa: bản đồ gốc là ceil((unlock_at - chain_genesis_time) / chain_period_seconds), mà—đối với trường hợp đã căn theo kỳ ở trên—đã chọn bản phát hành tròn đầy đủ một kỳ trước unlock_at, làm cho bản mã có thể giải mã sớm hơn đúng một khoảng thời gian. Hai ánh xạ khác nhau đúng bằng +1 khi delta chia giai đoạn, và đồng ý theo cách khác. Bởi vì drand_round được gập vào cái không thể thay đổi qub_id preimage (§4.1), các hiện vật được niêm phong theo ánh xạ cũ không thể được tái tạo; do đó, các kiểm chứng thực hiện bước §8 mục 6a vòng kiểm tra chéo PHẢI chấp nhận một bản lưu trữ drand_round bằng cả hai, một trong hai vòng dẫn xuất hoặc vòng tròn dẫn xuất trừ một (và PHẢI yêu cầu vòng tròn stanza tlock bằng đúng vòng tròn đã lưu). Sai số mở rộng chữ ký gating sớm nhất tối đa một khoảng. Dịch vụ staging pact áp dụng cùng một sai số khi nó tái tạo một pact đã được staging qub_id (tại giai đoạn và tại việc đồng ký): nếu vòng hiện tại của ánh xạ không tái tạo cam kết qub_id và delta chia giai đoạn, nó thử lại với vòng tròn trừ một, và nó niêm phong hiệp ước đã được hoàn tất với bất kỳ vòng nào qub_id thực sự ràng buộc—không bao giờ mù quáng với vòng được tính lại, điều này sẽ khiến hiện vật không thể suy ra được mãi mãi.

Xác thực: unlock_at PHẢI là trong tương lai vào thời điểm niêm phong. unlock_at KHÔNG được quá 10 năm kể từ created_at (để hạn chế rủi ro phụ thuộc drand dài hạn; giao diện NGƯỜI DÙNG NÊN cảnh báo cho các ngày mở khóa vượt quá 2 năm).


5. Newtype định dạng wire

Các newtype định dạng wire cung cấp sự an toàn tại thời điểm biên dịch chống lại việc nhầm lẫn các byte CBOR với JSON, văn bản thuần thô, hoặc các mã hóa byte khác.

Loại Chứa Sản xuất bởi Bị tiêu thụ bởi
SealedQubCbor CBOR chính tắc của SealedQub serialize_sealed_qub() Vật phẩm dây bên trong; được lưu trữ trần để giao công khai hoặc được bọc để giao riêng tư, sau đó được người xem thu hồi
QubEnvelopeCbor CBOR chuẩn của QubEnvelope serialize_qub_envelope() tlock mã hóa đầu vào, tlock giải mã đầu ra

5.1 Quy tắc xây dựng

// 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 Xác thực khi xây dựng

from_encoded() NÊN xác thực rằng đầu vào bắt đầu bằng một header map CBOR hợp lệ. Việc xác thực cấu trúc đầy đủ xảy ra tại thời điểm phân tích, không phải thời điểm xây dựng, để tránh phân tích kép.


6. Sổ đăng ký loại nội dung

Giá trị Loại Kích thước thân tối đa Ghi chú
0x00 Dành riêng (không hợp lệ) — KHÔNG ĐƯỢC sử dụng
0x01 Văn bản thuần (UTF-8, Markdown hạn chế) 50 KB trả phí / 10 KB miễn phí Xem §10 để biết quy tắc hiển thị. Phân chia miễn phí / trả phí được thực thi bởi dịch vụ tải lên; trần cứng ở lớp giao thức là 50 KB.
0x02 Dành riêng (tương lai) — Được cấp phát cho một loại nội dung trong tương lai; không hợp lệ trong v1. Người xem PHẢI từ chối theo quy tắc bên dưới.
0x03 Giao ước (thỏa thuận song phương, thân CBOR) 100 KB Thân là CBOR chuẩn PactTerms (§6.1). Ký bởi người đồng ký theo §9.7.
0x04 Phán quyết (người tạo tự chấm điểm, thân CBOR) 8 KB Thân là CBOR chuẩn VerdictBody (§6.2). Chỉ được phát ra bởi intent phía hệ thống verdict. Quan hệ với qub cha nằm ở tag Arweave Parent-Tx-Id, không nằm trong thân. Xem verdict-uplift-plan §3.4.

Người xem PHẢI từ chối các loại nội dung không xác định kèm theo lỗi rõ ràng cho người dùng. Người xem KHÔNG ĐƯỢC cố gắng hiển thị các loại không xác định dưới dạng văn bản.

6.1 Thân giao ước (content_type = 0x03)

Một thân giao ước là mã hóa CBOR chuẩn của giá trị 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 bytes), value: String (≤ 2,000 bytes) } // NFC
PartyIdentifier{ label: String (≤ 100 bytes), contact: Option<String (≤ 320 bytes)> }

Các thứ tự khóa CBOR chuẩn cho cả ba map được nêu trong §3.2. Tổng CBOR giao ước đã tuần tự hóa KHÔNG ĐƯỢC vượt quá 100 KB (khớp với §6).

Bộ phân biệt schema. Hàng đầu tiên trong terms cho một giao ước structured/v1 PHẢI là { key: "pact_schema", value: "structured/v1" }. Các hàng không có dấu hiệu này là các giao ước "tùy chỉnh" và không nhận được xác thực cấu trúc hoặc hiển thị nhận biết schema.

Các vị trí xác nhận đã đóng băng. Các giao ước structured/v1 mang chính xác bốn hàng xác nhận dưới các khóa này:

"initiator_standard_terms"
"initiator_capacity_terms"
"counterparty_standard_terms"
"counterparty_capacity_terms"

value cho mỗi cái là một trong tám chuỗi tiếng Anh đã đóng băng được chọn bởi cặp (role, kind), trong đó role ∈ { seller, buyer, provider, client } và kind ∈ { standard, capacity }. Bản thân các chuỗi là dữ liệu giao thức quy phạm — các chữ ký ML-DSA-65 của cả hai bên cam kết với các byte chính xác thông qua body_hash. Chúng KHÔNG được bản địa hóa; thân được ký là trung lập về ngôn ngữ. Bất kỳ thay đổi từ ngữ nào đều yêu cầu một phiên bản schema mới (structured/v2).

Tám chuỗi, cách tra cứu của chúng (acknowledgement_for(role, kind)), và lý do căn bản cho mỗi cái được ghim bởi triển khai tham chiếu. Các triển khai tuân thủ PHẢI phát ra các giá trị xác nhận giống hệt byte; các kiểm tra body-hash SHA3-256 cố định bao phủ cả bốn tổ hợp vai trò bắt được mọi sự trôi dạt.

Thứ tự hiển thị của người xem. Các chuỗi xác nhận chứa các cụm từ như "described above", giả định rằng các hàng mô tả / phạm vi hiển thị trước các xác nhận. Người xem PHẢI hiển thị mảng terms theo thứ tự CBOR; sắp xếp lại sẽ phá vỡ ngữ nghĩa văn bản.

Liên hệ của bên đối tác. Khi contact của Bên B là một địa chỉ email hợp lệ, dịch vụ tải lên qub tự động gửi một email mời xem xét / đồng ký tại thời điểm staging và ràng buộc đồng ký cuối cùng với việc xác minh cùng một địa chỉ đó (§9.7). Các giao ước mà liên hệ Bên B vắng mặt vẫn có thể được đồng ký, nhưng chỉ qua một kênh ngoài băng — dịch vụ từ chối các yêu cầu đồng ký không thể tạo ra một dấu hiệu xác minh email 15 phút khớp.

6.2 Thân phán quyết (content_type = 0x04)

Một thân phán quyết là mã hóa CBOR chuẩn của giá trị 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
}

Thứ tự khóa CBOR chuẩn:

"outcome"          (8 encoded bytes)
"reflection"       (11 encoded bytes)  ← only if present
"evidence_url"     (13 encoded bytes)  ← only if present
"verdict_version"  (16 encoded bytes)

Tổng CBOR phán quyết đã tuần tự hóa KHÔNG ĐƯỢC vượt quá 8 KB (khớp với hàng đăng ký bên trên).

Enum kết quả. Byte trên wire là trung lập về intent; bốn nhóm Right / Partial / Wrong / Unfalsifiable bao phủ không gian kết quả của mọi intent có phán quyết. Nhãn theo từng intent ("Đoán trúng" / "Đã giữ lời" / "Hoàn thành" / "Đã được xác nhận" cho Right, v.v.) là vấn đề hiển thị phía người xem, được phân giải dựa vào intent của qub cha — wire vẫn trung lập về ngôn ngữ và intent. Các giá trị ngoài khoảng 1..=4 PHẢI bị từ chối khi giải mã.

Liên kết với qub cha. Một qub phán quyết KHÔNG mang tham chiếu tới qub cha trong thân của nó. Mã giao dịch Arweave của qub cha được phát ra dưới dạng tag lưu trữ Parent-Tx-Id tại thời điểm tải lên (§7 lớp tag lưu trữ). Điều này giữ cho thân là một tuyên bố tự đánh giá đã ký, độc lập; chuỗi kiểm toán ("đúng về điều gì?") được thiết lập qua việc tra cứu tag Arweave.

An toàn URL bằng chứng (quy phạm). Khi evidence_url hiện diện, các trình xác thực (phía compose, phía wire, edge Worker) PHẢI thực thi:

  1. Chỉ HTTPS. Chuỗi PHẢI bắt đầu bằng dãy byte https://. Bất kỳ scheme nào khác — http, ftp, javascript, data, file, v.v. — đều bị từ chối.
  2. Giới hạn độ dài. ≤ 2.048 byte (giới hạn thực tế của URL trình duyệt).
  3. Kiểm tra NFC và điểm mã thù địch. Cùng quy tắc như title và reflection — các điểm mã bidi-override / zero-width / tag-block / BOM / C0 / C1 bị từ chối. Định nghĩa khớp với Rust crate::handle::contains_hostile_text_codepoint và TS workers/api/src/utils/unicode.ts::isHostileCodepoint (giữ đồng bộ).
  4. Không khoảng trắng, không ký tự điều khiển ASCII. Khoảng trắng / DEL / byte dưới 0x20 ở bất kỳ vị trí nào trong URL đều bị từ chối — đóng vector tấn công \n/\t mà quy tắc bidi không bao phủ.
  5. Phân đoạn host không rỗng. Mọi thứ giữa https:// và ký tự /, ? hoặc # đầu tiên PHẢI không rỗng.

Không lấy nội dung từ phía máy chủ. Worker KHÔNG ĐƯỢC proxy, fetch, hoặc xem trước URL. Giao thức lưu một chuỗi; việc hiển thị diễn ra phía người xem với rel="nofollow noopener noreferrer" target="_blank" và một host nhìn thấy được kèm theo văn bản liên kết.

Phản tư. Văn bản phản tư tùy chọn do người tạo viết ("điều gì đã thay đổi, bạn đã học được gì"). Cùng kiểm tra NFC và điểm mã thù địch như title. Đầu vào rỗng / chỉ có khoảng trắng sẽ gập lại thành vắng mặt tại thời điểm xây dựng.

Phiên bản schema. v1 chỉ hỗ trợ verdict_version = 0x01. Các bản sửa schema trong tương lai sẽ tăng byte này và xuất hiện cùng với một phiên bản giao thức mới theo §12.


7. Giao thức niêm phong

Trình tự niêm phong hoàn chỉnh. Mỗi bước là quy phạm.

 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.
    f. visibility is 0x00 (private) or 0x01 (public).
 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 = floor((unlock_at - chain_genesis_time) / chain_period_seconds) + 1
    (§4.3). (Computed here, before qub_id, because drand_round is bound into the
    qub_id preimage—§4.1.)
 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,
    visibility, unlock_at, drand_chain_id, and drand_round.
11. Serialise SealedQub using canonical CBOR → SealedQubCbor.
12. Select the delivery shape from visibility:
    a. Private (0x00): generate K = 32 random bytes and N = 12 random bytes
       using a CSPRNG. Compute W = wrap_sealed_qub(SealedQubCbor,
       qub_id=qub_id, key=K, nonce=N) per §13. Upload payload = W.
    b. Public (0x01): upload payload = bare SealedQubCbor; do not generate K.
13. Display seal-time disclosure. User confirms.
14. Validate upload eligibility via the qub upload service (bot-detection, entitlement, rate limits).
15. Submit the selected upload payload to the qub upload service. For a private
    browser seal, the service is byte-blind to the inner SealedQubCbor and never
    receives K. The Builder `/api/v1/seal` route is an explicit exception: it
    receives plaintext and caller-supplied K in memory, then persists neither.
16. Receive arweave_tx_id from the service. For private delivery, construct
    `<origin>/c/<arweave_tx_id>#<base64url(K)>` (or the equivalent short-code
    path). For public delivery, omit the fragment. Browsers do not transmit URL
    fragments to servers, so K from the browser-seal path is not observed by
    qub.social or any storage gateway.

Lớp thẻ lưu trữ (ngoài băng). Dịch vụ tải lên qub đính kèm một tập hợp thẻ giao dịch lưu trữ cố ý nhỏ cùng với dữ liệu tải lên được chọn. Content-Type=application/octet-stream được yêu cầu theo quy chuẩn. Dịch vụ tham khảo cũng gắn kèm ba thẻ tùy chọn khi người tạo chọn hiển thị chúng: Intent (ý định soạn thảo đã được xác thực trong danh sách cho phép—announcement, thesis, prediction, letter, secret, commitment, proof, hoặc do hệ thống phát ra verdict), Author (dấu vân tay khóa công khai §9.3 của người tạo dưới dạng 64 ký tự hex chữ thường), và Parent-Tx-Id (mã giao dịch lưu trữ của qub cha cho chuỗi phản hồi, 43 ký tự base64url).

Cái Author thẻ là tham gia tùy chọn theo qub: ứng dụng tạo tham chiếu chỉ gắn nó khi người dùng bật rõ ràng quyền ghi công công khai tại thời điểm đóng dấu. Khi công tắc tắt — mặc định — không có gì Author thẻ được viết và qub không được gán nhãn trên chuỗi: không có gì trong bộ nhớ vĩnh viễn liên kết việc tải lên với tay cầm của người tạo, email, hoặc các qub khác. Khi công tắc được bật, Author dấu vân tay được phân giải theo người sáng tạo đã chọn @handle thông qua chuỗi chứng thực §9.5. Mối quan hệ chuỗi hồi đáp và Intent không nhận dạng. Đối với giao hàng riêng tư, lớp bọc bên ngoài (§13) mã hóa phần bên trong có thể nhận dạng SealedQub Vật phẩm nên việc thu thập các gói lưu trữ và lấy chữ ký drand công khai vẫn chưa đủ để phục hồi thân thể mà không có K; các thẻ lưu trữ vẫn cố tình là siêu dữ liệu công khai.

Dịch vụ tham chiếu cố ý KHÔNG gắn các tag App-Name, App-Version, hoặc Type: bất kỳ bộ lọc giá trị đơn nào như vậy sẽ trả về toàn bộ kho qub cho một truy vấn GraphQL, điều này không nhất quán với phạm vi bảo mật chỉ-thân của lớp bao bọc.

Một trình xác minh tuân thủ KHÔNG ĐƯỢC phụ thuộc vào bất kỳ tag lưu trữ nào cho việc xác minh bên thứ ba §11; body hash / qub_id / chữ ký chỉ cam kết với CBOR bên trong, không bao giờ với tập hợp tag.


8. Giao thức mở khóa

Trình tự mở khóa hoàn chỉnh. Mỗi bước là quy phạm.

 1. Viewer opens delivery URL. Extract arweave_tx_id from the path and retain
    the optional URL fragment. Do not assume a missing fragment is an error:
    public/bare delivery intentionally has no K.
 2. Check denylist. If tx_id is denylisted → display block message. Stop.
 3. Fetch the stored bytes (with multi-gateway fallback).
 3a. Resolve the delivery shape structurally:
    a. If the bytes parse as OuterWrapper, require a well-formed 32-byte K in
       the URL fragment, require wrapper version 0x01, and unwrap per §13.
       Any missing/malformed K or AEAD failure is a terminal error.
    b. Otherwise require the bytes to parse as bare SealedQubCbor; no K is
       required. If neither shape parses, report an integrity error.
 4. Parse SealedQubCbor → SealedQub.
 5. Validate: SealedQub.version is known (0x01), visibility is known, and the
    delivery shape matches it (wrapped = 0x00 private; bare = 0x01 public).
    Reject any mismatch or unknown value.
 6. If current time < SealedQub.unlock_at → display countdown. Poll or wait.
 6a. Round-binding check. Recompute expected_round from
    SealedQub.unlock_at per §4.3. Reject unless SealedQub.drand_round ==
    expected_round OR SealedQub.drand_round == expected_round - 1 (the
    legacy pre-release mapping—see §4.3), AND the round baked into the tlock
    ciphertext stanza (read via the age/tlock header, no signature required)
    == SealedQub.drand_round exactly. 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.
12a. Verify: QubEnvelope.outcome_at == SealedQub.outcome_at (both absent, or
    both present and equal). Fail → integrity error.
12b. Content re-derivation. Recompute qub_id per §4.1 from the decrypted
    fields — (QubEnvelope.version, content_type, created_at, unlock_at,
    outcome_at, SealedQub.drand_round, QubEnvelope.body_hash,
    title_hash(SealedQub.title)) — and verify it equals SealedQub.qub_id.
    Fail → integrity error. The pairwise checks in steps 10-12a only prove
    the two layers agree with EACH OTHER; a forger who rewrites a bound
    field consistently on both surfaces (a pre-reveal title swap, or a
    post-round body swap with a recomputed body_hash re-encrypted to the
    same round under the same qub_id) passes them all. Only re-deriving
    the identity from content closes this.
13. Verify: QubEnvelope.content_type is known and renderable.
    Known values: 0x01 (text), 0x03 (pact), 0x04 (verdict).
    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 the appropriate renderer (see §10 for text and §6 for pact/verdict).
17. Construct RevealedQub for display.

9. Ký quyền tác giả

9.1 Lý do căn bản

Các qub được lưu trữ trong nơi lưu trữ vĩnh viễn. Các chữ ký quyền tác giả phải vẫn không thể giả mạo vô thời hạn, đó là lý do tại sao v1.0 sử dụng sơ đồ hậu lượng tử ML-DSA-65 (FIPS 204) thay vì một sơ đồ cổ điển mà tính bảo mật có thể suy giảm trong vòng đời vĩnh viễn của qub.

9.2 Sổ đăng ký thuật toán

sig_alg Kế hoạch Kích thước khóa Kích thước chữ ký Trạng thái
0x00 Không có chữ ký (chưa ký) — — Hoạt động
0x01 ML-DSA-65 (FIPS 204) 1.952 byte 3.309 byte Hoạt động
0x02 Ed25519 32 byte 64 byte Hằng số dự trữ; không được hỗ trợ trong giao thức v1

Người xem Protocol-v1 PHẢI từ chối mọi giá trị nằm ngoài {0x00, 0x01}, bao gồm người trầm lặng 0x02 giá trị. Việc đặt trước ngăn ngừa việc sử dụng lại một cách tình cờ; điều đó không phải kích hoạt. Việc kích hoạt nó đòi hỏi phải thực hiện thay đổi được quản lý như mô tả trong §15.

9.3 Xây dựng tiền ảnh đã ký

Đã tồn tại hai phiên bản tiền ảnh. Mọi chữ ký PHẢI dùng V2, và các trình xác minh PHẢI chỉ chấp nhận V2. Tiền ảnh V1 cũ (được ghi lại bên dưới để tham khảo lịch sử) từng được chấp nhận như một phương án dự phòng chỉ dùng để xác minh trong quá trình di chuyển sang V2; phương án dự phòng đó đã bị loại bỏ và một chữ ký chỉ theo V1 nay bị từ chối.

V2 (hiện hành — được tạo bởi mọi hoạt động ký tác giả mới, và bởi cả hai chữ ký của luồng staging / đồng ký giao ước):

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 tuân theo cùng quy ước giá trị vắng-mặt (absent-sentinel) như title_hash (§4.2.1): 32 byte 0 không phải là một đầu ra SHA3-256 hợp lệ, nên trạng thái "vắng mặt" không bao giờ có thể trùng với một nhãn hiện diện. Mọi trường đều có độ rộng cố định, nên tiền ảnh là rõ ràng mà không cần tiền tố độ dài.

V1 (cũ — ĐÃ LOẠI BỎ; không còn được tạo ra và không còn được chấp nhận khi xác minh):

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

Tiền ảnh V1 bỏ qua sender_label và reply_to. Nó từng được chấp nhận như một phương án dự phòng chỉ dùng để xác minh trong quá trình di chuyển sang V2; phương án dự phòng đó nay đã bị loại bỏ — các trình xác minh PHẢI chỉ chấp nhận tiền ảnh V2. Định nghĩa được giữ lại ở đây để tham khảo lịch sử và để giải thích dấu phân cách miền bên dưới. Một chữ ký chỉ xác minh được với V1 PHẢI được coi là một lỗi xác minh.

Dấu phân cách miền: "QUB_AUTHOR_SIG_V1" / "QUB_AUTHOR_SIG_V2" mỗi cái là 17 byte ASCII ([0x51, 0x55, 0x42, 0x5F, 0x41, 0x55, 0x54, 0x48, 0x4F, 0x52, 0x5F, 0x53, 0x49, 0x47, 0x5F, 0x56, 0x31/0x32]). Không có byte đệm. Dấu phân cách khác nhau tách miền hai cấu trúc, nên một chữ ký trên một tiền ảnh không bao giờ có thể xác minh được như tiền ảnh kia.

Byte org_id_present: byte theo sau unlock_at PHẢI là 0x00. Triển khai tham chiếu hiển thị điều này dưới dạng hằng số ORG_ID_PRESENT_INDIVIDUAL = 0x00 trong crates/qub-core/src/signing.rs; người xem tái tạo sig_input để xác minh PHẢI phát ra cùng một byte.

Phạm vi chữ ký — những gì được và không được bao phủ. sig_input V2 cam kết trực tiếp với version, qub_id, body_hash, unlock_at, sender_label, và reply_to (cộng với dấu phân cách miền cố định và byte org_id_present). qub_id chính nó được suy dẫn từ version, content_type, created_at, unlock_at, outcome_at, drand_round, và body_hash thông qua tiền ảnh §4.1, vì vậy bất kỳ thay đổi nào đối với các trường đó đều tạo ra một qub_id khác và làm mất hiệu lực chữ ký một cách bắc cầu. Do đó bề mặt được xác thực là:

Cánh đồng Được xác thực bằng chữ ký Như thế nào
version ✓ Nhập trực tiếp vào sig_input
qub_id ✓ Nhập trực tiếp
body_hash ✓ Nhập trực tiếp
unlock_at ✓ Nhập trực tiếp
sender_label ✓ Nhập trực tiếp qua sender_label_hash (Hình ảnh trước V2 — hình thức duy nhất được chấp nhận)
reply_to ✓ Nhập trực tiếp qua reply_to_or_zero (Tiền ảnh V2 — dạng duy nhất được chấp nhận)
content_type ✓ Một cách gián tiếp, thông qua qub_id tiền ảnh
created_at ✓ Một cách gián tiếp, thông qua qub_id tiền ảnh
outcome_at ✓ Một cách chuyển tiếp, thông qua qub_id tiền ảnh
drand_round ✓ Một cách chuyển tiếp, thông qua qub_id tiền ảnh
body ✓ Một cách chuyển tiếp, thông qua body_hash = SHA3-256(body)
author_pubkey — (ngầm định) Khóa đã xác minh chữ ký theo định nghĩa là tác giả
cosigner_pubkey / cosigner_signature — Độc lập ký chuyển quyền sở hữu cùng một sig_input (xem §9.7)
drand_chain_id, tlock_ciphertext, visibility — Bên ngoài SealedQub các trường, không phải bên trong phong bì — được bao phủ bởi các bất biến cấu trúc riêng của chúng (tính nhất quán vòng / chuỗi) nhưng không phải bởi chữ ký tác giả. (drand_round hiện nay bị ràng buộc một cách truyền qua bởi qub_id preimage — xem phía trên.)

Vì sao V2 là tiền ảnh duy nhất được chấp nhận.

Các triển khai hiển thị sender_label hoặc reply_to cho người dùng cuối PHẢI hiển thị danh tính đã xác thực (vân tay khóa công khai, chứng thực) làm tín hiệu danh tính chính, không phải nhãn.

9.4 Quy trình xác minh

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."

Xác minh chữ ký là thao tác đắt nhất (đặc biệt là ML-DSA-65). Nó NÊN được thực hiện sau khi tất cả các kiểm tra rẻ hơn (hash, qub_id, unlock_at) đã đạt.

9.5 Chứng thực danh tính

Chứng thực danh tính — ánh xạ author_pubkey đến các tuyên bố danh tính có thể nhận biết bởi con người như handle qub, địa chỉ email, handle mạng xã hội, hoặc thông tin xác thực passkey — là một cải tiến tiến bộ phía người xem và không bắt buộc cho việc xác minh chữ ký. Người xem phân giải chứng thực thành một danh tính hiển thị PHẢI áp dụng thứ tự ưu tiên:

handle > email > social > fingerprint

Dấu vân tay dự phòng là hex chữ thường của SHA3-256(author_pubkey); nó luôn có sẵn cho bất kỳ qub đã ký nào. Người xem CÓ THỂ rút gọn nó để hiển thị — trình xem tham chiếu hiển thị qub: theo sau là bốn byte đầu và bốn byte cuối (qub:<8 hex>…<8 hex>).

Một trình xác minh tuân thủ có thể hoàn thành mọi kiểm tra trong §9.4 mà không cần liên hệ với API qub, không cần mạng nào ngoài nơi lưu trữ vĩnh viễn và drand, và không cần tra cứu phía máy chủ. Phân giải chứng thực là một bước nỗ lực tốt nhất riêng biệt chỉ được thực hiện sau khi việc xác minh chữ ký đã thành công.

9.6 Tác động kích thước

Ed25519 ML-DSA-65
Chữ ký 64 byte 3.309 byte
Khóa công khai 32 byte 1.952 byte
Tổng cộng cho mỗi qub 96 byte 5.261 byte
Chênh lệch chi phí lưu trữ (ở mức ~$5/MB) ~$0.0005 ~$0.026

Đối với một qub văn bản 500–2.000 byte, ML-DSA-65 tăng kích thước lưu trữ lên khoảng ba lần. Chi phí tuyệt đối là không đáng kể.

9.7 Xác minh người đồng ký (thỏa thuận song phương giao ước)

Đối với các thỏa thuận song phương (content_type = 0x03), một lớp chữ ký thứ hai chứng minh cả hai bên đã đồng ý với các điều khoản giống nhau.

Các trường envelope:

Cả hai trường PHẢI hiện diện cùng nhau hoặc cả hai vắng mặt. Nếu chính xác một trường hiện diện, người xem PHẢI báo cáo lỗi toàn vẹn.

Quy trình xác minh:

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."

Tính chất:

Cổng ràng buộc email (vận hành). Khi một giao ước đã staging mang liên hệ email Bên B (§6.1), dịch vụ tải lên qub PHẢI từ chối yêu cầu đồng ký trừ khi tồn tại một dấu hiệu xác minh email tồn tại ngắn khớp với cả id staging và mã băm email đã chuẩn hóa của liên hệ đó. Dấu hiệu được ghi bởi /api/v1/auth/verify khi mã thông báo magic-link mang một staging_id và địa chỉ đã xác minh khớp với SHA-256(normalise_email(party_b.contact)) — trong đó normalise_email(addr) bảo toàn chữ hoa chữ thường của phần local và chỉ chuyển phần domain thành chữ thường (theo RFC 5321 §2.3.11), và SHA-256 ở đây là hàm băm NIST FIPS 180-4 (khác với SHA3-256 được sử dụng trong các suy dẫn §4) — và hết hạn 900 giây (15 phút) sau khi cấp. Đây là một cổng vận hành chống mạo danh, KHÔNG phải là một phần của bằng chứng qub trên chuỗi — một trình xác minh bên thứ ba phát lại §11 chỉ cần nơi lưu trữ vĩnh viễn và drand, không cần bất kỳ tra cứu phía máy chủ nào. Dấu hiệu chỉ tồn tại phía máy chủ và không bao giờ là một phần của thân được ký.

Tác động kích thước (tác giả ML-DSA-65 + người đồng ký):

Thành phần Kích thước
Chữ ký tác giả 3.309 byte
Khóa công khai tác giả 1.952 byte
Chữ ký người đồng ký 3.309 byte
Khóa công khai người đồng ký 1.952 byte
Tổng chi phí mật mã 10.522 byte
Chênh lệch chi phí lưu trữ ~$0.05

10. Hiển thị và làm sạch Markdown

Phần này quan trọng về mặt bảo mật. Người xem hiển thị các qub văn bản (content_type = 0x01) sử dụng một tập hợp con Markdown bị hạn chế.

10.1 Các phần tử được phép

10.2 Các phần tử bị cấm

Phần tử Xử lý
HTML thô (<div>, <script>, v.v.) Loại bỏ hoàn toàn. Không có HTML nào đi qua.
Hình ảnh (![alt](url)) Loại bỏ. Cú pháp hình ảnh bị xóa khỏi đầu ra.
Liên kết ([text](url)) URL được hiển thị dưới dạng văn bản thuần nhìn thấy. Không tự động liên kết. Không thể nhấp mà không có hành động rõ ràng từ người dùng.
Các sơ đồ URL nguy hiểm javascript:, data:, vbscript:, file: — loại bỏ.
Iframe, embed, object Loại bỏ.
Thực thể HTML Chỉ giải mã thành ký tự hiển thị nếu an toàn.

10.3 Triển khai

Các triển khai PHẢI sử dụng bộ phân tích danh sách cho phép nghiêm ngặt, không phải danh sách chặn. Cách tiếp cận được khuyến nghị:

  1. Phân tích Markdown bằng pulldown-cmark (hoặc tương đương).
  2. Duyệt AST và bỏ bất kỳ node nào không có trong danh sách cho phép (§10.1).
  3. Đối với các node liên kết: phát URL dưới dạng văn bản nhìn thấy, không phải dưới dạng phần tử <a> có thể nhấp.
  4. Chuyển đổi AST đã lọc thành một biểu diễn trung gian có kiểu (ví dụ, một enum MarkdownNode chỉ có các biến thể an toàn). HTML thô về mặt cấu trúc không thể biểu diễn được trong IR này.
  5. Hiển thị từ IR có kiểu đến lớp view đích (ví dụ, các thành phần view phản ứng, các node DOM). Không có sự ghép chuỗi HTML hoặc innerHTML tại bất kỳ thời điểm nào.

Các cách tiếp cận danh sách chặn rất mong manh vì các phần mở rộng Markdown mới hoặc các đặc tính riêng của bộ phân tích có thể đưa vào các phần tử không được lọc. Cách tiếp cận AST có kiểu làm cho XSS về mặt cấu trúc là không thể — không có biến thể nào có thể mang HTML tùy ý.

10.4 Giới hạn kích thước và cấu trúc


11. Xác minh bởi bên thứ ba

Bất kỳ bên thứ ba nào giữ các byte đã lưu trữ (và K cho một qub riêng/tự đóng gói) có thể xác minh hiện vật mật mã mà không có sự hợp tác của qub. Một cách độc lập có dấu thời gian sự tồn tại yêu cầu thêm nữa là phải có xác minh bao gồm lưu trữ vĩnh viễn per-qub hoặc bằng chứng nhật ký minh bạch §16 đã được xác minh.

1. Obtain the stored bytes. For a private delivery, also obtain K from the
   delivery-link fragment.
2. Resolve the delivery shape (§8 step 3a): unwrap OuterWrapper with K, or
   accept bare SealedQubCbor. Require shape/visibility agreement.
3. Parse SealedQubCbor → SealedQub; validate protocol version, visibility,
   content type, chain identity, and structural bounds.
4. Recompute expected_round from unlock_at (§4.3); require the stored round
   (allowing the documented legacy minus-one case) and ciphertext-stanza round
   to agree exactly as §8 step 6a specifies.
5. Obtain the drand signature for SealedQub.drand_round and verify its BLS
   signature against the pinned chain public key.
6. tlock_decrypt(tlock_ciphertext, round_signature) → QubEnvelope CBOR bytes.
7. Parse → QubEnvelope.
8. Verify SHA3-256(body) == body_hash.
9. Verify envelope/sealed equality for qub_id, unlock_at, and outcome_at.
10. Recompute qub_id from the decrypted fields, sealed drand_round, and title;
    require it to equal the carried qub_id (§4.1).
11. If sig_alg != 0x00, verify the V2 author signature (§9.4). If cosigner
    fields are present, verify their pairing, key separation, and signature
    (§9.7).
12. For an existence-time claim, independently verify either:
    a. the permanent-storage transaction's data-to-id binding, owner, block
       inclusion, and block timestamp; or
    b. a §16 inclusion proof through its pinned anchor and anchor block time.
13. Report each verified claim separately; do not collapse an absent storage
    or anchor proof into a successful timing verdict.

Xác minh chứng minh:

Nhập bằng chứng Những gì nó thiết lập
Gói hợp lệ / hiện vật niêm phong + chữ ký drand Thi thể được tìm thấy phù hợp body_hash; siêu dữ liệu được liên kết vào qub_id vẫn nguyên vẹn; bản mã được liên kết với vòng drand đã khai báo; và vòng đó đã kết thúc. Điều này không xác định khi nào văn bản mật mã được tạo ra.
Chữ ký hợp lệ của tác giả/người đồng ký V2 Người nắm giữ khóa bí mật tương ứng đã xác thực bề mặt được ký trong §9.3.
Giao dịch lưu trữ per-qub được xác minh độc lập Bản mã được lưu trữ chính xác tồn tại không muộn hơn dấu thời gian khối của nó.
Bằng chứng nhật ký minh bạch neo hợp lệ Yêu cầu theo loại lá trong §16.11, bao gồm thời gian cam kết giới hạn trên từ khối neo.

Những gì việc xác minh KHÔNG chứng minh:

Không chứng minh Tại sao
Tác giả Cái sender_label là trang trí. Không có sig_alg ≥ 0x01, bất cứ ai cũng có thể đã niêm phong nội dung này.
Ý định Hiện vật chứng minh các byte và mối quan hệ mật mã, không phải những gì người sáng tạo chủ quan muốn nói.
Cam kết có sẵn từ .qub một mình Một người sáng tạo có thể tập hợp một gói hợp lệ sau khi vòng giới hạn đã kết thúc. Chữ ký drand nhúng chứng minh rằng vòng đã kết thúc, không phải rằng bản mã đã tồn tại trước đó.
Thời gian bấm nút niêm phong chính xác Một dấu thời gian khối lưu trữ hoặc khối neo là một giới hạn trên có thể xác minh độc lập, và có thể bị trễ so với hành động địa phương của người dùng. sealed_at / received_at các khẳng định không có bằng chứng.

Bản ghi minh bạch đã triển khai (§16) mở rộng việc xác minh trên các qub với chống giả mạo đặt hàng và không cần tin cậy thời gian cam kết giới hạn trên (cái thời gian khối neo), được xác định theo loại lá (§16.11). Nó không thêm quyền tác giả hoặc ý định; đối với đường dẫn tải lên mặc định không nhìn thấy byte, chính nó không tự chứng minh body_hash hoặc drand_round, điều này tiếp tục xuất phát từ các kiểm tra hiện vật.


12. Quản lý Phiên bản và Phát hành

Việc phát hành tài liệu, giao thức dây bên trong và bao bọc bên ngoài là riêng biệt không gian phiên bản. Do đó, một sự làm rõ chỉ bằng tài liệu không im lặng thay đổi byte, và một di cư dây trong tương lai không thể giả dạng như một bài xã luận sửa đổi.

12.1 Phiên bản Phát hành Tài liệu

Đặc tả này sử dụng các bản phát hành tài liệu ngữ nghĩa (MAJOR.MINOR.PATCH) và một thẻ Git không thể thay đổi tên protocol-v<release>.

Tình trạng phát hành là một trong những Bản nháp (chưa phổ biến), Hiện tại (duy nhất mục tiêu triển khai được khuyến nghị), hoặc Bị thay thế (được giữ lại cho mục đích lịch sử xác minh). Không có phiên bản /protocol tuyến đường hiển thị phiên bản hiện tại; thẻ phát hành giữ nguyên nguồn gốc chính xác và mọi ngôn ngữ đã được phát hành cùng với nó. Thay đổi trạng thái hoặc số phiên bản yêu cầu cập nhật bảng này và phiên bản phát hành lịch sử trong cùng sự thay đổi đã được xem xét.

Phát hành tài liệu Ngày có hiệu lực Trạng thái Giao thức truyền dẫn Bao bì Nguồn
1.0.0 23-09-2026 Hiện tại 0x01 0x01 protocol-v1.0.0

12.2 Phiên bản Giao thức

Cái version trường (u8) trong cả hai SealedQub và QubEnvelope xác định phiên bản giao thức chính.

12.3 Lịch sử Phiên bản Giao thức

Phiên bản Giá trị Mô tả
v1 0x01 Giao hàng riêng/túi bọc và công khai/không bọc; văn bản (0x01), hiệp ước (0x03), và phán quyết (0x04) cơ thể; tác giả/đồng ký ML-DSA-65 V2 ký; drand quicknet tlock; SHA3-256.

12.4 Tương thích về phía trước

Một trình xem v1 khi gặp một QubEnvelope với các khóa bản đồ CBOR không xác định (các khóa không theo thứ tự chuẩn §3.2) PHẢI từ chối nó với lỗi giải mã (§3.1). Tính tương thích hướng tới tương lai phụ thuộc vào version trường, không phải trên dung sai khóa: các bổ sung trong tương lai — ngay cả siêu dữ liệu nhỏ — được phát hành dưới một version giá trị, mà một người xem v1 từ chối với lỗi rõ ràng "giao thức mới hơn" thay vì lặng lẽ loại bỏ nội dung mà các chữ ký cam kết.

Một người xem v1 gặp phải sig_alg = 0x01 (ML-DSA-65) nhưng thiếu hỗ trợ xác minh ML-DSA-65 NÊN hiển thị nội dung qub với thông báo “chữ ký có nhưng không thể xác minh”, không từ chối hoàn toàn qub. Triển khai tham chiếu hiện nay từ chối mọi sig_alg giá trị khác với 0x00 và 0x01 bởi vì đăng ký v1 không chứa thuật toán hợp lệ nào khác — từ chối nghiêm ngặt và thất bại mềm về quan sát là giống hệt cho đến khi một thuật toán thứ ba được đăng ký. Hành vi thất bại mềm ở trên trở nên có giá trị khi §9.2 chấp nhận một mục nhập mới, và trình xem tham chiếu sẽ được cập nhật thành thất bại mềm vào thời điểm đó.

12.5 Phiên bản Vỏ bên ngoài

OuterWrapper được mô tả trong §13 mang theo riêng của nó version byte, độc lập của SealedQub.version và QubEnvelope.version. Hai không gian phiên bản tiến hóa riêng biệt: một bản thay thế đối xứng an toàn sau lượng tử trong tương lai sẽ tăng byte của lớp bao bọc mà không ảnh hưởng đến phiên bản giao thức bên trong, và một bổ sung lớp giao thức trong tương lai (ví dụ, một trường phong bì mới) sẽ tăng phiên bản bên trong mà không ảnh hưởng đến byte của lớp bao bọc.

OUTER_WRAPPER_VERSION_* Giá trị Thuật toán Trạng thái
OUTER_WRAPPER_VERSION_1 0x01 AES-256-GCM với nonce 12 byte, tag xác thực 16 byte, AAD đã liên kết với qub_id Hoạt động cho giao hàng riêng
— 0x02–0xFF Đã đặt trước Tương lai

Người xem PHẢI từ chối các phiên bản bao bọc không xác định với một lỗi rõ ràng. Giao thức cố tình giữ không gian phiên bản bao bọc hẹp cho đến khi có một trình điều khiển di cư cụ thể xuất hiện (ví dụ: hướng dẫn của NIST ủng hộ một AEAD khác); a 0x02 khe sẽ được phân bổ trong cùng một bản sửa đổi giới thiệu thuật toán.


13. Lớp bao bọc mã hóa bên ngoài

13.1 Lý do căn bản

Các lớp giao thức (QubEnvelope → tlock → SealedQub) làm cho một qub đã niêm phong bị khóa thời gian: thân không thể đọc được cho đến unlock_at và chữ ký vòng drand đã được công bố. Tuy nhiên, sau khi mở khóa, chữ ký vòng là công khai và hình dạng CBOR chuẩn của SealedQub có thể nhận diện được, vì vậy một người thu thập đã lập chỉ mục các giao dịch lưu trữ vĩnh viễn có thể giải mã hàng loạt toàn bộ kho qub.

Đối với giao hàng riêng, lớp bọc mã hóa bên ngoài đóng kênh đó bằng cách chèn một lớp AEAD đối xứng bổ sung giữa các chuẩn SealedQubCbor và các byte đã lưu trữ. Trong đường dẫn browser-seal, khóa 256-bit K cuộc sống chỉ trong đoạn mảnh URL của URL giao hàng và trên thiết bị của người dùng; trình duyệt không truyền các đoạn mảnh URL tới các máy chủ, vì vậy qub.social, mọi cổng lưu trữ và mọi CDN phía trước đều không thể quan sát được K. Biểu diễn đã lưu trữ của một qub riêng tư do đó là bản mã hóa không thể nhìn thấu, mà bản rõ của nó không thể phục hồi nếu không có URL mà người tạo chọn để chia sẻ. Việc phân phối công khai cố ý bỏ qua lớp này (§13.8).

Hiệu ứng ròng:

13.2 Phân lớp

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
  ├─ public (visibility=0x01) ───────────────▶ stored directly (§13.8)
  └─ private (visibility=0x00)
       ↓ AES-256-GCM(K, nonce, AAD=qub_id) (§7 step 12, this section)
     OuterWrapper CBOR bytes         ← stored private payload

Niêm phong và mở khóa ở lớp giao thức (§7, §8) không thay đổi bên dưới ranh giới của lớp bao bọc; lớp bao bọc gắn vào tại điểm gọi của seal() và tách ra tại điểm gọi của unlock().

13.3 Cấu trúc dữ liệu OuterWrapper

struct OuterWrapper {
    version:    u8,           // 0x01, see §12.5
    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
}

Các bất biến của trường.

Mã hóa CBOR. CBOR chuẩn theo §3, với cùng quy tắc thứ tự khóa (sắp xếp theo độ dài byte đã mã hóa tăng dần, sau đó theo từ điển). Bốn khóa là:

Khóa Byte đã mã hóa Thứ tự
nonce 6 1
qub_id 7 2
version 8 3
ciphertext 11 4

Do đó byte đầu tiên của CBOR OuterWrapper là header map độ dài xác định cho một map 4 mục (0xA4).

13.4 Ràng buộc AAD với qub_id

Lớp bao bọc ràng buộc qub_id làm dữ liệu được xác thực bổ sung AEAD. Đây là phòng thủ cấu trúc quan trọng chống lại ba lớp tấn công:

Tấn công Phòng thủ
Di chuyển văn bản được mã hóa sang vị trí khác qub_id trường trong bao bọc AAD không khớp → Xác thực AEAD thất bại
Trộn đoạn URL của qub A với các byte đã lưu trữ của qub B Khóa sai (và AAD được ràng buộc độc lập) → xác thực AEAD thất bại
Can thiệp vào qub_id trường của bao bì sau khi tải lên AAD không khớp → Xác thực AEAD thất bại

Việc mang qub_id trong văn bản thuần của lớp bao bọc không làm suy yếu miễn nhiễm liệt kê đáng kể — qub_id chính nó là một hàm băm SHA3-256 của tiền ảnh §4.1 không có tiền ảnh có thể khôi phục được từ bản tóm tắt, và một người liệt kê đã thu thập các byte của lớp bao bọc không học được gì từ qub_id nhìn thấy được mà họ không thể suy luận từ chính sự tồn tại của bản tải lên.

13.5 Thuật toán bao bọc và tháo bao bọc

wrap_sealed_qub(SealedQubCbor S, qub_id Q, key K, nonce N):
    require K.len() == 32 and N.len() == 12 and Q.len() == 32
    I := canonical_cbor_decode(S) as SealedQub
    require I.qub_id == Q               // reject mismatched caller AAD
    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.5
    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
    S := canonical_cbor_decode(P) as SealedQub
    require S.qub_id == O.qub_id       // explicit inner/outer cross-check
    return P                            // P is the validated SealedQubCbor

Sự sụp đổ chế độ thất bại. K sai, nonce sai, AAD không khớp, và ciphertext bị giả mạo đều tạo ra cùng một lỗi DECRYPT_FAILED. Đây là một tính chất AEAD có chủ đích: phân biệt chế độ thất bại sẽ tạo ra một kênh phụ mà kẻ tấn công từ xa có thể dò bằng cách gửi các lớp bao bọc bị lỗi và đo thời gian phản hồi. Các triển khai tham chiếu PHẢI gộp tất cả các thất bại AEAD thành một hình dạng lỗi duy nhất.

13.6 Vật liệu khóa và phân phối

Khóa bao bọc K là một giá trị ngẫu nhiên đều 256 bit được tạo cho mỗi qub bởi một CSPRNG. Các triển khai tham chiếu lấy nó từ:

Phân phối: K PHẢI được mã hóa dưới dạng base64 an toàn cho URL (RFC 4648 §5, không đệm) và được nối vào URL bàn giao dưới dạng thành phần fragment:

delivery_url = <origin>/c/<arweave_tx_id>#<base64url(K)>

Fragment không bao giờ được truyền đến bất kỳ máy chủ nào bởi một trình duyệt tuân thủ. Các kênh khôi phục (chỉ mục lịch sử phía máy chủ, tự động gửi email chọn tham gia) duy trì URL bàn giao đầy đủ — bao gồm fragment — vượt ra ngoài thiết bị của người dùng là một sự đánh đổi rõ ràng chống lại thế crypto-shredding mặc định và PHẢI được kiểm soát bằng sự đồng ý rõ ràng của người dùng.

Mất fragment. Nếu một người dùng mất fragment URL và không có kênh khôi phục, qub không thể đọc được. Đây là sự đánh đổi quan trọng của thiết kế và PHẢI được công bố cho người dùng tại thời điểm niêm phong. MVP củng cố công bố tại thời điểm niêm phong với văn bản "lưu URL này" rõ ràng và một kênh khôi phục email đã xác minh cho những người dùng chọn tham gia.

13.7 Ngoài phạm vi cho phần này

13.8 Các qub công khai (lược bỏ lớp bao bọc)

Lớp vỏ bên ngoài là tùy chọn ở lớp giao hàng. Một người sáng tạo có thể niêm phong một qub như công cộng, trong trường hợp đó, chuẩn mực SealedQubCbor đi vào đường ống lưu trữ trực tiếp, không có OuterWrapper lớp và không có phím K:

SealedQubCbor bytes  ──(public)──▶  stored as-is
SealedQubCbor bytes  ──(private)─▶  AES-256-GCM(K, …) ▶ OuterWrapper ▶ stored

Một quán bar công cộng là bị khóa theo thời gian nhưng không bị kiểm soát bởi liên kết: nó vẫn không thể đọc được cho đến khi vòng drand của nó được xuất bản (lớp tlock không thay đổi), nhưng sau khi mở khóa bất kỳ ai có ID giao dịch lưu trữ đều có thể giải mã nó — không cần phân đoạn URL, vì không có K. Đây là thương mại có chủ ý dành cho các bề mặt mà máy chủ phải điều khiển: email thông báo tiết lộ, liên kết oEmbed/tự nhúng không mảnh vụn, và SEO phong phú hơn sau khi tiết lộ bài viết đều cần một liên kết hoạt động mà không cần bí mật mà máy chủ không bao giờ giữ (§13.6). Một qub riêng tư vẫn có thể sử dụng rõ ràng <qub-embed src="full_delivery_url"> hình thức khi nhà xuất bản cung cấp khả năng mang mảnh hoàn chỉnh của nó.

Các hệ quả mà một nhà sản xuất PHẢI tính đến:

Riêng tư (đã bao bọc) vẫn là mặc định; công khai là một lựa chọn rõ ràng của người tạo trên mỗi qub.


14. Các vector kiểm tra

14.1 Suy dẫn 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  = 4695446  (= floor((1736294400 - 1595431050) / 30) + 1, §4.3 mapping, 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—current protocol v1):
  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)
  0x000000000047A596  ||  // drand_round as u64 big-endian (4695446)
  body_hash           ||  // 32 bytes
  title_hash              // 32 bytes (all-zeros sentinel; title absent)

Expected output:
  qub_id = SHA3-256(preimage)
         = 4a84e3dfaec32954949c30073f8e6506
           fd3204c1bb97f9162b81c7587afe412e

Các triển khai PHẢI tạo ra kết quả giống hệt nhau body_hash và qub_id các giá trị cho đầu vào này. Vector kiểm tra này NÊN là bài kiểm tra đơn vị đầu tiên được viết. Các giá trị chuẩn ở trên được tính bởi bản triển khai tham chiếu và PHẢI khớp từng bit. Các bố cục nguyên mẫu trước khi ra mắt lịch sử (không có qub sống nào phụ thuộc vào hai cái đầu tiên) đã sử dụng 92 byte trước đó outcome_at (3d9fc2390eab043d38a1669ed3b71be76f9eefe872b9569ab1aaa027b88392b0) và 100 byte sau khi thêm outcome_at_or_zero (b0d032898ad629795150fdcb3f84e518f59ed05b7a2a82bc24ebdb87f52144ed). Bố cục 108 byte hiện tại sau đó được thêm vào drand_round và QUB_ID_V2 bộ phân tách miền. Một vectơ 108 byte ban đầu đã sử dụng phương pháp cũ ceil bản đồ tròn (drand_round = 4695445) và sản xuất 3a9fcb31b750d985c262fada6d4f777fd6a28be831d941d85c131f5a4bbaf8a4—vẫn hợp lệ qub_id đối với đầu vào vòng đó, trong khi ví dụ trên tuân theo ánh xạ vòng hiện tại §4.3.

14.2 Bản đồ Giải khóa-Vòng

Input:
  unlock_at           = 1735689600
  chain_genesis_time  = 1595431050
  chain_period_seconds = 30

Calculation:
  (1735689600 - 1595431050) / 30 = 4675285.0
  floor(4675285.0) + 1 = 4675286

drand_round = 4675286

Vòng 4675286 xuất bản vào 1595431050 + (4675286 - 1) * 30 = 1735689600—chính xác vào unlock_at, chưa từng có trước đây. (Phiên bản phát hành trước di sản ceil bản đồ đã cho 4675285, được xuất bản tại 1735689570—Sớm 30 giây; các kiểm chứng chấp nhận vòng cũ theo §4.3.)

14.3 Vòng lặp CBOR chuẩn

Các triển khai PHẢI xác minh rằng serialize(parse(serialize(qub))) == serialize(qub) cho tất cả các đầu vào hợp lệ. Đây là một kiểm tra thuộc tính, không phải một vector đơn lẻ.

14.4 CBOR PactTerms (content_type 0x03)

Input:
  pact_version = 1
  title        = "Scooter deposit"
  terms        = [
    { key: "Item",    value: "Honda Metropolitan scooter" },
    { key: "Price",   value: "$100" },
    { key: "Deposit", value: "$10" }
  ]
  party_a      = { label: "Alice" }
  party_b      = { label: "Bob", contact: "bob@example.com" }
  notes        = absent

Canonical CBOR key order (PactTerms):
  "notes"(6) < "terms"(6) < "title"(6) < "party_a"(8) < "party_b"(8) < "pact_version"(13)

Canonical CBOR key order (PactTerm):
  "key"(4) < "value"(6)

Canonical CBOR key order (PartyIdentifier):
  "label"(6) < "contact"(8)

Các byte CBOR chuẩn và body_hash SHA3-256 được tính toán bởi triển khai tham chiếu. Các triển khai PHẢI tạo ra CBOR giống hệt byte cho đầu vào này.

Các triển khai cũng PHẢI xác minh rằng serialize(parse(serialize(pact))) == serialize(pact) cho tất cả các đầu vào PactTerms hợp lệ (kiểm tra thuộc tính).

14.5 Các vector lớp bao bọc bên ngoài đa ngôn ngữ

Lớp bao bọc bên ngoài (§13) có một fixture chuẩn riêng tại crates/qub-core/tests/vectors/wrapper_v1.json. Mỗi trường hợp cố định một bộ (key, nonce, qub_id, sealed_cbor) làm đầu vào hex mờ và khẳng định một đầu ra expected_wrapper_hex cụ thể. Cả hai triển khai tham chiếu đều tiêu thụ cùng một file JSON:

Thiết bị cố định hiện đang ghim ba trường hợp bao bọc cấp thấp. Chúng kiểm tra tính quyết định OuterWrapper mã hóa và khả năng tương tác AEAD độc lập với bất biến hình thức giao hàng §13.8; đặc biệt, tên lịch sử basic-text-public và bên trong của nó visibility = 0x01 làm không làm cho các byte được bọc sau khi kết quả trở thành bản giao hàng công khai hợp chuẩn. Một nhà sản xuất VẪN PHẢI lưu trữ các byte bên trong công khai ở dạng trần và chỉ bọc các byte riêng tư (0x00) byte bên trong.

Trường hợp Phạm vi
basic-text-public Tên thiết bị mức thấp lịch sử. Thực tế nhỏ nhất SealedQub hình dạng, không có trường tùy chọn; chỉ kiểm tra các byte bao bọc và không phải là một giao hàng lưu trữ §13.8 tuân thủ.
with-recipient-pubkey SealedQub với recipient_pubkey đặt (đường dẫn tương lai đã được giữ). Thực hiện một tập khóa CBOR bên trong khác; nội dung phụ kiện riêng biệt của nó tạo ra một khác biệt qub_id (recipient_pubkey bản thân nó không có trong bản tiền ảnh §4.1).
longer-body ~4 KiB thân — thực hiện các tiền tố độ dài CBOR nhiều byte bên trong cả phong bì bên trong và bản mã bên ngoài.

Các triển khai PHẢI tạo ra expected_wrapper_hex giống hệt byte cho các đầu vào đã ghi. Việc tái tạo fixture yêu cầu QUB_REGEN_VECTORS=1 cargo test -p qub-core --test wrapper_vectors và được dành riêng cho các thay đổi định dạng có chủ ý.


15. Quản trị hồ sơ mật mã (Tương lai)

Phần này có tính thông tin cho v1 và trở thành quy phạm lần đầu tiên khi một thuật toán thứ hai bước vào bất kỳ nguyên thủy mật mã nào của qub.

15.1 Thế hiện tại

Giao thức v1 ràng buộc chính xác một thuật toán cho mỗi nguyên thủy:

Các bộ xác minh hiện tại mã hóa cứng độ dài khóa và chữ ký theo từng phương pháp đang hoạt động. sig_alg và các byte wrapper-version là các bộ chọn rõ ràng, nhưng v1 không thực hiện bất kỳ thương lượng trong băng tần nào và chỉ chấp nhận các giá trị đang hoạt động ở trên.

15.2 Hình dạng dự định

Khi một thuật toán thứ hai bước vào giao thức, trình xác minh sẽ được cấu hình cho một CryptoProfile có tên (ví dụ, ExqubV1) liệt kê tập hợp chính xác các giá trị được phép cho mỗi nguyên thủy — sig_algs, các chuỗi drand, các phiên bản lớp bao bọc, các loại nội dung. Hồ sơ được cố định tại thời điểm xác minh, không bao giờ được thương lượng trong băng. Bất kỳ giá trị nào ngoài hồ sơ đang hoạt động đều bị từ chối.

Điều này đảm bảo rằng việc thêm ML-DSA-87 hoặc kích hoạt Ed25519 không thể làm suy yếu hồi tố các cấu hình trình xác minh hiện có: một trình xác minh v1 vẫn là một trình xác minh v1 ngay cả sau khi một hồ sơ v2 được công bố.

15.3 Điều kiện kích hoạt

Thăng cấp §15 lên trạng thái quy phạm khi bất kỳ điều nào sau đây được đề xuất:

Cho đến lúc đó §15 là một chỗ giữ chỗ cố định hình dạng di chuyển để các PR tương lai đáp xuống một mục tiêu đã biết thay vì tái thẩm bề mặt thương lượng từ đầu.


16. Nhật ký minh bạch và các cấp độ bền vững (Thiết kế — đã hoàn tất rà soát)

Trạng thái. Phần này là thực hiện (W5/UP-B1, Giai đoạn 1–8), với nhà sản xuất và phạm vi gốc tin cậy được nêu ở đây. Các định dạng dây, băm, và đường dẫn xác minh đang hoạt động: các loại Merkle cốt lõi + CBOR chuẩn (qub-core), trình đóng gói TypeScript mirror + ANS-104 (workers/api/src/crypto/), tác giả đơn LogDO + kho nút R2 được khóa theo tọa độ, cái /upload cố gắng ghi nhật ký, các cron chốt hàng ngày + bundler-drain, GET /api/v1/qub/:tx_id/proof (sự bao hàm) và GET /api/v1/log/consistency (RFC 9162) các điểm kết chứng minh, bằng chứng bao gồm được đánh dấu kiểu mang trong .qub gói (§17.5), trình xác minh neo ANS-104 gốc (tools/qub-verify), và mỏ neo hai đầu tự xuất bản (§16.6). Một thành công /upload luôn bền R2 nhưng chỉ được phủ lớp vỏ gỗ khi LOG_DO được cấu hình và việc thêm trực tiếp thành công; chỉ khi đó phản hồi của nó mới mang log_seq, receipt, và anchor_status. Nếu RECEIPT_SK bị thiếu hoặc không hợp lệ, biên lai đó sig_b64url rỗng và không cung cấp sự không thể chối cãi. Hiện tại /seal và các đường dẫn xuất bản thỏa thuận lập lịch các giao dịch Arweave riêng lẻ nhưng không thêm một nút nhật ký. Hiện tại không có mã nào thực hiện /upload bình luận về đề xuất hòa giải sau khi ghi thêm thất bại. Đánh giá bên ngoài W5 đã hoàn tất: §16.15 ghi lại các quyết định thiết kế và các hạn chế khi khởi chạy, nhưng những hạn chế đó không mở rộng phạm vi nhà sản xuất vừa được nêu. Ba mục tin cậy/phân phối còn bị kiểm soát: (a) ví neo chuyên dụng (ANCHOR_JWK; LogProfile.anchor_owner vẫn là [0xAB; 32] chỗ giữ chỗ); (b) khóa ký biên nhận và khớp với mã khóa công khai (RECEIPT_SK là tùy chọn và LogProfile.receipt_pubkey hiện đang trống); và (c) kho lưu trữ GitHub self-published-heads + token (§16.6). Cho đến khi các chốt neo/hồ sơ được cung cấp, một trình xác minh độc lập sẽ báo cáo trạng thái bằng chứng một cách trung thực thay vì tuyên bố một xác minh đã được neo và chốt hoàn toàn. Thiết kế này hoàn toàn mang tính bổ sung và có không thay đổi gì đối với SealedQub / QubEnvelope định dạng dây.

16.1 Lý do căn bản và các cấp độ bền vững

Các con đường xuất bản hiện tại tách biệt việc xác nhận với xác nhận Arweave: chúng tạo ra và ký một giao dịch riêng lẻ, lưu trữ hiện vật và trạng thái gửi chính xác trong R2, sau đó đăng tải bất đồng bộ. Nhật ký minh bạch thêm một lớp sắp xếp được neo độc lập cho tập con chung. /upload các yêu cầu mà LogDO append thành công:

Cấp bậc Tên Bảo đảm Khi
T1 R2 - xác nhận đồng bộ đầu tiên Sàn độ bền — các byte đã được niêm phong và trạng thái xuất bản chính xác được ghi vào bộ lưu trữ bền vững trước khi trả về thành công. Được triển khai trên các đường xuất bản hiện tại.
T2 Bao gồm nhật ký minh bạch theo lô Chỉ thêm vào, cam kết có thể phát hiện sự giả mạo + sắp xếp tổng thể một khi đã được bao gồm và neo. Nhà sản xuất hiện tại: thành công LogDO ghép từ /upload; phản hồi mang theo bộ nhận biên lai. Không phổ quát.
T3 Độ vĩnh viễn của Arweave theo từng qub Một giao dịch Arweave cá nhân cho qub. Hiện tại được chuẩn bị cho mọi ấn phẩm đã được chấp nhận và đăng không đồng bộ; giao dịch đã ký chính xác vẫn còn trong hộp thư đi có thể dẫn ra cho đến khi được gửi đi.

Các cấp mô tả các bằng chứng và tính bền vững khác nhau, không phải kế hoạch thương mại hiện tại. Mã hiện tại vẫn lên lịch một giao dịch Arweave riêng cho mỗi bài đăng được chấp nhận; nó không chỉ hiển thị T3 như một tính năng trả phí. Mức trần giới hạn khóa API/tài khoản vẫn là các kiểm soát ứng dụng riêng biệt.

Sự bền bỉ trung thực. Ghi T1 là đồng bộ, vì vậy một phản hồi thành công thiết lập độ bền ở cấp ứng dụng mà không cần chờ một cổng Arweave. Nó không tự thiết lập một dấu thời gian độc lập. Một giao dịch cá nhân được xác nhận cung cấp giới hạn trên thời gian khối của nó. Đối với một phản hồi mang bộ biên nhận T2 đầy đủ, mỏ neo được xác nhận tiếp theo có thể cung cấp bằng chứng nhật ký như mô tả dưới đây. Nếu bộ dữ liệu không có, không có bề mặt nào có thể ngụ ý rằng qub này đã có trong nhật ký minh bạch. Độ trễ của mỏ neo và việc xuất bản không có SLA số ở cấp giao thức.

16.2 Cấu trúc LogLeaf (hai hình dạng đã cam kết)

Một mục nhật ký là một LogLeaf, được mã hóa dưới dạng CBOR chuẩn viết tay theo hồ sơ §3.1 (độ dài xác định, không tag, không số thực, số nguyên dạng ngắn nhất, văn bản NFC, các trường tùy chọn bị loại bỏ khi vắng mặt, các khóa được sắp xếp theo độ dài byte mã hóa tăng dần rồi theo byte). Lá chắn chuẩn phân tích → tái mã hóa → so sánh của §3.1 được áp dụng trên đường mã hóa trước khi băm (không chỉ khi giải mã), nên hai triển khai không thể bất đồng về các byte của lá thông qua một khác biệt về độ rộng số nguyên hay thứ tự khóa. Tất cả số nguyên là u8 / u64 / i64; tất cả bản tóm tắt là chuỗi byte 32 byte (bstr[32]). Một id giao dịch Arweave được lưu trữ là một bản tóm tắt SHA-256 thô 32 byte được mang dưới dạng bstr[32], không bao giờ là một chuỗi văn bản base64url (khớp với §3.3).

Chiếc lá có hai hình được chọn bởi một kind bát, bởi vì đường dẫn tải lên chung là mù byte: POST /api/v1/upload cố ý xem cả hai dạng payload được chấp nhận như không trong suốt và nhận qub_id và unlock_at chỉ như khẳng định của khách hàng không đáng tin cậy. Trên đường dẫn riêng mặc định, body_hash, drand_round, created_at, và drand_chain_version cũng được ẩn bên trong vỏ ngoài §13, khóa của nó Người Lao Động không bao giờ giữ. Hệ thống kiểu cũng xác định một hình dạng được chứng nhận cho một nhà sản xuất mà phát sinh body_hash / drand_round bản thân nó. Hiện tại /seal tuyến đường có những giá trị đó nhưng không gọi LogDO, vì vậy sản xuất hiện tại chỉ thải ra những điều đã được khẳng định (0x02) rời khỏi các lần thêm tải lên chung thành công. Việc chia tách giữ mọi giá trị đã cam kết trung thực mà không giả vờ người sản xuất đã được xác nhận bị điều khiển:

Chìa khóa Đính kèm thư Loại Sự hiện diện Ý nghĩa
seq bốn u64 bắt buộc Chỉ số lá toàn cục bắt đầu từ 0; vị trí mà bằng chứng bao gồm cam kết.
kind năm u8 bắt buộc 0x01 có khả năng xác nhận (được định nghĩa, hiện không được phát ra) hoặc 0x02 khẳng định (tải lên con dấu khách hàng / mù byte).
ref bốn bstr[32] bắt buộc ID tham chiếu lá. Chứng thực → thô qub_id. Khẳng định → the bị mù thẻ căn cước SHA3-256(qub_id ‖ log_blind_secret) (§16.2.1).
chash sáu bstr[32] bắt buộc Địa chỉ nội dung SHA3-256(stored_bytes) — mối liên kết nội dung duy nhất mà Người Lao Động luôn có thể tính toán một cách trung thực, trên cả hai con đường.
unlock_at tên i64 bắt buộc Được sao chép (chứng thực) hoặc khẳng định (khẳng định); đã được xác nhận > 0 trước khi nó vào lá.
received_at mười hai i64 bắt buộc Đồng hồ tường của công nhân tại R2-ack. Không có bằng chứng (do nhà điều hành xác nhận; §16.6). Có mặt để tự mô tả, không bao giờ là bằng chứng. Đã được xác thực > 0.
body_hash tên bstr[32] kind=0x01 chỉ Bị bỏ qua vào 0x02 — Người lao động thiếu nó theo §13.
drand_round mười hai u64 kind=0x01 chỉ Bị bỏ qua vào 0x02.

Một lá kind=0x02 cố ý không cam kết cả body_hash lẫn drand_round: nó chứng thực cam kết và thứ tự của một ciphertext mờ tại địa-chỉ-nội-dung chash, tuyên bố qub_id và unlock_at — không phải bản rõ hay vòng của nó. Các chân bản-rõ/vòng cho một qub đã khẳng định đến từ việc xác minh gói .qub §11 hiện có, không phải từ nhật ký (§16.11). drand_chain_version không nằm trong lá (nó nằm bên trong lớp bao bọc trên đường mặc định); độ chi tiết chuỗi nằm trên cái neo (§16.7). Kỷ luật mã hóa: từ chối một ref hoặc chash toàn-số-0, và từ chối unlock_at / received_at không-dương, phản chiếu lá chắn trị canh gác outcome_at > 0 trong cbor.rs.

16.2.1 Làm mù qub riêng tư

Nhật ký không được trở thành cái oracle liệt kê mà lớp bao bọc bên ngoài §13 tồn tại để ngăn chặn (§13.1). Đối với một qub riêng tư (đã bao bọc), lá asserted cam kết định danh đã làm mù SHA3-256(qub_id ‖ log_blind_secret), trong đó log_blind_secret là một bí mật do máy chủ giữ, và loại bỏ body_hash. Một bên thứ ba không thể buộc một lá như vậy với một qub_id cụ thể; người giữ qub, người có liên kết bàn giao và do đó có qub_id, có thể tính lại phép làm mù để xác nhận việc đưa-vào của chính mình. Một qub công khai (vốn đã có thể liệt kê, vốn đã mang tag Arweave Visibility: public theo §13.8) cam kết qub_id thô. Đây là một chỗ duy nhất mà khả năng xác minh độc lập cố ý nhường cho một bất biến riêng tư chịu tải; mối ràng buộc độc lập cho các qub riêng tư là chash (§16.9).

Quyền giám hộ log_blind_secret (đã giải quyết — §16.15 Q4). Phép làm mù bảo vệ tính không-thể-liên-kết của lá, không phải tính bảo mật của bản rõ (lớp bao bọc §13 nắm giữ điều đó một cách độc lập). Khi log_blind_secret bị lộ, đối với bất kỳ qub_id nào mà kẻ tấn công đã giữ hoặc có thể tái dựng (mọi qub mà nó có gói/URL, cộng với bất kỳ qub_id có entropy thấp hoặc công khai nào), nó tính lại ref của lá trong một phép băm và liên kết nó — đây là sự liên kết trực tiếp của một quần thể đã biết, không phải một phép vét cạn trên một không gian chưa biết. Phân loại log_blind_secret là một bí mật cấp tương-quan/Sybil thuộc cùng cấp giám hộ với các bí mật máy chủ khác, và chỉ luân chuyển tiến (một lần luân chuyển làm-mù-lại các lá tương lai; nó không thể hồi tố hủy-liên-kết các lá đã được neo).

16.3 Băm lá và băm nút

Băm phân tách miền theo RFC 6962 §2.1 với SHA-256 được thay bằng 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

Các byte tiền tố miền 0x02 (chuỗi mục, §16.4) và 0x03 (băm STH, §16.6) được dành riêng và rời rạc với các byte này. Chúng là các byte đơn nên không thể trùng với các dấu phân cách miền ASCII 10 byte hiện có (QUB_ID_V2, v.v.). Cây là cây RFC 6962 mất-cân-bằng đầy-bên-trái (mỗi điểm chia bên trong tại lũy thừa lớn nhất của hai nhỏ hơn hẳn số lá của cây con), điều này cho phép các bằng chứng đưa-vào và bằng chứng nhất quán chia sẻ một thuật toán đường-kiểm-toán. Đặc tả tham chiếu mang theo mã giả suy dẫn trái/phải tường minh và cố định một vector kiểm tra không-lũy-thừa-của-hai (5 lá) để trường hợp thăng cấp cạnh-phải — mà một vector 4-lá che giấu — được vận dụng.

16.4 Móc xích băm (nội bộ)

LogDO duy trì một chuỗi mục nội bộ chỉ để nhất quán khi sự cố. Nó không bao giờ được công bố và không bao giờ hướng tới trình xác minh:

entry_chain[seq] = SHA3-256(0x02 || entry_chain[seq-1] || leaf_hash[seq])
entry_chain[-1]  = SHA3-256("QUB_TLOG_GENESIS_V1")

Thẩm quyền chỉ-thêm được công bố là gốc Merkle tích lũy + cái neo của nó (§16.5–16.6), không bao giờ là thứ tự thô mà người vận hành tình cờ phục vụ các lá: chuỗi tính lại cho bất kỳ thứ tự nào được phục vụ, nên chỉ gốc đã được neo mới ghim vị trí chuẩn.

16.5 Cây Merkle tích lũy và việc gom lô

Có một cây RFC 6962 luôn-lớn-dần trên tất cả các lá theo thứ tự seq — không phải các cây riêng-lẻ theo từng lô. (Một cấu trúc móc-xích-lá-mang-sang theo từng lô đã bị bác bỏ: nó không phải một quan hệ tiền tố thực sự, nên "các bằng chứng nhất quán" của nó là không vững.) Cây tích lũy cho các bằng chứng nhất quán RFC 9162 đích thực và cho phép một cái neo gần đây duy nhất chứng minh việc đưa-vào cho bất kỳ qub cũ hơn nào.

Cái LogDO Đối tượng Bền bỉ là tác giả đơn (blockConcurrencyWhile, phản chiếu QuotaDO / EntitlementDO) — việc thêm vào nhật ký chung là đọc-sửa-ghi trên trạng thái chia sẻ và do đó PHẢI đi qua DO, không bao giờ là KV. Nó lưu vào bộ nhớ đệm biên phải của cây (O(log n) băm) vì vậy việc đóng một lô là O(batch). A lô là tập hợp các lá được gắn kết với nhau; các trình kích hoạt được thực hiện của nó là một tree_size tiến trước ít nhất LOG_BATCH_MAX_LEAVES (mặc định 4096), tuổi đạt nhịp neo, hoặc một lệnh đóng cưỡng bức hành chính/cron rõ ràng. root_i là giá trị băm Merkle Tree tích lũy trên các lá 0 .. tree_size_i.

16.6 Đầu cây đã ký thông qua cái neo Arweave

Giao dịch neo Arweave chính là Đầu Cây Đã Ký và thay thế một chữ ký người vận hành cho chính đầu cây: cái neo hằng ngày không cần khóa qub nào vì owner của giao dịch Arweave chính là chữ ký. Luận điểm hào nước đứng vững — nền tảng bất biến, không phải một bí mật do qub giữ, mới là cái chịu tải cho gốc đã được neo.

Thiết kế nhật ký yêu cầu một thao tác ghi thành công ấm áp khóa biên lai (§16.10), ghim vào LogProfile và được ký chéo bởi anchor_owner. Việc triển khai hiện tại chưa hoàn tất việc cung cấp gốc tin cậy đó: RECEIPT_SK là tùy chọn, một khóa bị thiếu/không hợp lệ sẽ tạo ra sig_b64url: "", và đã biên dịch LogProfile.receipt_pubkey rỗng. Một biên lai như vậy có thể mô tả tờ đính kèm nhưng không một biên lai đã ký không thể chối bỏ. Yêu cầu thiết kế mạnh hơn chỉ áp dụng sau khi một trình xác minh phát hành ghim khóa công khai tương ứng và chủ sở hữu mỏ neo ký chéo nó. Một phản hồi xuất bản mà không có bộ ba biên lai đầy đủ sẽ không đưa ra bất kỳ yêu cầu chấp nhận nhật ký nào; một phản hồi với chữ ký trống sẽ đưa ra yêu cầu về vị trí bổ sung nhưng không có yêu cầu xác minh chữ ký.

SignedTreeHead là CBOR chuẩn (các khóa theo độ dài mã hóa): size:u64, root:bstr[32], batch:u64, prev:bstr[32] (sth_hash trước; khởi nguồn = 32 byte zero), log_id:bstr[32], first_seq:u64, anchored_at:i64. Băm của nó là sth_hash = SHA3-256(0x03 || canonical_cbor(SignedTreeHead)).

Gốc tin cậy được ghim. log_id = SHA3-256("QUB_TLOG_V1" || anchor_owner_address). Một trình xác minh tuân thủ PHẢI yêu cầu anchor_tx.owner == LogProfile.anchor_owner, trong đó anchor_owner (và khóa công khai của khóa biên nhận) được nung vào qub_core dưới dạng LogProfile — bên cạnh các hằng số quicknet đã có trong DrandTimelockProvider::quicknet() — và phân phối cùng tệp nhị phân trình xác minh. Trình xác minh cũng PHẢI xác minh ràng buộc dữ liệu → tx_id của giao dịch Arweave cục bộ thay vì tin một phản hồi /raw/ của cổng. Điều này đóng lỗ hổng nói-nước-đôi do ví giả mạo: "đã được neo trên Arweave" là vô nghĩa cho đến khi trình xác minh ghim ví nào.

Luân chuyển là một mở rộng quản trị §15, không phải một sự tái sử dụng (đã giải quyết — §16.15 Q3). Bề mặt hồ sơ của §15.2 hiện chỉ liệt kê các sig_alg / chuỗi drand / phiên bản bao bọc / loại nội dung, và danh sách điều kiện kích hoạt của §15.3 không có cái nào trong số này — LogProfile / anchor_owner chưa nằm trong bề mặt của §15. Do đó quản trị luân chuyển phải được xây dựng: §15.3 được mở rộng (bên dưới) để thêm điều kiện kích hoạt LogProfile, và một lần luân chuyển là một bản nâng LogProfile đã ký được phát hành trong một bản cập nhật trình xác minh. Một lần luân chuyển có kế hoạch mang theo một đối-ký đi-ra → đi-vào; một lần luân chuyển do bị lộ thì không thể (khóa đi-ra không tin cậy/không khả dụng đúng vào lúc đó) và lùi về bản nâng do-§15-quản-trị, với kiểm tra phân nhánh neo-trước (bên dưới) giới hạn thiệt hại trong khoảng tạm thời.

Cửa sổ mập mờ (tham số tin cậy hạng nhất). Một chiếc lá chỉ chống lại sự mập mờ khi mỏ neo bọc của nó là Arweave-đã xác nhận. Cửa sổ thì received_at → anchor confirmation (chuỗi nhịp + tính cuối cùng của Arweave, mà không có đảm bảo độ trễ của giao thức). Trước khi cung cấp gốc tin cậy, triển khai hiện tại cung cấp tính toàn vẹn hoạt động của qub cùng với bất kỳ siêu dữ liệu bổ sung nào chưa được ký; nó không cung cấp đảm bảo phi từ chối đã được lên kế hoạch. Ba hiện vật trách nhiệm xác định thiết kế hoàn chỉnh (mô hình nhân chứng là giải pháp của §16.15 Q2):

  1. Biên nhận niêm phong (phụ thuộc vào cung ứng) — bản tương tự SCT được trả về khi việc thêm nhật ký của một lần tải lên thành công (§16.10). Nó chỉ trở nên không thể chối bỏ khi sig_b64url không rỗng và mối quan hệ khóa công khai/chủ sở hữu anchor tương ứng được cố định trong bộ xác minh. Chốt hồ sơ sản xuất hiện đang trống không thể hỗ trợ phán quyết đó. Kiểm soát này không áp dụng cho một bộ biên nhận bị bỏ qua hoặc biên nhận chưa ký.
  2. Phương pháp giám sát đã xuất bản + đi theo chuỗi trước — mỏ neo prev chuỗi được đi từ đầu→nguồn gốc; một nhánh (hai mỏ neo tại một size với khác nhau root, hoặc bị hỏng prev) là bằng chứng có thể công bố về hành vi sai trái. Phát hiện sự mơ hồ là một cam kết hoạt động đã được tuyên bố, không phải là một giả định ngầm.
  3. Hai đầu tự xuất bản — mỗi đầu mới {sth_hash, tree_size} được đăng lên một qub-owned chuyên dụng kho lưu trữ GitHub công khai, chỉ cho phép thêm (chân tự xuất bản có khả năng chịu lực và chống giả mạo), với một bài đăng xã hội chỉ để xác nhận nỗ lực tốt nhất. Một bài đăng thất bại PHẢI cảnh báo (không được im lặng thất bại). Đã triển khai (Giai đoạn 8) như sau publishHead móc vào neo cron (workers/api/src/utils/heads-publish.ts): một PUT tới API nội dung mà không có một sha chỉ có thể thêm mới (một 422 nghĩa là nhánh chính đã được xuất bản, không bao giờ bị ghi đè); chọn tham gia / triển khai có kiểm soát PUBLISH_HEAD_GITHUB_{TOKEN,OWNER,REPO} và trơ cho đến khi kho lưu trữ được cung cấp. Một trang lỗi GitHub nghiêm trọng thông qua health_alert kênh và làm tăng một chỉ số lỗi bền vững (m:tlog_publish_head_fail); chính mỏ neo Arweave không bao giờ lùi lại khi xuất bản thất bại. “Không im lặng khi thất bại” được đảm bảo bởi chỉ số bền vững đó — mà bộ phận vận hành PHẢI cảnh báo trên bảng điều khiển — ngay cả khi trang email nỗ lực tốt không thể gửi được. Hai hạn chế trung thực xuất phát từ “neo-trước-khi-tiến” (cron chỉ xuất bản khi kích thước tăng): một sự cố tạm thời của GitHub để lại một khoảng trống trong chuỗi đầu đã xuất bản cho kích thước đó — có giới hạn, không im lặng (nó phân trang), và vì mỗi đầu cam kết một cây tập hợp siêu, một bằng chứng nhất quán §16.9 bắc cầu khoảng cách; quan trọng là, bằng chứng nhất quán đó được tính từ cây được neo bởi Arweave có thẩm quyền, không từ bề mặt GitHub, vì vậy khoảng trống trên GitHub không bao giờ làm suy yếu khả năng xác minh. Việc bổ sung theo kịp để lấp đầy các khoảng trống của các nhánh đã được xuất bản là một cải tiến tạm hoãn.

Trung thực bị ràng buộc (ràng buộc bắt buộc). Bởi vì qub kiểm soát cả hai bề mặt đăng bài được lên kế hoạch, đây là tự xuất bản, không được chứng kiến một cách độc lập. Không sản phẩm, tiếp thị hay bề mặt pháp lý nào có thể tuyên bố rằng nhật ký này được “chứng kiến độc lập”. Sau khi biên lai/hồ sơ/cổng chính được cung cấp, tuyên bố được phép là sự lập lờ có thể phát hiện được và một phụ lục được ký thành công để lại biên nhận không thể từ chối. Trước đó, yêu cầu đó không khả dụng. Một nhân chứng bên thứ ba độc lập thực sự sẽ được hoãn lại cho một nâng cấp quản trị §15 trong tương lai.

received_at do người vận hành khẳng định và không tuyên bố nào được dựa vào nó — nó không bao giờ được trưng ra như bằng chứng hay như chứng-thực tranh chấp trên bất kỳ bề mặt sản phẩm / pháp lý / API / hiển-thị-bằng-chứng nào. Thời gian khối neo Arweave T là dấu thời gian không-cần-tin-cậy duy nhất (một cận trên trên "đã được ghi nhật ký bởi"). Bất kỳ kiểm tra-tỉnh-táo giám sát nào trên received_at PHẢI so sánh đối với T, không phải đối với trường STH anchored_at do người vận hành kiểm soát; một kiểm tra như vậy chỉ là một hàng rào chống một lỗi đồng hồ của người vận hành trung thực, không phải một kiểm soát quy trách đối với một người vận hành ác ý (§16.15 Q5).

16.7 Định dạng giao dịch neo và nhịp

AnchorBundle là thân giao dịch Arweave dạng CBOR-chuẩn, được ghi qua bộ-gom-bó §16.8: ver:u8, sth:bstr (các byte SignedTreeHead chuẩn), prev_anchor:bstr (id giao dịch neo trước dạng byte thô; bị loại bỏ tại khởi nguồn), chain_hash:tstr (chuỗi drand đang hiệu lực — quicknet), và luồng lá-CBOR của lô theo thứ tự seq để cái neo tự-chứa: một bộ giám sát tái-suy-dẫn root từ thân với phụ thuộc vào qub bằng không. (Nếu luồng lá trở nên lớn ở khối lượng cao, một bản sửa đổi tương lai có thể chỉ cam kết một dải lá bằng tham chiếu; được ghi nhận, không được áp dụng trong v1.)

Các tag Arweave cố ý có thể liệt kê — nhật ký được dành để được tìm thấy, khác với các qub riêng tư: App-Name: qub-tlog, Anchor-Format: 1, Log-Id: <hex>, Batch: <n>, Tree-Size: <n>, Root: <hex>, Prev-Anchor: <tx>, Content-Type: application/cbor. Các tag là các gợi ý không tin cậy; thân CBOR là thẩm quyền duy nhất.

Nhịp điệu: hàng ngày theo mặc định, được xem lại với khối lượng (kích hoạt kích thước tự động rút ngắn nhịp điệu hiệu quả khi chịu tải). Nhà sản xuất hiện tại không triển khai móc neo lực đóng dấu trả phí. The ví Anchor được dành riêng và có tốc độ thấp, tách biệt với ví tải lên — NÓ PHẢI là của nó JWK riêng (một khóa riêng biệt, không phải là vai trò logic trên ví tải lên) để việc xâm nhập ví tải lên không thể giả mạo các điểm neo — với ngân sách giao dịch neo cứng theo ngày. Tư thế quản lý lưu giữ được nêu rõ ràng: một phím tắt phạm vi hẹp với bộ ngắt mạch chặt chẽ và cân bằng thấp, không phải “lạnh” — một ví tự động ký hàng ngày không thể là lạnh, và đặc tả không giả vờ khác đi.

16.8 Bộ gom bó ANS-104

Một bộ mã hóa DataItem ANS-104 và bộ ký deep-hash tự xây, khoảng 300 dòng, chỉ Web Crypto, không phụ thuộc npm nào (cả hai Turbo SDK đều trượt cổng chuỗi-cung-ứng npm ci --ignore-scripts). Bố cục byte của 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

Việc ký là deepHash của Arweave — một bản tóm tắt SHA-384 đệ quy (yêu cầu wire của Arweave, crypto.subtle.digest("SHA-384")) trên ["dataitem", "1", sig_type, owner, target, anchor, encoded_tags, data] — rồi RSA-PSS trên deep hash với JWK của ví thông qua crypto.subtle; id = base64url(SHA-256(signature)). SHA-384 ở đây được cách ly như một nguyên thủy chỉ-dành-cho-wire-Arweave, không bao giờ là một nguyên thủy tin cậy của qub (§15 ghi lại hàng rào; băm tin cậy của qub là SHA3-256 xuyên suốt).

Đường dẫn mã ANS-104 phục vụ cho cơ chế dự phòng/trì hoãn và ghi AnchorBundle DataItems. Con đường xuất bản thông thường trước tiên tạo một giao dịch Arweave đã ký chính xác và giữ JSON của nó trong một hộp thư ra bền vững; đăng trực tiếp là một tối ưu hóa độ trễ, và con đường xả sẽ thử lại cùng một giao dịch trước khi áp dụng phương án dự phòng của bộ ghép. Sơ đồ chữ ký (đã giải quyết — §16.15 Q8): v1 ký bằng RSA-PSS (loại chữ ký 1) tái sử dụng cơ chế JWK của ví Arweave hiện có (không quản lý khóa dài hạn mới nào, phục vụ cho luận điểm "ít bí mật hơn"); Ed25519 được hoãn sang lộ trình PQ-migration §15.

Deep hash tự-cuộn là mã rủi-ro-cao-nhất, độ-phủ-tự-nhiên-thấp-nhất trong W5, nên việc kiểm soát nó là không thể thương lượng (§16.15 Q8):

  1. Vector kiểm tra đa-ngôn-ngữ tlog_v1.json (Rust + TS, mẫu wrapper_v1.json của §14.5) bao phủ deep-hash, các byte DataItem + id, các băm lá, một gốc 5-lá + đường kiểm toán, một băm STH, một bằng chứng đưa-vào, và một bằng chứng nhất quán — theo cả hai chiều ký và xác minh (chiều xác minh quan trọng vì kiểm tra cục bộ tx → tx_id của §16.6 kéo deep hash vào mọi trình xác minh độc lập, không chỉ người ghi).
  2. Một lần kiểm tra liên-thông quay-vòng một lần qua một bộ-gom-bó ANS-104 tham chiếu, được tiêu thụ dưới dạng chỉ dữ liệu kiểm tra tĩnh — không bao giờ là một phụ thuộc thời-gian-chạy npm (tư thế chỉ-Web-Crypto / không-script-cài-đặt đứng vững).
  3. Đường deep-hash + RSA-PSS phải quay-vòng qua cùng các nguyên thủy crypto.subtle mà production dùng, để bộ mã hóa tự xây tương thích byte.
  4. Một bộ giám sát chấp nhận sau-gom-bó liên tục xác nhận mỗi DataItem neo / dự phòng thực sự đạt được sự chấp nhận của Arweave, với một báo động + ngắt mạch — vì deep hash cũng phục vụ hàng đợi dự phòng khi Arweave không khả dụng, nên một thoái lui âm thầm sẽ lấp đầy hàng đợi đó bằng các mục bị-mạng-từ-chối đúng vào lúc gián đoạn mà nó tồn tại để bao phủ.

16.9 Bằng chứng đưa-vào và bằng chứng nhất quán

Cả hai đều theo RFC 9162, SHA3-256, được phục vụ dưới dạng CBOR chuẩn.

InclusionProof — GET /api/v1/qub/:tx_id/proof: ver:u8, leaf:bstr (CBOR lá chính xác — trình xác minh tự tính lại leaf_hash và không bao giờ tin một băm được cung cấp), 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. Một danh sách khóa rõ ràng duy nhất, được ghim bởi vector kiểm tra.

Xác minh độc lập (không có máy chủ qub, mở rộng §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).

Nơi lưu trữ phục vụ bằng chứng PHẢI được khóa theo tọa độ (đã giải quyết — §16.15 Q7, điều kiện tiên quyết chặn). Việc sinh bằng chứng cho lá-nguội là trung-lập-về-tính-đúng-đắn chỉ khi vật liệu kiểm toán R2 là một kho nút Merkle bền vững được khóa theo tọa độ cây tuyệt đối (level, index) — không phải các delta nút theo từng batch. Với một kho được khóa theo tọa độ, bất kỳ đường kiểm toán (leaf i, size N) nào cũng là một tập hợp O(log N) phép GET R2 trực tiếp với không tính-lại nào qua các ranh giới lô; với một kho được khóa theo lô thì không, đó chính là khoảng-trống-bố-trí-lưu-trữ mà cách giải quyết này đóng lại. Các thân lá cũng tương tự có thể địa-chỉ-hóa-theo-nội-dung bởi seq. Một vector kiểm tra W5 PHẢI chứng minh một lá nguội thời-khởi-nguồn đối với một gốc muộn-hơn-nhiều chỉ dùng R2 + Arweave với kho lưu trữ LogDO bị xóa sạch, để tuyên bố an-toàn-thu-hồi trong §16.13 được chống lưng thay vì khẳng định. Các phép GET R2 tuần tự O(log N) chỉ thuộc về riêng điểm cuối bằng chứng bất đồng bộ — không bao giờ trên đường nóng niêm phong (§16.10) hay một cron theo-mỗi-tick.

16.10 Thứ tự xác nhận R2-trước

Đã được triển khai POST /api/v1/upload chuỗi là:

  1. Cổng nửa trước (xác thực, kiểm tra, khóa phân mảnh idempotency) — không thay đổi.
  2. Tạo, gắn thẻ và ký giao dịch Arweave cá nhân chính xác. Điều này xuất phát tx_id cục bộ, mặc dù việc tạo giao dịch có thể lấy siêu dữ liệu phần thưởng/mỏ neo từ một cổng. Một sự cố chuẩn bị vẫn sẽ làm yêu cầu thất bại trước khi được xác nhận.
  3. Đồng bộ ghi tác phẩm được chọn tại qub-cache/<tx_id> và lưu trữ các bản ghi tạo-thao tác/ hộp thư đi ổn định. Đây là mức độ bền và thử lại cơ bản; các lỗi trước khi hoàn tất sẽ trả về 503.
  4. Khi LOG_DO được cấu hình, cố gắng đồng bộ LogDO.append(leaf). Người viết đơn độc chỉ định seq, mở rộng chuỗi mục nhập, và cập nhật biên. RPC append chỉ làm đúng điều đó; batch close chạy ngoài đường trên cảnh báo. Hiện tại, lỗi truyền nhận/ứng dụng append thất bại-mềm: phản hồi vẫn có thể thành công mà không cần log_seq, receipt, hoặc anchor_status. Mặc dù có một bình luận về việc triển khai, nhưng hiện nay không có sự điều chỉnh nhật ký tự động sau này nào được kết nối.
  5. Trả lại sự công nhận. Bao gồm { log_seq, anchor_status: "pending", receipt } chỉ khi append trả về tuple thành công hoàn chỉnh. receipt.sig_b64url trống khi người ký biên nhận không có mặt; khách hàng KHÔNG ĐƯỢC gọi giá trị đó là đã ký hoặc không thể chối bỏ. Việc không có bộ đôi có nghĩa là chỉ công bố bền vững, không phải chấp nhận bởi nhật ký minh bạch.
  6. Sử dụng một tác vụ trì hoãn để đăng giao dịch đã ký chính xác. Thành công sẽ xóa hộp thư đi; thất bại sẽ để lại cho cron xả có giới hạn và không được thay đổi những mục đã được xác nhận tx_id. Dữ liệu tạm thời và các phần phụ trợ nỗ lực tốt nhất khác cũng được hoãn lại.

Ranh giới độ trễ. Đường dẫn yêu cầu bao gồm công việc quyền/định mức nửa trước, chuẩn bị/ký giao dịch, ghi R2 bền vững, và (khi được cấu hình) LogDO cố gắng. < 300 ms xuất hiện trong đánh giá thiết kế như một mục tiêu vận hành, không phải là đảm bảo giao thức; bước chuẩn bị giao dịch hiện tại có thể thực hiện yêu cầu siêu dữ liệu cổng. Cảnh báo độ trễ và cổng khởi chạy là các kiểm soát vận hành, không phải là bằng chứng có sẵn cho người xác minh.

16.11 Mô hình tin cậy — tuyên bố chính xác, được phạm-vi-hóa theo loại lá

Đối với kind=0x01 (đã chứng thực): "Nội dung này — thân khớp với body_hash, được định danh bởi qub_id — đã được cam kết vào nhật ký chỉ-thêm của qub tại vị trí seq và đã tồn tại không muộn hơn thời gian khối Arweave T; nó không thể đọc được về mặt mật mã cho đến vòng drand R = unlock_round(unlock_at)." Đây là bộ ba {ràng buộc vòng tlock + đưa-vào Merkle + gốc đã neo} đầy đủ.

Đối với kind=0x02 (đã khẳng định, mặc định): "Một ciphertext mờ với địa-chỉ-nội-dung chash, tuyên bố qub_id và unlock_at, đã được cam kết vào nhật ký chỉ-thêm tại vị trí seq và đã tồn tại không muộn hơn thời gian khối Arweave T." Các chân vòng và thân được cung cấp bởi việc xác minh gói .qub §11 hiện có (qub_core::unlock), không phải bởi nhật ký; cái mà nhật ký thêm vào so với một giao dịch trần cho mỗi-qub là thứ tự chống-can-thiệp, một thời điểm cam kết cận-trên không-cần-tin-cậy, và khả năng chống nói-nước-đôi.

Cả hai tuyên bố đều loại trừ, theo §11: quyền tác giả mà không có sig_alg ≥ 0x01, ý định, và định thời ở độ chi tiết dưới-cấp-neo. Không tuyên bố nào được dựa vào received_at.

Yêu cầu trần (ràng buộc khởi động — đã được giải quyết §16.15 Câu 1). Đối với một tuyên bố (kind=0x02) lá, tuyên bố phạm vi ở trên là trần nhà trên bất kỳ bề mặt nào của sản phẩm, marketing, điều khoản hoặc việc hiển thị bằng chứng có thể khẳng định. Không bề mặt nào được tuyên bố hoặc ám chỉ rằng bản ghi chứng minh nội dung hoặc vòng mở khóa của một tải lên mù byte — bản ghi chứng minh thứ tự + thời gian cam kết giới hạn trên không tin cậy của một bản mã hóa tối. Bằng chứng nội dung và vòng chỉ đến từ §11 hiện có. .qub-xác minh gói, không phụ thuộc vào nhật ký. Một bài xuất bản mà không có việc ghi thêm/nhận thành công sẽ không có bất kỳ yêu cầu nhật ký nào cả.

16.12 Phiên bản hóa và phối hợp W3

Có không SealedQub gối dây vì vậy không tăng phiên bản giao thức (§12.2): nhật ký là một sidecar cam kết với các trường và byte hiện có, vì vậy nó không tham gia vào lịch sử phiên bản giao thức §12.3. Tùy chọn của W3 drand_chain_version không bị ảnh hưởng và vẫn là lựa chọn duy nhất SealedQub lĩnh vực. Thay vào đó, nhật ký giới thiệu các không gian phiên bản độc lập riêng của nó — LOG_VERSION_1, ANCHOR_FORMAT_1, InclusionProof.ver — phản chiếu sự độc lập về phiên bản bao bọc §12.5 (bao bọc mang một byte phiên bản độc lập với phiên bản giao thức, và các phiên bản nhật ký tuân theo cùng sự tách biệt này).

Việc phân phối bằng chứng được fetch theo mặc định, với một tùy chọn đi-kèm. Một bằng chứng không thể tồn tại tại thời điểm niêm phong (cái neo chưa được ghi), nên gói .qub tại thời điểm niêm phong vẫn không-có-bằng-chứng. Trình xác minh của W7 fetch GET …/proof một lần, hoặc ở chế độ hoàn-toàn-ngoại-tuyến tái dựng bằng chứng từ AnchorBundle công khai thông qua một truy vấn Arweave trên Log-Id. Gói .qub (W7) dành riêng một thành viên inclusion_proof tùy chọn — vắng mặt tại thời điểm niêm phong, được điền bởi một lần tái-xuất sau-neo cho lưu trữ nguội — theo cùng mẫu "tùy chọn, bị loại bỏ theo mặc định, bổ sung" như drand_chain_version của W3.

16.13 Lưu giữ

Các cửa sổ lưu giữ cho phần đuôi mở của LogDO, nền phục-vụ-bằng-chứng R2, các bộ đếm ngắt-mạch neo, và hàng đợi dự phòng của bộ gom bó được đặc tả trong docs/DATA-RETENTION.md. Nguyên tắc: nơi lưu trữ nóng theo-mỗi-mục của nhật ký (LogDO) có thể thu hồi sau-neo; vật liệu kiểm toán của nó — kho nút Merkle được khóa theo tọa độ (level, index) + các thân lá được địa-chỉ-hóa-theo-seq (§16.9) + các cái neo Arweave — là vĩnh viễn. Việc thu hồi một lá nguội khỏi DO không bao giờ làm vô hiệu một bằng chứng đã phát hành, vì một bằng chứng phân giải đối với kho nút R2 vĩnh viễn đó và cái neo Arweave, không phải DO (và vector kiểm tra DO-bị-xóa-sạch của §16.9 chứng minh điều đó).

16.14 Các vector kiểm tra

W5 phát hành vector kiểm tra đa-ngôn-ngữ tlog_v1.json (§16.8) cộng với các vector đã-tính-toán: một lá kind=0x01 và một lá kind=0x02 → leaf_hash; gốc tích lũy 5-lá; một bằng chứng đưa-vào; một bằng chứng nhất quán; một AnchorBundle; và một id DataItem. Chúng nằm cạnh các vector lớp-bao-bọc-bên-ngoài §14.5 và được vận dụng bởi cả hai triển khai Rust (qub-core) và TypeScript (Worker).

16.15 Xem xét Quyết định (W5 — đã giải quyết)

Đánh giá ngoại bộ W5 (một lần kiểm tra thiết kế đối kháng + xác nhận của chủ sở hữu) đã hoàn tất. Mỗi quyết định dưới đây đã được giải quyết và phản ánh trong văn bản §16 ở trên; ràng buộc khởi động được nhắc lại vào cuối. Việc thực hiện có thể tiến hành theo chúng.

  1. Đường dẫn mặc định (kind=0x02) lá trung thực — ĐÃ GIẢI QUYẾT. Vận chuyển loại hai lá đã tách ra như đã chỉ định: kind=0x02 không cam kết nào cả body_hash cũng không drand_round. Không *_body_hash trường trên đường dẫn mù byte (nó sẽ là tín hiệu “xác thực” giả dễ đọc nhất cho các bộ tích hợp và là một tiện ích mà §11 đã cung cấp từ gói). Làm không yêu cầu dấu niêm phong máy chủ cho qubs được chứng thực bằng nhật ký (điều đó sẽ buộc văn bản thuần đi qua Worker và phá hủy rào cản xé nát mật mã). Bất kỳ mạch tắt tự mô tả nào đều thuộc về .qub gói / phong bì bằng chứng như một trường được tái tính toán bởi người xác minh, không bao giờ là trường lá. Trần yêu cầu được xác nhận bởi chủ sở hữu: §16.11.
  2. Trách nhiệm về nói nước đôi / bỏ sót — THIẾT KẾ ĐÃ HOÀN THÀNH, CUNG CẤP CHƯA ĐẦY ĐỦ. Thiết kế yêu cầu chìa khóa niêm phong-biên nhận phải được ghim vào LogProfile và được ký chéo bởi anchor_owner, cộng với phương pháp giám sát, đi bộ chuỗi trước, và hai đầu tự xuất bản. Hồ sơ đã biên dịch và các hook triển khai vẫn là chỗ giữ chỗ/tùy chọn như chi tiết trong §16.6, vì vậy yêu cầu có thể phát hiện + có biên nhận mạnh hơn hiện tại chưa áp dụng cho đến khi các cổng đó đóng lại. Nó không bao giờ được quảng cáo là được chứng kiến độc lập. Một nhân chứng bên thứ ba thực sự được hoãn lại đến một nâng cấp quản trị §15.
  3. Gốc tin cậy của chủ sở hữu mỏ neo đã được ghim + xoay vòng — ĐÃ GIẢI QUYẾT. Nhận nuôi LogProfile chốt (§16.6); người kiểm chứng kiểm tra anchor_tx.owner == anchor_owner và xác minh dữ liệu tx → liên kết tx_id tại chỗ. Quản trị xoay vòng là một §15 phần mở rộng để xây dựng (§15.3 kích hoạt được thêm), không phải tái sử dụng; các lượt xoay dự kiến sẽ ký chéo, các lượt xoay dựa trên thỏa hiệp sẽ quay lại §15 với kiểm tra nhánh để giới hạn thiệt hại.
  4. Mù lá Private-qub — ĐÃ GIẢI QUYẾT. Tiếp tục làm mù cho các qubs riêng tư (ref = SHA3-256(qub_id ‖ log_blind_secret)), sống qub_id cho các qubs công cộng (đã §16.2.1), chash như chiếc cà vạt độc lập. log_blind_secret là một bí mật cấp độ tương quan/Sybil, chỉ xoay về phía trước (§16.2.1).
  5. received_at — ĐÃ QUYẾT ĐỊNH. Giữ nó trong lá, cam kết nhưng rõ ràng không phải bằng chứng; không bao giờ xuất hiện như bằng chứng hoặc sự xác nhận tranh chấp trên bất kỳ bề mặt nào. Bất kỳ kiểm tra sự tỉnh táo của bộ giám sát nào cũng so sánh với thời gian khối Arweave T, không phải do người điều khiển anchored_at (§16.6).
  6. Thời gian chứng minh phân tầng — GIẢI PHÁP THIẾT KẾ, KHÔNG PHẢI ĐƯỜNG DẪN HIỆN TẠI. Thiết kế đã được xem xét phân công thời gian khối neo cho tầng theo lô và bằng chứng giờ chính xác cho T3 trả phí, không có SLA số học cho tầng trước. Các tuyến hiện tại chưa kết nối phân biệt thương mại đó: chúng lập lịch một giao dịch riêng lẻ cho mỗi ấn phẩm được chấp nhận, và ghi nhận phạm vi vẫn phụ thuộc như được nêu trong §16.1/§16.10. Bản sao sản phẩm phải mô tả việc triển khai, không phải sự phân tách tầng trong tương lai này.
  7. Cây tích lũy về Công nhân — ĐÃ ĐƯỢC GIẢI QUYẾT. Cây RFC 9162 tích lũy đơn + LogDO chỉ-viết-đơn được lưu vào bộ nhớ đệm biên (khoảng trống thoải mái so với trần ~1k ghi/giây của DO; hoãn sharding Merkle-của-các-gốc-mảnh cho đến khi gần đạt giới hạn đó). Các khóa-điều phối (level, index) R2 node store + vectơ kiểm tra lá lạnh wiped-DO được triển khai (§16.9). < 300 ms vẫn là một mục tiêu về thiết kế/vận hành, không phải là một lời hứa về giao thức (§16.10).
  8. Sơ đồ chữ ký ANS-104 + băm sâu — ĐÃ GIẢI QUYẾT. RSA-PSS (loại chữ ký 1, tái sử dụng JWK ví neo chuyên dụng); Ed25519 được hoãn sang đường dẫn PQ §15. Hàm băm sâu SHA-384 tự chế được kiểm soát bởi tính năng chéo cả hai chiều, kiểm tra tương tác bộ liên kết tham chiếu chỉ tĩnh, chia sẻ-crypto.subtle khứ hồi, và bộ theo dõi chấp nhận Arweave sau gói (§16.8).

Ràng buộc khởi chạy (thực hiện + kiểm tra sản phẩm/pháp lý):


17. Gói Xác Thực Di Động (.qub)

Trạng thái. Phần này là thực hiện (W7 / UP-C2): qub_core::export tạo và phân tích gói, và tools/qub-verify là một CLI công khai, tự chứa mà xác minh ngoại tuyến. §11 và §16.9 đã đề cập đến "the" .qub "gói" là đơn vị mà một trình xác minh độc lập sử dụng; phần này xác định số byte của nó và hướng dẫn kiểm tra. Nó hoàn toàn bổ sung — gói đóng gói các đầu vào §11 hiện có và không thay đổi định dạng truyền tải trên chuỗi.

17.1 Mục đích

§11 quy định rằng bất kỳ bên thứ ba nào cũng có thể xác minh hiện vật mật mã của qub mà không cần sự hợp tác của qub. The .qub gói thực hiện việc xác minh đó di động và ngoại tuyến: nó đóng gói CBOR đã được niêm phong và chữ ký vòng drand mở khóa nó thành một hiện vật tự chứa duy nhất, để người nhận có thể xác minh tính toàn vẹn của nội dung, ràng buộc vòng, và bất kỳ chữ ký tác giả nào với không có cuộc gọi mạng nào cả (không truy xuất lưu trữ, không yêu cầu drand trực tiếp, không API qub). Một gói riêng lẻ không chứng minh được khi nào mật văn của nó được tạo ra; một giao dịch lưu trữ được xác minh độc lập hoặc chứng minh nhật ký được neo cung cấp tuyên bố thời gian tồn tại riêng biệt đó (§11, §17.5).

17.2 Định dạng Gói

A QubBundle là CBOR chuẩn được viết tay theo hồ sơ §3.1 (chiều dài xác định, không có nhãn, không có số thực, số nguyên dạng ngắn nhất, văn bản NFC, các trường tùy chọn bị bỏ khi không có, các khóa được sắp xếp theo chiều dài byte được mã hóa tăng dần rồi theo thứ tự byte). Ba khóa 15 ký tự được sắp xếp d < i < s. Một cái sống .qub tệp chính xác là những byte này; đối với việc truyền qua URL hoặc sao chép-dán, cùng những byte này được mã hóa base64url (không có dấu pad).

Chìa khóa Đính kèm Loại Sự hiện diện Ý nghĩa
version tám u8 bắt buộc Phiên bản định dạng gói (0x01).
sealed_at tên i64 tùy chọn Thời gian đóng dấu do người tạo xác nhận (giây Unix); tự mô tả, không có giá trị làm bằng chứng.
drand_round mười hai u64 bắt buộc Vòng mà qub được khóa vào. Một phần nhô ra của qub đã được niêm phong nhúng.
arweave_tx_id mười bốn tstr bắt buộc ID giao dịch dưới đó các byte được niêm phong được lưu trữ (con trỏ nguồn gốc).
drand_chain_id mười lăm tstr bắt buộc Chuỗi drand (hex). Một phép chiếu của qub được niêm phong nhúng.
drand_signature mười sáu bstr bắt buộc Chữ ký tín hiệu đèn hiệu drand cho drand_round — giá trị mở khóa bản văn bản mã hóa.
inclusion_proof mười sáu bstr tùy chọn Bằng chứng bao gồm Merkle của log minh bạch §16, sau khi một bằng chứng đã được cố định có sẵn (§17.5).
sealed_qub_cbor mười sáu bstr bắt buộc Bên trong SealedQubCbor byte (sau khi bóc gói §13), tức là đầu vào xác minh §11.

drand_round và drand_chain_id là các dự báo tiện lợi của sealed_qub_cbor, được mang theo để công cụ có thể đọc chúng mà không cần phân tích CBOR bên trong. Chúng được tạo ra khi xây dựng và kiểm tra lại trên giải mã chống lại qub đã được phân tích và niêm phong; một gói mà trường cấp cao nhất của nó không khớp với phần tải bị từ chối. Kỷ luật mã hóa phản ánh phần còn lại của định dạng truyền dẫn: từ chối một drand_signature hoặc arweave_tx_id, và ràng buộc mọi trường có độ dài thay đổi.

17.3 Những gì chữ ký drand nhúng chứng minh

Gói đính kèm mang chữ ký drand thay vì yêu cầu người xác minh phải lấy nó. Giải mã khóa thời gian (tlock trên chuỗi drand, §8) chỉ có thể thành công với chân thật chữ ký beacon cho vòng bị ràng buộc — một giá trị mà chuỗi chỉ công bố một lần khi vòng đó kết thúc, và đó là một chữ ký BLS hợp lệ theo khóa công khai của chuỗi. Một chữ ký giả mạo hoặc sai sẽ thất bại khi xác minh BLS hoặc giải mã IBE/AEAD. Vì vậy, một gói được giải mã chứng minh: bản văn mật mã bị ràng buộc với vòng R, và vòng R đã trôi qua. Trình xác minh ghim chuỗi (DrandTimelockProvider::quicknet()) và áp dụng kiểm tra ràng buộc vòng §11, vì vậy một gói không thể tuyên bố một vòng mà văn bản mã hóa của nó không bị ràng buộc.

Đây là bằng chứng điều kiện phát hành, không phải dấu thời gian tạo. Sau khi vòng R đã đã trôi qua, bất kỳ ai cũng có thể tạo ra một bản mã mới cho R và đóng gói bản công khai đã có chữ ký. Do đó gói tài liệu riêng lẻ KHÔNG ĐƯỢC mô tả như là bằng chứng rằng văn bản mật hoặc nội dung tồn tại trước R, trước unlock_at, hoặc trước bất kỳ sự kiện nào.

17.4 Hướng dẫn kiểm tra ngoại tuyến

qub-verify <file.qub> chạy toàn bộ quy trình tiêu chuẩn §11 hoàn toàn từ gói, điều khiển qub_core::unlock::unlock với một cái ghim DrandTimelockProvider:

1. Parse the .qub bytes → QubBundle (canonical-CBOR guard; bound every field;
   re-check drand_round / drand_chain_id against the embedded sealed qub).
2. BLS-verify bundle.drand_signature for the pinned chain and round, then
   tlock_decrypt(sealed.tlock_ciphertext, bundle.drand_signature) → QubEnvelope.
3. Verify SHA3-256(body) == body_hash               (§11 step 8).
4. Verify QubEnvelope.qub_id   == SealedQub.qub_id   (§11 step 9).
5. Verify QubEnvelope.unlock_at == SealedQub.unlock_at (§11 step 10).
6. Verify ciphertext round == unlock_round(unlock_at) and the chain binding.
7. If sig_alg != 0x00: verify author_signature (and any cosigner; §9.4).
8. Report integrity, round-elapsed/round-binding, authorship, and cosigner
   verdicts separately, plus the recovered body. Do not report a commitment
   timestamp unless step 9 succeeds.
9. Optional existence-time leg: verify an included §16 proof through its pinned
   anchor, or independently verify the referenced storage transaction. Report
   its block time as an upper bound on ciphertext existence.

CLI thoát 0 (đã xác minh), 1 (xác minh không thành công — vẫn bị khóa, không khớp băm thân, liên kết vòng/dây bị hỏng, hoặc chữ ký không thể xác minh), hoặc 2 (sử dụng / gói bị lỗi). A --json báo cáo đưa ra cùng những phán quyết cho tự động hóa. Vì gói này là độc lập, thư viện xác minh (qub-core) và CLI (qub-verify) là phần mềm duy nhất mà bên thứ ba cần; cả hai đều công khai và tái sử dụng đường dẫn xác minh hiện có của giao thức — không cần mã hóa tùy chỉnh.

17.5 Mối quan hệ với nhật ký minh bạch

inclusion_proof là một trường tùy chọn cho bằng chứng bao gồm Merkle §16. Xác minh chỉ gói (§17.4) được hoàn tất cho tính toàn vẹn, liên kết tròn / tròn đã trôi, và quyền tác giả tùy chọn, nhưng cố ý không có tuyên bố tồn tại được đánh dấu thời gian một cách độc lập. Một phiên bản đã được điền dữ liệu, được xác minh đầy đủ bằng mốc neo inclusion_proof thêm cam kết cụ thể theo loại lá và thời gian giới hạn tối đa từ §16.11 mà không thay đổi phiên bản định dạng gói. Một bằng chứng vắng mặt chỉ có nghĩa là "không có bằng chứng đi kèm"—không phải là "không hợp lệ" và không nhất thiết là "không được neo".

Trong triển khai tham chiếu, khe bây giờ là đã gõ: qub_core::export::QubBundle::inclusion_proof_typed() trả về một Option<InclusionProof> mang toàn bộ cấu trúc §16.9 (lá, đường dẫn kiểm toán, gốc neo, và AnchorRef) thông qua cùng một trường CBOR mờ — không tăng phiên bản định dạng gói. Riêng lẻ qub-verify CLI tiêu thụ nó thông qua --anchor chân, và — cho đến khi ví neo được cung cấp (§16, Trạng thái) — báo cáo một chứng minh chủ sở hữu đã được điền nhưng chỉ là chỗ giữ chỗ như chỉ bao gồm thay vì hoàn toàn được xác minh neo.