元界的HD账户模型及加密

元界的HD账户模型及加密

元界钱包使用账户对钱包中的资产进行管理。账户设计应用到了HD钱包、数据库、单向散列函数等技术。

1 HD钱包

1.1 HD钱包原理

HD钱包又称分层确定性钱包,它是基于比特币BIP0032标准的。分层确定性钱包包含从数据结构所生成的钥匙。这种母钥匙可以生成子钥匙序列。所生成的子钥匙又可以衍生出孙钥匙,基于些种规则,以此可以无穷类推。可以生成一个含有无穷多个子孙钥匙的树结构。HD钱包使用的便利性还表现在“助记词”,元界HD钱包便是基于此规则生成,用户只需要记住“助记词”和地址个数就可恢复出该账户所持有的资产的。

以12单词助记词为例,从“助记词”到“根种子”运算原理如下图所示:

助记词生成过程:
助记词生成过程

根种子生成过程:
根种子生成过程

HD钱包的“根种子”为128到256位的随机数。它使用CKD(child key derivation)方程从母密钥衍生出子密钥。子密钥衍生方程是基于单向散列函数。这个函数结合了:一个母公共钥匙、一个叫做链码(256位)的种子、一个索引号(32位)。这三个参数相结合并散列可以生成子密钥。”母公共钥匙+链码+索引号“合并在一起,并且用HMAC-SHA512散列之后可以产生512位的散列值。并将其拆分为两部分。右半部分的256位产生出可以给子链当链码。左半部分256位散列以及索引友被加载在母私钥上来衍生子私钥。如下图所示:

从母密钥衍生出子密钥

这样改变索引可以让我们延长母密钥假造序列中的其他子密钥。每个母密钥可以产生2的32次方个子密钥。

1.2 HD账户实现

元界中新账户对应一个新生成的分层确定性钱包,新账户建立成功后会返回24个英文助记词,通过账户助记词可以恢复出用户的所有普通地址(后续元界还引入了多重签名地址)上的资产信息。一个账户可以连续生成多个地址,目前地址的最大个数为4294967296(2的32次方)个。每个元界HD账户生成的过程为:

  1. 用户通过RPC发送getnewaccout命令,并带有用户名和密码给mvsd。

  2. mvsd通过由“密码学上安全的随机数生成器”生成“种子随机数”。

  3. mvsd根据上述步骤中所得到的“种子随机数”生成“助记词”。生成“助记词”的目的是为了便于人们存储和输入。

  4. mvsd由“助记词”进行解码恢复出步骤3中所产生的随机数“种子”。

  5. mvsd根据“种子”计算“HD私钥”,该“HD私钥”为该账户的“根私钥”,以后所有的地址生成都是基于该“根私钥”和当前账户地址“索引值”生成的。“索引值”默认为0。账户生成时,会应用后续步骤生成第一个默认地址。

1.3 账户地址

HD钱包的所有地址都是经由“助记词”和地址索引生成的。新地址产生流程为:

  1. 由“助记词”解码出随机数“种子”。

  2. 根据“种子”计算“主HD私钥”,并修改当前账户最新地址的“索引值”。计算出新的地址的“HD私钥”,该“HD私钥”是基于“主HD私钥”计算出的第“索引值”个“子HD私钥”

  3. 将“子HD私钥”换算成“EC私钥”

  4. 根据“EC私钥”通过单向散列函数计算出其“EC公钥”

  5. 根据“EC公钥”将其进行编码处理,计算出“元界地址”

参考示例

1.4 多重签名地址

在元界中,普通地址是以M开头的,而所有以数字3开头的地址是P2SH地址。多重签名作为合约脚本,其所对应的多重签名地址都是以3开头的脚本地址。它可以指定交易中受益人作为哈希的脚本,而不是公钥的所有者。该功能是依据BIP0016。资金被发送到以3开头的地址时,不仅仅需要一个公钥哈希值,同进也需要一个私钥签名作为所有都证明。在创建地址的时候,这些要求会被定义在脚本中,所有对地址的输入都会被这些要求阻隔。多重签名地址脚本是一种最常见的P2SH。在多重签名中需要多个签名来证明来证明所有权,此后才能消费资金。它需要从总共N个密钥中需要M个签名,被称为M-N多重签名,其中M是等于或小于N。M是需要的最小匹配的签名,N是提供公钥的数量。

若要创建一个多重签名合约,所有参与人都要给其他人一个地址公钥。然后,任何得到的所参与人的公钥的人可以创建P2SH脚本。如2-3签名脚本,OP_2 [A’s pubkey] [B’s pubkey] [C’s pubkey] OP_3 OP_CHECKMULTISIGOP_2和OP_3代表实际数字2和3。OP_2指定需要2个签名,OP_3指定需要提供3个未哈希过的公钥。

2 HD账户设计

在元界钱包中的账户设计中主要涉及account、acccount_multisig两个类。其中account类是对HD账户的抽象,account_multisig类是对多重签名的抽象。

account类和account_multisig类为组合关系,一个account实例可以拥有0个或多个account_multisig实例。

account类主要通过以下字段记录账户相关关键信息。

name —-账户的名字,对应于钱包页面的用户名,该字段是以字符串的形式持久存储于钱包的本地账户数据库表中的。

mnemonic —-账户注册成功后,为使得用户存储、记录其账户在的信息所生成的助记词。该字段是以加密字符串的形式持久存储在钱包的本地账户数据库表中的。该字段是用户最重要的信息,若用户忘记旧的用户名或者密码,用户完全可以从备份在U盘或者纸张上的助记词重新导入新账户达到恢复资产的目的。

passwd —-账户的密码,对应用钱包页面的用户密码,针对密码,元界钱包在用户注册时针对用户密码应用单向散列函数进行了哈希计算,而不是存储的密码明文,这样做的好处增加了密码的安全性,即使获取到了钱包的本地账户数据表,也无法从哈希值反向计算出用户密码。

hd_index —-账户地址索引,对应于钱包从主助记词导入账户页面中的地址个数。主要用户记录账户地址个数的。其值加1即为该账户目前已建立地址个数,该字段以数值的形式存储于钱包本地账户数据库表中。

mulitisg_vec —-账户多重签名信息,账户可以从自己的地址列表选择地址,并获取其公钥,然后与其他账户地址的公钥共同生成多重签名合约。该字段被序列化后存储于钱包本地账户数据库表中。

account_multisig类主要通过以下字段记录账户多重签名相关关键信息。

m_ —-记录该项多重签名最少签名个数

n_ —-记录该项多重签名脚本中公钥的最大个数

pubkey_ —-记录该项多重签名所使用的该账户地址的公钥

cosigner_pubkeys_ —-用于存储该项目多重签名中所有其他参与方提供的公钥

address_ —-记录该多重签名合约所对应的地址

元界的地址是通过account_address类进行抽象的,它与account类之间是关联关系,每个账户可以拥有多个地址,它们主要是基于根私钥,依据索引值产生新的地址。

类主要应用如下字段存储地址关键信息。

name —-用于存储该地址所属账户的用户名

prv_key —-该字段用于存储地址所对应的私钥,由于获取到地址的私钥后就可以花费或转移该地址上的所有资产,出于安全性考虑,没有在数据库的地址表中存储私钥的明文,而是存储是加密后的私钥信息。

hd_index —-用于存储该地址的索引值,即从根私钥产生该地址所应用的索引值。

address —-用于存储地址字符串的实际值。

账户除具有熵(ETP)之外,还可以拥有各种在元界中发行的数据资产。asset_detail类是元界中数据资产的抽象,它与account类是通过account_address类作为中介关联起来的,可以将这种关系理解为间接关联。

asset_detail类主要应用如下字段存储地址关键信息。

symbol —-用于存储该资产的名字,该资产在元界是唯一的,若已有用户发布过同名的资产则该资产则不能以现有的名字进行发布。

maximum_supply —-用于存储该资产发行的最大份数。该值是在资产建立时就指定的。

decimal_number —-用于指定单份资产可以被切分的小数位数。

address —-用于指定最初发布资产的发起地址。

description —-用于指定该资产的描述信息。