分层确定性钱包(BIP0032/BIP0044)
分层确定性钱包包含从数结构所生成的钥匙。这种母钥匙可以生成子钥匙的序列。这些子钥匙又可以衍生出孙钥匙,以此无穷类推。这个树结构表如下图所示。
1.1、生成助记词的过程
规定熵的位数必须是 32 的整数倍,所以熵的长度取值位 128 到 256 之间取 32 的整数倍的值,分别为 128, 160, 192, 224, 256;
校验和的长度为熵的长度/32 位, 所以校验和长度可为 4,5,6,7,8 位
助记词库有 2048 个词,用 11 位可全部定位词库中所有的词,作为词的索引,故一个词用 11 位表示,助记词的个数可为 (熵+校验和)/11,值为 12,15,18,21,24
种子生成助记词如图:
步骤如下:
步骤一生成一个长度为 128~256 位 (bits) 的随机序列(熵)
步骤二取熵哈希后的前 n 位作为校验和 (n= 熵长度/32)
步骤三随机序列 + 校验和 -> 拼接起来
步骤四把步骤三得到的结果每 11 位切割得到的每 11 位字节(二进制转为->十进制)通过Index获取匹配词库的一个词
步骤五得到的结果就是助记词串
1.2、助记词生成种子的过程
为了从助记词中生成二进制种子,BIP39 采用PBKDF2函数推算种子,其参数如下:
助记词句子作为密码
“mnemonic” + passphrase 作为盐
2048 作为重复计算的次数
HMAC-SHA512 作为随机算法
512 位(64 字节)是期望得到的密钥长度
1.3、从种子中创造HD钱包
HD钱包从单个root seed中创建,为128到256位的随机数。HD钱包的所有的确定性都衍生自这个根种子。
任何兼容HD钱包的根种子也可重新创造整个HD钱包。所以简单的转移HD钱包的根种子就让HD钱包中所包含的成千上百万的密钥被复制,储存导出以及导入。根种子一般总是被表示为a mnemonic word sequence,助记码词汇可以让人们更容易地抄写和储存。
创建主密钥以及HD钱包地主链代码的过程如下图所示。
根种子输入到HMAC-SHA512算法中就可以得到一个可用来创造master private key(m) 和 a master chain code的哈希。主私钥(m)之后可以通过使用我们在本章先前看到的那个普通椭圆曲线m * G过程生来成相对应的主公钥(M)。链代码可以给从母密钥中创造子密钥的那个方程中引入的熵。
1.4私钥 公钥 比特币地址
一个比特币钱包中包含一系列的密钥对,每个密钥对包括一个私钥和一个公钥。私钥(k)是一个数字,通常是随机选出的。
有了私钥,我们就可以使用椭圆曲线乘法这个单向加密函数产生一个公钥(K)。
有了公钥(K),我们就可以使用一个单向加密哈希函数生成比特币地址(A)。
公私钥单向关系示意图
压缩格式化公钥
比特币地址生成
Base58编码生成流程
1.4、HD钱包密钥识别符(路径)
HD钱包中的密钥是用“路径”命名的,且每个级别之间用斜杠(/)字符来表示。由主私钥衍生出的私钥起始以“m”打头。因此,第一个母密钥生成的子私钥是m/0。第一个公共钥匙是M/0。第一个子密钥的子密钥就是m/0/1,以此类推。
密钥的“祖先”是从右向左读,直到你达到了衍生出的它的主密钥。举个例子,标识符m/x/y/z描述的是子密钥m/x/y的第z个子密钥。而子密钥m/x/y又是m/x的第y个子密钥。m/x又是m的第x个子密钥。
BIP0044指定了包含5个预定义树状层级的结构:
m / purpose' / coin_type' / account' / change / address_index
第一层的目的地总是被设定为44'。第二层的“coin_type”特指密码货币硬币的种类并且允许多元货币HD钱包中的货币在第二个层级下有自己的亚树状结构。目前有三种货币被定义:Bitcoin is m/44'/0'、Bitcoin Testnet is m/44'/1',以及Litecoin is m/44'/2'。
树的第三层级是“account”,这可以允许使用者为了会计或者组织目的,而去再细分他们的钱包到独立的逻辑性亚账户。举个例子,一个HD钱包可能包含两个比特币“账户”:m/44'/0'/0' 和 m/44'/0'/1'。每个账户都是它自己亚树的根。
第四层级就是“change”。每一个HD钱包有两个亚树,一个是用来接收地址一个是用来创造找零地址。注意无论先前的层级是否使用是否使用强化衍生,这一层级使用的都是常规衍生。这是为了允许这一层级的树可以在可供不安全环境下,输出扩展的公共钥匙。被HD钱包衍生的可用的地址是第四层级的子级,就是第五层级的树的“address_index”。
**BitCoin不同地址生成
BIP 44 普通地址 以1开头的地址
String path = "m/44'/0'/0'/0/0; // 账户路径
AbstractBitcoinNetParams networkParameters = coinEnum.getNetworkParameters(); // 网络上下文
DeterministicSeed seed = new DeterministicSeed(mnemonicCodes, seeds, "", 0L); // 根据助记词生成种子
DeterministicKeyChain keyChain = DeterministicKeyChain.builder().seed(seed).build();
DeterministicKey ecKey= keyChain.getKeyByPath(childNumbers, true); // 根据种子路径生成密钥对
LegacyAddress legacyAddress = LegacyAddress.fromKey(networkParameters, ecKey)
String address = legacyAddress.toBase58()
P2SH (Pay-to-Script Hash)和多重签名地址
以数字3开头的比特币地址是P2SH地址,有时被错误的称谓多重签名或多重签名地址。他们指定比特币交易中受益人作为哈希的脚本,而不是公钥的所有者。这个特性在2012年1月由BIP0016引进,目前因为BIP0016提供了增加功能到地址本身的机会而被广泛的采纳。不同于P2PKH交易发送资金到传统1开头的比特币地址,资金被发送到3开头的地址时,需要的不仅仅是一个公钥的哈希值,同时也需要一个私钥签名作为所有者证明。在创建地址的时候,这些要求会被定义在脚本中,所有对地址的输入都会被这些要求阻隔。
一个P2SH地址从事务脚本中创建,它定义谁能消耗这个事务输出。编码一个P2SH地址涉及使用一个在创建比特币地址用到过的双重哈希函数,并且只能应用在脚本而不是公钥.
脚本哈希的结果是由Base58Check编码前缀为5的版本、编码后得到开头为3的编码地址。一个P2SH地址例子是32M8ednmuyZ2zVbes4puqe44NZumgG92sM。P2SH 不一定是多重签名的交易。虽然P2SH地址通常都是代表多重签名,但也可能是其他类型的交易脚本。
BIP 49 之前的隔离见证地址 以3开头的地址(BTC 的 p2shHeader为 0 LTC 的 p2shHeader为 5)
String path = "m/49'/0'/0'/0/0; // 账户路径
AbstractBitcoinNetParams networkParameters = coinEnum.getNetworkParameters(); // 网络上下文
DeterministicSeed seed = new DeterministicSeed(mnemonicCodes, seeds, "", 0L); // 根据助记词生成种子
DeterministicKeyChain keyChain = DeterministicKeyChain.builder().seed(seed).build();
DeterministicKey ecKey= keyChain.getKeyByPath(childNumbers, true); // 根据种子路径生成密钥对
// 对公钥hash进行一次转换
int version = 0;
byte[] bytes1 = OpCodes.push(version);
byte[] bytes2 = OpCodes.push(parent.getPubKeyHash());
byte[] bytes3 = new byte[bytes1.length + bytes2.length];
System.arraycopy(bytes1, 0, bytes3, 0, bytes1.length);
System.arraycopy(bytes2, 0, bytes3, bytes1.length, bytes2.length);
byte[] keyhash = Utils.sha256hash160(bytes3);
LegacyAddress legacyAddress = LegacyAddress.fromScriptHash(networkParameters, keyhash)
String address = legacyAddress.toBase58() // 是P2WSH Base58前缀是5
BIP 84 最新隔离见证地址 以bc1开头的地址(BTC 的 segwitAddressHrp 为 bc LTC 的 segwitAddressHrp 为 ltc)
String path = "m/84'/0'/0'/0/0; // 账户路径
AbstractBitcoinNetParams networkParameters = coinEnum.getNetworkParameters(); // 网络上下文
DeterministicSeed seed = new DeterministicSeed(mnemonicCodes, seeds, "", 0L); // 根据助记词生成种子
DeterministicKeyChain keyChain = DeterministicKeyChain.builder().seed(seed).build();
DeterministicKey ecKey= keyChain.getKeyByPath(childNumbers, true); // 根据种子路径生成密钥对
SegwitAddress segwitAddress = SegwitAddress.fromKey(networkParameters, ecKey);
String address = segwitAddress.toBech32()
HDWallet 推导密钥流程
比特币地址详解
密钥、地址、钱包
BIP44