Sing-song:用于长数字和密钥的可发音编码

Lobsters Hottest 工具

摘要

Sing-song 是一种可逆编码方案,将字节字符串转换为可发音的音节,旨在实现语音表达和可转录性,同时保持确定性和前缀稳定性。

<p><a href="https://lobste.rs/s/wvwqro/sing_song_speakable_encoding_for_long">评论</a></p>
查看原文
查看缓存全文

缓存时间: 2026/08/19 20:35

# Sing-song:一种用于长数字和密钥的可朗读编码 来源:https://blog.vrypan.net/2026/08/19/260819-sing-song/ 这是一个有趣的实验,最初是为了给 Nostr 的 `npub` 密钥生成确定性“用户名”(见最后一节)。即使是简单音节,英语处理起来也相当困难,因此结果不如我期望的那样好——一种你可以通过电话读给对方并确保他们听懂的字符串——但也不算差。如果大家都说意大利语,Sing-song 会更有价值😊 --- *状态:草稿,v0.1.0 ——欢迎评论。* ## 摘要 Sing-song 是一种可逆编码,可将任意字节串编码为可发音的 CV 音节。其 64 音节字母表将每个 6 位值直接映射到一个音节。完整编码保留字节长度和前导零字节,无需外部长度元数据,且是规范的。编码具有前缀稳定性:共享输入前缀会产生共享音节前缀。可选的变体后缀为同一字节串提供了可逆的替代表示。 ## 动机 面向机器的编码(如十六进制和 Base58)虽然紧凑,但难以朗读、转录和记忆。Sing-song 牺牲了一些书写密度,以换取一个小巧、规则的发音语法,同时保持确定性、可逆性和计算简单性。 ## 设计目标 编码应是**确定性的**、**可逆的**、**前缀稳定的**、**无需训练即可朗读和转录的**、对于完整字节串是**自包含大小的**,并且无需依赖重载标点符号即可**自我分隔**。 ## 编码方案 ### 字母表 | 位置 | 符号 | 数量 | |------|------|------| | 辅音(奇数位) | `b d f g j k l m n p r s t v w z` | 16 | | 元音(偶数位) | `a i o u` | 4 | 辅音和元音严格交替,产生 64 个开音节 CV 音节,没有辅音丛或音节尾。位置奇偶性决定符号表。省略了 `h`、`y` 和 `e`,因为它们的发音相对不稳定。 ### 音节与分组 每个音节恰好编码 6 位。显示组包含两个音节(如 `zila`、`sibo`),并以装饰性连字符分隔。解析器**必须**忽略连字符:`zilasibotivajuzu` 和 `zila-sibo-tiva-juzu` 是等价的。分组提供了自然的朗读停顿点。 ### 算法 将输入视为比特流,将其拆分为 6 位块(最高有效位优先)。每个块直接映射到一个音节: ``` 位 5..2 → 辅音索引 0..15 位 1..0 → 元音索引 0..3 ``` 对于 `L` 个输入字节,输出 `n = ceil(8·L / 6)` 个音节。如果最后一个块少于六个输入位,则在低位补零。这些零是规范填充,不携带任何信息。完整编码是自包含大小的:`L = floor(6·n / 8)`。解码器重建 6 位块,推断 `L`,返回前 `8·L` 位,并且**必须**拒绝非规范的音节计数或非零填充。前导零字节被保留。 这适用于**完整编码**。截断前缀不表示后面是否还有更多音节。`k` 个音节的前缀对应编码值的前 `6·k` 位,并通过重新计算(而非解码)来验证。 ## 变体 变体是同一字节串的可逆替代表示。变体标识符编码在表示中,因此解码无需外部元数据。 对于输入 `X` 和变体 `v = 0...15`: ``` M(0, n) = 0^n M(v, n) = SHAKE-256("sing-song/variant" ‖ byte(v), n) (对于 v > 0) Y = X XOR M(v, len(X)) ``` 使用普通的 Sing-song 编解码器编码 `Y`。由于 XOR 是自逆的: ``` X = Y XOR M(v, len(Y)) ``` 掩码是公开的,不提供机密性。SHAKE-256 产生确定性流,保持上述前缀稳定性。变体 0 是直接编码。变体标识符渲染为尾随的两个字母后缀:一个元音后跟 `l m n r` 之一: ``` v = 4·i + j 其中 vowel = "aiou"[i], consonant = "lmnr"[j] 0=al 1=am 2=an 3=ar 4=il 5=im 6=in 7=ir 8=ol 9=om 10=on 11=or 12=ul 13=um 14=un 15=ur ``` 变体 0 **应**渲染为无后缀;解析器**必须**接受显式的 `al` 作为等效。奇偶性用于区分后缀:内容辅音占据奇数位置,因此元音出现在奇数位置时只能开始变体后缀。解析器**必须**要求恰好两个尾随字母(元音后跟 `l/m/n/r`),并拒绝其他奇偶性违规。 ## 前缀稳定性 每个完整音节恰好表示六个连续的输入位。因此,如果两个字节串共享前 `6k` 位,则它们的直接 Sing-song 编码共享前 `k` 个音节。对于字节对齐的前缀,边界每 24 位同时是字节对齐和音节对齐的: ``` 3 字节 = 24 位 = 4 个音节 ``` 在这些边界上,截断编码等同于编码截断的字节串: ``` SingSong(X)[0:4k 音节] = SingSong(X[0:3k 字节]) ``` 对于变体,同样适用此属性。SHAKE-256 掩码作为输出流生成,因此较短的掩码是较长掩码的前缀: ``` M(v, 3k) = M(v, len(X))[0:3k] ``` 因此: ``` body(SingSong(X, v))[0:4k 音节] + suffix(v) = SingSong(X[0:3k 字节], v) ``` 对于前缀未结束在字节和音节边界上的情况,共享的前导音节仍表示相同的前导位,但截断的文本本身不是字节串的完整规范编码。 ## 转录与错误处理 位置奇偶性使得有限的修正安全:`0→o`、`1→l` 和 `e→i`。解析器**可以**应用这些修正,**必须**拒绝其他超字母表或奇偶性错误。错误按组定位:当前缀停止匹配时,客户端可以请求重复该组,而不是整个字符串。 ## 考虑过的替代方案 基础语法在三种替代方案中得以保留,值得记录。 ### 精选音节词典 手工挑选的代码本可以通过合并 b/p、d/t、g/k、f/v、s/z、m/n 和 l/r 等音,将易混淆的最小对归为等价类。大约十个声母类 × 四个元音 × 三个韵尾类产生约 120 个稳健音节,或每个约 6.9 位:比 Sing-song 减少约 17% 的音节,具有更好的容错性。代价是大型查找表、更长的书写形式和更重的闭音节。 示例: ``` ban-fok-rim-tus-gal-nom-pik-sur ``` 收益不值得放弃简单的生成语法和轻快、开放的发音。 ### 放宽交替为“无辅音丛”约束 允许 CV、VC 和 CVC,同时仅禁止相邻辅音,将理论容量从 2.95 提高到 3.32 位/字母。一旦禁止重复元音,元音串受限,只允许清晰的双元音(`ai`、`au`、`oi`、`ou`、`ui`),实际收益降至书写长度约 3%,而朗读密度几乎为零。 示例: ``` zilai-sibo-tauva-juzu ``` 微小的收益不足以证明用自动机替代奇偶规则、削弱错误修复能力和使变体解析复杂化是合理的。 ### 精选辅音丛声母 保持开音节但允许精选的英语 CC 声母,产生 `(C | 精选 CC)V`,如 `ba`、`gro`、`pli`、`tru`。使用当前的 16 个简单声母加上十二个辅音丛(`br`、`bl`、`dr`、`fr`、`fl`、`gr`、`gl`、`kr`、`kl`、`pr`、`pl`、`tr`),字母表有 112 个音节,或每个约 6.81 位。一个 256 位值将需要约 38 个音节。 示例: ``` zila-grovi-pluma-triso-fraku-silo-bruna-koti ``` 这保留了 Sing-song 的大部分开放、旋律特性,但牺牲了统一的 CV 语法和奇偶解析,以适度减少朗读长度。16 × 4 CV 字母表是实用的边界:每个音节恰好 6 位,编解码器简单,同时保留了小语法、开放发音和位置解析。 ## 与其他编码的比较 Sing-song 牺牲书写密度以换取朗读密度。每个字母携带 3 位,每个音节恰好 6 位。十六进制每个字符携带 4 位,Base58 约 5.9 位。 | 位数 | 十六进制 | Base58 | Sing-song | 分组 | |------|----------|--------|-----------|------| | 4 | 1 | 2 | 2 | 6 | | 8 | 2 | 2 | 2 | 12 | | 16 | 4 | 3 | 3 | 16 | | 32 | 8 | 6 | 6 | 12 | | 48 | 12 | 9 | 8 | 1 | | 64 | 16 | 12 | 11 | 2 | | 256 | 64 | 44 | 43 | 1.5 | 当值被朗读时,此权衡会发生逆转:十六进制字符名更长且包含强押韵类,而 Sing-song 在每个短 CV 音节中携带 6 位。一个完整的 256 位值需要 43 个音节。 在不存在人类通道的情况下,十六进制或 Base58 更短且更可取。Sing-song 适用于人类必须朗读、说出、输入或记忆的值。 ## 测试向量 编解码器处理字节而不为其赋予语义。 输入 = 32 × `00`: ``` 输入 0000000000000000000000000000000000000000000000000000000000000000 sing-song baba-baba-baba-baba-baba-baba-baba-baba-baba-baba-baba-baba-baba-baba-baba-baba-baba-baba-baba-baba-baba-ba ``` 输入 = SHA-256(`sing-song`): ``` 输入 7910c06577ab67de51fed45ba18f27fc28eb618ebc1b78f9bced0f47fcefec2d sing-song moji-buba-liku-moru-lizi-wiji-zusi-jilu-rala-zapu-zubo-nuru-lala-woza-dovu-nuwi-sugo-vagu-jizu-tusu-wubo-va ``` 另一个 256 位输入: ``` 输入 d16997955b621dde4e0debc35fbbd3497eeb641008787903fea57437665399fa sing-song vako-poku-piki-sino-dumi-wigo-bumo-subu-kuwu-suju-joku-wuru-libi-bafa-modu-pabu-zuro-kiva-givo-liju-pomu-ra ``` 变体推导(输入 = 32 × `00`): ``` v 1 掩码 607aa3412838d5ebff0ae2b8521c453e0bf24d48d5438217dbee1dcb39991be7 派生 607aa3412838d5ebff0ae2b8521c453e0bf24d48d5438217dbee1dcb39991be7 sing-song ladu-ronu-jajo-nawa-vimo-suzu-boso-fowa-kani-tidi-guna-suto-juka-nuki-jawa-faku-vozo-wami-totu-poli-dozo-ma-am v 5 掩码 6a0dea99f82a4d9776babb55ded1d9824fa22789bbcb0e95da7035a7df307946 派生 6a0dea99f82a4d9776babb55ded1d9824fa22789bbcb0e95da7035a7df307946 sing-song lona-vuro-pomu-naro-juli-mivo-soru-siki-vusi-duli-napa-zono-fiwa-powu-tota-woki-vopu-bavi-rizi-zata-moka-la-im ``` 解码 Sing-song 正文得到 `derived`;与相同掩码进行 XOR 恢复 `input`。 ## 参考实现 (见原文中的 Python 代码) 示例: ```bash $ python singsong.py encode 7910c06577ab67de51fed45ba18f27fc28eb618ebc1b78f9bced0f47fcefec2d moji-buba-liku-moru-lizi-wiji-zusi-jilu-rala-zapu-zubo-nuru-lala-woza-dovu-nuwi-sugo-vagu-jizu-tusu-wubo-va $ python singsong.py decode moji-buba-liku-moru-lizi-wiji-zusi-jilu-rala-zapu-zubo-nuru-lala-woza-dovu-nuwi-sugo-vagu-jizu-tusu-wubo-va 7910c06577ab67de51fed45ba18f27fc28eb618ebc1b78f9bced0f47fcefec2d ``` `apply_variant` 是其自身的逆运算:应用两次相同变体会恢复原始字节。 ## 应用:Nostr 用户名 Nostr 的 `npub` 是 32 字节公钥的 Bech32 表示。应用程序可以通过解码 `npub` 并取直接 Sing-song 编码的前八个音节(四个显示组)来派生固定长度的 Sing-song 用户名: ``` P = bech32_decode(npub) # 32 字节公钥 用户名 = SingSong(P) 的前 8 个音节 ``` 八个音节恰好表示 48 位,因此这等效于编码公钥的前六个字节: ``` 用户名 = SingSong(P[0:6]) ``` 这直接遵循 Sing-song 的前缀稳定性规则:`6 字节 = 48 位 = 8 个音节`。因此,生成的用户名是公钥前缀的可读表示,而不是派生哈希的指纹。用户可以将用户名解码回六字节的十六进制,并直接与公钥开头进行比较。同样,应用程序可以在不进行哈希的情况下派生用户名,并通过比较解码的前缀来找到候选匹配项。 用户名不是全局唯一的:许多 32 字节的公钥可以共享相同的前六个字节。需要更强标识的应用程序可以使用更多音节,最多到完整的 Sing-song 编码,它可以精确逆转为完整的 32 字节公钥。 然而: - 安娜告诉鲍勃她的用户名是 `kalo-tadu-komu-tigi`。 - 鲍勃在他的 Nostr 客户端中输入该字符串。 - 客户端将其转换为 `51ac0759fc4d`,并搜索 `npub` 以该十六进制开头的已知用户。 - 客户端将匹配项呈现给鲍勃,鲍勃选择安娜的账户。 ## 先前工作 Sing-song 建立在可发音编码工作的基础上,包括 S/Key 词编码(RFC 1751)、PGP 词表、Bubble Babble、Oren Tirosh 的助记编码、proquints、BIP39 和 Urbit `@p`。其独特的组合是一种可逆、前缀稳定的字节串编码,具有 64 音节 CV 语法、直接 6 位映射、自包含大小的完整形式,以及编码的可逆变体。

相似文章

WanSong v1.0 技术报告

Hugging Face Daily Papers

WanSong是一个纯扩散式音乐生成模型,能够一次性直接生成长达5分钟的高保真多语种歌曲,并输出双音轨(人声和背景音乐),解决了高效生成、长音频和可控性方面的挑战。

看见鸟鸣

Hacker News Top

Seeing Birdsong 是一个将鸟类鸣叫声转化为几何形态和 3D 可视化的框架,架起了艺术与声学科学之间的桥梁。它利用频谱描述符来构建数据丰富的结构,以用于研究、教育和艺术表演。

扩展单义性:从Claude 3 Sonnet中提取可解释特征

arXiv cs.AI

本文展示稀疏自编码器能够从生产级语言模型Claude 3 Sonnet中提取可解释特征,解决了字典学习方法在扩展性方面的担忧。这些特征具有多语言、多模态特性,并涵盖欺骗、谄媚等安全相关概念,且对模型输出具有因果影响。

supertone-inc/supertonic

GitHub Trending (daily)

Supertonic 是一个开源的端内文本转语音(TTS)系统,专为本地推理设计,具有极低的开销。现已发布第 3 版,支持 31 种语言,并提升了准确性。