← Gray Password 论文库 · GP-24a

24字符外星密码体系(v ↔ U)——从手写防呆到8字节无损压缩的全栈设计

Jingsong Deng & Gemini 联合架构组 · 发表日期:2000-01-24

📜 原文忠实版

本页严格保留作者原文设计:字母表使用人类惯用的四进制数字 0 1 2 3,不替换、不删减任何字符。
ALIEN24_ALPHABET = "0123abcdefghvABCDEFGHU,!"
(另一个工程化改写版本见 GP-24)

摘要

本文按原文设计给出 24 字符外星密码体系:4 个四进制数字 0 1 2 3、8 个小写字母 a–h 加 v、8 个大写字母 A–H 加 U,以及两个标点 “,” 与 “!”。小写与大写一一配对(a↔A … h↔H),v ↔ U 是这一配对中的特殊一组:手写时 v 与 U 的形态互为“镜像”,作者把二者设计成一对,用于手写防呆。存储层比较两种 8 字节方案:每符号 5 bit 定长可存 12 个符号;24 进制整数打包利用 \(24^{13}<2^{64}\) 可存 13 个符号。最后给出打分器、极坐标分级公式 \(\text{Level}_{16}=(r\ll 8)\,|\,\theta\) 与 Python 示例。

Abstract

Faithful to the original design: the alphabet is exactly 0123abcdefghvABCDEFGHU,!, with quaternary digits 0–3, paired lowercase/uppercase letters (v ↔ U), and the punctuation ',' and '!'. Radix-24 packing stores 13 symbols in a uint64 since \(24^{13}<2^{64}\).

第一部分:字母表构成

分组符号数量索引
四进制数字0 1 2 340–3
小写字母a b c d e f g h v94–12
大写字母A B C D E F G H U913–21
标点, !222–23
合计24
索引符号索引符号索引符号索引符号
006c12v18F
117d13A19G
228e14B20H
339f15C21U
4a10g16D22,
5b11h17E23!

第二部分:v ↔ U 配对设计

小写组与大写组按索引相差 9 一一对应:

$$\text{pair}(i)=i+9,\qquad 4\le i\le 12$$
小写abcdefghv
索引456789101112
大写ABCDEFGHU
索引131415161718192021

前 8 对是自然的大小写关系;第 9 对 v ↔ U 是作者的设计:v 是尖底、U 是圆底,开口方向相同,手写时可以用“尖/圆”区分,同时又作为一对保留在体系中。四进制数字 0 1 2 3 则沿用人类最熟悉的写法,降低记忆负担。

第三部分:5-bit 与 24 进制打包公式

单符号信息量 \(\log_2 24\approx 4.585\) bit。

3.1 5-bit 定长

$$W_5(s)=\bigvee_{i=0}^{n-1}\big(\mathrm{idx}(c_i)\ll 5(n-1-i)\big),\qquad 5n\le 64\Rightarrow n_{\max}=12$$

3.2 24 进制

$$W_{24}(s)=\sum_{i=0}^{n-1}\mathrm{idx}(c_i)\cdot 24^{\,n-1-i}$$ $$24^{13}=876\,488\,338\,465\,357\,824\ <\ 2^{64}=18\,446\,744\,073\,709\,551\,616\ <\ 24^{14}$$
方案符号数 / uint64使用位数利用率
ASCII86457.3%
5-bit 定长126086.0%
24 进制1359.6093.1%

(利用率 = 有效熵 / 64 bit。)

第四部分:打分器

$$S(s)=n\log_2 24+B_{\text{mix}}-P_{\text{rep}}-P_{\text{pair}}$$
项判定分值
\(B_{\text{mix}}\)同时含数字、小写、大写、标点四类+4(每多一类 +1)
\(P_{\text{rep}}\)相邻相同符号−3/处
\(P_{\text{pair}}\)相邻为配对(如 aA、vU)−2/处

第五部分:极坐标分级

$$r=\min\!\left(255,\left\lfloor\frac{S}{13\log_2 24}\cdot 255\right\rfloor\right),\quad \theta=\left\lfloor\frac{\arctan2(y,x)+\pi}{2\pi}\cdot 255\right\rfloor$$ $$\text{Level}_{16}=(r\ll 8)\,|\,\theta$$

\(x=\) 小写占比 − 大写占比,\(y=\) 数字与标点占比 − 0.5。

\(r\)等级
0–95白
96–191灰
192–255黑

第六部分:Python 示例

import math

ALIEN24_ALPHABET = "0123abcdefghvABCDEFGHU,!"
assert len(ALIEN24_ALPHABET) == 24 and len(set(ALIEN24_ALPHABET)) == 24
IDX = {c: i for i, c in enumerate(ALIEN24_ALPHABET)}
H = math.log2(24)
MAX_LEN = 13                       # 24**13 < 2**64

def pair(c: str) -> str:
    """a<->A ... h<->H, v<->U"""
    i = IDX[c]
    if 4 <= i <= 12:
        return ALIEN24_ALPHABET[i + 9]
    if 13 <= i <= 21:
        return ALIEN24_ALPHABET[i - 9]
    return c

def pack24(s: str) -> int:
    assert 1 <= len(s) <= MAX_LEN and all(c in IDX for c in s)
    w = 0
    for c in s:
        w = w * 24 + IDX[c]
    return w * 21 + len(s)         # 24**13 * 21 < 2**64,附带长度

def unpack24(w: int) -> str:
    w, n = divmod(w, 21)
    out = []
    for _ in range(n):
        w, d = divmod(w, 24)
        out.append(ALIEN24_ALPHABET[d])
    return "".join(reversed(out))

def pack5(s: str) -> int:
    assert len(s) <= 12
    w = 0
    for c in s:
        w = (w << 5) | IDX[c]
    return (w << 4) | len(s)

def classes(s):
    return {"digit" if IDX[c] < 4 else "lower" if IDX[c] < 13
            else "upper" if IDX[c] < 22 else "punct" for c in s}

def score(s: str) -> float:
    k = len(classes(s))
    bonus = k if k == 4 else max(0, k - 1)
    pen = 0
    for a, b in zip(s, s[1:]):
        if a == b:
            pen += 3
        elif pair(a) == b:
            pen += 2
    return max(0.0, len(s) * H + bonus - pen)

def level16(s: str) -> int:
    r = min(255, int(score(s) / (MAX_LEN * H) * 255))
    n = len(s)
    x = (sum(4 <= IDX[c] <= 12 for c in s) - sum(13 <= IDX[c] <= 21 for c in s)) / n
    y = sum(IDX[c] < 4 or IDX[c] >= 22 for c in s) / n - 0.5
    theta = int((math.atan2(y, x) + math.pi) / (2 * math.pi) * 255)
    return (r << 8) | theta

if __name__ == "__main__":
    p = "3vA,b2!UhC0gE"                  # 13 个符号,含 ',' 与 '!'
    w = pack24(p)
    assert w < 2**64 and unpack24(w) == p
    assert pair("v") == "U" and pair("U") == "v"
    print(p, w, round(score(p), 2), hex(level16(p)), bin(pack5(p[:12])))

结论

原文设计以 0 1 2 3 四进制数字、a–h/A–H 大小写配对、v ↔ U 特殊配对与 “,” “!” 两个标点组成 24 字符体系;24 进制打包让一个 uint64 无损容纳 13 个符号并附带长度信息。

参考文献(示意)

  1. Gray Password GP-000101 / GP-000102 / GP-16 / GP-24(本站前文)。