#offline #sign #bitcoin #private-key #cold #cli

app firma-cli

firm-cli 是一个命令行界面工具,用于创建存储在离线设备上的私钥的比特币多签钱包

8 个版本 (破坏性更改)

0.20.0 2021 年 8 月 6 日
0.19.0 2020 年 12 月 23 日
0.18.0 2020 年 12 月 15 日
0.17.0 2020 年 12 月 3 日
0.13.0 2020 年 10 月 14 日

#6#cold

MIT 许可证

225KB
4.5K SLoC

MIT license Crates

创建 2of2 多签钱包 p2wsh

在以下步骤中,我们将创建一个测试网 2of2 多签钱包并签名并广播一笔交易。需要同步的比特币节点。

在第一步中,我们将创建两个主密钥。

创建第一个主密钥

这一步创建第一个主密钥。 (可以使用骰子创建密钥,请参阅 firma-offline dice --help)

firma-offline random --key-name a1
{
  "id": {
    "kind": "MasterSecret",
    "name": "a1",
    "network": "testnet"
  },
  "key": "tprv8ZgxMBicQKsPdQsGb1U22Lw7bPwhbxRkV8Q1mf8mv42q6HpJS7MW5hx1J44gKK6m2pQyC32mG1i6v1P9C97MDx7MvKZzgoXTpcwUgTSEobm"
}

我们可以在保存到磁盘之前加密密钥,例如利用现有的 gpg 设置,如下所示

 # encryption key creation and storage in encrypted gpg
  dd if=/dev/urandom bs=1 count=32 | gpg --encrypt -r 'DEADBEEF!' >encryption_key.gpg

  # bitcoin private key creation
  gpg --decrypt encryption_key.gpg | firma-offline --encrypt random --key-name a1

在这种情况下,密钥文件 ~/.firma/testnet/keys/a1/master_secret.json 看起来是这样的

{
  "t": "encrypted",
  "c": {
    "t": "base64",
    "c": "5Vqdw61WCoxyvl6mj6WBGEPzzI/SCLxwukHbbxCYsQphkPdoGDMaPhLL7Jg7Ok4yJa7E79LiiOSaRcszjnyLH3lfskF3ii2u5qTcacQhmuh5HV8d275hGAoYejY24MU58h/4Mo5A3om6woRpIgABmAEFXGCeTsjgvvXO+iD0EJA2tse+YQJRhMQGYCMeNH7BcrnWrAhhu3eBCsZdt0j5bsrP6aX3DLQIW6uUhsP7nklscGdRstu82+NEkdwonP+hBXBrkFxfe9DCer/x4IbeZF6TGA=="
  }
}

在这种情况下,要读取密钥的纯文本

gpg --decrypt encryption_key.gpg | firma-offline --encrypt export --kind MasterSecret --name a1
{
  "id": {
    "kind": "MasterSecret",
    "name": "a1e",
    "network": "testnet"
  },
  "key": "tprv8ZgxMBicQKsPdHXHYrBsowgZXAh1bisk2nxvJLqRakJ9tZDLTLgFSGZDH79bKF19cTkmW8LHV3ZFbRytQAxjXx1MUFrrzpdfxiFcqqfpjkf"
}

注意:如果钱包文件已加密,则需要使用加密密钥对数据进行加密和解密。

创建第二个主密钥

这个密钥是通过提供骰子启动创建的

firma-offline dice --key-name a2 --faces 20 -l 12 -l 11 -l 1 -l 1 -l 16 -l 8 -l 1 -l 12 -l 7 -l 4 -l 12 -l 8 -l 1 -l 1 -l 1 -l 1 -l 1 -l 1 -l 1 -l 1 -l 1 -l 1 -l 1 -l 1 -l 1 -l 1 -l 1 -l 1 -l 1 -l 1 -l 1 -l 1 -l 1 -l 1 -l 18 -l 19 -l 12 -l 1 -l 16 -l 1 -l 18 -l 1 -l 13 -l 1 -l 1 -l 16 -l 4 -l 3 -l 1 -l 1 -l 1 -l 1 -l 1 -l 20 -l 19 -l 18 -l 17 -l 12 -l 2
{
  "dice": {
    "faces": 20,
    "launches": "[12, 11, 1, 1, 16, 8, 1, 12, 7, 4, 12, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 19, 12, 1, 16, 1, 18, 1, 13, 1, 1, 16, 4, 3, 1, 1, 1, 1, 1, 20, 19, 18, 17, 12, 2]",
    "value": "33146769803929392242686007705600000000000000300775117168313561497600063822621"
  },
  "id": {
    "kind": "MasterSecret",
    "name": "a2",
    "network": "testnet"
  },
  "key": "tprv8ZgxMBicQKsPdGNW7N9EPsGpWBc56L8kKncoZfxC83M5ipBV2fMhujCBnxiTx33HnqiERg6fYsgKVBdSMNKm8nEcESHfUXAUecnyWnrx6Ls"
}

创建 2of2 多签钱包

首次使用 firma-online 工具时,您需要初始化连接参数

firma-online connect --url http://127.0.0.1:8332 --cookie-file $HOME/.bitcoin/.cookie

每次每个网络都需要这样做,并且每次节点配置更改时也是如此。

对于示例,我们使用先前步骤中创建的两个主密钥。从离线机器将 $HOME/.firma/testnet/keys/a1/descriptor_public_key.json$HOME/.firma/testnet/keys/a2/descriptor_public_key.json 复制到在线机器。您可以选择将文件复制到正确的目标目录,或使用 import 命令,这将允许您选择性地加密这些数据。

firma-online create-wallet --wallet-name firma-wallet -r 2 --key-name a1 --key-name a2
{
  "created_at_height": 1934912,
  "descriptor": "wsh(multi(2,[2f15d226/48'/1'/0'/2']tpubDFHFgFr6HbP88U7grBQ44yvocSU1EGkXX1dArKRum1qvb4Y6hy4CpJuPqpKZSyVnHptf6zoaW4HUjFHXgmtfy2vTGF1fccPy2ioNvKeZUnq/0/*,[7938c502/48'/1'/0'/2']tpubDEJZZGYXbZKMNEWgCdG9XZDycYM19Y8WxNc2cYcxLYhnNvKpbFNkgAza1x4GCUAHLdxx28R6dX88VhjgmZscW8Dzw6pGDzJ8a4gUCqHh1ny/0/*))#jpa3vwyx",
  "id": {
    "kind": "Wallet",
    "name": "firma-wallet",
    "network": "testnet"
  }
}

使用sign_wallet命令可以使用参与者密钥之一对钱包文件wallet.json进行签名,这可以防止攻击者在未被察觉的情况下篡改仅查看钱包。

创建接收地址

从刚刚生成的钱包中创建一个新的地址。由于已经保存在$HOME/.firma/testnet/firma-wallet/descriptor.json中,不再需要比特币节点参数。

firma-online get-address --wallet-name firma-wallet 
{
  "address": "tb1qdkl3aufvvk2zst22dy3ffjt0kfdl79mhvu6jcwecm5exm6j8dveseklast",
  "path": "m/0/0"
}

索引状态保存在$HOME/.firma/testnet/wallets/firma-wallet/indexes.json中,再次调用命令我们有:

{
  "address": "tb1q8m2456wjxu8mlkf708d2yvtmtlg59awvd2l3jjzkmt37gtzmx6psva9fnl",
  "path": "m/0/1"
}

向地址tb1qdkl3aufvvk2zst22dy3ffjt0kfdl79mhvu6jcwecm5exm6j8dveseklast发送一些资金

检查余额和硬币

firma-online balance --wallet-name firma-wallet
{
  "confirmed": {
    "btc": "0.00000000",
    "satoshi": 0
  },
  "pending": {
    "btc": "0.00586300",
    "satoshi": 586300
  }
}
firma-online list-coins --wallet-name firma-wallet 
{
  "coins": [
    {
      "amount": 586300,
      "outpoint": "43d3a56e8afe96eeb1c3a260bae735d064e5946190d9fb90524047bd21dbf383:0",
      "unconfirmed": true
    }
  ]
}

创建PSBT

在收到资金确认后,我们可以创建PSBT,指定接收者和金额,您可以指定多个接收者,并可以使用--coin显式地使用特定的utxo,请参阅firma-online create-tx --help

firma-online create-tx --wallet-name firma-wallet --recipient tb1q8m2456wjxu8mlkf708d2yvtmtlg59awvd2l3jjzkmt37gtzmx6psva9fnl:22400 --psbt-name test
{
  "address_reused": [],
  "funded_psbt": {
    "name": "test",
    "psbt": "cHNidP8BAH0CAAAAAaF+ubg9XAD6ZmGErqdrAdpu4ALBdz7M+TM0oPWNu5scAAAAAAD+////AqMBAAAAAAAAIgAgaMI+YcHlEUY9mvkIVax3/a4d42jXZgcjrbWqpKNFp7l4BQAAAAAAABYAFJmYo0dJtoF0R0qMtwYR5jtL6UGJAAAAAAX8bmFtZQZ0ZXN0LWEAAQEr0AcAAAAAAAAiACASrnn5+Jhe7Sivhhv6EwzbxegCw/oJSyLNg+b0h851tAEFR1IhAuOPRdJj6043K51DVaw+MIyMHEBOuEGrv89me8fOaQLpIQLgQluouXrqa42FwP/Ki9mwFxHFQy/50SN4Zcn73HSwZFKuIgYC4EJbqLl66muNhcD/yovZsBcRxUMv+dEjeGXJ+9x0sGQMeTjFAgAAAAAAAAAAIgYC449F0mPrTjcrnUNVrD4wjIwcQE64Qau/z2Z7x85pAukMyr4y1wAAAAAAAAAAAAEBR1IhAkiG9PSdcBAS08R6LIRS6iGFbQ5ZbjY2an2EMxXcmGbPIQM2XzQNCYGxaFTBlw1c4XU4hQxj7p7ntZZDaVLjrJg39VKuIgICSIb09J1wEBLTxHoshFLqIYVtDlluNjZqfYQzFdyYZs8Myr4y1wEAAAABAAAAIgIDNl80DQmBsWhUwZcNXOF1OIUMY+6e57WWQ2lS46yYN/UMeTjFAgEAAAABAAAAAAA="
  },
  "psbt_file": "$HOME/.firma/testnet/psbts/test/psbt.json",
  "qr_files": [
    "$HOME/.firma/testnet/psbts/test/qr/qr-0.png",
    "$HOME/.firma/testnet/psbts/test/qr/qr-1.png"
  ]
}

从节点A进行签名

firma-offline sign --psbt-name test --key-name a1 --wallet-name firma-wallet
{
  "balances": "",
  "fee": {
    "absolute": 193,
    "absolute_fmt": "0.00000193 BTC",
    "rate": 1.0157894736842106
  },
  "info": [
    "Added signatures"
  ],
  "inputs": [
    {
      "outpoint": "43d3a56e8afe96eeb1c3a260bae735d064e5946190d9fb90524047bd21dbf383:0",
      "signatures": [
        "2f15d226"
      ],
      "value": "0.00586300 BTC"
    }
  ],
  "outputs": [
    {
      "address": "tb1q8m2456wjxu8mlkf708d2yvtmtlg59awvd2l3jjzkmt37gtzmx6psva9fnl",
      "value": "0.00022400 BTC"
    },
    {
      "address": "tb1qye8gt2pjwpdn8mj7eh3jgnl0hnfwq23lq4cat6s55hsnka3v2kss4jxsmm",
      "value": "0.00563707 BTC"
    }
  ],
  "psbt_file": "",
  "size": {
    "estimated": 190,
    "psbt": 1083,
    "unsigned": 137
  }
}

现在位于~/.firma/testnet/psbts/test/psbt.json的psbt.json已经有了1个签名(注意输出中的Added signatures)。

从节点B进行签名

firma-offline sign --psbt-name test --key-name a2 --wallet-name firma-wallet
{
  "balances": "TODO",
  "fee": {
    "absolute": 193,
    "absolute_fmt": "0.00000193 BTC",
    "rate": 1.0157894736842106
  },
  "info": [
    "Added signatures"
  ],
  "inputs": [
    {
      "outpoint": "43d3a56e8afe96eeb1c3a260bae735d064e5946190d9fb90524047bd21dbf383:0",
      "signatures": [
        "2f15d226",
        "7938c502"
      ],
      "value": "0.00586300 BTC"
    }
  ],
  "outputs": [
    {
      "address": "tb1q8m2456wjxu8mlkf708d2yvtmtlg59awvd2l3jjzkmt37gtzmx6psva9fnl",
      "value": "0.00022400 BTC"
    },
    {
      "address": "tb1qye8gt2pjwpdn8mj7eh3jgnl0hnfwq23lq4cat6s55hsnka3v2kss4jxsmm",
      "value": "0.00563707 BTC"
    }
  ],
  "psbt_file": "",
  "size": {
    "estimated": 190,
    "psbt": 1191,
    "unsigned": 137
  }
}

合并、最终化和发送交易

firma-online send-tx --wallet-name firma-wallet --psbt-name test --broadcast
{
  "broadcasted": true,
  "hex": "0200000000010183f3db21bd47405290fbd9906194e564d035e7ba60a2c3b1ee96fe8a6ea5d3430000000000feffffff0280570000000000002200203ed55a69d2370fbfd93e79daa2317b5fd142f5cc6abf194856dae3e42c5b3683fb99080000000000220020264e85a832705b33ee5ecde3244fefbcd2e02a3f0571d5ea14a5e13b762c55a10400473044022041785595cc34a022686213b8d7b34bac2f2bfc77e37a8fa2f2f3019b0646bbfb022047e12715e32b081be49865ffdbca73829b0231e44f77c9afcd6aa25582186e300148304502210081f298aadf2e5f68e322c030b1e97e23f45a1ac9ddf5fa4b964c1a57847f37b70220129c3d54e9f5c946511bfd30fc755846014654d4d693455fa08279a994617e410147522102e43ee99d46f46cd17d25987701576ae07129ab268ca9879e53a345546537dc862102ccbef362214e9e7ece2bcd33731cdabd0c2937d9bec9db2684fb68021297f8b752ae00000000",
  "txid": "4e08b321a79465cdbba8ad811ddaa68ffe79604406413b25b55c76b9850902e5"
}

查看交易 4e08b321a79465cdbba8ad811ddaa68ffe79604406413b25b55c76b9850902e5

依赖项

~17–27MB
~340K SLoC