이 번역은 참고용입니다. 정식 기준은 영어판이며, 내용이 다를 경우 영어판이 우선합니다. 영어판 읽기

알고리즘 레지스트리

해시, AEAD, KEM, KDF, 서명을 식별하는 명명된 식별자 레지스트리, 그리고 포스트 양자 마이그레이션을 호환성을 깨는 일이 아니라 추가만으로 끝나게 하는 민첩성 규칙에 대하여.

Label 309의 모든 암호 방식 선택은 확장 가능한 레지스트리에서 가져온 문자열 식별자로 명명됩니다. 예를 들면 sha2-256, chacha20-poly1305-stream64k, EdDSA 등입니다. 레코드는 원시 알고리즘 번호나 암묵적 가정을 결코 품지 않으며, 어떤 프리미티브를 사용했는지 명시하고 검증자는 그 식별자를 조회합니다. 이것이 알고리즘 민첩성 불변 원칙을 떠받치는 메커니즘입니다. 레지스트리는 시간이 지나면서 늘어날 수 있으며, 자신이 구현하지 않은 식별자를 마주한 검증자는 안정적이고 타입이 지정된 오류로 레코드를 거부합니다. 결코 비정상 종료하지 않으며, 검증할 수 없는 것을 조용히 받아들이지도 않습니다.

바로 이 하나의 규칙이 포스트 양자 알고리즘으로의 마이그레이션을 추가적인 것으로 만듭니다. 새 식별자는 테이블에 행이 하나 늘어나는 일일 뿐, 와이어 포맷의 새 버전이 아닙니다. 오래된 레코드는 이전과 정확히 똑같이 계속 검증되며, 오래된 검증자는 이해하도록 만들어지지 않은 레코드에 대해 안전하게 닫히는 쪽으로 실패합니다.

두 가지 상시 규칙

모든 레지스트리에 걸쳐 절대 양보할 수 없는 두 가지 제약이 있습니다. 구현은 독자적인 암호 방식을 고안해서는 안 됩니다(MUST NOT) — 모든 프리미티브는 명명된 공개 표준으로 거슬러 올라갈 수 있어야 합니다. 그리고 모든 암호화는 인증되어야 합니다(MUST) — 오직 AEAD 구성만이 허용되며, 덧붙인(또는 누락된) 무결성 검사를 갖춘 비인증 암호는 결코 허용되지 않습니다.

Hash

콘텐츠 해시는 모든 레코드의 주된 주장이므로, 해시 레지스트리는 가장 중심적인 역할을 담당합니다. 등록된 두 함수는 모두 32바이트 다이제스트를 생성하며, 적합한 구현이라면 그 둘 모두를 지원하는 것이 필수입니다.

IdentifierAlgorithmDigest
sha2-256SHA-256 (FIPS 180-4)32 B
blake2b-256BLAKE2b-256 (RFC 7693)32 B

게시자는 심층 방어를 위해 동일한 콘텐츠를 두 함수 모두로 해시해도 됩니다(MAY). 유효한 레코드에는 해시 하나만 있으면 충분합니다.

Merkle commitment

순서가 정해진 리프 목록을 단일 온체인 루트 아래에 커밋하기 위해, Label 309는 하나의 Merkle 커밋먼트 식별자를 등록합니다. 이는 SHA-256 이진 Merkle 트리에 대해 IANA에 등록된 문자열이며, 리프와 노드의 충돌을 막는 도메인 분리, 즉 리프 접두사(0x00)와 내부 노드 접두사(0x01)를 공유합니다.

IdentifierAlgorithmRoot
rfc9162-sha256RFC 9162 binary Merkle tree, SHA-25632 B

리프가 하나뿐인 트리는 맨 리프가 아니라 SHA-256(0x00 ‖ leaf)에 커밋합니다. 따라서 단일 파일 증명은 1-리프 트리가 아니라 반드시 일반 해시 식별자를 사용해야 합니다(MUST).

AEAD

AEAD 레지스트리는 와이어상에서 봉인된 페이로드를 어떤 콘텐츠 포맷이 보호하는지, 즉 enc.aead 필드를 규정합니다. enc.scheme: 1 아래에는 정확히 하나의 식별자가 등록되어 있으며, 그것은 단발(single-shot) 암호가 아니라 세그먼트화된 포맷입니다.

IdentifierAlgorithmKey / Nonce / Per-chunk nonce / TagStatus
chacha20-poly1305-stream64kChaCha20-Poly1305, 64 KiB segmented STREAM32 B / 24 B / 12 B / 16 B per chunkMandatory — the wire format
aes-256-gcmAES-256-GCMReserved (future profile)

chacha20-poly1305-stream64kage v1 명세의 64 KiB 세그먼트화 STREAM 레이아웃을 적용한 ChaCha20-Poly1305(RFC 8439)입니다. 평문은 65536바이트 청크로 분할되고, 각 청크는 콘텐츠 키 아래에서 12바이트의 청크별 논스 uint88_be(counter) ‖ final_flag(counter는 0부터, final_flag는 마지막 청크에서 0x01)와 빈 청크별 AAD로 봉인되어 청크마다 16바이트 태그를 생성합니다. 24바이트의 enc.nonce는 청크 논스가 아닙니다. 그것은 콘텐츠 키 HKDF의 엔벨로프별 고유 솔트이며, 바로 이것이 카운터 논스를 안전하게 유지합니다. 콘텐츠 키는 일회용이므로 두 스트림이 (key, nonce) 쌍을 공유하는 일은 결코 없으며, 상태를 갖지 않는 게시자가 엔벨로프 사이에서 논스를 조율할 필요도 없습니다. 세그먼트화된 레이아웃 덕분에 검증자는 큰 페이로드를 제한된 메모리로 점진적으로 인증하고 방출할 수 있으며, 최종 플래그는 절단(truncation)을 탐지 가능하게 만듭니다. 와이어상의 철자는 정확히 chacha20-poly1305-stream64k이며, 다른 철자를 생성해서는 안 됩니다(MUST NOT). 전체 구성은 봉인된 PoE에 있습니다.

chacha20-poly1305-stream64k는 와이어상의 콘텐츠 포맷으로 나타날 수 있는 유일한 식별자입니다. 별도의 구성인 chacha20-poly1305(RFC 8439, 32바이트 키 / 12바이트 논스 / 16바이트 태그)는 봉인 구성의 내부에서 수신자별 키를 래핑하는 데 사용됩니다. 즉 12바이트 전체 0 논스, 선택된 KEM의 info 라벨로 설정된 AAD로 48바이트 wrap(32바이트 래핑된 키 + 16바이트 태그)을 생성합니다. 이는 구성 요소일 뿐 와이어 식별자가 아니므로, 이를 enc.aead에 명명한 레코드는 거부되어야 합니다(MUST). aes-256-gcm은 명명되어 있으나 비활성입니다. 미래의 암호화 프로파일(enc.scheme: 2)을 위해 예약되어 있으며, v1 검증자는 이를 선택한 레코드를 모두 거부합니다.

KEM

KEM 레지스트리는 봉인된 페이로드를 특정 수신자에게 지정하는 데 사용하는 키 캡슐화 메커니즘을 다룹니다. Label 309는 고전적인 곡선 기반 KEM 하나와, 첫 릴리스부터 활성 상태로 제공되는 포스트 양자 하이브리드를 등록합니다.

IdentifierAlgorithmPublic key / SecretCiphertext / Shared secret
x25519X25519 ECDH (RFC 7748)32 B / 32 B32 B / 32 B
mlkem768x25519X-Wing hybrid (ML-KEM-768 + X25519)1216 B / 32 B1120 B / 32 B

mlkem768x25519draft-connolly-cfrg-xwing-kem-10에 기반한 X-Wing 구성입니다. 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 철자에 맞추어 내부에 하이픈 없이 표기합니다.

이 하이브리드는 콘텐츠 AEAD와 독립적으로, 암호화 헤더에 의해 레코드별로 선택됩니다. 이미 등록되어 있으므로, 포스트 양자 기밀성은 새 와이어 포맷 버전을 기다리는 것이 아니라 식별자를 선택하기만 하면 되는 문제입니다.

하나의 레코드는 정확히 하나의 enc.kem을 명명하며, 모든 슬롯은 그 KEM의 형태를 사용합니다. 형태가 잘못된 슬롯은 ENC_SLOT_INVALID_SHAPE, 길이가 잘못된 epk(≠ 32 B)나 kem_ct(≠ 1120 B)는 KEM_EPK_LENGTH_MISMATCH / KEM_CT_LENGTH_MISMATCH, 등록되지 않은 enc.kemUNSUPPORTED_KEM_ALG가 됩니다. 캡슐화 재료는 또한 하나의 slots[] 안에서 서로 달라야 합니다. 모든 epk 값(x25519의 경우)이나 모든 kem_ct 값(mlkem768x25519의 경우)이 서로 달라야 합니다(MUST). 레코드 내부의 중복은, 어떤 KEM이나 AEAD 프리미티브가 실행되기 전에 ENC_SLOTS_DUPLICATE_KEM_MATERIAL로 거부됩니다. epkkem_ct의 반복은 전체 0 논스 래핑이 의존하는 슬롯별 키 고유성을 깨뜨리기 때문입니다. 검증자는 또한 어떤 프리미티브보다도 먼저 파서의 리소스 사용을 제한합니다. slots[]가 참조 상한인 1024 슬롯을 초과하는 엔벨로프는 ENC_SLOTS_TOO_MANY, 디코딩된 enc 엔벨로프가 65 536바이트를 초과하는 것은 ENC_ENVELOPE_TOO_LARGE가 됩니다. 두 상한 모두 정직한 레코드를 제한하는 약 16 KiB의 Cardano 메타데이터 상한을 훨씬 웃돕니다. 이들은 와이어 필드가 아니라 검증자가 강제하는 배포 고정 상수이며, 배포 측에서 더 엄격하게 조여도 됩니다(MAY).

KDF

KDF 레지스트리는 키 도출 함수에 이름을 붙입니다. hkdf-sha256은 봉인 구성 내부에서 키를 도출하고, argon2id는 무차별 대입 공격에 맞서 사람의 패스프레이즈를 늘려 펴며 필수 파라미터 하한을 갖습니다.

IdentifierAlgorithmParameters
hkdf-sha256HKDF-SHA-256 (RFC 5869)salt (optional), info (optional), output length
argon2idArgon2id (RFC 9106)memory ≥ 65536 KiB, iterations ≥ 3, parallelism ≥ 1

Argon2id 하한은 규범적입니다. 패스프레이즈로 보호된 페이로드는 최소 64 MiB의 메모리, 최소 3회 반복, 최소 1개 레인을 사용해야 합니다(MUST). 게시자는 더 강한 파라미터를 선택해도 되며(MAY), 그 파라미터는 검증자가 도출을 재현할 수 있도록 레코드와 함께 전달됩니다. 플랫폼이 지원하는 경우, 게시자는 병렬도 p = 4를 설정해야 합니다(SHOULD) — 이는 RFC 9106 §4의 두 번째 권장 프로파일입니다 — 반면 검증자는 배포 상한에 따르는 한 p ≥ 1의 어떤 값이라도 받아들여도 됩니다(MAY). 이 상한은 구현상의 MAY가 아니라 SHOULD입니다. 검증자는 터무니없는 파라미터로 인한 검증자 측 서비스 거부를 막기 위해 상한을 강제해야 하며(SHOULD), ENC_PASSPHRASE_PARAMS_EXCEED_POLICY를 보고합니다. 이 상한은 하드웨어에 따라 달라지고 비규범적이며, 하한 코드 ENC_PASSPHRASE_ARGON2_PARAMS_TOO_LOW와 혼동해서는 안 됩니다(MUST NOT).

와이어에서 선택할 수 있는 것은 argon2id뿐입니다. 이는 레코드가 enc.passphrase.alg에 명명할 수 있는 유일한 식별자입니다. hkdf-sha256내부 구성 요소로서, 시드에서 키로의 도출, 슬롯별 KEK 도출, 슬롯 집합 MAC 키, 패스프레이즈 커밋먼트 MAC 키, 그리고 콘텐츠 키 도출의 배후에 있는 고정된 추출-확장(extract-and-expand) 단계이며, 와이어 식별자를 갖지 않습니다. enc.passphrase.alghkdf-sha256을 명명한 레코드는 거부되어야 합니다(MUST). HKDF는 고엔트로피 입력을 위해 만들어진 것이지, 저엔트로피 패스프레이즈를 늘려 펴기 위한 것이 아닙니다.

내부 라벨은 상수이며, 결코 와이어에 실리지 않는다

봉인 구성은 고정된 라벨 리터럴 집합에서 도메인 분리를 끌어냅니다 — HKDF info 태그와 SHA-256 접두사(KEK 솔트 접두사, 트랜스크립트 접두사, 그리고 아이템 해시 접두사)입니다. 각각은 enc.scheme: 1의 상수이며, 종결자도 길이 접두사도 없는 엄밀한 ASCII입니다. 어느 것도 직렬화되지 않으며, 어떤 레지스트리를 통해서도 선택할 수 없습니다. 전부 열한 개입니다.

LabelRole
cardano-poe-kek-v1HKDF info for the per-slot KEK on the x25519 path
cardano-poe-kek-mlkem768x25519-v1HKDF info for the per-slot KEK on the mlkem768x25519 path
cardano-poe-x25519-kek-salt-v1SHA-256 prefix for the x25519 KEK HKDF salt
cardano-poe-xwing-kek-salt-v1SHA-256 prefix for the mlkem768x25519 KEK HKDF salt
cardano-poe-item-hashes-v1SHA-256 prefix for the item-hashes digest hashes_hash
cardano-poe-slots-transcript-v1SHA-256 prefix for the slots-transcript hash slots_hash
cardano-poe-slots-mac-v1HKDF info for the slot-set MAC key
cardano-poe-passphrase-transcript-v1SHA-256 prefix for the passphrase-transcript hash pw_hash
cardano-poe-passphrase-mac-v1HKDF info for the passphrase commitment MAC key
cardano-poe-payload-v1HKDF info for the slots-path content key
cardano-poe-payload-passphrase-v1HKDF info for the passphrase-path content key

두 KEK 솔트는 각자 자신의 KEM별 라벨 아래에서 하나의 라벨 부착 해시 형태 — SHA-256(label ‖ enc.nonce ‖ <slot KEM material> ‖ pub_R) — 를 공유합니다. 이 라벨들은 의 시드 도출 info 문자열과도, 서명의 레코드 서명 도메인 접두사와도 구별됩니다. 이 집합은 충돌이 없고 접두사가 겹치지 않으므로, 어떤 레코드별 봉인 라벨도 장기 키 도출 라벨과 같거나 그것의 바이트 접두사가 되지 않으며, 신원 키 도출과 레코드별 키 래핑이 결코 충돌하지 않습니다. 검증자는 각 리터럴을 바이트 단위로 그대로 사용해야 합니다(MUST). 단 한 바이트라도 어긋나면 정직한 게시자가 재현할 수 없는 slots_mac, 커밋먼트, 또는 AEAD 태그가 됩니다. 각 라벨을 소비하는 바이트 수준 구성은 봉인된 PoE에 있습니다.

Signature

Label 309는 하나의 서명 알고리즘을 등록합니다. 저작자 서명은 항상 선택적이지만, 존재할 경우 Ed25519를 사용한 COSE_Sign1(RFC 9052)으로 운반됩니다.

IdentifierCOSE algAlgorithmWrapper
EdDSA-8Ed25519 (RFC 8032)COSE_Sign1 (RFC 9052)

검증은 RFC 8032 §5.1.7에 따라 엄격합니다. 구현은 비정규(non-canonical) 서명 인코딩과 소위수(small-order) 점을 거부해야 합니다(MUST) — 코팩터 제거 확장은 없습니다. 이는 Cardano 지갑 전반에서 사용되는 보수적인 수용 기준과 일치하므로, 어떤 적합 구현에서 검증되는 서명은 그 모든 구현에서 검증됩니다.

서명 지원은 콘텐츠 주장과 독립적입니다. 레코드의 서명 알고리즘을 구현하지 않은 검증자는 그 서명 슬롯을 미지원으로 표시하고 타임스탬프와 콘텐츠 주장은 완전히 유효한 채로 둡니다 — 알 수 없는 서명 알고리즘이 레코드 자체를 무효화하는 일은 결코 없습니다.

Reserved identifiers

몇몇 식별자는 명명되어 있으나 아직 활성화되지 않았습니다. 이들은 합의된 마이그레이션 경로를 표시하여, 미래의 프로파일이 임시방편 문자열이 아니라 안정적이고 사전에 약속된 이름을 사용하도록 합니다. 적합한 게시자는 이들을 내보내서는 안 되며(MUST NOT), 적합한 검증자는 이 중 하나를 사용하는 레코드를 대응하는 타입 지정 오류로 거부해야 합니다(MUST).

IdentifierAlgorithmRole
aes-256-gcmAES-256-GCM (NIST SP 800-38D)Content AEAD
ml-kem-768ML-KEM-768 (FIPS 203), standaloneKEM
ml-dsa-65ML-DSA (FIPS 204)Signature
slh-dsa-sha2-128sSLH-DSA (FIPS 205)Signature

ml-kem-768단독의 포스트 양자 KEM으로, 등록된 하이브리드 mlkem768x25519와는 별개입니다. Label 309가 제공하는 것은 하이브리드 쪽이며, 이는 포스트 양자 절반이 추가된 뒤에도 고전적 폴백은 남아 있어야 한다는 원칙에 따른 것입니다.

Algorithm agility and migration

알고리즘 추가는 그 자체로 완결되는 추가적 작업입니다. 프리미티브에 대해 공개 표준을 인용하고, 식별자를 적절한 레지스트리에 추가하고, 충분히 검토된 신뢰할 만한 구현을 제공하고, 독립적인 구현들이 바이트 단위로 일치하도록 언어 간 적합성 픽스처를 게시합니다. 스키마가 바뀌지 않으므로 와이어 포맷 버전은 바뀌지 않습니다 — 늘어나는 것은 인식되는 문자열 집합뿐입니다.

그 귀결은 레지스트리 설계에서 곧바로 따라 나옵니다.

  • 오래된 레코드는 검증 가능한 채로 남는다. 그 식별자는 여전히 레지스트리에 있으므로, 기존의 모든 레코드는 게시된 그날과 정확히 똑같이 검증됩니다.
  • 오래된 검증자는 안전하게 닫히며 실패한다. 새 식별자보다 앞서 만들어진 검증자는 그것을 사용하는 레코드를 추측하는 것이 아니라 안정적인 UNSUPPORTED_* 오류로 거부합니다 — 조용히 받아들이는 경로는 존재하지 않습니다.
  • 포스트 양자 지원은 추가적이다. mlkem768x25519가 이미 등록되어 있고, 새로운 KEM과 서명도 같은 메커니즘에 들어맞으므로, 포스트 양자 전환은 레지스트리의 확장일 뿐 호환성을 깨는 마이그레이션이 아닙니다.

와이어 포맷 버전 상향은 진정으로 호환성을 깨는 스키마 변경 — 필수 필드 추가, 필드 제거, 타입 변경 — 에만 한정됩니다. 레지스트리 확장은 결코 여기에 해당하지 않으며, 바로 그것이 암호 방식 카탈로그가 게시된 증명을 결코 고립시키지 않으면서 진화할 수 있게 합니다.