Реестры алгоритмов
Реестры именованных идентификаторов для хешей, AEAD, KEM, KDF и подписей — и правило гибкости выбора алгоритмов, благодаря которому миграция на постквантовые алгоритмы является дополнением, а не ломающим изменением.
Каждый криптографический выбор в Label 309 задаётся строковым идентификатором,
взятым из расширяемого реестра — sha2-256, chacha20-poly1305-stream64k, EdDSA
и так далее. Запись никогда не содержит сырого номера алгоритма или неявных допущений: в
ней явно указано, какой примитив был использован, а верификатор находит этот
идентификатор в реестре. Это и есть механизм, реализующий инвариант гибкости
выбора алгоритмов: реестры могут пополняться со временем, и верификатор, встретив
незнакомый идентификатор, отклоняет запись с устойчивой, типизированной ошибкой —
он никогда не завершается аварийно и никогда не принимает молча то, что не умеет
проверить.
Именно это правило делает миграцию на постквантовые алгоритмы дополнением. Новый идентификатор — это новая строка в таблице, а не новая версия формата. Старые записи продолжают проверяться точно так же, как прежде, а старые верификаторы безопасно отклоняют записи, с которыми они не были рассчитаны работать.
Два неизменных правила
Для всех реестров без исключений действуют два абсолютных ограничения. Реализации НЕ ДОЛЖНЫ изобретать новую криптографию — каждый примитив восходит к именованному открытому стандарту. И всё шифрование ДОЛЖНО быть аутентифицированным: допускаются только конструкции AEAD, но никак не неаутентифицированный шифр с привинченной сбоку (или отсутствующей) проверкой целостности.
Хеш
Хеш содержимого является основным утверждением каждой записи, поэтому реестр хешей несёт наибольшую нагрузку. Обе зарегистрированные функции порождают 32-байтовый дайджест, и совместимая реализация обязана поддерживать их обе.
| Идентификатор | Алгоритм | Дайджест |
|---|---|---|
sha2-256 | SHA-256 (FIPS 180-4) | 32 B |
blake2b-256 | BLAKE2b-256 (RFC 7693) | 32 B |
Издатель МОЖЕТ хешировать одно и то же содержимое обеими функциями в целях глубокой защиты; для действительной записи достаточно одного хеша.
Дерево Merkle
Для фиксации упорядоченного списка листьев под единым ончейн-корнем Label 309
регистрирует один идентификатор Merkle-обязательства. Это зарегистрированная IANA
строка для двоичного дерева Merkle на основе SHA-256, использующего разделение
областей с помощью префикса листа (0x00) и префикса внутреннего узла (0x01),
что предотвращает коллизии между листьями и узлами.
| Идентификатор | Алгоритм | Корень |
|---|---|---|
rfc9162-sha256 | Двоичное дерево Merkle по RFC 9162, SHA-256 | 32 B |
Дерево из одного листа фиксирует SHA-256(0x00 ‖ leaf), а не сам лист —
поэтому доказательство для одного файла ДОЛЖНО использовать идентификатор простого
хеша, но никак не дерево из одного листа.
AEAD
Реестр AEAD регулирует, какой формат содержимого защищает запечатанные данные на
проводе — поле enc.aead. Под enc.scheme: 1 зарегистрирован ровно один
идентификатор, и это сегментированный формат, а не однопроходный шифр.
| Идентификатор | Алгоритм | Ключ / Nonce / Nonce на фрагмент / Тег | Статус |
|---|---|---|---|
chacha20-poly1305-stream64k | ChaCha20-Poly1305, сегментированный STREAM по 64 КиБ | 32 B / 24 B / 12 B / 16 B на фрагмент | Обязательный — формат на проводе |
aes-256-gcm | AES-256-GCM | — | Зарезервирован (будущий профиль) |
chacha20-poly1305-stream64k — это ChaCha20-Poly1305
(RFC 8439) в сегментированной компоновке
STREAM по 64 КиБ из
спецификации age v1: открытый текст
разбивается на фрагменты по 65536 байт, и каждый фрагмент запечатывается под ключом
содержимого с 12-байтовым nonce на фрагмент uint88_be(counter) ‖ final_flag
(счётчик от 0, final_flag 0x01 на последнем фрагменте) и пустым AAD на фрагмент,
давая 16-байтовый тег на фрагмент. 24-байтовый enc.nonce — это не nonce
фрагмента: это уникальная для конверта соль HKDF ключа содержимого, и именно она
держит счётные nonce безопасными — ключ содержимого одноразов, так что никакие два
потока не делят пару (key, nonce), а производители без состояния никогда не
согласуют nonce между конвертами. Сегментированная компоновка позволяет верификатору
аутентифицировать и выдавать большую полезную нагрузку инкрементально, при
ограниченной памяти, а финальный флаг делает усечение обнаружимым. Точное написание
на проводе — ровно chacha20-poly1305-stream64k; альтернативные написания
производить НЕЛЬЗЯ. Полная конструкция — на странице Запечатанное
PoE.
chacha20-poly1305-stream64k — единственный идентификатор, который может появиться
как формат содержимого на проводе. Отдельная конструкция, chacha20-poly1305
(RFC 8439, 32-байтовый ключ / 12-байтовый
nonce / 16-байтовый тег), используется внутри запечатанной конструкции для
оборачивания ключа каждого получателя: 12-байтовый нулевой nonce, AAD, равный метке
info выбранного KEM, на выходе — 48-байтовый wrap (32-байтовый обёрнутый ключ +
16-байтовый тег). Это строительный блок, а не идентификатор на проводе, и запись,
называющая его в enc.aead, ДОЛЖНА быть отклонена. aes-256-gcm указан, но не
активен; он зарезервирован для будущего профиля шифрования (enc.scheme: 2), и
верификатор версии 1 отклоняет любую запись, в которой он выбран.
KEM
Реестр KEM охватывает механизмы инкапсуляции ключей, используемые для адресации запечатанных данных конкретным получателям. Label 309 регистрирует классический KEM на основе эллиптических кривых и постквантовый гибридный KEM, активный с первого выпуска.
| Идентификатор | Алгоритм | Открытый ключ / Секрет | Шифртекст / Общий секрет |
|---|---|---|---|
x25519 | X25519 ECDH (RFC 7748) | 32 B / 32 B | 32 B / 32 B |
mlkem768x25519 | Гибрид X-Wing (ML-KEM-768 + X25519) | 1216 B / 32 B | 1120 B / 32 B |
mlkem768x25519 — это конструкция X-Wing из
draft-connolly-cfrg-xwing-kem-10:
она объединяет ML-KEM-768 (FIPS 203) с
X25519 (RFC 7748) так, что злоумышленнику
нужно взломать оба алгоритма, чтобы восстановить общий секрет. Открытый ключ —
это ключ инкапсуляции ML-KEM-768, конкатенированный с открытым ключом X25519
(1184 B ‖ 32 B = 1216 B); секрет представляет собой 32-байтовый сид, из которого
выводится полный ключ. Шифртекст каждого получателя — это шифртекст ML-KEM-768,
конкатенированный с эфемерным открытым ключом X25519 (1088 B ‖ 32 B = 1120 B), а два
общих секрета объединяются комбайнером X-Wing на SHA3-256
(FIPS 202) в итоговый 32-байтовый
секрет. Label 309 использует X-Wing как KEM-чёрный ящик — инкапсуляция,
декапсуляция, 32-байтовый общий секрет — и не опирается ни на какое свойство
внутреннего хеширования комбайнера. Идентификатор записывается без внутренних дефисов
в соответствии с устоявшимся написанием X-Wing.
Гибридная схема выбирается для каждой записи в заголовке шифрования, независимо от шифра содержимого. Поскольку она уже зарегистрирована, постквантовая конфиденциальность — вопрос выбора идентификатора, а не ожидания новой версии формата.
Одна запись называет ровно один enc.kem, и каждый слот использует форму этого
KEM; слот неверной формы — это ENC_SLOT_INVALID_SHAPE, epk неверной длины
(≠ 32 B) или kem_ct неверной длины (≠ 1120 B) — это KEM_EPK_LENGTH_MISMATCH /
KEM_CT_LENGTH_MISMATCH, а незарегистрированный enc.kem — это
UNSUPPORTED_KEM_ALG. Материал инкапсуляции обязан также быть различным в пределах
одного slots[]: все значения epk (для x25519) или все значения kem_ct (для
mlkem768x25519) ДОЛЖНЫ различаться. Дубликат внутри записи отклоняется с кодом
ENC_SLOTS_DUPLICATE_KEM_MATERIAL ещё до запуска любого примитива KEM или AEAD,
поскольку повторяющийся epk или kem_ct разрушает уникальность ключей по слотам,
от которой зависит обёртывание с нулевым nonce. Верификатор также ограничивает
ресурсы парсера ещё до любого примитива: конверт, чей slots[] превышает контрольный
порог в 1024 слота, — это ENC_SLOTS_TOO_MANY, а декодированный конверт enc,
превышающий 65 536 байт, — это ENC_ENVELOPE_TOO_LARGE. Оба порога лежат намного
выше потолка метаданных Cardano в ~16 КиБ, ограничивающего любую честную запись; это
закреплённые на стороне развёртывания константы, проверяемые верификатором, — а не
проводные поля, — и развёртывания МОГУТ ужесточать их.
KDF
Реестр KDF перечисляет функции формирования ключей. hkdf-sha256 формирует ключи
внутри запечатанной конструкции; argon2id растягивает парольную фразу человека
против перебора и несёт обязательный нижний порог параметров.
| Идентификатор | Алгоритм | Параметры |
|---|---|---|
hkdf-sha256 | HKDF-SHA-256 (RFC 5869) | salt (опционально), info (опционально), длина вывода |
argon2id | Argon2id (RFC 9106) | memory ≥ 65536 KiB, iterations ≥ 3, parallelism ≥ 1 |
Нижний порог для Argon2id является нормативным: полезная нагрузка, защищённая
парольной фразой, ДОЛЖНА использовать не менее 64 МиБ памяти, не менее трёх
итераций и не менее одного потока. Издатель МОЖЕТ выбрать более строгие параметры;
они хранятся вместе с записью, чтобы верификатор мог воспроизвести выведение ключа.
Там, где платформа это поддерживает, издателям СЛЕДУЕТ задавать параллелизм p = 4
— второй рекомендованный профиль
RFC 9106 §4, — тогда как
верификатор МОЖЕТ принимать любое p ≥ 1 в пределах потолков развёртывания. Эти
потолки — это СЛЕДУЕТ для реализации, а не МОЖЕТ: верификатору СЛЕДУЕТ обеспечивать
верхние границы против отказа в обслуживании на стороне верификатора из-за абсурдных
параметров, сообщая ENC_PASSPHRASE_PARAMS_EXCEED_POLICY. Потолок зависит от
оборудования и не нормативен, и его НЕ ДОЛЖНО смешивать с нижним порогом, кодом
ENC_PASSPHRASE_ARGON2_PARAMS_TOO_LOW.
Только argon2id выбирается на проводе: это единственный идентификатор,
который запись может указать в enc.passphrase.alg. hkdf-sha256 —
внутренний строительный блок: это фиксированный шаг извлечения-и-разворачивания
за выведением сид → ключ, выведением KEK по слотам, ключом MAC набора слотов, ключом
MAC обязательства по парольной фразе и выведением ключа содержимого, — и он не несёт
проводного идентификатора. Запись, называющая hkdf-sha256 в enc.passphrase.alg,
ДОЛЖНА быть отклонена: HKDF рассчитан на высокоэнтропийные входы, а не на растягивание
низкоэнтропийной парольной фразы.
Внутренние метки — это константы, никогда не на проводе
Запечатанная конструкция берёт своё разделение доменов из фиксированного набора
литералов-меток — теги info для HKDF и префиксы SHA-256 (префиксы соли KEK,
префиксы транскриптов и префикс хешей элемента). Каждый из них — константа
enc.scheme: 1, точный ASCII без терминатора и префикса длины; ни один не
сериализуется и ни один не выбирается через какой-либо реестр. Их одиннадцать:
| Метка | Роль |
|---|---|
cardano-poe-kek-v1 | info для HKDF при выведении KEK по слотам на пути x25519 |
cardano-poe-kek-mlkem768x25519-v1 | info для HKDF при выведении KEK по слотам на пути mlkem768x25519 |
cardano-poe-x25519-kek-salt-v1 | Префикс SHA-256 для salt HKDF при выведении KEK x25519 |
cardano-poe-xwing-kek-salt-v1 | Префикс SHA-256 для salt HKDF при выведении KEK mlkem768x25519 |
cardano-poe-item-hashes-v1 | Префикс SHA-256 для дайджеста хешей элемента hashes_hash |
cardano-poe-slots-transcript-v1 | Префикс SHA-256 для хеша транскрипта слотов slots_hash |
cardano-poe-slots-mac-v1 | info для HKDF при выведении ключа MAC набора слотов |
cardano-poe-passphrase-transcript-v1 | Префикс SHA-256 для хеша транскрипта парольной фразы pw_hash |
cardano-poe-passphrase-mac-v1 | info для HKDF при выведении ключа MAC обязательства по парольной фразе |
cardano-poe-payload-v1 | info для HKDF при выведении ключа содержимого на пути слотов |
cardano-poe-payload-passphrase-v1 | info для HKDF при выведении ключа содержимого на пути парольной фразы |
Обе соли KEK разделяют одну форму помеченного хеша —
SHA-256(label ‖ enc.nonce ‖ <KEM-материал слота> ‖ pub_R) — под собственной меткой
для своего KEM. Эти метки отличаются от строк info выведения сида на странице
Ключи и от префикса домена подписи записи на странице
Подписи: набор свободен от коллизий и от совпадения префиксов, так
что ни одна запечатанная метка по записи не равна метке выведения долгоживущего ключа
— и не является её байтовым префиксом, — а выведение ключа идентичности и обёртывание
ключей по записи никогда не сталкиваются. Верификатор ДОЛЖЕН использовать каждый
литерал байт в байт; единственный отличающийся байт даёт slots_mac, обязательство
или тег AEAD, который честный производитель не сможет воспроизвести. Побайтовая
конструкция, потребляющая каждую метку, описана на странице Запечатанное
PoE.
Подпись
Label 309 регистрирует один алгоритм подписи. Подписи авторства всегда необязательны,
но если они присутствуют, они оформляются как COSE_Sign1 (RFC 9052) с
использованием Ed25519.
| Идентификатор | COSE alg | Алгоритм | Обёртка |
|---|---|---|---|
EdDSA | -8 | Ed25519 (RFC 8032) | COSE_Sign1 (RFC 9052) |
Проверка выполняется строго согласно RFC 8032 §5.1.7: реализации ДОЛЖНЫ отклонять неканонические кодировки подписей и точки малого порядка (расширение с очисткой кофактора не применяется). Это соответствует консервативным критериям приёмки, принятым в кошельках Cardano, поэтому подпись, прошедшая проверку в одной совместимой реализации, проходит её во всех.
Поддержка подписей независима от утверждения о содержимом. Верификатор, не реализующий алгоритм подписи из записи, помечает этот слот подписи как неподдерживаемый и оставляет временну́ю метку и утверждения о содержимом полностью действительными — неизвестный алгоритм подписи никогда не делает саму запись недействительной.
Зарезервированные идентификаторы
Ряд идентификаторов указан, но ещё не активен. Они обозначают согласованный путь миграции, чтобы будущие профили использовали устойчивые, заранее зафиксированные имена, а не произвольные строки. Совместимый издатель НЕ ДОЛЖЕН их использовать, а совместимый верификатор ДОЛЖЕН отклонять любую запись, в которой они присутствуют, с соответствующей типизированной ошибкой.
| Идентификатор | Алгоритм | Роль |
|---|---|---|
aes-256-gcm | AES-256-GCM (NIST SP 800-38D) | Шифр содержимого (AEAD) |
ml-kem-768 | ML-KEM-768 (FIPS 203), отдельный | KEM |
ml-dsa-65 | ML-DSA (FIPS 204) | Подпись |
slh-dsa-sha2-128s | SLH-DSA (FIPS 205) | Подпись |
ml-kem-768 — это чистый постквантовый KEM, отличный от зарегистрированного
гибридного mlkem768x25519; именно гибридный вариант является тем, что Label 309
использует в работе, исходя из принципа, что классический запасной вариант должен
сохраняться даже после добавления постквантовой половины.
Гибкость выбора алгоритмов и миграция
Добавление алгоритма — это самодостаточная, дополняющая операция: нужно сослаться на открытый стандарт для примитива, добавить идентификатор в соответствующий реестр, предоставить проверенную и тщательно отрецензированную реализацию, а также опубликовать межъязыковую фикстуру соответствия, чтобы независимые реализации совпадали байт в байт. Версия формата при этом не меняется, поскольку схема не меняется — растёт лишь набор распознаваемых строк.
Последствия непосредственно вытекают из устройства реестров:
- Старые записи остаются проверяемыми. Их идентификаторы по-прежнему находятся в реестре, поэтому каждая существующая запись проверяется точно так же, как в день публикации.
- Старые верификаторы безопасно отклоняют новые записи. Верификатор, созданный
до появления нового идентификатора, отклоняет записи, использующие его, с
устойчивой ошибкой
UNSUPPORTED_*, а не угадывает — пути к молчаливому принятию нет. - Поддержка постквантовых алгоритмов является дополнением. Поскольку
mlkem768x25519уже зарегистрирован и новые KEM и подписи встраиваются в тот же механизм, постквантовый переход — это рост реестра, а не ломающая миграция.
Смена версии формата зарезервирована для по-настоящему ломающих изменений схемы — нового обязательного поля, удалённого поля, изменённого типа. Рост реестра никогда не является основанием для смены версии, что и позволяет криптографическому каталогу развиваться, не делая ни одно опубликованное подтверждение существования устаревшим.
Содержимое и хеширование
Как Label 309 связывает запись с её содержимым — что хранит карта hashes, к чему привязан хеш и как обязательства Merkle закрепляют множество элементов под одним корнем.
Ключи
Модель ключей Label 309 — один 32-байтовый сид, три пары ключей разных алгоритмов, выведенные из него с помощью домен-разделённого HKDF-SHA-256, ключи шифрования ключей по слотам, которые запечатанное PoE выводит поверх них, и то, как кодируются открытые ключи получателей и их секреты.