本文档详细介绍了SeedQR格式规范,这是一种将BIP-39助记词短语编码为QR码的方法,旨在简化SeedSigner等硬件钱包的密钥输入过程。文章对比了标准SeedQR和CompactSeedQR两种格式,讨论了它们的优缺点,包括数据存储优化、手动转录的难易程度以及在项目不再维护时的数据恢复能力,并提供了多种测试用例。
SeedSigner 是一个开源、DIY、完全气隙的比特币硬件钱包,每次关闭时会擦除内存中的所有私有数据。这意味着用户每次使用它时都需要重新输入他们的助记词种子短语。
为了加速这个密钥输入过程,我们定义了一种将 BIP-39 助记词种子短语编码为 QR 码的方式,该 QR 码可以立即扫描到 SeedSigner 或任何其他带有摄像头的比特币硬件钱包中。
该方法专门设计用于编码尽可能少的数据量,以使生成的 QR 码足够小,可以手动转录。这听起来起初很荒谬,但请记住,这是不应存储在任何数字介质中的秘密数据。即使是打印机也存在一些额外的风险向量。
<table align="center"> <tr><td><img src="img/handmade_qr.jpg"><br/><em>显然,这个 SeedQR 只是为了演示目的;永远不要拍摄你的 SeedQR!</em></td></tr> </table>
我们定义了两种 QR 格式:
每种格式的规范如下,以及对每种格式的优缺点的讨论。
备份比特币钱包的典型方法是存储其由 12 或 24 个单词组成的 BIP-39 助记词种子短语。
SeedQR 明确假设并建议使用英文 BIP39 单词列表。 虽然 BIP39 支持多种特定于语言的单词列表(例如,日语、西班牙语、法语),但没有机制来指定或检测创建或扫描 SeedQR 时使用了哪种语言单词列表。使用非英文单词列表可能会导致不正确或无效的种子。
每个单词都来自一个 包含 2048 个单词的列表。这些单词本身没有意义;重要的是单词在单词列表中的位置编号(也称为索引)。
例如,“tomato”是列表中的第 1,825 个单词。
但是代码总是从零开始计算列表项。因此,“tomato”的索引实际上是 1824
(如果你正在查看 github 单词列表的行号,请记住始终减一)。
因此,我们可以将一个 12 个单词的种子转换为一系列索引:
1. vacuum 1924
2. bridge 222
3. buddy 235
4. supreme 1743
5. exclude 631
6. milk 1124
7. consider 378
8. tail 1770
9. expand 641
10. wasp 1980
11. pattern 1290
12. nuclear 1210
SeedQR
规范我们获取助记词种子短语的索引,并将它们连接成一个长的数字流。每个索引必须正好是四位数,因此较短的数字必须用零填充(12
变为0012
)。
使用上面的例子:
## 带有零填充的索引:
1924 0222 0235 1743 0631 1124 0378 1770 0641 1980 1290 1210
## 最终组装的数字流:
192402220235174306311124037817700641198012901210
然后将该数字流编码到 QR 码中。
在这里值得注意的是,QR 码可以用多种不同的方式编码数据:
<table align="center"> <tr><td align="center"><img src="img/qrcode_capacity.png"><br/><em><a href="https://www.qrcode.com/en/about/version.html">qrcode.com</a></em></td></tr> </table>
QR 码通常用于编码网站 url,在这种情况下,必须使用“字母数字”格式(编码的数据可以包含大写和小写字母、数字和某些允许的符号)。
如果你有一个很长的 url,比如 https://ohnoihavealongurl.com
(29 个字符),图表显示它不适合 21x21 的 QR 码;它的最大容量是 25 个字母数字字符。但它在 25x25 大小的 47 个字符容量范围内。
请注意,“数字”列具有更大的容量。这是因为当你需要编码的可能字符较少时,指定每个字符所需的数据就越少。
字母数字格式支持 44 个可能的字符。它们成对编码,这意味着有 44^2 = 1,936 种可能的配对来描述。然后可以使用 11 位对每对进行编码:
2^11 = 2048
如果只使用 10 位,则只能指定 2^10 = 1,024 个可能的值;对于 1,936 种可能的配对来说远远不够。11 位是这种格式的最佳选择。
数字格式能够仅使用 10 位存储 3 个数字。可能的最大 3 位数字是 999
,因此 10 位 (2^10 = 1,024) 就足够了。
这就是为什么 25x25 QR 码只能存储 47 个字母数字字符,而 77 个数字。就位而言,总数据量是相同的:
47 个字母数字字符 / 每对 2 个字符 * 每对 11 位 = 259 位
77 个数字 / 每组 3 个数字 * 每组 10 位 = 257 位
(两种格式都向上舍入到 260 位)
有了这些知识,我们就可以编码我们的 SeedQR 了。
我们的 SeedQR 数据将仅包含数字,以便我们可以使用更高效的“数字”格式。我们的 12 字助记词种子短语需要:
12 个单词 * 每个单词 4 个数字 = 48 个数字
48 个数字不适合使用“L”(低)纠错模式的 21x21(最大数字容量为 41),但很容易适合 25x25:
<table align="center"> <tr><td><img src="img/standard_12word.png"></td></tr> </table>
如果你用手机扫描这个二维码,会看到人类可读的数字流:
<table align="center"> <tr><td><img src="img/phone_screenshot_standard.jpg"></td></tr> </table>
并亲眼看看数字流是否与上面从助记词种子单词索引生成的数字流匹配。
192402220235174306311124037817700641198012901210
此时,SeedSigner 或其他比特币硬件钱包可以很容易地将数字流解析回各个 BIP-39 单词列表索引,并重建你的整个助记词种子短语。
回顾数字数据的 QR 码容量图表,我们确切地知道生成的 SeedQR 将有多大:
12 字助记词(48 位数字)= 25x25
24 字助记词(96 位数字)= 29x29
例子: <table align="center"> <tr> <td align="center"><img src="img/standard_12word.png"><br/>12 字标准 SeedQR</td> <td align="center"><img src="img/vector1_standard_24word.png"><br/>24 字标准 SeedQR</td> </tr> </table>
CompactSeedQR
规范CompactSeedQR
格式建立在“标准”SeedQR
格式的基础上,通过进一步优化数据的存储方式,以生成更小的 QR 码,这些 QR 码更容易手动转录。
请注意,在上面的 QR 码容量图表中,还有一个“二进制”列,但其相对容量计数最初看起来并不令人印象深刻;25x25 QR 码限制为 32。
但这里描述的单位不是字母数字字符或数字;而是最大字节数。
1 字节 = 8 位
与其让 QR 格式将我们的数据解释为数字或字符,不如直接编码确定我们助记词种子短语的相关位。
我们可以从上面生成的助记词种子短语数字流中提取这些位。
让我们回顾一下助记词种子短语的各个索引:
1924 0222 0235 1743 0631 1124 0378 1770 0641 1980 1290 1210
我们知道 BIP-39 单词列表包含 2048 个单词。这意味着我们需要 11 位来用二进制表示每个索引 (2^11 = 2048; 这不是巧合!):
1924 11110000100
0222 00011011110
0235 00011101011
1743 11011001111
0631 01001110111
1124 10001100100
0378 00101111010
1770 11011101010
0641 01010000001
1980 11110111100
1290 10100001010
1210 10010111010
我们将所有这些二进制值连接到一个大的 132 位流:
111100001000001101111000011101011110110011110100111011110001100100001011110101101110101001010000001111101111001010000101010010111010
BIP-39 在每个助记词种子短语的末尾指定一个校验和词。在 12 个单词的助记词中,最后 4 位是校验和。在 24 个单词的助记词中,最后 8 位是校验和。
校验和很容易从先前的位计算出来(在本例中,是我们流的前 128 位)。因此,我们不需要将那些位包含在我们的 CompactSeedQR 中。
12 字助记词 = 12 个单词 * 每个单词 11 位 = 132 位
12 字 CompactSeedQR = 132 位 - 4 位校验和 = 128 位
24 字助记词 = 24 个单词 * 每个单词 11 位 = 264 位
24 字 CompactSeedQR = 264 位 - 8 位校验和 = 256 位
这些位流在“二进制”QR 码中能很好地适应吗? 回顾 QR 码容量图表,我们发现以下内容适用于“L”(低)错误校正模式:
12 字助记词:128 位 / 每字节 8 位 = 16 字节 = 21x21
24 字助记词:256 位 / 每字节 8 位 = 32 字节 = 25x25
因此,通过使用最佳效率的二进制编码,我们使每个 CompactSeedQR 比其标准 SeedQR 对应物小一个尺寸。
例子: <table align="center"> <tr> <td align="center"><img src="img/vector4_compact_12word.png"><br/>12 字 CompactSeedQR</td> <td align="center"><img src="img/vector1_compact_24word.png"><br/>24 字 CompactSeedQR</td> </tr> </table>
这是并排的两种格式。
每种格式中相同的 12 字种子: <table align="center"> <tr> <td align="center"><img src="img/vector4_standard_12word.png"><br/>标准 SeedQR (25x25)</td> <td align="center"><img src="img/vector4_compact_12word.png"><br/>CompactSeedQR (21x21)</td> </tr> </table>
每种格式中相同的 24 字种子: <table align="center"> <tr> <td align="center"><img src="img/vector1_standard_24word.png"><br/>标准 SeedQR (29x29)</td> <td align="center"><img src="img/vector1_compact_24word.png"><br/>CompactSeedQR (25x25)</td> </tr> </table>
由于 SeedQR 概念的目标是使其易于手动转录,因此很自然地认为 CompactSeedQR 更好。
让我们比较一下每个尺寸的实际“空间”。 我们所有的 QR 尺寸在角上都有三个大的 8x8 注册块。 29x29 和 25x25 在右下角有一个较小的 5x5 注册块。
29x29 - (3*8x8) - 5x5 = 624 个块
25x25 - (3*8x8) - 5x5 = 408 个块
21x21 - (3*8x8) = 249 个块
因此,通过将 24 字标准 SeedQR 从 29x29 缩小到 25x25 的 CompactSeedQR,我们减少了必须手动转录的区域:
408 / 624 = 65%
同样,将 12 字 25x25 标准 SeedQR 缩小到 21x21 的 CompactSeedQR:
249 / 408 = 61%
如果你要在金属 SeedQR 板上手动打孔,那么会减少大约 35-40% 的工作量!
<table align="center"> <tr><td><img src="img/seedqr_plate.jpg"></td></tr> </table>
但是还有其他需要考虑的权衡。
如果你丢失了 SeedSigner,或者该项目以某种方式被放弃或禁止,你将如何读回你的 SeedQR?
使用标准 SeedQR 格式,这很简单——任何智能手机都可以解码数字流。 但是 CompactSeedQR 的原始字节数据无法以相同的方式解密。 现在大多数 QR 读取器都假定数据是字母数字或人类可读的数字数据。 由于这种假设,它们错误地解释了二进制格式数据:
<table align="center"> <tr> <td align="center"><img src="img/phone_screenshot_standard.jpg"><br/>标准 SeedQR</td> <td align="center"><img src="img/phone_screenshot_compact.jpg"><br/>CompactSeedQR</td> </tr> </table>
如果需要,可以手动将清晰可读的标准 SeedQR 数字流转录回助记词种子短语,而无需其他计算机辅助。
这只是上述过程的逆转:
## 12 字标准 SeedQR 数字流
192402220235174306311124037817700641198012901210
## 分隔成 4 位数的单个索引
1924 0222 0235 1743 0631 1124 0378 1770 0641 1980 1290 1210
## 查找每个 BIP-39 索引号(如果使用 github 列表,则为 index+1!)
1. vacuum 1924
2. bridge 222
3. buddy 235
4. supreme 1743
5. exclude 631
6. milk 1124
7. consider 378
8. tail 1770
9. expand 641
10. wasp 1980
11. pattern 1290
12. nuclear 1210
手动从 CompactSeedQR 重新创建你的种子会更加困难。 诸如 zxing.org 或 ZBar 之类的工具可以帮助你将二进制数据作为十六进制字符串输出:
<img src="img/zxing_screenshot.png">
请注意,对于某些 QR 解码器,特别是 zxing,可能会返回比紧凑种子本身更多的数据:数据类型、数据长度和填充。 例如,来自低纠错模式下 12 字 CompactSeedQR 的 zxing 结果将以 41 0
开头(指定二进制数据格式并说明数据长度为 16 字节),并以 0 ec
结尾 (未使用的字节和一半)。 同样,24 字 CompactSeedQR 将以 42 0
开头(二进制,数据长度为 32 字节),并以 0
结尾(未使用的半个字节)。
ZBar 库仅返回编码的数据,不带元数据或填充。
相反,对读取二进制 QR 码的有限支持以及上述复杂性被某些人视为额外的安全功能。 如果有人偷了你的 CompactSeedQR 或拍下了它的照片,他们必须非常精通才能知道如何解码它。
我们的主要用例是能够使用你的助记词种子短语快速初始化 SeedSigner。 但是使用 QR 码作为你的密钥加载程序——甚至作为蚀刻在金属中的永久备份——还有其他优点。
现在 QR 码无处不在,因此存在大量硬件和软件来读取和生成它们。
QR 码具有内置的纠错功能。“L”纠错模式被描述为具有大约 7% 的校正率。
通常,QR 码对不可读块具有令人难以置信的弹性。 例如,你经常会看到中间块被有意地用徽标覆盖:
<table align="center"><tr><td><img src="img/standard_24word_with_logo.png"></td></tr></table>
这就在 SeedSigner 读取此 24 字 SeedQR 的能力的极限,尽管存在无法访问的块。
同样,QR 码可以承受手动转录过程中的人为错误。 几个编码错误的块、涂抹的墨水斑点或其他物理缺陷通常不会引起任何问题。
用于验证你自己的编码和解码实现的样本测试向量:
## 24 字种子:
attack pizza motion avocado network gather crop fresh patrol unusual wild holiday candy pony ranch winter theme error hybrid van cereal salon goddess expire
## 标准 SeedQR 数字流:
011513251154012711900771041507421289190620080870026613431420201617920614089619290300152408010643
## CompactSeedQR 比特流:
0000111001110100101101100100000100000111111110010100110011000000110011001111101011100110101000010011110111001011111011000011011001100010000101010100111111101100011001111110000011100000000010011001100111000000011110001001001001011001011111010001100100001010
## CompactSeedQR 字节流:
b'\x0et\xb6A\x07\xf9L\xc0\xcc\xfa\xe6\xa1=\xcb\xec6b\x15O\xecg\xe0\xe0\t\x99\xc0x\x92Y}\x19\n'
<table align="center"> <tr> <td align="center"><img src="img/vector1_standard_24word.png"><br/>标准 SeedQR</td> <td align="center"><img src="img/vector1_compact_24word.png"><br/>CompactSeedQR</td> </tr> </table>
请注意,此向量和下面的一些其他向量在其 CompactSeedQR 字节流中包含空字节字符 (\x00
)。 对于大多数 QR 读取器来说,这是一个特别麻烦的字符; 大多数会将此字符读取为停止读取任何进一步数据的指令。
请格外小心以确认你的实现正确读取这些字符及其后的所有剩余数据!
## 24 字种子:
atom solve joy ugly ankle message setup typical bean era cactus various odor refuse element afraid meadow quick medal plate wisdom swap noble shallow
## 标准 SeedQR 数字流:
011416550964188800731119157218870156061002561932122514430573003611011405110613292018175411971576
## CompactSeedQR 比特流:
0000111001011001110111011110001001110110000000001001001100010111111100010010011101011111000100111000100110001000100000000111100011001001100100110110100011010001111010000010010010001001101101011111011000101001010100110001111111000101101101101010010101101110
## CompactSeedQR 字节流:
b"\x0eY\xdd\xe2v\x00\x93\x17\xf1'_\x13\x89\x88\x80x\xc9\x93h\xd1\xe8$\x89\xb5\xf6)S\x1f\xc5\xb6\xa5n"
<table align="center"> <tr> <td align="center"><img src="img/vector2_standard_24word.png"><br/>标准 SeedQR</td> <td align="center"><img src="img/vector2_compact_24word.png"><br/>CompactSeedQR</td> </tr> </table>
## 24 字种子:
sound federal bonus bleak light raise false engage round stock update render quote truck quality fringe palace foot recipe labor glow tortoise potato still
## 标准 SeedQR 数字流:
166206750203018810361417065805941507171219081456140818651401074412730727143709940798183613501710
## CompactSeedQR 比特流:
1100111111001010100011000110010110001011110010000001100101100010010101001001001001010010101111000111101011000011101110100101101100001011000000011101001001101011110010101110100010011111001010110101111011001110101111100010011000111101110010110010101000110110
## CompactSeedQR 字节流:
b'\xcf\xca\x8ce\x8b\xc8\x19bT\x92R\xbcz\xc3\xba[\x0b\x01\xd2k\xca\xe8\x9f+^\xce\xbe&=\xcb*6'
<table align="center"> <tr> <td align="center"><img src="img/vector3_standard_24word.png"><br/>标准 SeedQR</td> <td align="center"><img src="img/vector3_compact_24word.png"><br/>CompactSeedQR</td> </tr> </table>
## 12 字种子:
forum undo fragile fade shy sign arrest garment culture tube off merit
## 标准 SeedQR 数字流:
073318950739065415961602009907670428187212261116
## CompactSeedQR 比特流:
01011011101111011001110101110001101010001110110001111001100100001000001100011010111111110011010110011101010000100110010101000101
## CompactSeedQR 字节流:
b'[\xbd\x9dq\xa8\xecy\x90\x83\x1a\xff5\x9dBeE'
<table align="center"> <tr> <td align="center"><img src="img/vector4_standard_12word.png"><br/>标准 SeedQR</td> <td align="center"><img src="img/vector4_compact_12word.png"><br/>CompactSeedQR</td> </tr> </table>
## 12 字种子:
good battle boil exact add seed angle hurry success glad carbon whisper
## 标准 SeedQR 数字流:
080301540200062600251559007008931730078802752004
## CompactSeedQR 比特流:
01100100011000100110100001100100001001110010000000110011100001011100001000110011011111011101100001001100010100001000100111111101
## CompactSeedQR 字节流:
b"dbhd' 3\x85\xc23}\xd8LP\x89\xfd"
<table align="center"> <tr> <td align="center"><img src="img/vector5_standard_12word.png"><br/>标准 SeedQR</td> <td align="center"><img src="img/vector5_compact_12word.png"><br/>CompactSeedQR</td> </tr> </table>
## 12 字种子:
approve fruit lens brass ring actual stool coin doll boss strong rate
## 标准 SeedQR 数字流:
008607501025021714880023171503630517020917211425
## CompactSeedQR 比特流:
00001010110010111011101000000000100011011001101110100000000001011111010110011001011010110100000010100011010001110101110011011001
## CompactSeedQR 字节流:
b'\n\xcb\xba\x00\x8d\x9b\xa0\x05\xf5\x99k@\xa3G\\\xd9'
<table align="center"> <tr> <td align="center"><img src="img/vector6_standard_12word.png"><br/>标准 SeedQR</td> <td align="center"><img src="img/vector6_compact_12word.png"><br/>CompactSeedQR</td> </tr> </table>
显式检查其字节流包含 \n
、\r
或 \r\n
的 Compact SeedQR:
\n
:
## 12 字种子:
dignity utility vacant shiver thought canoe feel multiply item youth actor coyote
## 标准 SeedQR 数字流:
049619221923158517990268067811630950204300210397
## CompactSeedQR 比特流:
00111110000111100000101111000001111000110001111000001110010000110001010100110100100010110111011011011111111011000000101010011000
## CompactSeedQR 字节流:
b'>\x1e\x0b\xc1\xe3\x1e\x0eC\x154\x8bv\xdf\xec\n\x98'
<table align="center"> <tr> <td align="center"><img src="img/vector7_compact_12word.png"><br/>CompactSeedQR</td> </tr> </table>
\r
:
## 12 字种子:
corn voice scrap arrow original diamond trial property benefit choose junk lock
## 标准 SeedQR 数字流:
038719631547010112530489185713790169032209701051
## CompactSeedQR 比特流:
00110000011111101010111100000101100001100101100111001010011110100111101000001101011000110001010100100101000010011110010101000001
## CompactSeedQR 字节流:
b'0~\xaf\x05\x86Y\xcazz\rc\x15%\t\xe5A'
<table align="center"> <tr> <td align="center"><img src="img/vector8_compact_12word.png"><br/>CompactSeedQR</td> </tr> </table>
\r\n
:
## 12 字种子:
vocal tray giggle tool duck letter category pattern train magnet excite swamp
## 标准 SeedQR 数字流:
19621853078318290
>- 原文链接: [github.com/SeedSigner/se...](https://github.com/SeedSigner/seedsigner/blob/dev/docs/seed_qr/README.md)
>- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!