Guías · Parte 4 de 6
Construir una PoE sellada
Una PoE simple prueba que cierto contenido existió. Una PoE sellada prueba lo mismo manteniendo en secreto el propio contenido: cifra los bytes para una o varias claves de destinatario, almacena únicamente el texto cifrado y ancla el registro en cadena. Cualquiera puede ver que el registro existe y verificar su estructura; solo quien posea una clave privada correspondiente puede descifrar la carga útil. Consulte PoE sellada para el formato del sobre y Sellada hasta su reclamación para el modelo de amenaza.
Identificar a los destinatarios
Un destinatario se identifica mediante una cadena al estilo de age. Hay dos
tipos, y el prefijo los distingue:
age1…: una clave clásica X25519 (32 bytes).age1pqc…: una clave híbrida X-Wing (ML-KEM-768 + X25519, 1216 bytes).
X-Wing (mlkem768x25519) es el KEM predeterminado: se mantiene seguro frente
a un futuro adversario cuántico, y toda identidad dispone siempre de una
dirección age1pqc….
Un destinatario le entrega su cadena por un canal externo. Para decodificarla y
recuperar la clave pública sin procesar que necesita el asistente de sellado, use
parseAgeRecipient:
import { parseAgeRecipient } from '@cardanowall/sdk-ts';
const them = parseAgeRecipient('age1pqc…'); // { kem: 'mlkem768x25519', publicKey: Uint8Array }Si usted mismo dispone de una semilla de 32 bytes, recipientsFromSeed le
proporciona sus dos direcciones propias: comparta una para que otros puedan
sellarle registros, e incluya su propia clave en la lista de destinatarios para
conservar el acceso de lectura a lo que envía:
import { recipientsFromSeed } from '@cardanowall/sdk-ts';
const me = recipientsFromSeed(mySeed); // { age: 'age1…', age1pqc: 'age1pqc…' }Sellar y publicar
El sellado se realiza a través de una pasarela, que construye y difunde la transacción de Cardano y almacena el texto cifrado por usted. Apunte el cliente a la pasarela que utilice; el SDK es independiente de la pasarela.
publishSealed recibe claves públicas de destinatario sin procesar, así que
recopile el publicKey de cada dirección decodificada. Todos los destinatarios
deben compartir un mismo KEM: agrupe las claves age1pqc…. Primero fije un
precio con quote y luego publique:
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 quote = await client.poe.quote({
recordBytes: 512,
recipientCount: recipients.length,
fileBytesTotal: content.length,
});
const result = await client.poe.publishSealed({
content,
recipients,
quoteId: quote.quote_id,
// kem defaults to 'mlkem768x25519' (X-Wing); pass 'x25519' only for age1… keys.
});
console.log(result.tx_hash);El asistente cifra el contenido, sube el texto cifrado, vincula su URI ar:// y
el hash del texto plano en un registro de Label 309 y lo envía. Su semilla y el
texto plano nunca salen de su máquina sin cifrar.
Con Python
cardanowall-sdk es un gemelo byte por byte: mismo KEM predeterminado, mismo sobre:
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:
quote = await client.poe.quote(
record_bytes=512, recipient_count=len(recipients), file_bytes_total=len(content)
)
result = await client.poe.publish_sealed(
content=content, recipients=recipients, quote_id=quote["quote_id"]
)
print(result["tx_hash"])
asyncio.run(main())Con Rust
El crate cardanowall sella a través del mismo cliente de pasarela.
parse_age_recipient decodifica cada dirección a la clave sin procesar, y
kem: None mantiene el valor predeterminado X-Wing:
use cardanowall::client::{
Label309Client, Label309ClientConfig, PublishSealedInput, QuoteInput,
};
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];
let quote = client.poe().quote(&QuoteInput {
record_bytes: 512,
recipient_count: recipients.len() as u64,
file_bytes_total: content.len() as u64,
})?;
let result = client.poe().publish_sealed(&PublishSealedInput {
content,
recipients,
quote_id: quote.quote_id,
hash_alg: None,
kem: None, // defaults to mlkem768x25519 (X-Wing); set Some for x25519
signer: None,
idempotency_key: None,
})?;
println!("{:?}", result.tx_hash);
Ok(())
}La CLI publica registros solo con hash y registros Merkle; el sellado es hoy un flujo exclusivo del SDK.
Una vez que el registro se consolida, cada destinatario lo descubre, descifra la carga útil con su clave privada y recalcula el hash del texto plano para cerrar el ciclo: esa es la mitad del destinatario de Verificar un registro.
Séllese también a usted mismo
publishSealed nunca lo añade a la lista de destinatarios de forma silenciosa. Si no incluye una
de sus propias claves, publica un registro que nunca podrá volver a leer. Incluya me.age1pqc (o
me.age) entre los destinatarios siempre que quiera conservar el acceso a lo que envió.