설정¶
dealcode 인스턴스("코덱")는 키와 네 가지 옵션으로 정의됩니다. 같은 설정은 모든 언어에서 같은 매핑을 만듭니다.
| 파라미터 | 타입 | 기본값 | 의미 |
|---|---|---|---|
key |
bytes 또는 string | — (필수) | AES 키 재료; 키 참고 |
alphabet |
string | "hex" |
프리셋 이름 또는 커스텀 알파벳 |
min_length |
integer | 6 |
시작 코드 길이 |
max_length |
integer | 전체 코드 공간이 2^63 − 1에 들어가는 가장 큰 길이 |
최대 코드 길이 |
domain |
string | "" |
네임스페이스 라벨, FF1 tweak에 바인딩 |
잘못된 설정은 생성 시점에 거절됩니다(ConfigError 또는 각 언어의 관용적
등가물) — 조용히 고쳐지는 일은 없습니다. 정확한 제약은
스펙에 있습니다.
알파벳¶
인덱스 i의 문자가 숫자값 i를 나타내고 코드는 빅엔디언으로
렌더링됩니다. 8가지 프리셋에는 합리적인 디코드 정규화가 딸려 있습니다:
| 이름 | 기수 | 문자 (순서대로) | 디코드 정규화 |
|---|---|---|---|
dec |
10 | 0123456789 |
없음 |
hex |
16 | 0123456789abcdef |
입력을 ASCII 소문자로 |
base32 |
32 | ABCDEFGHIJKLMNOPQRSTUVWXYZ234567 (RFC 4648) |
입력을 ASCII 대문자로 |
crockford |
32 | 0123456789ABCDEFGHJKMNPQRSTVWXYZ (Crockford Base32) |
ASCII 대문자화 후 O→0, I→1, L→1 매핑 |
base36 |
36 | 0123456789abcdefghijklmnopqrstuvwxyz |
입력을 ASCII 소문자로 |
base58 |
58 | 123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz (Bitcoin) |
없음 |
base62 |
62 | 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz |
없음 |
base64url |
64 | ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_ (RFC 4648 §5) |
없음 |
정규화는 decode 입력에만 적용되고 encode는 항상 표준 문자를
출력합니다. 사람이 입력하는 코드에는 crockford가 친절한 선택입니다:
혼동 문자가 없고 0 대신 O를 치는 오타도 자동으로 되돌립니다.
구분자는 무시되지 않습니다
Crockford의 원래 Base32 에세이와 달리 dealcode는 하이픈/공백을
건너뛰지 않습니다: decode("H4P-FG6")은 거부됩니다. 코드를
XXXX-XXXX처럼 묶어 표시한다면 디코드 전에 구분자(및 앞뒤 공백)를
제거하세요.
커스텀 알파벳은 서로 다른 출력 가능 ASCII 문자(0x21–0x7E, 공백과
제어 문자 제외) 2–94자로 된 아무 문자열이나 됩니다 — "!@#$%^&*"도
동작합니다. 커스텀 알파벳에는 정규화가 없습니다: 디코드 입력이 정확히
일치해야 합니다.
도메인¶
domain은 네임스페이스 라벨입니다("orders", "coupons", "invites").
같은 키에 다른 도메인이면 서로 무관한 순열이 나옵니다 — 키 하나로
독립적인 코드 스트림을 무제한으로 만들 수 있고 네임스페이스마다 키를
따로 두는 것보다 운영이 훨씬 쌉니다. 도메인은 "dealcode/v1/" + domain
형태로 FF1 tweak에 바인딩되므로 포맷 v1은 미래의 v2와도, 같은 키의 다른
FF1 용도와도 분리됩니다.
제약: 유효한 유니코드(U+0000 금지, 짝 없는 서로게이트 금지), UTF-8 바이트 길이 ≤ 255.
키¶
키는 여러 모양으로 존재하고 모두 하나의 결정적 규칙으로 받아들여집니다 — 모든 언어가 공유하는 규칙입니다:
- 길이가 정확히 16/24/32인 바이트 → 그대로 AES 키로 사용.
- 그 외 비어 있지 않은 바이트와 모든 문자열 → AES-256 키로 확장:
SHA-256("dealcode/v1/kdf" ‖ 재료). - 빈 키 재료 →
ConfigError.
hex처럼 보이는 문자열은 hex 디코딩되지 않습니다
문자열은 항상 UTF-8 바이트로 취급되어 파생됩니다 — hex처럼 보여도
마찬가지입니다. openssl rand -hex 32의 출력을 문자열 그대로 넘기면
모든 언어가 같은 AES-256 키를 파생합니다. 하지만 한 서비스에서는 직접
hex 디코딩하고 다른 서비스에서는 문자열로 넘기면 서로 다른 두
순열이 됩니다. 한 형태를 정해 모든 곳에서 쓰세요. (추측 금지 규칙은
의도적입니다: 자동 감지는 "deadbeef..."를 모호하게 만듭니다.)
파생은 도메인 분리이지 패스워드 스트레칭이 아닙니다: 패스프레이즈 키의
강도는 정확히 그 패스프레이즈만큼입니다. 128비트 이상의 랜덤
재료(openssl rand -hex 32)를 쓰세요. 문자열 키 재료는 유효한 유니코드여야
합니다 — U+0000과 짝 없는 서로게이트는 조용히 재인코딩되지 않고
거절됩니다. 모든 언어가 같은 키를 파생하거나, 아무 언어도 파생하지 않거나
둘 중 하나입니다.
길이 스테이징¶
코드는 min_length에서 시작해 현재 길이가 소진됐을 때만 한 글자씩
자랍니다. 기수 r에서 첫 스테이지는 카운터 [0, r^min_length)를, 스테이지
d는 [r^(d−1), r^d)를 담당합니다:
hex에min_length=6: 6자리 코드 16,777,216개를 다 쓴 뒤에야 — 그때만 — 7자리로 넘어갑니다.- 길이가 다른 코드끼리는 자명하게 충돌 불가, 같은 길이 안에서는 FF1이 순열 — 따라서 전체 매핑이 전단사입니다.
min_length == max_length면 고정 길이 코드입니다. 기본 max_length는
부호 있는 64비트 카운터로 전체 코드 공간에 도달할 수 있는 가장 큰
길이입니다(hex → 15, dec → 18, base32/crockford/base36 → 12,
base58/base62/base64url → 10). 길거나 고정된 모양(16자리 hex, 12자리
base62)을 위해 r^max_length ≤ 2^128까지 올릴 수 있습니다. 카운터는
여전히 2^63으로 제한되고 남는 코드 공간은 decode가 거절합니다.
작은 첫 스테이지(r^min_length ≥ 100까지)도 지원되고 상호 운용되지만
아주 작은 코드 공간은 손쉽게 열거됩니다 — 보안 모델을
보세요.
고정 길이 순환 모드¶
코드가 절대 길어지면 안 될 때 — 항공권 예약코드(PNR)처럼 항상 정확히
L자 — 순환 모드(SPEC §11)는 고정 길이를 유지한 채, 공간이 소진되면 한
글자를 늘리는 대신 다른 순열(사이클 1, 사이클 2, …)로 같은 공간을 다시
채웁니다. 카운터 n은 사이클 n ÷ rᴸ에 속하고 각 사이클은 가능한 모든
문자열을 키·사이클에 따라 달라지는 새로운 순서로 정확히 한 번씩 발급합니다.
사이클을 넘으면 코드가 반복됩니다 — 설계상 그렇습니다
재사용이 이 모드의 존재 이유이므로, 사이클을 가로지르는 전역
UNIQUE(code) 계약은 더 이상 성립하지 않습니다. 유일성 범위마다 한
사이클의 코드만 살아 있게 유지하고(넘어가기 전에 만료·회수),
UNIQUE(cycle, code)로 인덱싱하고, 살아 있는 코드의 사이클을
저장하세요 — 같은 문자열이 사이클마다 다른 카운터로 풀리기 때문에
decode(code, cycle)에 사이클이 필요합니다.
제약: 2 ≤ L ≤ 128, radix^L ≥ 100, radix^L ≤ 2^63 (사이클이 카운터
공간 안에서 완주 가능해야 합니다 — 더 큰 고정 모양은 일반 모드의
min_length == max_length를 쓰세요).
설정은 출시되는 순간 동결¶
한 번 쓰면 끝인 설정
한 네임스페이스(하나의 카운터 시퀀스)에서 설정 전체 — 키, 알파벳,
min_length, max_length, domain — 는 첫 코드가 나가는 순간
동결됩니다. 다른 설정은 다른 순열이고 한 카운터 공간 위의 두
순열은 이미 발급된 코드와 충돌할 수 있습니다.
새로운 체계가 필요하면? 새 도메인(또는 새 키 + 새 네임스페이스). 키 로테이션도 새 네임스페이스를 뜻합니다 — 기존 코드는 기존 설정에서만 복호화됩니다.
따름정리: 두 시퀀스를 같은 코덱+도메인에 넣지 말 것, 시퀀스를 뒤로 리셋하지
말 것, 그리고 데이터베이스 연동에서 설명한 UNIQUE 경보
인덱스를 유지할 것.