外星微缩字母表:16字符体系在计算机科学与信息论中的数学巧合与应用
摘要
设想一个只使用 16 个符号的“外星微缩字母表”。本文指出,这一看似随意的选择与计算机科学存在一连串数学巧合:一个符号恰好是 4 bit(半字节,nibble),16 个符号恰好填满一个 64 位机器字,\(16^{16}=2^{64}\),使密码空间与 uint64 的取值空间一一对应、零浪费。在此基础上,本文给出存储层的 8 字节打包方案、空间坍缩计算、打分法则、极坐标分级公式 \(\text{Level}_{16}=(r\ll 8)\,|\,\theta\),讨论彩虹表在该体系中的意义与防御,并给出 Python 参考实现结构。
Abstract
We study a 16-symbol "alien micro-alphabet". Each symbol is exactly one nibble, 16 symbols fill one 64-bit word, and \(16^{16}=2^{64}\), so the password space maps bijectively onto uint64. We present 8-byte packing, space-collapse arithmetic, a scoring rule, the polar level formula \(\text{Level}_{16}=(r\ll 8)|\theta\), a discussion of rainbow tables, and a Python reference structure.
第一部分:字母表定义
为与十六进制兼容,取 \(\Sigma_{16}=\{0,\dots,9,A,\dots,F\}\),每个符号的值即其 4 位二进制码:
| 符号 | 值 | 二进制 | 符号 | 值 | 二进制 |
|---|---|---|---|---|---|
| 0 | 0 | 0000 | 8 | 8 | 1000 |
| 1 | 1 | 0001 | 9 | 9 | 1001 |
| 2 | 2 | 0010 | A | 10 | 1010 |
| 3 | 3 | 0011 | B | 11 | 1011 |
| 4 | 4 | 0100 | C | 12 | 1100 |
| 5 | 5 | 0101 | D | 13 | 1101 |
| 6 | 6 | 0110 | E | 14 | 1110 |
| 7 | 7 | 0111 | F | 15 | 1111 |
每符号信息量 \(\log_2 16=4\) bit,恰为整数。这是 16 字符体系的第一个巧合:编码无需算术编码或进制转换,移位即可。
第二部分:存储层——8 字节 uint64 打包
长度为 16 的密码 \(s=c_0c_1\cdots c_{15}\) 按大端顺序打包:
$$W(s)=\sum_{i=0}^{15} v(c_i)\cdot 16^{15-i}=\bigvee_{i=0}^{15}\big(v(c_i)\ll 4(15-i)\big)$$| 项目 | 数值 |
|---|---|
| 符号数 | 16 |
| 每符号位数 | 4 bit |
| 总位数 | 16 × 4 = 64 bit = 8 字节 |
| 利用率 | 64 / 64 = 100% |
| 对比 ASCII 存储 | 16 字节 → 8 字节,节省 50% |
解包:\(c_i=\Sigma_{16}\big[(W\gg 4(15-i))\,\&\,\texttt{0xF}\big]\)。打包结果可直接作为数据库主键、哈希表键或 SIMD 比较单元,一条 64 位比较指令即可判断两个密码是否相等。
第三部分:空间坍缩计算
“空间坍缩”指字符串空间坍缩为整数空间后,其大小与机器字完全重合:
$$|\Sigma_{16}|^{16}=16^{16}=(2^4)^{16}=2^{64}=18\,446\,744\,073\,709\,551\,616$$| 长度 \(n\) | 空间 \(16^n\) | 熵(bit) | 容器 |
|---|---|---|---|
| 4 | \(2^{16}=65\,536\) | 16 | uint16 |
| 8 | \(2^{32}\approx 4.29\times10^{9}\) | 32 | uint32 |
| 12 | \(2^{48}\approx 2.81\times10^{14}\) | 48 | uint64(余 16 位) |
| 16 | \(2^{64}\approx 1.84\times10^{19}\) | 64 | uint64(满) |
按每秒 \(10^{10}\) 次离线猜测,穷举 \(2^{64}\) 约需 \(1.84\times10^{9}\) 秒,约 58 年;平均命中约 29 年。长度每减 1,空间缩小 16 倍。
第四部分:打分法则
均匀随机生成时熵为 \(4n\) bit;人类挑选的密码存在模式,故定义:
$$S(s)=4n-P_{\text{rep}}(s)-P_{\text{seq}}(s)-P_{\text{dict}}(s),\qquad S\in[0,64]$$| 扣分项 | 判定 | 扣分 |
|---|---|---|
| \(P_{\text{rep}}\) 重复 | 相邻相同符号(如 AAAA) | 3 bit/处 |
| \(P_{\text{seq}}\) 顺序 | 相邻值差 ±1(如 1234、FEDC) | 2 bit/处 |
| \(P_{\text{dict}}\) 词典 | 含 DEADBEEF、CAFE、C0FFEE 等十六进制“单词” | 8 bit/个 |
| 分数区间 | 等级 |
|---|---|
| \(S<24\) | 白(弱) |
| \(24\le S<48\) | 灰(中) |
| \(S\ge 48\) | 黑(强) |
第五部分:极坐标分级公式
沿用 GP-000101 的极坐标叶状剖分,把分数视为半径、模式特征视为角度:
$$r=\left\lfloor \frac{S}{64}\cdot 255\right\rfloor,\qquad \theta=\left\lfloor \frac{\arctan2(y,x)+\pi}{2\pi}\cdot 255\right\rfloor$$其中 \(x\) 为数字符号占比减 0.5,\(y\) 为 D–F 符号占比减 0.5。两个 8 位量拼成 16 位等级码:
$$\text{Level}_{16}=(r\ll 8)\,|\,\theta,\qquad 0\le \text{Level}_{16}\le 65\,535$$高字节决定强度环,低字节决定扇区。按 \(\text{Level}_{16}\) 排序即先按强度、再按风格聚类;而它本身恰好又是一个 4 字符的 16 进制串,体系在自身内部闭合。
第六部分:彩虹表说明
彩虹表以时间换空间:预先计算哈希链 \(p_0\xrightarrow{H}h_0\xrightarrow{R}p_1\xrightarrow{H}\cdots\),只存链首与链尾。覆盖 \(2^{64}\) 空间需 \(mt\approx 2^{64}\);即使链长 \(t=10^{6}\),仍需约 \(1.8\times10^{13}\) 条链,每条 16 字节,总计约 295 TB。
| 场景 | 结论 |
|---|---|
| 无盐快速哈希(MD5/SHA-1) | 长度 ≤ 10(\(2^{40}\))的 16 字符密码可被彩虹表实际覆盖 |
| 每用户随机盐(≥ 64 bit) | 预计算失效,须为每个盐重建 |
| 慢哈希(Argon2id / scrypt) | 单次计算代价放大 \(10^{4}\) 倍以上 |
由于空间结构完全规则,约简函数 \(R\) 极易设计,这对攻击者有利。因此加盐与慢哈希是本体系的强制要求。
第七部分:Python 代码结构
import math
ALPHABET = "0123456789ABCDEF"
IDX = {c: i for i, c in enumerate(ALPHABET)}
DICT = ("DEADBEEF", "CAFE", "C0FFEE", "BADC0DE", "FACE")
def pack(s: str) -> int:
"""16 符号 -> uint64(大端)"""
s = s.upper()
assert len(s) == 16 and all(c in IDX for c in s)
w = 0
for c in s:
w = (w << 4) | IDX[c]
return w
def unpack(w: int) -> str:
return "".join(ALPHABET[(w >> (4 * (15 - i))) & 0xF] for i in range(16))
def score(s: str) -> int:
s = s.upper()
v = [IDX[c] for c in s]
pen = sum(3 if a == b else 2 if abs(a - b) == 1 else 0
for a, b in zip(v, v[1:]))
pen += 8 * sum(w in s for w in DICT)
return max(0, min(64, 4 * len(s) - pen))
def level16(s: str) -> int:
s = s.upper()
r = int(score(s) / 64 * 255)
x = sum(c.isdigit() for c in s) / len(s) - 0.5
y = sum(c in "DEF" for c in s) / len(s) - 0.5
theta = int((math.atan2(y, x) + math.pi) / (2 * math.pi) * 255)
return (r << 8) | theta
if __name__ == "__main__":
p = "3A9F0C17E2B54D68"
w = pack(p)
assert unpack(w) == p and w < 2**64
print(hex(w), score(p), hex(level16(p)))
结论
16 字符体系的价值不在“更难猜”,而在“与机器完全同构”:4 bit/符号、\(16^{16}=2^{64}\)、等级码自身也是 16 进制串。它是白灰密码体系中最紧凑、最易实现的基准层;GP-24 将讨论更适合人类手写的 24 字符体系。
参考文献(示意)
- Gray Password GP-000101 / GP-000102(本站前文)。
- Oechslin, P. Making a Faster Cryptanalytic Time-Memory Trade-Off, CRYPTO 2003.
- RFC 9106: Argon2 Memory-Hard Function.