钱包集成

将 Unlukey 客户端 SDK 集成到钱包中,当用户的恢复短语是由已知的弱种子生成漏洞生成时向其发出警告。

该 SDK 发布在 coinspect/unlukey 仓库中。

检测原理

  1. 钱包从恢复短语派生出 BIP-39
  2. 客户端 SDK 使用 SHA-256 对熵进行哈希,并截取结果哈希的一小段前缀
  3. 它仅从静态托管服务下载与该前缀匹配的数据集分桶(bucket)
  4. 它在本地将哈希的剩余部分与该分桶中的条目进行比对。

前缀将许多可能的密钥归入同一个分桶(k-匿名性)。静态托管服务只能看到请求的是哪个分桶,永远无法得知被检测的完整密钥,也无法得知是否匹配。

数据集按熵长度划分:一个用于 128 位(12 个单词)熵,另一个用于 256 位(24 个单词)熵。客户端会自动选择正确的数据集。

安装

npm install @unlukey/client

(在该包正式发布之前,可直接从仓库安装:npm install github:coinspect/unlukey#path:client。)

基本用法

import { check } from '@unlukey/client'
import { mnemonicToEntropy } from '@scure/bip39'
import { wordlist } from '@scure/bip39/wordlists/english'

const entropy = mnemonicToEntropy(secretRecoveryPhrase, wordlist)

const { vulnerable } = await check(entropy)

if (vulnerable) {
  // 警告用户:该恢复短语与已知的弱种子匹配,
  // 应将资金转移到新生成的钱包中。
}

查询逻辑在客户端本地运行。恢复短语和熵永远不会离开设备;只有熵哈希的一个前缀会被发送到数据集托管服务。entropy 是一个 Uint8Array,其长度必须为:

  • 16 字节,对应 12 个单词的助记词,或
  • 32 字节,对应 24 个单词的助记词。

处理结果

check() 返回 { vulnerable, key, prefix, bucketPath, reason? }

  • vulnerable: true — 该熵与已知的弱种子候选项匹配。提示用户将资金移至使用安全随机数生成的新钱包。

  • vulnerable: false — 未找到匹配项。这并不能证明该恢复短语是安全的;它只说明该熵与 Unlukey 当前数据集中的任何候选项都不匹配。覆盖范围仍在扩大,参见路线图

reason 提供用于调试集成的诊断信息,不会改变 vulnerable 的含义。

何时运行检测

在用户导入已有恢复短语、且钱包已经派生出 BIP-39 熵之后运行该检测。

自定义托管

默认情况下,客户端从 Unlukey 的公共数据集托管服务下载分桶。可以向 check() 传入不同的基础 URL,以使用其他数据集托管服务(例如你自己的 CDN):

const result = await check(
  entropy,
  'https://your-cdn.example.com/unlukey-datasets'
)

如需完全控制数据集分桶的获取方式,可使用 checkWith(entropy, readBucket),并提供你自己的 readBucket(bits, prefixHex) 实现。参见 SDK 仓库中的 client/index.js

本地测试

SDK 仓库的 CLI 工具可用于在不搭建界面的情况下测试集成:

node client/cli.js --remote 72039ecb02a3c880d4249e4b206933945a4f3a76ebaab26fa14e47a24e0f907e
# VULNERABLE

参见 SDK 仓库的 README,了解如何生成本地示例数据集并针对该数据集测试客户端。