Rand Protocol
文檔
核心概念

帳戶與地址

鏈上兩類密鑰、受保護的 rand1 地址如何推導、viewing key 披露哪些資料,以及鏈 11 的短地址為何被撤回。

使用本頁可為不同用途生成正確的密鑰、解析或驗證地址,並了解把密鑰交給他人會披露甚麼。此鏈上沒有帳戶:餘額是關於密鑰檔案的事實,而非關於鏈的事實。

兩種密鑰,兩種地址

節點密鑰錢包密鑰
由何者寫入rand-node keygenrand keygen
秘密32 字節種子256 位花費密鑰
公開身份32 字節地址,base58,32 至 44 個字元屏蔽地址,rand1…,1,665 或 1,666 個字元
簽署區塊、投票、faucet 鑄造、Unbond、Withdraw、Registration,自 chain 20 起還有 AdmitValidator 投票,並在 chain 21 上簽署多重簽名帳戶的付款與輪換,以及 SetRandPrice 投票;作為代幣 Key 鑄造授權者時,簽署 TokenMint 與 SetAuthority。自 chain 20 起,這些訊息每一項還涵蓋創世雜湊(Transactions)無:轉帳由其證明授權
在鏈上的呈現區塊提議者、驗證者登記冊中的一行、faucet 鑄造的鑄造者、代幣的 key 授權者從不出現在轉帳中,在轉帳裏它被封存於信封之內。在價值以公開金額進入池之處會被公佈:橋接存款、代幣鑄造,以及自 chain 20 起的 invoke 支付,均會指明收款人的地址;驗證者的收款地址記錄於登記冊中;chain 20 的創世區塊指明橋的費用金庫;自 chain 14 起,faucet 鑄造與創世 alloc 票據會公佈擁有者的 pk,即地址的前 32 字節
檔案{ "seed", "address", "public_key" },權限 0600{ "version": 2, "spend_key": "<64 hex>" },權限 0600

兩者從不混用。驗證者由第一種密鑰識別,同一種 Dilithium2 密鑰形態也用於代幣的 Key 鑄造授權者(rand token create --authority-key-out 會寫出一個形態與 rand-node keygen 相同的檔案)、橋的暫停密鑰及其六個後量子守護者密鑰。守護者的證明密鑰為 secp256k1,採用 Ethereum 風格的 20 字節地址(Bridge)。價值則由第二種密鑰持有。

透明地址

節點密鑰是一個 32 字節種子,由它確定性地派生出一對 Dilithium2 密鑰:1,312 字節的公鑰與 2,420 字節的簽名。地址是公鑰經域分隔的 BLAKE3 雜湊,以 base58 表示:

address = blake3("rand-address" || public_key)      // 32 bytes, shown as base58

已簽署的對象(投票、區塊、鑄造、質押操作)均附帶完整公鑰,因此驗證者檢查的是 blake3("rand-address" || public_key) == address,而不是信任一個孤立的地址。同一個種子還會產生節點的 libp2p 身份,即由 blake3("rand-p2p-identity" || seed) 得出的 ed25519 密鑰,它就是引導 multiaddr 中 /p2p/ 之後的 peer id。

rand-node keygen --out node.key.json      # prints the address
rand-node address --key node.key.json     # address, public key (hex), libp2p peer id

示例:EdrEC2QRQrQF64iRXxF9927jNj6RidiHHByzx5xD6F1e 是 chain 21 的驗證者之一。Chain 15 至 21 沿用為 chain 14 輪換的十八把密鑰,因此其地址與 peer id 不變,而 chain 13 的驗證者地址與 peer id 已無一仍在使用;chain 15 上另有八名驗證者完成質押加入,自 chain 16 起,全部 26 名均載於創世檔案中。

屏蔽地址

錢包只有一個秘密,即 256 位花費密鑰 sk,其餘一切均由它派生。派生採用 Poseidon2,並以域標籤作為首個吸收的字(H(domain, msg)),與 zkVM 在電路內計算的是同一個函數:

spend key   sk                          256 bits, in wallet.key.json
   │
   ├─ viewing key   nk = H(NK, sk)      sees the whole history; cannot spend
   │     ├─ pk = H(PK, nk)              the field a note names its owner by
   │     ├─ nullifier(cm) = H(NF, nk, cm)   what a spend publishes
   │     ├─ ovk                         opens envelopes this wallet sent
   │     └─ ML-KEM-768 decapsulation key    opens envelopes sent to this wallet
   └─ address   rand1 + base58(pk || kem_ek)

地址是 pk 的 32 字節,後接 1,184 字節的 ML-KEM-768 封裝密鑰,在 rand1 前綴之後以 base58 表示:1,665 或 1,666 個字元(base58 的長度取決於開頭的字節;約十四個地址中有一個是較短的),約 1.6 KB,且沒有校驗和。發送者需要封裝密鑰來封存票據信封,這就是它包含在地址中的原因。它按設計是公開的:任何人都可向其付款,而持有它並不透露其中持有甚麼。

rand keygen                      # wallet.key.json; refuses to overwrite an existing file
rand address                     # rand1… on stdout, its fingerprint XXXX-XXXX-XXXX-XXXX on stderr

自 v0.5.10 起,rand address 在 stdout 上只輸出地址及一個換行符,因此 $(rand address) 可在腳本中使用。指紋則輸出至 stderr。

解析方式與 ShieldedAddress::parse 完全一致:去掉 rand1,進行 base58 解碼,並要求恰好為 32 + 1,184 = 1,216 字節;前 32 字節是以八個小端序 u32 字表示的 pk,其餘為封裝密鑰。RPC 會在解析之前拒絕任何長於 2,000 個字元的參數。

錢包會在密鑰檔案旁保存 <key>.key.json.notes.json,這是此密鑰已打開的票據的快取。它包含票據明文,因此與密鑰一樣以權限 0600 寫入;其中每一行都可以從 leaf 0 重新掃描而恢復。

分享地址:指紋與 randpay: 連結

地址太長,無法朗讀或憑肉眼比對,且沒有校驗和,因此自 v0.5.10 起,每個錢包都在地址旁顯示一個指紋。指紋僅供顯示:鏈上與網絡傳輸中均不攜帶任何指紋。

fingerprint = first 80 bits of blake3("rand-address-fingerprint-1" || pk_bytes || kem_ek)
            = 16 Crockford base32 characters, shown as XXXX-XXXX-XXXX-XXXX

雜湊涵蓋的是地址所編碼的 1,216 個原始字節。字母表為 0123456789ABCDEFGHJKMNPQRSTVWXYZ;解析時忽略大小寫與連字號,並將 O 讀作 0,將 I 或 L 讀作 1。

randpay: 連結攜帶一個地址,並可選擇性地附帶付款內容:

randpay:<rand1…>[?amount=<decimal>][&asset=<index | 64 hex | rpl1…>][&memo=<percent-encoded UTF-8>]

amount 以資產的顯示單位計(RAND 為九位小數的十進制數,代幣則按其登記冊行自身的 decimals),且不得為零。memo 至多 510 字節的 UTF-8。協議名稱的匹配不區分大小寫;未知參數、重複參數或錯誤的百分號編碼均會被拒絕。

rand address --uri --amount 1.5 --memo "invoice #42" --qr   # a randpay: link, as a terminal QR
rand contacts add alice rand1q9f…                            # shows the fingerprint, asks add? [y/N]
rand send alice 1.5 --memo "coffee"                          # to a contact, with a memo

rand send <TO> 接受 rand1… 地址、randpay: 連結或已儲存聯絡人的名稱,並按此順序嘗試。連結中的 amount、asset 與 memo 會補上命令行所缺的內容,而以兩種方式給出且互相矛盾的值會被拒絕。在生成證明之前,send 會輸出 to <contact, if any> · fingerprint XXXX-XXXX-XXXX-XXXX · <amount> <asset> 並詢問確認;腳本可傳入 --yes。聯絡人儲存在密鑰旁的 <key>.contacts.json,權限 0600。備註隨票據信封一同傳送(Notes)。

不存在 rand balance <address>,也沒有餘額 RPC:鏈無法為任何人回答這個問題。錢包以其查看密鑰掃描鏈上的每一個信封來計算自己的餘額(Notes)。

可交予他人的密鑰

披露是密鑰的屬性,鏈無法強制其中任何一項。

密鑰可打開粒度
查看密鑰 nk(64 hex)錢包曾收到的每一張票據,並通過 ovk 打開其曾發出的每一張票據,連同每次花費的作廢符全有或全無,追溯既往並涵蓋日後
交易密鑰 TxKey(32 字節)恰好是它所封存的那一個信封:票據,以及自 chain 18 起的備註一筆付款
調用密鑰 K_call一次保密調用的私有輸入記錄一次調用

查看密鑰不能花費。自 chain 17 起(拆分授權),捆綁證明本身由 nk 生成,而每個捆綁還附帶第二個小型的授權證明,只有花費密鑰才能生成,並且綁定於該筆交易(Notes)。這使得受委託的證明者可以獲交 nk,從而得知錢包的全部歷史,卻無法花費;授權證明始終由錢包在自己的機器上生成。拆分並不改變地址、密鑰與既有票據。錢包每次運行時派生 nk,且從不儲存;每個 TxKey 針對每個信封重新抽取,並在封存後丟棄。可通過 rand_importViewingKey 將查看密鑰交給節點(保存在記憶體中,每個節點至多 64 個,重啟後消失),使其代持有者掃描,這就是瀏覽器的路徑;rand_checkTransaction(hash, key) 則以一次無狀態調用,對照 TxKey 檢查一筆付款。rand viewing-key 輸出 nk,而 rand tx-key <hash> 則輸出此錢包可打開的某筆交易中每個輸出的密鑰。

代幣 id 不是地址

RPL 代幣有第三種文字標識符,它指代的是代幣,而從不指代持有者。代幣的 32 字節資產 id 以 64 個 hex 字元及 rpl1… 表示:即 bech32m(BIP-350),人類可讀部分為 rpl,涵蓋 32 個 id 字節,52 個數據字元加 6 個字元的校驗和,共 62 個字元。解析是嚴格的:校驗和錯誤、人類可讀部分不同、載荷不是恰好 32 字節,或大小寫混用,均會被拒絕,因此輸入錯誤絕不會解析為另一個代幣。票據並不攜帶 id;其 asset 字是代幣的緊密登記冊索引(RPL tokens)。

橋的收款人

橋的傳輸格式有一個 32 字節的收款人欄位,而屏蔽地址放不進去。現時該欄位攜帶的是地址的雜湊:

recipient_hash = blake3("rand-shielded-recipient" || pk_bytes || kem_ek)

源鏈上的存款人指明該雜湊,守護者對其簽名,而 BridgeAttest 交易則攜帶完整地址,供帳本對照該雜湊檢查(Bridge)。

短屏蔽地址:曾於 chain 11 試行,已回退

Chain 11(fullnode 標籤 v0.2,2026-09-17)以長度為 53 至 55 個字元的接收者標識符(receiver id)取代了長地址,其格式為 rand1 + base58(blake3(receiver signing key) ‖ checksum),並將 ML-KEM 封裝密鑰移入一份已簽署的接收者記錄(receiver record),發送方須從瀏覽器的登記表取得,或在付款請求中以內嵌方式收到。該設計僅運行一日,即於同日撤回(fullnode 17db41d);chain 12 恢復使用長地址,與上文所述完全一致,其後的每條鏈(包括 chain 20)均沿用長地址。

撤回的原因。接收者標識符是一個哈希值,發送方無法將 note 封存至哈希值。向從未登記的錢包作首次付款時,接收者須提供付款請求或記錄檔案;而登記本身須以自我轉賬支付,全新的空錢包無法做到這一點。兩種傳遞途徑亦會讓登記表得知誰即將收款。若要兼顧短地址、無條件可發送性與密碼學層面的私隱,可行的設計是混合地址:內嵌一個 32 字節的 X25519 密鑰(約 93 個字元),後量子密鑰則透過查詢取得;向未登記錢包的首次付款可抵禦經典敵手,其後每一次付款均完全具備後量子安全性。該設計將於下一節說明;在其推出之前,長地址即為正式地址。

Chain 11 的規格及其實作仍保留於 fullnode 的歷史記錄中(docs/superpowers/specs/2026-09-17-short-shielded-address.md,標籤 v0.2),以供混合設計沿用其中的部分:派生的接收者簽署密鑰、已簽署的記錄及其驗證器,以及作為鏈上狀態的登記表。

最後一次對照 fullnode 提交 c0878c3f(chain 21)核實的日期為 2026-10-12。 如代碼與本頁內容有出入,以代碼為準;請告知我們。