Anleitungen

Anleitungen · Teil 5 von 6

Stapelweise mit Merkle

Manchmal haben Sie nicht eine Datei, sondern tausend. Einen Ordner voller Dokumente, einen Strom von Ereignissen, die Audit-Log-Zeilen eines ganzen Tages. Jedes Element in einer eigenen Transaktion zu verankern wäre verschwenderisch. Hashen Sie stattdessen jeden Eintrag zu einem Blatt, falten Sie die Blätter zu einer einzigen Merkle-Wurzel und veröffentlichen Sie nur diese eine Wurzel. Die geordnete Blätterliste bleibt off-chain; später lässt sich die Aufnahme eines einzelnen Elements in die Menge mit einem Beweis nachweisen, der nur logarithmisch mit der Stapelgröße wächst.

Das Wesentliche: Den Baum zu erstellen und Beweise zu verifizieren ist vollständig offline möglich. Kein Gateway, kein Konto, kein Netzwerk. Allein das Veröffentlichen der Wurzel berührt ein Gateway; alles andere ist reine Berechnung, die Sie überall und jederzeit ausführen können.

Mit dem CLI

Übergeben Sie merkle build die Dateien, die Sie verankern möchten. Es hasht jede zu einem Blatt, erstellt die RFC 9162-Wurzel und gibt die kanonische Blätterliste aus:

cardanowall merkle build --file a.pdf --file b.pdf --file c.pdf --json

Sie können auch vorberechnete Blätter übergeben (einen 64-stelligen SHA-256-Digest in Hex pro Zeile), über stdin oder per --in leaves.txt. Bewahren Sie die root auf (sie wird veröffentlicht) ebenso wie die Blätterliste (alle, die später eine Aufnahme nachweisen müssen, werden sie benötigen).

Um nachzuweisen, dass ein Element zu einer veröffentlichten Wurzel gehört, schreiben Sie eine kleine Proof-Datei mit dem Prüfpfad und verifizieren sie, vollständig offline und gegen jede Wurzel, der Sie vertrauen:

cardanowall merkle verify --root <root-hex> --proof proof.json

Die Struktur von proof.json ist { tree_alg, tree_size, index, leaf, proof[] }; mit --leaf <hex> überschreiben Sie das aus der Datei abgeleitete Blatt. Der Exit-Code 0 bedeutet, das Blatt liegt im Baum, 1 bedeutet, es ist nicht enthalten. Damit lässt es sich direkt in CI einbinden.

Mit dem TypeScript-SDK

Hashen Sie Ihre Elemente zu Blättern, erstellen Sie Wurzel und Beweise lokal und veröffentlichen Sie dann nur die Wurzel über ein Gateway:

import { Label309Client, hash, merkle } from '@cardanowall/sdk-ts';

const items = [docA, docB, docC]; // Uint8Array content
const leaves = items.map((bytes) => hash.sha2256(bytes));

const root = merkle.merkleSha2256Root(leaves);

// Prove item 1 is in the set — no network, no gateway.
const proof = merkle.merkleSha2256InclusionProof(leaves, 1);
const ok = merkle.merkleSha2256VerifyInclusion(leaves[1], 1, leaves.length, proof, root);
console.log(ok); // true

merkleSha2256VerifyInclusion(leaf, index, treeSize, proof, root) ist ein reines boolesches Prädikat. Es stellt nie eine Netzwerkverbindung her und wirft bei einem ungültigen Beweis keine Ausnahme, sondern gibt schlicht false zurück. Wer die Blätterliste besitzt, kann die Wurzel neu berechnen und jeden Beweis neu ableiten; der Aussteller ist dabei nie beteiligt.

Die Wurzel zu veröffentlichen ist der einzige Schritt, der ein Gateway braucht. Holen Sie dafür ein Angebot ein und veröffentlichen Sie dann die Blätter: Das SDK berechnet die Wurzel lokal, das Gateway speichert die Blätterliste und verankert die Festlegung on-chain.

const client = new Label309Client({
  baseUrl: 'https://your-gateway.example',
  apiKey: process.env.CW_API_KEY,
});

const quote = await client.poe.quote({
  recordBytes: 512,
  recipientCount: 0,
  fileBytesTotal: leaves.length * 32,
});

const published = await client.poe.publishMerkle({
  leaves, // raw 32-byte digests or hex strings
  quoteId: quote.quote_id,
});

console.log(published.root, published.leaf_count, published.tx_hash, published.ar_uri);

Mit dem Python-SDK

Der byteidentische Zwilling erstellt denselben Baum und dieselben Beweise:

import cardanowall

items = [doc_a, doc_b, doc_c]  # bytes
leaves = [cardanowall.hash.sha2_256(b) for b in items]

root = cardanowall.merkle.merkle_sha2_256_root(leaves)

proof = cardanowall.merkle.merkle_sha2_256_inclusion_proof(leaves, 1)
ok = cardanowall.merkle.merkle_sha2_256_verify_inclusion(
    leaves[1], 1, len(leaves), proof, root
)
print(ok)  # True

Mit dem Rust-SDK

Das cardanowall-Crate erstellt denselben Baum und dieselben Beweise offline und veröffentlicht dann nur die Wurzel über den Gateway-Client:

use cardanowall::client::{
    Label309Client, Label309ClientConfig, MerkleLeaf, PublishMerkleInput, QuoteInput,
};
use cardanowall::{hash, merkle};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let items: Vec<Vec<u8>> = vec![doc_a, doc_b, doc_c]; // content bytes
    let leaves: Vec<[u8; 32]> = items.iter().map(|b| hash::sha256(b)).collect();

    // Build the root and prove inclusion — pure computation, no network.
    let root = merkle::merkle_root(&leaves)?;
    let proof = merkle::merkle_inclusion_proof(&leaves, 1)?;
    let ok = merkle::verify_inclusion(&leaves[1], 1, leaves.len(), &proof, &root);
    println!("{ok}"); // true

    // Publishing the root is the one step that needs a gateway.
    let client = Label309Client::new(Label309ClientConfig {
        base_url: Some("https://your-gateway.example".into()),
        api_key: std::env::var("CW_API_KEY").ok(),
    })?;

    let quote = client.poe().quote(&QuoteInput {
        record_bytes: 512,
        recipient_count: 0,
        file_bytes_total: (leaves.len() * 32) as u64,
    })?;

    let published = client.poe().publish_merkle(&PublishMerkleInput {
        leaves: leaves.iter().map(|l| MerkleLeaf::Bytes(l.to_vec())).collect(),
        quote_id: quote.quote_id,
        hash_alg: None,
        signer: None,
        idempotency_key: None,
        chunk_bytes: None,
    })?;

    println!("{} {} {:?}", published.root, published.leaf_count, published.tx_hash);
    Ok(())
}

Eine Wurzel, viele Elemente, kein Vertrauen nötig

Die Wurzel legt sich auf jedes Blatt und dessen Position fest. Monate später, allein mit der Blätterliste und der on-chain verankerten Wurzel, kann jede und jeder einen Beweis neu ableiten und bestätigen, dass ein Element im Stapel enthalten war, ganz ohne Ihr Gateway, Ihren Server oder Ihre Mitwirkung. Wie Blätter gehasht werden, beschreibt Inhalt und Hashing; den Ablauf für ein einzelnes Element zeigt Veröffentlichen Sie Ihren ersten PoE.