长亭百川云 - 文章详情

走进区块链的第一步:钱包服务

零鉴科技

51

2024-07-14

加密货币钱包(Cryptocurrency wallet),是存储加密数字货币的公钥与私钥、私钥所对应的地址、该地址(群)的货币结算,以及货币交易的支持系统。

按照私钥存储方式,可以将钱包分为冷钱包和热钱包。

冷钱包


冷钱包(Cold Wallet),与热钱包相对应,也称离线钱包或者断网钱包,指网络不能访问到用户私钥的钱包。

冷钱包通常依靠“冷”设备(不联网的电脑,手机,专用的存储介质等)确保比特币私钥的安全,运用二维码通信让私钥不触网,避免了被黑客盗取私钥的风险,但是也可能面临物理安全风险。

将私钥存储在额外的特制硬件设备,使用时交易需在硬件内部进行交易签署才提交,只要硬件没有被破解,就能够保障私钥的安全性。

热钱包


热钱包(Hot Wallet),与冷钱包相对应,也称在线钱包或者联网钱包(Online Wallet),指网络能够访问到用户私钥的钱包。

热钱包因其联网特性,外人可能通过互联网访问到用户存储私钥的设备,因此安全性比冷钱包低,但比冷钱包更便利。

本文主要关注区块链上使用较广泛的钱包服务:多签钱包和分层确定性钱包(助记词钱包)。

多签钱包

  简介

多签钱包,顾名思义,就是需要多个人去签名执行某个操作的钱包。使用多签钱包进行转账时,往往需要大于 1 个人去签名发送交易之后,转账操作才真正完成。

使用多签钱包时,可以指定 m/n 的签名模式,就是 n 个人里面有 m 个人签名即可完成操作。多签规则可以根据自己的需求进行设置,例如:

**• 1/2 多签模式:**两个互相信任的朋友或自己的两个钱包,可以凭各自的私钥独立发起交易(类似于合伙账户)。

**• 2/2 多签模式:**金库中的资金需要2个管理员均同意才能动用这笔资金(需要两个私钥才能转移资金)。

**• 2/3 多签模式:**三个合伙人共同管理资金,为了规避私钥丢失的风险,其中两个私钥签名就可以转移资金。

多签钱包的验证过程类似于数字签名的验证,通过公私钥算法对签名内容进行校验,并判断当前签名的信息是否由特定的私钥进行签署。

  应用场景

多签钱包最常见的应用场景是需求强安全性的个人,以及管理公共资产的投资机构、交易所以及项目方。

1、资金安全

在多签钱包出现以前,账户(地址)的所有权掌握在私钥拥有者的手中。一但私钥泄露或遗忘就意味着失去了对钱包的控制权,与之关联的加密资产将完全丢失。

即使存在一些比较安全的方案来防止私钥的泄露和丢失(硬件钱包,助记词),但依旧无法有效的解决这样的问题。

多签钱包的存在,能够在很大程度上降低加密资产损失的风险。

以2/3多签模式为例,在全部的3个私钥中,只要有2个私钥完成签名授权就能完成加密资产的转移。

当然为了方便的话,也可以使用1/3多签模式,但这种方式仅仅是降低了密钥丢失的风险,并不能保证资产的安全性。

2、资金共管

很多DeFi 协议/ DAO 组织/区块链团队往往都有自己的金库,金库里的资产是整个生态所共享的,控制权不能掌握在某个人的手中,每次动用都要经过多数人的同意或社区投票。

多签钱包可以保证金库里的资产由领导者(贡献者)共同持有。

3、多签操作

在目前这个发展阶段,很多去中心化协议其实都是有个管理员权限的,这个管理员权限往往可以更改协议的某些关键参数。

行业普遍做法是把这个管理员权限交给一个多签钱包或时间锁,当需要更改参数时,需要多个人共同签署相关操作。

  实现原则

以太坊

以太坊原生并不支持多签地址,通常需要依靠智能合约来实现这一机制。

目前来说,以太坊上使用最广泛的多签智能合约由Gnosis团队进行开发,最新版本(1.3.0)主要由 GnosisSafe ProxyFactory,GnosisSafe proxy,GnosisSafe 三个合约组成,其中 ProxyFactory 和 Safe 合约由 Gnosis 官方进行部署,用户进行管理和操作的是 proxy 合约。

生成多签钱包

以rinkeby上一笔生成多签钱包的交易为例(0xd94dae4be055f443d47ad2b84db6ec740bda39bc8f6084b4dfd868a1b521ece4):

1、用户调用 ProxyFactory 合约的 createProxyWithNonce 函数创建多签钱包,此时传入的参数如下:

 `_singleton: 0xd9Db270c1B5E3Bd161E8c8503c55cEABeE709552``  initializer: 0xb63e800d0000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000140000000000000000000000000f48f2b2d2a534e402487b3ee7c18c33aec0fe5e400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000005ce0b4d552a80ca79ef391a1d87be7350f3e09ab0000000000000000000000000000000000000000000000000000000000000000  `` saltNonce: 1661943294934`

2、createProxyWithNonce 函数内部会调用 deployProxyWithNonce 函数部署 proxy 合约。部署 proxy 合约所使用的 creation code 为 GnosisSafeProxy 合约的 creation code ,并在 creation code 后带上 implementation 合约(Gnosis Safe)的地址作为 constructor 的参数 。 

创建的 proxy 合约地址为:0xc4CbE91175B315f5BaD83f8337d9103316492eD1。 

           

3、创建合约使用的是内联汇编的方式,通过 call 调用 proxy 合约内的函数,具体需要调用的初始化函数由参数 initializer 来实现。 

4、回到创建钱包的交易。通过解析 initializer 参数可以发现,调用的是 proxy 合约的 setup 函数进行初始化。

`>>> sha3.keccak_256('setup(address[],uint256,address,bytes,address,address,uint256,address)'.encode('utf-8')).hexdigest()``>>> 'b63e800d34f56a9238e5b86a8547a23865164bec371bede606e899182da118bf'``>>> initializer[:8]``>>> 'b63e800d'`

setup 函数会将用户设置的多签规则(owner, threshold)设置到 proxy 合约中,完成用户对于多签钱包的特定需求。 

执行多签操作

相较于 Gnosis 旧版本的合约 MultiSigWallet 来说,新版本的多签合约不需要所有(阈值数)验证者都发起一笔表示“同意此次操作”的交易来完成多签操作,取而代之的是在最后一个验证者(达到阈值)同意多签操作后,他会将投同意票的验证者的签名进行汇总形成交易,并发送到链上来完成多签操作。

1、在 Gnosis app 上发送一笔多签交易,并等待其他验证者来签名交易。此时不会向链上发送签名交易,Gnosis 会将当前验证者所签名的信息存储在服务端。 

2、当验证者的数量达到阈值时,最后确认交易的验证者会向链上发送交易,执行对应的多签操作。 

当前多签交易的哈希为:0x13401cb61972e7df739f1be6cc137c7aa48e0b0ccc39e6d5e2c99059ec35242f,调用的是 proxy 合约的 execTransaction 函数。 

 

3、execTransaction 函数的主要逻辑有两部:调用 checkSignatures 函数来验证签名,调用 execute 函数来执行操作。所有的签名信息通过 signatures 参数传入函数。 

4、checksignatures 函数会对传入的 signatures 进行解析,在获取到每个验证者的签名信息后,根据签名的类型进行不同的验证。可以看到,对于个人地址来说,主要是通过调用 ecrecover 函数从签名信息中恢复公钥(地址),并判断地址是否均在 owners 数组中。 

5、execute 函数的功能是根据传入的 operation 和 data 执行对应的多签操作。 

比特币

在比特币中有2种类型的地址,1开头的是P2PKH(pay to script hash),就是个人地址,3开头的是P2SH(pay to script hash),一般是多签地址。

普通的比特币地址是由公钥做哈希后得到的,而多重签名地址基于脚本哈希,所以能够实现复杂的交易逻辑,因此在原生上比特币就支持多签。

实现多签的操作码为OP_CHECKMULTISIG,它允许将 UTXO 锁定到 N 个公钥上,并设置多签规则,需要至少提供 M 个签名,才能解锁资金。

在 P2SH 出现之前,实现多签采用的是付款到多重签名( P2MS,pay to multi signature)的脚本来锁定 UTXO。

设置 M/N 多重签名条件的锁定脚本一般形式为:

M <Public Key 1> <Public Key 2> ... <Public Key N> N CHECKMULTISIG

解锁脚本为:

00 <Signature 1> <Signature 2> ... <Signature M> M <Public Key 1> <Public Key 2> ... <Public Key N> N CHECKMULTISIG

P2SM 在使用时有诸多不便,因为付款方需要了解锁定脚本(由收款方定义)的全部细节,并且付款方要为大量的交易数据支付高额的费用。

为了避免这种问题,BIP-16 提案引入了 P2SH ,允许将 UTXO 锁定到一个脚本的哈希(数据指纹)上。

在 P2SH 中,由哈希值代替的锁定脚本称为赎回脚本(redeem script),赎回脚本形式如下:

<Script> OP_HASH160 <Script Hash> OP_EQUAL

Script Hash 为解锁脚本的哈希值,在收款方需要使用到这笔 UTXO 时,会将赎回脚本与锁定脚本比对,确认哈希匹配后,解锁脚本会被执行以释放赎回脚本。

P2SH 让“向 N 个多重签名的具体脚本支付”,等同于“向有该哈希值的脚本支付”,变得跟 P2PKH 一样简单。

• 向付款方提供脚本哈希,就像 P2PKH 需要公钥一样

• 赎回脚本的内容,从锁定脚本转移到解锁脚本中,更多的交易费也从发送方转移到收款方

其他

波场链上的账户(地址)支持多重签名的操作,为账户设置了三种权限:owner-permission,witness-permission 和 active-permission。Owner permission 是一个账户的最高级权限,用于控制账户的归属、调整权限结构。因此即使拥有某个账户的私钥,也不一定拥有对这个账户的所有权限。

以 TEq6VNyFm7jiUcEssrkgsu8NV4C2jG5aWU 为例,这个账户的Owner permission的 threshold 为 2 ,地址为TEq6VNyFm7jiUcEssrkgsu8NV4C2jG5aWU 和 TDzfQDMXknfv12guDyP32zeJMgyyNGcqHD。这意味着对这个账户的所有操作都需要经过这两个地址同意才可以进行。

  风险

多签钱包最大的风险问题是:当多签钱包的部分私钥掌握在某些人(群体)中时,他们实际上也就拥有了对多签钱包的控制权。

如果在多签的群体中,有不怀好意的验证者企图控制多签钱包时,他可以联合其他多签者来获得钱包的所有权。

此时,其他负责任的验证者也无法改变“多签钱包已被毒化”的事实——他们无法联合足够的验证者来完成修正工作。多签钱包中的多签规则能够在一定程度上预防上述的问题。

但如果设置的多签规则中阈值未超过验证者数量的一半,那么意味着少数人的共识就能够代表大多数人,又或者如果验证者的数量过少,那么恶意的验证者仅需要花费较小的成本(策反部分验证者)就能够控制多签钱包。

例如前段时间跨链桥项目 Harmony 被攻击,损失了将近1亿美元,其中有一部分原因就是多签规则的设置存在问题(2/5的多签对则),导致攻击者仅需要获取其中两个的私钥就可以控制多签钱包。

因此,使用了多签钱包并不意味着绝对的安全和去中心化(社区自治)。同时还需要设置好多签规则,分配好对应的私钥,并确保拥有验证者私钥的主体之间不存在直接的利益关系。

多签规则的设计可以参考以下规则来提高多签钱包的安全性:

1、提高阈值,保证阈值大于验证者数量的一半

2、增加验证者的数量


分层确定性钱包

分层确定性钱包(heirarchical determinstic wallet, HD wallet),最早出现在BIP32的提案中。

在分层确定性钱包出现之前,拥有一个地址就意味着要管理一份公私钥对,这对于有大量需求的使用者来说是极为不方便的事情,并且容易发生遗漏的现象。

分层确定性钱包解决了这样的问题,它通过一个种子和一系列算法批量地生成私钥,使用者仅需要保存种子即可在后序的使用中获取到所有的公私钥对。

后来又提出了助记词的概念,将种子转化为(12/15/18/21/24)个单词,使得使用者能够更方便地构建钱包,批量生成和管理私钥,以及备份钱包。

  生成助记词

生成助记词的主要步骤:

•生成一个长度为 128~256 位的随机序列(熵)

•取熵的 SHA256 后的前 n 位作为校验和(n=熵长度/32)

•将随机序列和校验和进行拼接

•把步骤 3 得到的结果按“每 11 位”进行切割

•步骤 4 得到的 11 位字节按照顺序,匹配官方词库中的词

官方词库中一共有(2^11=2048)个单词,并且在 BIP39 提案中规定了下面 3 个要求:

1、只使用前 4 个字母就可以无歧义地找到某个单词,即词库不中存在前 4 个字母相同的多个单词

2、避免包含相似的词,比如不会同时包含单词“woman”和“women”

3、词库本身排序

  助记词生成私钥

助记词生成私钥的主要步骤:

1、助记词转换为 512 位 seed 。使用 PBKDF2 算法对初始密钥进行延伸(key streching),以此来降低初始密钥被暴力破解的概率。

`passphrase =""  # default value is ""``salt = bytes("mnemonic"+ passphrase, 'utf8')``seed = hashlib.pbkdf2_hmac('sha512', mnemonic, salt, 2048)`

2、seed 生成 Master Private Key 和 Master Chain Code 。使用 HMAC-SHA512 算法对 seed 进行单向哈希得到 512 位二进制字符串,左边 256 位为 Master Private Key ,右边 256 位为 Master Chain Code 。

`h = hmac.new(b'Bitcoin seed', seed, hashlib.sha512).digest()``master_private_key, master_chain_code = h[:32], h[32:]`

  

3、使用 Master Private Key , Master Chain Code 和 index 作为第一轮导出函数的输入,不断地进行推导,得到 index 位置上的子私钥。

推导子私钥的简要步骤如下:

 child_private_key = HMAC-SHA512(Key=parent_chain_code, Data=(parent_private_key*secp256k1.G||index)) + parent_private_key

具体算法细节可以参考 BIP32 提案中 Key Derivation 部分

https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki)。

  私钥生成公钥

有两种方法可以生成公钥:

1、通过私钥求得(secp256k1椭圆曲线算法,G为椭圆曲线的基点)

public_key = private_key * secp256k1.G

2、通过父公钥推导出子公钥

在推导子私钥的过程中可以看到,由父私钥可以推导出子私钥。由公私钥之间的关系,可以构造出一个公钥推导函数,由父公钥推导出子公钥。



`(1) child_private_key = HMAC-SHA512(Key=parent_chain_code, Data=(parent_private_key*secp256k1.G||index)) + parent_private_key``(2) public_key = private_key * secp256k1.G``由 (1) 和 (2) 公式可以推导出:``child_public_key = HMAC-SHA512(Key=parent_chain_code, Data=(parent_public_key||index))*secp256k1.G + parent_public_key`


这个特性在实际使用过程中有重大的意义,因为它允许在不使用父私钥的情况下,可以生成很多受父私钥控制的钱包地址**。**

比如说,私钥掌控人可以在服务器上存放父扩展公钥(parent extended public key),这样可以为需要使用服务的商户生成一系列的子公钥地址,用于收款或者其他用途。即使服务器被黑客攻破,私钥也不会泄露。

扩展密钥(extended key)是 BIP32 中规定的一种对密钥信息进行特定格式序列化后的结果。

扩展密钥包含6种信息,分别为version, depth, parent key fingerprint, child number, chain code, public key。

  安全性

上述所展示均为 Non-Hardened Derivation。因为它存在一定的安全问题:从父扩展公钥子私钥(non-hardened),可以推导出父私钥,从而推导出所有的子私钥。

推导过程简述如下:

`已知:parent_extended_public_key 和 child_private_key``(1) 解析parent_extended_public_key,得到parent_chain_code和parent_public_key``(2) 由公钥推导函数可以通过爆破计算出index``(3) 变换私钥推导函数为parent_private_key = child_private_key - hmac_sha512(parent_chain_code, parent_private_key*G || index) ,计算出parent_private_key`

为了避免上述的安全问题,官方对私钥的推导函数进行了完善。推导函数分为 Hardened 和 Non-Hardened 模式,Hardened 模式直接使用私钥作为 HMAC-SHA512 的输入, Non-Hardened(也就是上述的推导过程) 使用公钥作为 HMAC-SHA512 的输入。

`Hardened Derivation:``child_private_key = HMAC-SHA512(Key=parent_chain_code, Data=(0x00||parent_private_key||index)) + parent_private_key``Non-Hardened Derivation:``child_private_key = HMAC-SHA512(Key=parent_chain_code, Data=(parent_private_key*secp256k1.G||index)) + parent_private_key`

Hardened Derivation 解决了 Non-Hardened Derivation 存在的安全问题,不过这也意味着在对应的 index 下,父公钥将无法导出子公钥。

  BIP 44

BIP44 规定了每次推导时使用的 index 值,这些 index 串起来(使用 / 做分隔符 )称为 path,每一个 index 在 BIP44 中都有不同含义。BIP44 提案扩展了助记词钱包的使用范围,使得这套规范能够在不同的链,不同的应用中都能够使用。

BIP44 的 path 规范为:

m / purpose' / coin_type' / account' / change / address_index

• m:固定值

• purpose:被设置为常量44,表示当前所使用的提案为 BIP44

• coin_type:用于区分不同的币种(关于已注册的 coin_type,可参考:SLIP-0044 : Registered coin types for BIP-0044)

• account:表示账户索引,从 0 开始

• change:为 0 表示“接收”地址(外部地址),为 1 表示“找零”地址(内部地址)

• address_index:表示地址索引,从 0 开始

对于比特币钱包而言,钱包的 path 为:

m / 44'/ 0' / 0' / 0 / 0

以太坊钱包的 path 为:

m / 44' / 60' / 0'/ 0 / 0

如果 index 中有单引号字符('),则表示 Hardened Derivation,对应 index 需要额外加上 0x80000000 ,如 44' 表示 0x8000002c ,60'表示 0x8000003c。

  批量生成地址

通过一些第三方库,可以很方便的由助记词生成私钥以及地址。下图是由一组助记词生成前10个以太坊地址的示例:

References

参考

比特币多签钱包

[1]  https://blog.csdn.net/BitTribeLab/article/details/102696746

[2]  https://aaron67.cc/2018/12/29/bitcoin-transaction-p2ms-p2sh/

[3]  https://www.youtube.com/watch?v=6Fa04MnURhw

分层确定性钱包

[1]  https://www.alibabacloud.com/blog/how-ethereum-bip-32-hardware-digital-wallet-works\_597788

[2]  https://github.com/bitcoin/bips/blob/master/bip-0032.mediawik

[3]  http://aandds.com/blog/mnemonic-hd-wallet.html

[4]  https://bitcoin.stackexchange.com/questions/62533/key-derivation-in-hd-wallets-using-the-extended-private-key-vs-hardened-derivati?rq=1

[5]  https://bitcoin.stackexchange.com/questions/87834/hardened-keys-vs-normal-keys-a-simpler-explanation

「 往期文章 」

以太坊标准——EIP712

走进区块链的第一步:mev浅析

Unstable Stablecoins(上)

相关推荐
关注或联系我们
添加百川云公众号,移动管理云安全产品
咨询热线:
4000-327-707
百川公众号
百川公众号
百川云客服
百川云客服

Copyright ©2024 北京长亭科技有限公司
icon
京ICP备 2024055124号-2