由比特币的签名机制可知,如果丢失了私钥,没有任何办法可以花费对应地址的资金。

这样就使得因为丢失私钥导致资金丢失的风险会很高。为了避免一个私钥的丢失导致地址的资金丢失,比特币引入了多重签名机制,可以实现分散风险的功能。

具体来说,就是假设N个人分别持有N个私钥,只要其中M个人同意签名就可以动用某个“联合地址”的资金。

多重签名地址实际上是一个Script Hash,以2-3类型的多重签名为例,它的创建过程如下:

  1. const bitcoin = require('bitcoinjs-lib');
  2. let
  3. pubKey1 = '026477115981fe981a6918a6297d9803c4dc04f328f22041bedff886bbc2962e01',
  4. pubKey2 = '02c96db2302d19b43d4c69368babace7854cc84eb9e061cde51cfa77ca4a22b8b9',
  5. pubKey3 = '03c6103b3b83e4a24a0e33a4df246ef11772f9992663db0c35759a5e2ebf68d8e9',
  6. pubKeys = [pubKey1, pubKey2, pubKey3].map(s => Buffer.from(s, 'hex')); // 注意把string转换为Buffer
  7. // 创建2-3 RedeemScript:
  8. let redeemScript = bitcoin.script.multisig.output.encode(2, pubKeys);
  9. console.log('Redeem script: ' + redeemScript.toString('hex'));
  10. // 编码:
  11. let scriptPubKey = bitcoin.script.scriptHash.output.encode(bitcoin.crypto.hash160(redeemScript));
  12. let address = bitcoin.address.fromOutputScript(scriptPubKey);
  13. console.log('Multisig address: ' + address); // 36NUkt6FWUi3LAWBqWRdDmdTWbt91Yvfu7

首先,我们需要所有公钥列表,这里是3个公钥。然后,通过bitcoin.script.multisig.output.encode()方法编码为2-3类型的脚本,对这个脚本计算hash160后,使用Base58编码即得到总是以3开头的多重签名地址,这个地址实际上是一个脚本哈希后的编码。

以3开头的地址就是比特币的多重签名地址,但从地址本身无法得知签名所需的M/N。

如果我们观察Redeem Script的输出,它的十六进制实际上是:

  1. 52
  2. 21 026477115981fe981a6918a6297d9803c4dc04f328f22041bedff886bbc2962e01
  3. 21 02c96db2302d19b43d4c69368babace7854cc84eb9e061cde51cfa77ca4a22b8b9
  4. 21 03c6103b3b83e4a24a0e33a4df246ef11772f9992663db0c35759a5e2ebf68d8e9
  5. 53
  6. ae

翻译成比特币的脚本指令就是:

  1. OP_2
  2. PUSHDATA(33) 026477115981fe981a6918a6297d9803c4dc04f328f22041bedff886bbc2962e01
  3. PUSHDATA(33) 02c96db2302d19b43d4c69368babace7854cc84eb9e061cde51cfa77ca4a22b8b9
  4. PUSHDATA(33) 03c6103b3b83e4a24a0e33a4df246ef11772f9992663db0c35759a5e2ebf68d8e9
  5. OP_3
  6. OP_CHECKMULTISIG

OP_2OP_3构成2-3多重签名,这两个指令中间的3个PUSHDATA(33)就是我们指定的3个公钥,最后一个OP_CHECKMULTISIG表示需要验证多重签名。

发送给多重签名地址的交易创建的是P2SH脚本,而花费多重签名地址的资金需要的脚本就是M个签名+Redeem Script。

注意:从多重签名的地址本身并无法得知该多重签名使用的公钥,以及M-N的具体数值。必须将Redeem Script公示给每个私钥持有人,才能够验证多重签名地址是否正确(即包含了所有人的公钥,以及正确的M-N数值)。要花费多重签名地址的资金,除了M个私钥签名外,必须要有Redeem Script(可由所有人的公钥构造)。只有签名,没有Redeem Script是不能构造出解锁脚本来花费资金的。因此,保存多重签名地址的钱包必须同时保存Redeem Script。

利用多重签名,可以实现:

  • 1-2,两人只要有一人同意即可使用资金;
  • 2-2,两人必须都同意才可使用资金;
  • 2-3,3人必须至少两人同意才可使用资金;
  • 4-7,7人中多数人同意才可使用资金。

最常见的多重签名是2-3类型。例如,一个提供在线钱包的服务,为了防止服务商盗取用户的资金,可以使用2-3类型的多重签名地址,服务商持有1个私钥,用户持有两个私钥,一个作为常规使用,一个作为应急使用。这样,正常情况下,用户只需使用常规私钥即可配合服务商完成正常交易,服务商因为只持有1个私钥,因此无法盗取用户资金。如果服务商倒闭或者被黑客攻击,用户可使用自己掌握的两个私钥转移资金。

大型机构的比特币通常都使用多重签名地址以保证安全。例如,某个交易所的3-6多重签名地址3D2oetdNuZUqQHPJmcMDDHYoqkyNVsFk9r

利用多重签名,可以使得私钥丢失的风险被分散到N个人手中,并且,避免了少数人窃取资金的问题。

比特币的多重签名最多允许15个私钥参与签名,即可实现1-2至15-15的任意组合(1⩽M⩽N⩽15)。

小结

多重签名可以实现N个人持有私钥,其中M个人同意即可花费资金的功能。

多重签名降低了单个私钥丢失的风险。

支付比特币到一个多重签名地址实际上是创建一个P2SH输出。

读后有收获可以支付宝请作者喝咖啡:

多重签名 - 图1