Registri degli algoritmi
I registri di identificatori per hash, AEAD, KEM, KDF e firme, e la regola di agilità che rende la migrazione post-quantistica additiva anziché incompatibile.
In Label 309 ogni scelta crittografica è indicata da un identificatore testuale
tratto da un registro estensibile: sha2-256, chacha20-poly1305-stream64k,
EdDSA e così via. Un record non porta mai un numero d'algoritmo grezzo né
un'assunzione implicita: dichiara quale primitiva ha usato, e il verificatore cerca quell'identificatore.
È questo il meccanismo dietro l'invariante agile rispetto agli algoritmi: i
registri possono crescere nel tempo, e un verificatore che incontra un identificatore
non implementato rifiuta il record con un errore tipizzato e stabile. Non va mai
in crash, e non accetta mai in silenzio qualcosa che non è in grado di controllare.
È proprio questa regola a rendere additiva la migrazione verso gli algoritmi post-quantistici. Un nuovo identificatore è una nuova riga in una tabella, non una nuova versione del formato wire. I record più vecchi continuano a verificarsi esattamente come prima, e i verificatori più vecchi falliscono in modo sicuro davanti a record che non erano mai stati progettati per comprendere.
Due regole permanenti
In ogni registro, due vincoli sono assoluti. Le implementazioni NON DEVONO inventare crittografia nuova: ogni primitiva si riconduce a uno standard pubblico con un nome preciso. E ogni cifratura DEVE essere autenticata: sono ammessi solo i costrutti AEAD, mai un cifrario non autenticato con un controllo di integrità aggiunto a posteriori (o del tutto assente).
Hash
L'hash del contenuto è la rivendicazione primaria di ogni record, perciò il registro degli hash è quello che porta il maggior peso. Entrambe le funzioni registrate producono un digest di 32 byte, ed entrambe sono obbligatorie per un'implementazione conforme.
| Identificatore | Algoritmo | Digest |
|---|---|---|
sha2-256 | SHA-256 (FIPS 180-4) | 32 B |
blake2b-256 | BLAKE2b-256 (RFC 7693) | 32 B |
Un produttore PUÒ calcolare l'hash dello stesso contenuto con entrambe le funzioni per ridondanza difensiva; un singolo hash è sufficiente per un record valido.
Impegno Merkle
Per impegnarsi a una lista ordinata di foglie sotto un'unica radice on-chain (sulla
blockchain), Label 309 registra un solo identificatore di impegno Merkle. È la
stringa registrata presso IANA per l'albero di Merkle binario SHA-256, che adotta
la separazione di dominio tramite prefisso di foglia (0x00) e prefisso di nodo
interno (0x01) per impedire le collisioni tra foglie e nodi.
| Identificatore | Algoritmo | Radice |
|---|---|---|
rfc9162-sha256 | albero di Merkle binario RFC 9162, SHA-256 | 32 B |
Un albero con una sola foglia si impegna a SHA-256(0x00 ‖ leaf), non alla
foglia nuda: per questo una prova su un singolo file DEVE usare un identificatore
di hash semplice, mai un albero a 1 foglia.
AEAD
Il registro AEAD stabilisce quale formato di contenuto protegge un payload
sigillato sul wire, cioè il campo enc.aead. Sotto enc.scheme: 1 è registrato
esattamente un identificatore, ed è un formato segmentato anziché un cifrario a colpo
singolo.
| Identificatore | Algoritmo | Chiave / Nonce / Nonce per chunk / Tag | Stato |
|---|---|---|---|
chacha20-poly1305-stream64k | ChaCha20-Poly1305, STREAM segmentato 64 KiB | 32 B / 24 B / 12 B / 16 B per chunk | Obbligatorio, il formato del wire |
aes-256-gcm | AES-256-GCM | — | Riservato (profilo futuro) |
chacha20-poly1305-stream64k è ChaCha20-Poly1305
(RFC 8439) nel layout STREAM segmentato da
64 KiB della specifica age v1: il
testo in chiaro è suddiviso in chunk da 65536 byte, e ogni chunk è sigillato sotto la
chiave del contenuto con un nonce per chunk da 12 byte uint88_be(counter) ‖ final_flag (contatore da 0, final_flag 0x01 sull'ultimo chunk) e un AAD per chunk
vuoto, producendo un tag da 16 byte per chunk. Il enc.nonce da 24 byte non è un
nonce di chunk: è il salt unico per busta dell'HKDF della chiave del contenuto, ed è
ciò che mantiene sicuri i nonce a contatore — la chiave del contenuto è monouso, perciò
due stream non condividono mai una coppia (key, nonce) e i produttori privi di stato
non coordinano mai i nonce tra le buste. Il layout segmentato permette a un
verificatore di autenticare e rilasciare un payload di grandi dimensioni in modo
incrementale con memoria limitata, e il flag finale rende rilevabile la troncatura. La
grafia on-wire è esattamente chacha20-poly1305-stream64k; grafie alternative NON
DEVONO essere prodotte. Il costrutto completo è in Sealed PoE.
chacha20-poly1305-stream64k è l'unico identificatore che può comparire come formato
di contenuto on-wire. Un costrutto distinto, chacha20-poly1305
(RFC 8439, chiave da 32 byte / nonce da 12
byte / tag da 16 byte), è usato internamente per avvolgere una chiave per
destinatario all'interno del costrutto sigillato: un nonce azzerato da 12 byte, l'AAD
impostata alla label info del KEM scelto, che produce un wrap da 48 byte (chiave
avvolta da 32 byte + tag da 16 byte). È un mattone di base, non un identificatore del
wire, e un record che lo nomina in enc.aead DEVE essere rifiutato. aes-256-gcm è
nominato ma inattivo; è riservato a un profilo di cifratura futuro (enc.scheme: 2) e
un verificatore v1 rifiuta qualsiasi record che lo selezioni.
KEM
Il registro KEM copre i meccanismi di incapsulamento di chiave usati per indirizzare un payload sigillato a destinatari specifici. Label 309 registra un KEM classico su curva e un ibrido post-quantistico che è attivo fin dalla prima release.
| Identificatore | Algoritmo | Chiave pubblica / Segreto | Testo cifrato / Segreto condiviso |
|---|---|---|---|
x25519 | X25519 ECDH (RFC 7748) | 32 B / 32 B | 32 B / 32 B |
mlkem768x25519 | ibrido X-Wing (ML-KEM-768 + X25519) | 1216 B / 32 B | 1120 B / 32 B |
mlkem768x25519 è il costrutto X-Wing definito in
draft-connolly-cfrg-xwing-kem-10:
abbina ML-KEM-768 (FIPS 203) a X25519
(RFC 7748) in modo che un attaccante debba
violare entrambi per recuperare il segreto condiviso. La chiave pubblica è la
chiave di incapsulamento ML-KEM-768 concatenata con la chiave pubblica X25519
(1184 B ‖ 32 B = 1216 B); il segreto è un seme da 32 byte da cui si deriva la chiave
completa. Il testo cifrato di ciascun destinatario è il testo cifrato ML-KEM-768
concatenato con una chiave pubblica X25519 effimera (1088 B ‖ 32 B = 1120 B), e i
due segreti condivisi vengono combinati dal combiner SHA3-256 di X-Wing
(FIPS 202) nel segreto finale da
32 byte. Label 309 consuma X-Wing come KEM a scatola nera: incapsula, decapsula,
il segreto condiviso da 32 byte, e non fa affidamento su alcuna proprietà
dell'hashing interno del combiner. L'identificatore è scritto senza trattini interni,
per allinearsi alla grafia consolidata di X-Wing.
L'ibrido viene scelto per ciascun record tramite l'intestazione di cifratura, indipendentemente dall'AEAD di contenuto. Poiché è già registrato, la confidenzialità post-quantistica è solo questione di scegliere l'identificatore, senza dover attendere una nuova versione del formato wire.
Un singolo record nomina esattamente un enc.kem, e ogni slot usa la forma di quel
KEM; uno slot della forma sbagliata è ENC_SLOT_INVALID_SHAPE, un epk (≠ 32 B) o un
kem_ct (≠ 1120 B) di lunghezza errata è KEM_EPK_LENGTH_MISMATCH /
KEM_CT_LENGTH_MISMATCH, e un enc.kem non registrato è UNSUPPORTED_KEM_ALG. Il
materiale di incapsulamento deve inoltre essere distinto all'interno di un singolo
slots[]: tutti i valori epk (per x25519) o tutti i valori kem_ct (per
mlkem768x25519) DEVONO differire. Un duplicato all'interno dello
stesso record viene rifiutato con ENC_SLOTS_DUPLICATE_KEM_MATERIAL prima
dell'esecuzione di qualsiasi primitiva KEM o AEAD, perché un epk o un kem_ct
ripetuto rompe l'unicità della chiave per slot su cui si fonda l'avvolgimento a
nonce azzerato. Un verificatore limita inoltre l'uso di risorse del parser prima di
qualsiasi primitiva: una busta i cui slots[] superino la soglia di riferimento di
1024 slot è ENC_SLOTS_TOO_MANY, e una busta enc decodificata che superi i
65 536 byte è ENC_ENVELOPE_TOO_LARGE. Entrambe le soglie stanno ben al di sopra
del tetto di ~16 KiB dei metadati Cardano che vincola qualsiasi record onesto; sono
costanti applicate dal verificatore e fissate dal deployment, non campi del wire, e
i deployment POSSONO restringerle.
KDF
Il registro KDF nomina le funzioni di derivazione di chiave. hkdf-sha256 deriva
le chiavi all'interno del costrutto sigillato; argon2id irrobustisce una passphrase
umana contro gli attacchi a forza bruta e porta con sé una soglia minima obbligatoria
di parametri.
| Identificatore | Algoritmo | Parametri |
|---|---|---|
hkdf-sha256 | HKDF-SHA-256 (RFC 5869) | salt (opzionale), info (opzionale), lunghezza dell'output |
argon2id | Argon2id (RFC 9106) | memoria ≥ 65536 KiB, iterazioni ≥ 3, parallelismo ≥ 1 |
La soglia minima di Argon2id è normativa: un payload protetto da passphrase DEVE
usare almeno 64 MiB di memoria, almeno tre iterazioni e almeno una corsia (lane).
Un produttore PUÒ scegliere parametri più robusti, che viaggiano insieme al record
così che un verificatore possa riprodurre la derivazione. Dove la piattaforma lo
consente, i produttori DOVREBBERO impostare il parallelismo p = 4, il secondo
profilo raccomandato dalla
RFC 9106 §4, mentre un
verificatore PUÒ accettare qualsiasi p ≥ 1, fatti salvi i tetti del deployment.
Quei tetti sono un DOVREBBE per l'implementazione, non un PUÒ: un verificatore
DOVREBBE imporre soglie superiori contro un denial-of-service lato verificatore
provocato da parametri assurdi, segnalando ENC_PASSPHRASE_PARAMS_EXCEED_POLICY. Il
tetto dipende dall'hardware ed è non normativo, e NON DEVE essere confuso con il
codice della soglia minima ENC_PASSPHRASE_ARGON2_PARAMS_TOO_LOW.
Solo argon2id è selezionabile sul wire: è l'unico identificatore che un record
può nominare in enc.passphrase.alg. hkdf-sha256 è un mattone di base interno:
è il passo fisso di estrazione ed espansione dietro la derivazione da seme a chiave,
la derivazione del KEK per slot, la chiave del MAC dell'insieme di slot, la chiave del
MAC dell'impegno con passphrase e la derivazione della chiave del contenuto, e non
porta alcun identificatore del wire. Un record che nomina hkdf-sha256 in
enc.passphrase.alg DEVE essere rifiutato: HKDF è pensato per input ad alta entropia,
non per irrobustire una passphrase a bassa entropia.
Le label interne sono costanti, mai sul wire
Il costrutto sigillato trae la sua separazione di dominio da un insieme fisso di
literali di label: tag info di HKDF e prefissi SHA-256 (prefissi del salt del KEK,
prefissi di trascrizione e il prefisso degli hash dell'elemento). Ciascuno è una
costante di enc.scheme: 1, ASCII esatto senza terminatore né prefisso di
lunghezza; nessuno viene mai serializzato, e nessuno è selezionabile attraverso alcun
registro. Sono undici:
| Label | Ruolo |
|---|---|
cardano-poe-kek-v1 | info di HKDF per il KEK per slot sul percorso x25519 |
cardano-poe-kek-mlkem768x25519-v1 | info di HKDF per il KEK per slot sul percorso mlkem768x25519 |
cardano-poe-x25519-kek-salt-v1 | prefisso SHA-256 per il salt HKDF del KEK x25519 |
cardano-poe-xwing-kek-salt-v1 | prefisso SHA-256 per il salt HKDF del KEK mlkem768x25519 |
cardano-poe-item-hashes-v1 | prefisso SHA-256 per il digest degli hash dell'elemento hashes_hash |
cardano-poe-slots-transcript-v1 | prefisso SHA-256 per l'hash di trascrizione degli slot slots_hash |
cardano-poe-slots-mac-v1 | info di HKDF per la chiave del MAC dell'insieme di slot |
cardano-poe-passphrase-transcript-v1 | prefisso SHA-256 per l'hash di trascrizione della passphrase pw_hash |
cardano-poe-passphrase-mac-v1 | info di HKDF per la chiave del MAC dell'impegno con passphrase |
cardano-poe-payload-v1 | info di HKDF per la chiave del contenuto sul percorso a slot |
cardano-poe-payload-passphrase-v1 | info di HKDF per la chiave del contenuto sul percorso a passphrase |
Entrambi i salt del KEK condividono un'unica forma a hash etichettato —
SHA-256(label ‖ enc.nonce ‖ <materiale KEM dello slot> ‖ pub_R) — sotto la propria
label per KEM. Queste label sono distinte dalle stringhe info di derivazione del
seme su Chiavi e dal prefisso di dominio di firma del record su
Firme: l'insieme è privo di collisioni e privo di prefissi, perciò
nessuna label sigillata per record è uguale a — né è un prefisso di byte di — una label
di derivazione di chiave a lungo termine, e la derivazione della chiave d'identità e
l'avvolgimento della chiave per record non collidono mai. Un verificatore DEVE
usare ogni literale byte per byte; un solo byte divergente produce uno slots_mac, un
impegno o un tag AEAD che il produttore onesto non è in grado di riprodurre. Il
costrutto a livello di byte che consuma ciascuna label è su Sealed PoE.
Firma
Label 309 registra un solo algoritmo di firma. Le firme di paternità sono sempre
opzionali, ma quando sono presenti vengono trasportate come COSE_Sign1 (RFC 9052)
usando Ed25519.
| Identificatore | alg COSE | Algoritmo | Wrapper |
|---|---|---|---|
EdDSA | -8 | Ed25519 (RFC 8032) | COSE_Sign1 (RFC 9052) |
La verifica è stretta secondo RFC 8032 §5.1.7: le implementazioni DEVONO rifiutare le codifiche di firma non canoniche e i punti di ordine piccolo (nessuna estensione con azzeramento del cofattore). Questo coincide con i criteri di accettazione conservativi adottati dai wallet Cardano, così che una firma valida per un'implementazione conforme risulti valida per tutte.
Il supporto alle firme è indipendente dalla rivendicazione sul contenuto. Un verificatore che non implementa l'algoritmo di firma di un record contrassegna quello slot di firma come non supportato e lascia pienamente valide le rivendicazioni di timestamp e di contenuto: un algoritmo di firma sconosciuto non invalida mai il record in sé.
Identificatori riservati
Diversi identificatori sono nominati ma non ancora attivi. Segnano il percorso di migrazione concordato, così che i profili futuri usino nomi stabili e fissati in anticipo anziché stringhe improvvisate. Un produttore conforme NON DEVE emetterli, e un verificatore conforme DEVE rifiutare qualsiasi record che ne usi uno, con l'errore tipizzato corrispondente.
| Identificatore | Algoritmo | Ruolo |
|---|---|---|
aes-256-gcm | AES-256-GCM (NIST SP 800-38D) | AEAD di contenuto |
ml-kem-768 | ML-KEM-768 (FIPS 203), autonomo | KEM |
ml-dsa-65 | ML-DSA (FIPS 204) | Firma |
slh-dsa-sha2-128s | SLH-DSA (FIPS 205) | Firma |
ml-kem-768 è il KEM post-quantistico nudo, distinto dall'ibrido registrato
mlkem768x25519; è l'ibrido ciò che Label 309 mette in campo, secondo il principio
che un fallback classico debba restare anche dopo l'aggiunta della metà
post-quantistica.
Agilità degli algoritmi e migrazione
Aggiungere un algoritmo è un'operazione autonoma e additiva: citare uno standard pubblico per la primitiva, aggiungere l'identificatore al registro appropriato, fornirne un'implementazione vagliata e ben revisionata, e pubblicare una fixture di conformità multilinguaggio così che implementazioni indipendenti concordino byte per byte. La versione del formato wire non cambia, perché lo schema non cambia: cresce soltanto l'insieme delle stringhe riconosciute.
Le conseguenze discendono direttamente dalla progettazione dei registri:
- I vecchi record restano verificabili. I loro identificatori sono ancora nel registro, quindi ogni record esistente si verifica esattamente come il giorno in cui è stato pubblicato.
- I vecchi verificatori falliscono in modo sicuro. Un verificatore precedente
a un nuovo identificatore rifiuta i record che lo usano con un errore stabile
UNSUPPORTED_*, anziché tirare a indovinare: non c'è alcun varco verso un'accettazione silenziosa. - Il supporto post-quantistico è additivo. Poiché
mlkem768x25519è già registrato, e poiché i nuovi KEM e le nuove firme si inseriscono nello stesso meccanismo, la transizione post-quantistica è una crescita del registro, non una migrazione incompatibile.
Un incremento della versione del formato wire è riservato a modifiche dello schema realmente incompatibili: un nuovo campo obbligatorio, un campo rimosso, un tipo cambiato. La crescita del registro non rientra mai in questa categoria, ed è proprio ciò che permette al catalogo crittografico di evolvere senza mai lasciare a piedi una prova già pubblicata.
Contenuto e hashing
Come Label 309 lega un record al suo contenuto: la mappa degli hash, ciò a cui l'impronta si vincola e gli impegni Merkle per ancorare molti elementi sotto un'unica radice.
Chiavi
Il modello delle chiavi di Label 309, un unico seed da 32 byte, tre coppie di chiavi (una per algoritmo) derivate da esso tramite HKDF-SHA-256 con separazione di dominio, le chiavi di cifratura della chiave per slot che una PoE sigillata deriva al di sopra, e come le chiavi pubbliche dei destinatari e i segreti vengono codificati.