Verwenden Sie diese Seite, um die passende Bibliothek für die Interoperabilität mit der Chain zu wählen, um einen Parameter mit dem abzugleichen, was der Node durchsetzt, und um eine ID oder ein Commitment selbst nachzurechnen. Jeder Wert hier ist der, mit dem der Code auf chain 20 (fullnode v0.6.8) läuft.
Primitive und ihr Einsatz
| Primitiv | Parameter | Verwendung |
|---|---|---|
| Dilithium2 | öffentlicher Schlüssel von 1.312 Byte, Signatur von 2.420 Byte; Schlüsselpaare aus einem 32-Byte-Seed abgeleitet | Stimmen und Blockvorschläge der Validatoren; Faucet-Mints; Unbond, Withdraw und die Registration eines Validators; die Stimmen eines AdmitValidator (chain 20); die Aktionen der Aggregatoren; die Key-Mint-Berechtigung eines RPL-Tokens (TokenMint, SetAuthority); die postquantensicheren Mitsignaturen der Guardians der Bridge, ihr Pause-Schlüssel und, auf chain 20, die Besitznachweise der neuen Schlüssel bei einer Rotation (siehe unten) |
| ML-KEM-768 | Kapselungsschlüssel von 1.184 Byte, Chiffretext von 1.088 Byte | Versiegeln des Schlüssels pro Transaktion eines Note-Umschlags an die Adresse des Empfängers; Versiegeln eines Call-Input-Umschlags an einen Auditor; Versiegeln eines Proving-Auftrags an einen gekoppelten Prover |
| ChaCha20-Poly1305 | 32-Byte-Schlüssel, zufällige 12-Byte-Nonce vorangestellt, 16-Byte-Tag | jeder Teil eines Umschlags: Note-Inhalte, verpackte Transaktionsschlüssel, Call-Input-Transkripte; die Aufträge und Antworten eines gekoppelten Provers |
| BLAKE3 | 32-Byte-Ausgabe, stets mit einem vorangestellten Domain-String | Adressen, Transaktions-IDs, das Transaction Binding und das Call Binding, Programm-IDs, Asset-IDs von Token, der State Root und seine Merkle-Bäume, die p2p-Identität, Signaturnachrichten, Asset-IDs der Bridge, das Blinding einer Bridge-Einzahlung und die Blindings der Gebühren-Notes der Bridge |
| Poseidon2 über Goldilocks | Breite 8, Rate 4, Kapazität 4, Overwrite-Sponge ohne Padding; Nachrichtenelemente sind 32-Bit-Wörter; die 86 Rundenkonstanten sind seit dem chain-15-Cut eine Literaltabelle im Node-Quellcode (poseidon2_constants.rs), dieselben Werte, die zuvor die Seeded-Ziehung lieferte | alles innerhalb eines Beweises: Schlüssel, Note-Commitments, Nullifier, der Commitment-Baum, der Programm-Digest hc, die Input-Commitments H_IN und H_PUB, der Bundle-Digest, das Autorisierungs-Commitment |
| secp256k1 ECDSA + keccak256 | Low-s-Signaturen, Guardian-Adressen im Ethereum-Stil mit 20 Byte, mu = keccak256(keccak256(body)) | Attestierungen der Bridge-Guardians, sodass derselbe Schlüssel auf den EVM-Contracts, im Solana-Programm und auf Rand funktioniert; auf Rand braucht jede Attestierung zusätzlich das untenstehende Dilithium2-Quorum |
| bech32m (BIP-350) | Human-readable Part rpl, 32-Byte-Payload, 52 Datenzeichen + 6 Prüfzeichen = 62 | die Textform rpl1… der Asset-ID eines RPL-Tokens |
| Plonky3 batch STARK | Goldilocks p = 2⁶⁴ − 2³² + 1, hiding FRI, Blowup 8, Folding-Arity 8, 80 Queries, 20 Proof-of-Work-Bits | jeder Bundle-Beweis, Auth-Beweis und Call-Beweis; ein Bundle-Beweis und sein Auth-Beweis tragen die acht Binding-Wörter ihrer Transaktion als öffentliches Eingabesegment |
Die Zielparameter des Whitepapers weichen an einigen Stellen von dem ab, was die Implementierung ausführt (zum Beispiel der 384-Bit-Transkript-Hash des Papers gegenüber dem Poseidon2-Transkript der zkVM). Diese Seiten beschreiben den Code.
Postquantensichere Mitsignaturen auf der Bridge
Die Attestierungen der Guardians der Bridge sind secp256k1-ECDSA-Signaturen, die ein Quantengegner fälschen könnte. Seit chain 14 muss jedes BridgeAttest – eine Einzahlung ebenso wie eine Rotation der Guardian-Menge – zusätzlich ein Quorum von Dilithium2-Signaturen derselben Guardians über denselben Digest tragen:
M = "rand-bridge-pq-cosign-1" || rand_chain_id (u64 BE) || mu // 63 bytes, deterministic signing
wobei mu = keccak256(keccak256(body)) das ist, was das ECDSA-Quorum signiert. Die Rand-Chain-ID in M verhindert, dass eine Mitsignatur von testnet auf einer anderen Rand-Chain verifiziert, selbst wenn Guardian-Schlüssel wiederverwendet würden. M bindet nur die Chain-ID, auch auf chain 20: Es ist die eine signierte Nachricht, die binding_domain nicht hinter den Genesis-Hash verschoben hat, weil die Guardian-Daemons, die sie signieren, in einem anderen Repository liegen. Eine Kopie einer Chain unter derselben Chain-ID mit derselben Guardian-Menge würde die Mitsignaturen ihrer Einzahlungen akzeptieren; der Index der Guardian-Menge ist nicht in M enthalten, sodass eine Mitsignatur eine Rotation der ECDSA-Menge überdauert. Das Feld pq_signatures der Aktion ist eine Liste von PqSignature { index: u8, signature }, geprüft nach dem Prinzip „billig vor teuer“: quorum(n) ≤ len ≤ n (PqNoQuorum), Indizes streng aufsteigend (PqIndexOrder), jeder Index kleiner als n (PqIndexOutOfRange), jede Signatur genau 2.420 Byte lang (PqBadSignatureLength) und zuletzt jede Signatur verifiziert unter pq_guardians[index] (PqBadSignature). Die PQ-Signierer müssen nicht die ECDSA-Signierer sein; jedes Quorum wird für sich gezählt. Das Feld liegt innerhalb des Transaction Binding und kann daher auf einer Kopie weder entfernt noch ausgetauscht werden.
Die PQ-Menge ist das Genesis-bridge.pq_guardians – auf chain 20 acht Schlüssel zu je 1.312 Byte, wie auf den chains 15 bis 19, indexgleich mit der ECDSA-Menge des Genesis, Guardian-Menge 1 (chain 14 hatte sechs, ausgerichtet an Menge 0). Eine Rotation der ECDSA-Guardian-Menge verändert sie nie. Auf chain 14 war sie für die Lebensdauer der Chain fest; seit chain 15 enthält das Genesis die Gruppe rules_v2 der Bridge, unter der ein PQ-Quorum die gesamte PQ-Menge (RotatePqGuardians) oder den Pause-Schlüssel (RotatePauseKey) ersetzen kann, jeweils unter der rotation_nonce der Bridge. Das Genesis von chain 20 fügt bridge.rotation hinzu: Eine Rotation muss die V2-Aktion sein und die eigene Dilithium2-Signatur jedes neuen Schlüssels über dieselbe Nachricht tragen (Besitznachweis); sie wird einen Tag nach ihrer Aufnahme wirksam, sofern der aktuelle Pause-Schlüssel sie nicht abbricht (Bridge). rand_getBridgeState liefert die Schlüssel, und ein dekodiertes bridge_attest listet pq_signers, die Indizes, die signiert haben. Dasselbe PQ-Quorum autorisiert die Governance-Nachrichten der Bridge, jede ein festes Big-Endian-Layout mit der Chain-ID und einer Nonce. Auf chain 20 (Genesis binding_domain: 1) ist die Versionsziffer jeder Domain 2, und der 32-Byte-Genesis-Hash steht zwischen der Domain und der Chain-ID; die chains 14 bis 19 verwenden die -1-Formen:
| Nachricht | Domain (chains 14–19 / chain 20) | signiert von |
|---|---|---|
M_pause | rand-bridge-pause-1 / -2 | dem einen Pause-Schlüssel des Genesis (Dilithium2), der pausieren, aber nie wieder freigeben kann |
M_unpause | rand-bridge-pq-unpause-1 / -2 | einem PQ-Guardian-Quorum |
M_list | rand-bridge-pq-list-1 / -2 | einem PQ-Guardian-Quorum (ListBacking) |
M_register | rand-bridge-pq-register-1 / -2 | einem PQ-Guardian-Quorum (RegisterBridgedToken) |
M_rotate_pq | rand-bridge-pq-rotate-pq-1 / -2 | einem Quorum der aktuellen PQ-Menge (RotatePqGuardians, rules_v2-Chains); auf chain 20 zusätzlich jedem neuen Schlüssel als Besitznachweis |
M_rotate_pause | rand-bridge-pq-rotate-pause-1 / -2 | einem Quorum der aktuellen PQ-Menge (RotatePauseKey, rules_v2-Chains); auf chain 20 zusätzlich dem neuen Schlüssel |
M_cancel | rand-bridge-cancel-rotation-1 / -2, mit einem abschließenden kind-Byte | dem aktuellen Pause-Schlüssel (CancelRotation, Chains mit bridge.rotation: chain 20) |
Das STARK in Produktion
Die zkVM steht auf constraint set 8: neun obligatorische Tabellen (program, cpu, memory, alu, range, nibble, poseidon2, input, public) sowie eine keccak- und eine sha256-Tabelle, die ein Beweis nur dann enthält, wenn sein Guest den passenden Syscall aufgerufen hat, verbunden durch siebzehn Busse und bewiesen als ein Batch-STARK. Seit constraint set 7 hat jede deklarierte Tabelle mindestens 2⁷ Zeilen, und der LogUp-Abschluss jeder Tabelle wird über den siebzehnten Bus, BLIND, geblindet. Die öffentliche Schnittstelle eines Beweises besteht aus 35 Körperelementen (pv::NUM): dem Einstiegs-pc, dem Tier, den acht Ausgabewörtern, dem Programm-Digest hc (8 Wörter), dem gesalzenen Commitment auf die privaten Eingaben H_IN (8), dem ungesalzenen Digest des öffentlichen Segments H_PUB (8) und, seit constraint set 8, dem deklarierten Gas-Limit GAS_LIMIT.
| Parameter | Produktion | Anmerkung |
|---|---|---|
| FRI-Queries | 80 | die Neuabstimmung auf 27 Queries der constraint sets 3 und 4 wurde nach dem Audit vom 2026-09-12 zurückgenommen: Sie ließ ~42 bewiesene Bits übrig |
| Blowup | 8 (log_blowup = 3) | der maximale Constraint-Grad jeder Tabelle ist unter der Obergrenze von 8 festgelegt |
| Folding-Arity | 8 | |
| Proof-of-Work-Bits | 20 | |
| Soundness | 3·80 + 20 = 260 Bit vermutet (ethSTARK); etwa 86 Bit bewiesen unter Proximity Gaps | |
| Zero-Knowledge | statistisch: die LDE und das FRI-Batch-Polynom sind randomisiert, sodass sich zwei Beweise desselben Laufs unterscheiden | seit constraint set 7 hat jede deklarierte Tabelle mindestens 2⁷ Zeilen, mehr als die 82 Punkte, die ein Beweis öffnet, und die LogUp-Abschlüsse sind geblindet |
| Tiers | 10, 12, 14, 16, 18, 20 | ein Beweis legt das Tier offen, nie die Zyklenzahl; seit fullnode v0.5.6 wird ein Call-Beweis oberhalb von tier 14 abgelehnt (CallTierTooHigh), ein Bundle-Beweis ist auf tier 14 und ein Auth-Beweis auf tier 10 festgelegt |
| Beweisobergrenze | das Genesis-max_proof_bytes: 4 MiB (4.194.304) auf den chains 17 bis 20; 8 MiB auf den chains 13 bis 16; 2 MiB (MAX_PROOF_BYTES) bei einem Genesis ohne dieses Feld, etwa chain 12 | 2 MiB liegt über jedem hashtabellenfreien Beweis, den die eingesetzten Guests erzeugen können, und unter einem Keccak-tragenden; 4 MiB lässt beide zu |
| Gas | 1 pro cpu-Zeile; 3 pro Poseidon2-Absorb-Zeile; 64 pro SHA256-Zeile; 192 pro KECCAK-Zeile | akkumuliert in der GAS-Spalte der cpu-Tabelle und bewiesen höchstens GAS_LIMIT; der Verifier lehnt ein Limit oberhalb von gas_max(t, k, s) = (2ᵗ − 1) + 2ᵗ⁻² + 191·(2ᵏ/32) + 63·(2ˢ/64) ab, das für einen hashfreien Header auf tier 10 den Wert 1.279 und für einen auf tier 14 den Wert 20.479 ergibt |
Gemessene Größen bei Constraint-Set 6 (Apple Silicon, Release-Build): Ein keccak-freier Produktionsbeweis umfasste bei Stufe 10 1.298.729 Bytes und bei Stufe 12 1.359.978 Bytes; ein keccak-haltiger Beweis bei Stufe 10 umfasste 3.198.430 Bytes, über den standardmäßigen 2 MiB und unter den 8 MiB der Chains 13 bis 15. Ein Stufe-14-Beweis des ausgemusterten 2-in-2-out-Bundle-Guest maß auf Chain 8 1.321.773 Bytes und auf Chain 13 1.418.406 bis 1.420.423 Bytes. Der 4-in-4-out-Bundle-Guest für verborgene Assets von Chain 14 bleibt bei Stufe 14 und nutzt keine der beiden Hash-Tabellen; seine Beweise maßen auf Chain 14 (2026-09-20) 1.422.116 und 1.423.170 Bytes, und Chain 15 legte denselben Guest fest (hc_bundle unverändert). Ein Bundle-Beweis deklarierte dort public_log_height 4, die Höhe der acht Binding-Wörter, und der Knoten wies jeden anderen Wert zurück, bevor er einen Verifier-Schlüssel erstellte. Der keccak-haltige Beweis des ERC-20-Aufrufs approve, der am 2026-09-19 auf Chain 13 erstellt wurde (Stufe 16), umfasst 3.412.405 Bytes; jede Chain seit Fullnode v0.5.6 weist diesen Aufruf bei Stufe 16 zurück.
Die Blinding-Spalten und Tabellenuntergrenzen von Constraint-Set 7 erhöhen einen hash-freien Beweis um etwa 5 %: Laut Messung des Fullnode vom 2026-09-28 umfasst fib bei Stufe 10 1.367.688 Bytes und bei Stufe 12 1.424.299 Bytes, ein keccak-haltiger Stufe-10-Beweis 3.283.898 Bytes und ein Stufe-14-Bundle-Beweis für verborgene Assets 1.498.821 (Guest v1) und 1.497.156 (Guest v2). Ein Bundle-Beweis deklariert seither public_log_height 7. Constraint-Set 8 fügt weniger als 1 % hinzu. Gemessen auf Chain 18 am 2026-09-30 (Apple Silicon): Auth-Beweise von 1.364.940 bis 1.375.371 Bytes (Stufe 10), Bundle-Beweise von 1.494.151 bis 1.504.260 Bytes (Stufe 14, Guest v3) und Aufrufbeweise von 1.498.589 Bytes bei Stufe 14 ohne Hash-Tabelle, 1.911.152 bei Stufe 14 mit der SHA-256-Tabelle und 3.346.865 bei Stufe 12 mit der Keccak-Tabelle. Alle passen in die 4-MiB-Obergrenze der Chains 18 bis 20.
Die Verifikation dauert etwa 16 ms mit einem warmen Verifier-Schlüssel und etwa 230 ms, wenn ein Schlüssel für (tier, heights) zum ersten Mal erstellt wird. Das FRI-Profil test (16 Queries) existiert für die Testsuite und ist unsicher; das Genesis von Chain 20 legt production fest. Fullnode v0.6.8 ändert keinen Constraint: Chain 20 legt dieselben hc_bundle und hc_auth fest wie die Chains 17 bis 19.
Hash-Konstruktionen zum Nachvollziehen
BLAKE3 mit einer Domain: blake3(domain || data), der Domain-String ohne Trennzeichen.
Die Binding-Domain. Das Genesis von Chain 20 setzt binding_domain: 1 (Fullnode v0.6.8, Audit v6 BIND-1). Auf einer solchen Chain bindet jedes Beweis-Binding und jede signierte Aktionsnachricht, die bisher nur die Chain-ID band, nun zusätzlich den Genesis-Hash: Die Versionsnummer der Domain steigt um eins, und der 32-Byte-Genesis-Hash steht im Preimage vor der Chain-ID. Ein Beweis oder eine Signatur, die für eine Chain erstellt wurde, verifiziert dann auf keiner anderen, selbst wenn diese die Chain-ID und die Schlüssel wiederverwendet, wie es bei einem Neuschnitt der Fall ist. Die Binding-Wörter sind eine öffentliche Eingabe der Beweise, daher hat sich weder ein Guest noch ein Verifier-Schlüssel geändert. Die Tabelle nennt beide Formen; die Chains 14 bis 19 verwenden die erste, Byte für Byte. Bereits zuvor an das Genesis gebunden und unverändert: Stimmen und Vorschläge (seit consensus_domain: 1), die v2-Registration und eine AdmitValidator-Stimme. Nicht verschoben: die Mint-Mitsignatur der Bridge (oben). Eine Wallet benötigt v0.6.8, um auf Chain 20 zu senden, und bestimmt die Form anhand der Chain-ID, nicht anhand dessen, was ein Knoten behauptet; rand_getLimits.binding_domain meldet sie.
| value | construction |
|---|---|
| transparent address | blake3("rand-address" || dilithium2_public_key), base58 |
| transaction id | blake3("rand-txid-3" || bincode(view)), wobei view die Transaktion ist, in der die Beweisbytes des Bundles durch blake3(proof) und sein Auth-Beweis durch blake3(auth_proof) ersetzt sind; auth_commit geht unverändert ein. Die Domain lautete bis Chain 16 rand-txid-2, ohne Auth-Felder |
| transaction binding | blake3("rand-tx-bind-1" || bincode(chain_id, bundle', action')) auf den Chains 14 bis 19; blake3("rand-tx-bind-2" || bincode(genesis_hash, chain_id, bundle', action')) auf Chain 20. Acht Little-Endian-u32-Wörter, wobei ' bundle.proof, bundle.auth_proof und das proof eines Aggregate durch den leeren Vektor ersetzt; bincode mit Little-Endian-Ganzzahlen fester Breite. Jeder Bundle-Beweis und Auth-Beweis wird über diese Wörter erstellt und gegen sie verifiziert |
| call binding | blake3("rand-call-bind-1" || …), oder rand-call-bind-2 mit dem Genesis-Hash zuerst auf Chain 20: die Konstruktion des Transaktions-Bindings, wobei zusätzlich das eigene proof des Call (oder Invoke) geleert wird. Auf einem hardening_v6-Genesis, wie dem von Chain 20, besteht das öffentliche Segment eines Aufrufbeweises aus den öffentlichen Wörtern des Programms zur Deploy-Zeit, gefolgt von diesen acht Wörtern; das eines Invoke fügt danach seinen Übergang als Kontextwörter an |
| program id | blake3("rand-program" || base_pc as 4 LE bytes || words as 4 LE bytes each) |
| p2p identity | ed25519-Schlüssel aus blake3("rand-p2p-identity" || seed) |
| bridge asset id (per backing) | blake3("rand-bridge-asset" || token_chain as 2 BE bytes || token_address (32 bytes)) — rand_bridgeAssetId berechnet sie, und rand_getAssets gibt sie pro Backing-Zeile aus; sie identifiziert eine Quell-Coin auf der Leitung, nicht den Token |
| RPL token asset id, native | blake3("rand-rpl-asset" || bincode(name, symbol, decimals, authority, initial: Option<InitialMint>, salt)), wobei salt 32 vom Ersteller gewählte Bytes sind; dargestellt als Hex und als rpl1… |
| RPL token asset id, bridged | blake3("rand-rpl-asset" || bincode(name, symbol, BRIDGE_DECIMALS, salt)) — nicht über ein Paar (chain, token), da ein gebridgeter Token mehrere Backings umfasst |
| bridge deposit blinding | r = blake3("rand-deposit-r-1" || mu), das einzige r, das die Zulassung für ein BridgeAttest akzeptiert (sonst WrongDepositBlinding) |
| bridge fee note blindings (chain 20) | die Gebühren-Note einer Einzahlung: r = blake3("rand-bridge-fee-r-1" || mu); die einer Verbrennung: r = blake3("rand-bridge-burn-fee-r-1" || txid); beide gelesen als acht Little-Endian-Wörter. Die Noten haben keinen Umschlag: Jedes Feld ist öffentlich, der Eigentümer ist der Genesis-Eintrag bridge.fees.recipient |
| bridge recipient | blake3("rand-shielded-recipient" || pk_bytes || kem_ek) über die vollständige Shielded-Adresse |
faucet Mint message | blake3("rand-mint-2" || bincode(chain_id, cm, pk, time, r, envelope, amount)); auf Chain 20 blake3("rand-mint-3" || bincode(genesis_hash, chain_id, cm, pk, time, r, envelope, amount)) |
TokenMint, SetAuthority messages | blake3("rand-rpl-mint-1" or "rand-rpl-authority-1", chain_id || asset_id || nonce || body); der Body eines Mints enthält blake3(bincode(envelope)). Auf Chain 20 rand-rpl-mint-2 und rand-rpl-authority-2, mit dem Genesis-Hash zuerst |
Registration message | blake3("rand-register-2" || bincode(genesis_hash, chain_id, validator, payout)) auf einem Genesis mit staking.registration_v2 oder binding_domain: 1, wie Chain 20 (eine v1-Registrierung wird dort zurückgewiesen); blake3("rand-register" || bincode(chain_id, payout)) anderswo |
AdmitValidator vote (chain 20) | blake3("rand-admit-validator-1" || genesis_hash || candidate_address), von jedem abstimmenden Validator signiert |
Unbond message | blake3("rand-unbond" || bincode(chain_id, validator, amount, nonce)); auf Chain 20 blake3("rand-unbond-2" || bincode(genesis_hash, chain_id, validator, amount, nonce)) |
Withdraw message | blake3("rand-withdraw" || bincode(chain_id, validator, amount, nonce, time, r, envelope)); auf Chain 20 rand-withdraw-2, mit dem Genesis-Hash zuerst |
| Merkle node (state trees) | blake3("rand-merkle-node" || left || right) |
| token registry leaf | blake3("rand-token-leaf-1" || bincode(TokenInfo)), in Indexreihenfolge, unter tokens_root |
| state root | auf Chain 20 blake3("rand-state-admitted-1" || inner || admitted_root) um inner = blake3("rand-state-8" || tree_root || nullifier_root || validators_root || programs_root || bridge_root || tokens_root || faucet_epoch || faucet_minted_in_epoch || bond_queue_root || gas_price || byte_price || program_state_root), wobei program_state_root = blake3("rand-program-state-1" || cells_root || vaults_root) (RPL-2), die beiden Faucet-Zähler und die beiden Live-Preise je 8 Big-Endian-Bytes sind und der Wrapper die zugelassene Menge festschreibt (staking.admission_by_vote). Die von Chain 19 war blake3("rand-state-7" || …) über dieselben Felder bis byte_price (ein Genesis-Abschnitt staking hängt die drei nach tokens_root unter rand-state-5 an, wie auf den Chains 15 bis 17; ein Genesis-Abschnitt gas.dynamic hängt die beiden Preise an und verschiebt die Domain auf rand-state-7); rand-state-4 über die ersten sechs auf Chain 14; rand-state-2 über die ersten vier auf einer Chain ohne Abschnitt bridge, tokens oder aggregation (Consensus) |
Poseidon2 mit einem Domain-Tag: H(domain, msg) = sponge_hash([domain, msg...]), wobei das Tag das zuerst absorbierte Wort ist, jedes Wort ein Goldilocks-Element, der Digest aus 4 Elementen in acht u32-Wörter aufgeteilt (untere Hälfte, dann obere Hälfte jedes Elements). Domain-Tags:
| Tag | Wert | Konstruktion |
|---|---|---|
NK | 1 | Viewing Key nk = H(1, sk) |
PK | 2 | öffentlicher Wert der Note pk = H(2, nk) |
NF | 3 | Nullifier H(3, nk || cm) |
CM | 4 | Note-Commitment H(4, pk(8) || from(8) || amount_lo || amount_hi || asset || time || r(8)) — 28 Wörter |
OVK, KEM_SEED | 5, 6 | der Outgoing Viewing Key und der ML-KEM-Seed, über einen Wide-Hash im Zählermodus [domain, nk, counter] |
NODE | 7 | Baumknoten H(7, left || right); das leere Blatt besteht nur aus Nullen |
HC | 8 | der Programm-Digest; das Tag, base_pc und len liegen in den Capacity-Lanes der ersten Permutation, danach werden die Wörter zu je vier pro Block absorbiert |
OUT | 9 | der Ausgabe-Digest des Transfer-Guests |
IN | 10 | H_IN: Capacity-Header [10, n_in, 0], danach ein Salt aus 4 Wörtern, danach die Eingaben |
BUNDLE | 11 | der Digest des stillgelegten 2-in-2-out-Bundles über 47 öffentliche Wörter; keine Chain legt diesen Guest mehr fest |
| hidden bundle | 64 | der Digest des Hidden-Asset-Bundles über 81 Wörter auf den Chains 14 bis 16: Anchor, vier Nullifier, vier Commitments, fee, burn_a, burn_r (je zwei Wörter), burn_asset, time und zuletzt das Taint-Wort. Auf den Chains 17 bis 20 (Bundle-Guest v3) sind es 89 Wörter: Die acht Wörter des Autorisierungs-Commitments c stehen unmittelbar vor dem Taint-Wort. Das private Asset A ist darin nicht enthalten. Das Tag ist knotenlokal und liegt abseits der mitgelieferten Tags 1 bis 15 |
AUTH | 65 | das Autorisierungs-Commitment c = H(65, nk || salt), 16 Wörter, mit einem frischen 256-Bit-Salt pro Bundle; vom Bundle-Proof in seinem Digest veröffentlicht und vom Auth-Proof als seine acht Ausgabewörter, und vom Bundle als auth_commit mitgeführt (Chains 17 bis 20). Knotenlokal, wie 64 |
PUB | 15 | H_PUB: Header [15, n_pub, 0], kein Salt; bei einem Programm sind auf Chain 20 die Wörter beim Deploy festgelegt (höchstens 32.768), das Segment jedes Aufrufs besteht aus diesen Wörtern gefolgt von den acht Wörtern der Aufrufbindung, und der Aufruf wird gegen den Digest dieses Segments geprüft; bei einem Bundle-Proof und einem Auth-Proof ist das Segment die acht Bindungswörter der Transaktion; ein Genesis ohne max_program_public_words lässt nur das leere Segment zu |
hc, H_IN und H_PUB sind keine schlichten, mit einem Präfix versehenen Schwamm-Hashes: Der Header geht in die Capacity, damit die Digest-Zeilen in der cpu-Tabelle genau vier Wörter pro Permutation absorbieren. Reproduzieren Sie sie mit der mitgelieferten Crate (randprotocol_zkvm::hash::{input_digest, public_digest}, isa::Program::digest) statt von Hand.
Der schlichte Schwamm füllt nicht auf, daher hashen innerhalb des ersten Blocks [a] und [a, 0] gleich. Jede der obigen Konstruktionen hasht eine Nachricht fester Länge unter ihrem eigenen Tag. Für Daten mit variabler Länge hat Constraint-Set 7 einen längengebundenen Schwamm hinzugefügt (hash::sponge_hash_len, der Syscall POSEIDON2_LEN): Er beginnt im Zustand [0, 0, 0, 0, n, 0, 0, 0], wobei n die Wortanzahl ist, und permutiert mindestens einmal. Es ist ein anderer Hash derselben Wörter, und keine Note, kein Nullifier, keine Wurzel und kein Digest der Chain verwendet ihn.
Zwei Eigenschaften sind festzuhalten: hc ist bindend, aber nicht verbergend (kein Salt, sodass sich ein erratenes Programm bestätigen lässt und zwei Deployments desselben Programms verknüpfbar sind), und H_IN ist ebenso verbergend wie bindend (ein frischer 128-Bit-Salt pro Proof), sodass die Veröffentlichung von H_IN nichts über die Eingaben preisgibt, bis der Salt-Inhaber es öffnet.
Schlüsselableitungen
| Schlüssel | aus |
|---|---|
| Dilithium2-Schlüsselpaar (Node) | deterministisch aus dem 32-Byte-Seed |
| libp2p ed25519 (Node) | blake3("rand-p2p-identity" || seed) |
Viewing Key, pk, ovk, ML-KEM-Schlüsselpaar (Wallet) | Poseidon2-Ableitungen des Spend Keys, wie oben tabelliert; das ML-KEM-Paar ist MlKem768::from_seed(kem_seed) |
Die Papers auf der Papers-Seite enthalten die Sicherheitsargumente: die Post-Quanten-Entscheidungen, die FRI-Soundness-Bilanz und warum 80 Queries beibehalten werden, sowie die Schranke für die Trace-Länge.