Anleitungen · Teil 4 von 8
Einen versiegelten PoE erstellen
Ein einfacher PoE belegt, dass ein bestimmter Inhalt existiert hat. Ein versiegelter PoE belegt dasselbe, hält den Inhalt selbst aber geheim: Sie verschlüsseln die Bytes für einen oder mehrere Empfängerschlüssel, speichern nur den Chiffretext und verankern den Datensatz on-chain (in der Blockchain). Jede und jeder kann sehen, dass der Datensatz existiert, und seine Struktur verifizieren; entschlüsseln können die Nutzdaten aber nur diejenigen, die einen passenden privaten Schlüssel besitzen. Das Umschlagformat beschreibt Versiegelter PoE, das Bedrohungsmodell Versiegelt bis zur Abholung.
Empfänger adressieren
Ein Empfänger wird über eine Zeichenkette im age-Stil identifiziert. Es gibt zwei
Arten, die sich am Präfix unterscheiden lassen:
age1…: ein klassischer X25519-Schlüssel (32 Byte).age1pqc…: ein hybrider X-Wing-Schlüssel (ML-KEM-768 + X25519, 1216 Byte).
X-Wing (mlkem768x25519) ist der Standard-KEM. Er bleibt auch gegenüber einem
künftigen Quantenangreifer sicher, und jede Identität verfügt stets über eine
age1pqc…-Adresse.
Ein Empfänger teilt Ihnen seine Zeichenkette über einen separaten,
vertrauenswürdigen Kanal mit. Mit parseAgeRecipient wandeln Sie sie zurück in den
rohen öffentlichen Schlüssel, den die Versiegelungs-Hilfsfunktion benötigt:
import { parseAgeRecipient } from '@cardanowall/sdk-ts';
const them = parseAgeRecipient('age1pqc…'); // { kem: 'mlkem768x25519', publicKey: Uint8Array }Wenn Sie selbst einen 32-Byte-Seed besitzen, liefert Ihnen recipientsFromSeed
beide eigenen Adressen. Geben Sie eine davon weiter, damit andere an Sie versiegeln
können, und nehmen Sie Ihren eigenen Schlüssel in die Empfängerliste auf, um den
Lesezugriff auf das von Ihnen Versendete zu behalten:
import { recipientsFromSeed } from '@cardanowall/sdk-ts';
const me = recipientsFromSeed(mySeed); // { age: 'age1…', age1pqc: 'age1pqc…' }Versiegeln und veröffentlichen
Das Versiegeln läuft über ein Gateway, das die Cardano-Transaktion erstellt und verteilt und den Chiffretext jedes Elements für Sie speichert. Richten Sie den Client auf das von Ihnen genutzte Gateway; das SDK ist gateway-unabhängig.
publishSealed erwartet rohe öffentliche Empfängerschlüssel, entnehmen Sie also
publicKey aus jeder geparsten Adresse. Alle Empfänger müssen denselben KEM
verwenden, halten Sie age1pqc…-Schlüssel daher beieinander. items ist eine
Liste, Sie können also einen ganzen Satz Dateien in einem einzigen Datensatz an
dieselben Empfänger versiegeln; hier enthält sie nur eine einzelne Nutzlast:
import { Label309Client, parseAgeRecipient } from '@cardanowall/sdk-ts';
const client = new Label309Client({
baseUrl: 'https://your-gateway.example',
apiKey: process.env.CW_API_KEY,
});
const content = new TextEncoder().encode('the secret payload');
const recipients = ['age1pqc…recipient', me.age1pqc].map((r) => parseAgeRecipient(r).publicKey);
const result = await client.poe.publishSealed({
items: [{ content }],
recipients,
maxUsdMicros: 2_000_000n, // refuse to spend more than $2
// kem defaults to 'mlkem768x25519' (X-Wing); pass 'x25519' only for age1… keys.
});
console.log(result.response.id, result.uris);Es gibt keinen separaten quote-Aufruf und kein eigenes Schätzen von recordBytes:
publishSealed misst den exakten versiegelten Datensatz, schreibt einen Preis fest,
lädt jeden Chiffretext hoch und reicht ihn ein — alles in einem einzigen Aufruf.
maxUsdMicros ist Ihre Obergrenze; die Veröffentlichung verweigert sich, wenn der
angebotene Preis darüber liegt, und prüft die Obergrenze erneut gegen einen frischen
Preis, falls ein langsamer Upload die erste Festschreibung überdauert hat — so kann
ein großer Upload seinem Angebot niemals davonlaufen. Ihr Seed und der Klartext
verlassen Ihren Rechner dabei niemals im Klartext.
Standardmäßig ist die On-Chain-Behauptung jedes Elements sein sha2-256-Digest.
Um einen zweiten Digest in denselben Datensatz zu binden, hashen Sie das Element
unter beiden Algorithmen zugleich: Übergeben Sie publishSealed im SDK
hashAlgs: ['sha2-256', 'blake2b-256'], oder wiederholen Sie beim seal des CLI
--hash-alg sha2-256 --hash-alg blake2b-256. Die beiden Registry-Algorithmen
verhalten sich in jedem Versiegelungsmodus identisch.
An eine Passphrase versiegeln
Nicht jede und jeder hat einen Schlüssel. Manchmal möchten Sie an Personen
versiegeln, die eine geheime Phrase teilen, keinen Schlüssel — ein
Team-Passwort, eine am Telefon vorgelesene Phrase, einen Wert, der bereits in
Ihren CI-Secrets liegt. Geben Sie seal eine Passphrase statt --to, und jede
und jeder, die sie kennt, kann den Datensatz öffnen: keine age-Adresse, kein
Schlüsselaustausch.
cardanowall seal \
--file ./contract.pdf \
--passphrase-file ./pw.txt \
--base-url https://your-gateway.example \
--api-key "$CW_API_KEY"Ein Datensatz wird an Empfänger oder an eine Passphrase versiegelt, niemals
an beide — --passphrase gemeinsam mit --to/--to-self zu übergeben, wird
abgewiesen. Halten Sie die Phrase von der Befehlszeile fern: --passphrase-file,
--passphrase-stdin oder die Umgebungsvariable CARDANOWALL_PASSPHRASE lesen
sie alle ein, ohne dass sie in der Shell-History landet. Der Content-Key wird mit
Argon2id aus der Phrase gestreckt, sodass allein eine starke Passphrase mit hoher
Entropie zwischen dem Chiffretext und jemandem steht, der ihn zu erraten
versucht — dieser Weg ist nur so sicher wie die Phrase, die Sie wählen.
Zum Öffnen braucht es nichts als die Phrase. Der eigenständige Verifizierer
entschlüsselt und prüft den Inhalts-Hash erneut; der inbox-Befehl schreibt den
wiederhergestellten Klartext in eine Datei:
cardanowall verify <tx-hash> --passphrase-file ./pw.txt
cardanowall inbox decrypt <tx-hash> --passphrase-file ./pw.txt --out ./recovered.pdfDas Ablösen funktioniert unter beiden Modi gleich. Ein erneutes Versiegeln ist
stets ein brandneuer Datensatz — die Verschlüsselung wird jedes Mal randomisiert
(ein frischer Content-Key und eine frische Nonce sowie ein frisches
Argon2id-Salt auf dem Passphrase-Weg), sodass die Bytes niemals dedupliziert
werden. Um ein frisches Versiegeln als Nachfolger eines früheren zu markieren —
eine korrigierte Datei, eine geänderte Empfängermenge — verweisen Sie mit
--supersedes darauf zurück:
cardanowall seal --file ./contract-v2.pdf --to age1pqc…recipient --supersedes <tx-hash>Nach einem Absturz fortsetzen
Das Versiegeln zieht jedes Mal einen frischen Content-Key, eine frische Nonce und
frisches KEM-Material pro Slot; ein naiver erneuter Versuch würde also neu
verschlüsseln, einen zweiten Chiffretext-Upload bezahlen und andere Datensatz-Bytes
erzeugen. Für CI-Jobs und mehrere Gigabyte große Nutzlasten teilen Sie den Ablauf:
sealPrepare verschlüsselt offline und liefert ein portables Artefakt, das Sie
speichern können; submitSealed führt die Online-Hälfte dagegen aus.
import { sealPrepare, preparedSealToJson, preparedSealFromJson } from '@cardanowall/sdk-ts';
// Phase 1 — pure and offline: encrypt every item to the recipient set.
const prepared = sealPrepare({ items: [{ content }], recipients });
await save(preparedSealToJson(prepared)); // the portable prepared_seal_json_v1 artifact
// Phase 2 — online: quote, upload each ciphertext, publish. If it throws after
// an upload, the error's `uploads` carry validated receipts — pass them back as
// `uploaded` and the finished uploads are never paid for again.
const submission = await client.poe.submitSealed({
prepared: preparedSealFromJson(await load()),
maxUsdMicros: 2_000_000n,
});
console.log(submission.response.id, submission.uris);publishSealed oben ist lediglich sealPrepare + submitSealed in einem Aufruf;
die Python- und Rust-SDKs bieten dasselbe Paar.
Wenn die Veröffentlichung auf halbem Weg scheitert
Das CLI erreicht dieselbe Wiederaufnahme, ohne den zweiphasigen Code. Ein seal --to …-Lauf, der
nach einem Chiffretext-Upload abbricht, schreibt eine geheimnisfreie
<seal-fingerprint>.l309-seal-resume.json (die abgeschlossenen Uploads, keine Schlüssel und kein
Klartext). Führen Sie ihn mit cardanowall seal --resume <seal-fingerprint>.l309-seal-resume.json erneut aus: Es holt ein neues Preisangebot ein, erledigt
nur die noch ausstehenden Uploads und veröffentlicht. Ein signierter Lauf braucht seinen Seed
erneut; Passphrase-Versiegelungen halten keinen Fortsetzungszustand vor, führen Sie diese daher
von vorn aus.
Mit Python
cardanowall-sdk ist ein byteidentischer Zwilling: derselbe KEM-Standard, derselbe
Umschlag.
import asyncio
import os
from cardanowall import Label309Client, parse_age_recipient
async def main():
content = b"the secret payload"
recipients = [parse_age_recipient("age1pqc…recipient").public_key]
async with Label309Client(
base_url="https://your-gateway.example",
api_key=os.environ["CW_API_KEY"],
) as client:
submission = await client.poe.publish_sealed(
items=[content], # a list of plaintext items (bytes or str)
recipients=recipients,
max_usd_micros=2_000_000, # refuse to spend more than $2
)
print(submission.response["id"], submission.uris)
asyncio.run(main())Für einen fortsetzbaren Ablauf liefert seal_prepare(...) (aus cardanowall.client)
das vorbereitete Artefakt, und client.poe.submit_sealed(prepared=...) führt die
Online-Hälfte aus — dieselben zwei Phasen wie oben.
Mit Rust
Das cardanowall-Crate versiegelt über denselben Gateway-Client.
parse_age_recipient dekodiert jede Adresse in den rohen Schlüssel, und der KEM ist
standardmäßig der X-Wing-Hybrid:
use cardanowall::client::{
Label309Client, Label309ClientConfig, PublishSealedInput, SealPrepareItem,
};
use cardanowall::recipient::parse_age_recipient;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let client = Label309Client::new(Label309ClientConfig {
base_url: Some("https://your-gateway.example".into()),
api_key: std::env::var("CW_API_KEY").ok(),
})?;
let content = b"the secret payload".to_vec();
let recipients = vec![parse_age_recipient("age1pqc…recipient")?.public_key];
// One-shot: seal, quote the exact record size, upload, publish. The KEM
// defaults to mlkem768x25519 (X-Wing); `with_kem` selects x25519.
let submission = client.poe().publish_sealed(
&PublishSealedInput::new(vec![SealPrepareItem::new(&content)], recipients)
.with_max_usd_micros(2_000_000), // refuse to spend more than $2
)?;
println!("{}", submission.response.id);
Ok(())
}Für einen fortsetzbaren Ablauf liefert seal_prepare ein PreparedSeal, das Sie
speichern können, und client.poe().submit_sealed(&SubmitSealedInput::new(&prepared))
führt die Online-Hälfte aus. Auch das CLI versiegelt von der Kommandozeile aus, mit
denselben Phasen im Hintergrund: cardanowall seal --file <path> --to <address>.
Sobald der Datensatz endgültig in die Blockchain aufgenommen ist, findet ihn jeder Empfänger, entschlüsselt die Nutzdaten mit seinem privaten Schlüssel und berechnet den Klartext-Hash neu, um den Kreis zu schließen. Das ist die Empfänger-Seite von Einen Datensatz verifizieren.
Versiegeln Sie auch an sich selbst
publishSealed fügt Sie nicht stillschweigend zur Empfängerliste hinzu. Nehmen Sie keinen Ihrer
eigenen Schlüssel auf, veröffentlichen Sie einen Datensatz, den Sie nie wieder lesen können.
Nehmen Sie me.age1pqc (oder me.age) unter die Empfänger auf, wann immer Sie den Zugriff auf
das von Ihnen Versendete behalten möchten.