Skip to content
Timo Hanke edited this page Feb 4, 2013 · 13 revisions

Multi-Party

Example 3: Multiple parties

Intro

This example demonstrates a case where two parties A and B jointly issue a certificate that contains a multisignature base key which they split among themselves. Think of A and B as business partners who do not want either one of them to be able to control incoming payments alone (without the other partner). For simplicity we assume A and B have their machines running online. In practive, of course, the owner and receiving base keys should be generated on an offline machine. The joint project is called fooproj.

Certificate creation

A and B create their receiving base keys:

@onlineA: ./bitcoind -testnet getnewaddress fooproj_recvA true
0285b2eb2c0f2e4a12646dbcf38d08c29ef557b5616048575b133a2084a56bb84a

@onlineB: ./bitcoind -testnet getnewaddress "fooproj_recvB" true
03ba3137ddbee4e164390b7b67e0975d12969ef23ac1fd7b1f7e880319d072b323

A and B create their owner keys (revokation keys) for the certificate:

@onlineA: ./bitcoind -testnet getnewaddress "fooproj_ownerA" true
0397badc73e72ab8ddde12fa6512bc52e2de58870b682dffe9e08c31620f71b8e4

@onlineB: ./bitcoind -testnet getnewaddress "fooproj_ownerB" true
025c62affbfb6889603a204ccbde287d4d84c993b30e74a86e4ed51a56584ca822

B sends both his base pubkeys to A, who drafts the certificate using his and B's receiving base pubkey:

version: 0.1
data:
  subjectname: Foo Project
  contacts: 
   - type: EMAIL
     value: [email protected] 
   - type: EMAIL
     value: [email protected] 
   - type: URL  
     value: "http://fooproject.com"
  paymentkeys:
    - algorithm:
       type: P2CMULTI
       version: 0.1
      value: [ 2, 0285b2eb2c0f2e4a12646dbcf38d08c29ef557b5616048575b133a2084a56bb84a, 03ba3137ddbee4e164390b7b67e0975d12969ef23ac1fd7b1f7e880319d072b323 ]
--- 

A runs bcert/mkcert.py on it:

data {
  version: "0.1"
  subjectname: "Foo Project"
  contacts {
    type: EMAIL
    value: "[email protected]"
  }
  contacts {
    type: EMAIL
    value: "[email protected]"
  }
  contacts {
    type: URL
    value: "http://www.fooproject.com"
  }
  paymentkeys {
    usage: PAYMENT
    algorithm {
      type: P2CMULTI
      version: "0.1"
    }
    value: "2"
    value: "\002\205\262\353,\017.J\022dm\274\363\215\010\302\236\365W\265a`HW[\023: \204\245k\270J"
    value: "\003\27217\335\276\344\341d9\013{g\340\227]\022\226\236\362:\301\375{\037~\210\003\031\320r\263#"
  }
}

hash of data part is: 3a4e6531c3ab1a3877caa811b7d8b8c92064fe12
hex binary cert: 12b3010a03302e31120b466f6f2050726f6a6563742214080112104140666f6f70726f6a6563742e636f6d2214080112104240666f6f70726f6a6563742e636f6d221d08021219687474703a2f2f7777772e666f6f70726f6a6563742e636f6d2a540801120708021203302e311a01321a210285b2eb2c0f2e4a12646dbcf38d08c29ef557b5616048575b133a2084a56bb84a1a2103ba3137ddbee4e164390b7b67e0975d12969ef23ac1fd7b1f7e880319d072b323

Signing

A checks if fooproject does not yet exist in the blockchain.

@onlineA: ./bitcoind -testnet bclist fooproject
{
    "fRegistered" : false,
}

A signs the certificate using both owner pubkeys plus the hex binary certificate on the commandline:

@onlineA: ./bitcoind -testnet bcsigncert '{"alias":"fooproject","owners":["0397badc73e72ab8ddde12fa6512bc52e2de58870b682dffe9e08c31620f71b8e4","025c62affbfb6889603a204ccbde287d4d84c993b30e74a86e4ed51a56584ca822"]}' 12b3010a03302e31120b466f6f2050726f6a6563742214080112104140666f6f70726f6a6563742e636f6d2214080112104240666f6f70726f6a6563742e636f6d221d08021219687474703a2f2f7777772e666f6f70726f6a6563742e636f6d2a540801120708021203302e311a01321a210285b2eb2c0f2e4a12646dbcf38d08c29ef557b5616048575b133a2084a56bb84a1a2103ba3137ddbee4e164390b7b67e0975d12969ef23ac1fd7b1f7e880319d072b323
{
    "nFee" : 0.00050000,
    "txid" : "76755b27e14bf737a418ab2891ebf0414b8643996aa23c38873b66d9ae9e9b9f",
    "fname" : "933e81f136834fafe8aafe05feef13e9f17249ad"
}

Transfer and Verification by B

A send the file ~/.bitcoin/testnet3/bcerts/933e81f136834fafe8aafe05feef13e9f17249ad.bcrt per email to B. B imports it by moving it to ~/.bitcoin/testnet3/bcerts/ on his machines. B verifies that his receiving base pubkey appears in the cert and the signature value is fooproject:

@onlineA: bcert/dumpcertstore.py fooproject
data {
  version: "0.1"
  subjectname: "Foo Project"
  contacts {
    type: EMAIL
    value: "[email protected]"
  }
  contacts {
    type: EMAIL
    value: "[email protected]"
  }
  contacts {
    type: URL
    value: "http://www.fooproject.com"
  }
  paymentkeys {
    usage: PAYMENT
    algorithm {
      type: P2CMULTI
      version: "0.1"
    }
    value: "2"
    value: "\002\205\262\353,\017.J\022dm\274\363\215\010\302\236\365W\265a`HW[\023: \204\245k\270J"
    value: "\003\27217\335\276\344\341d9\013{g\340\227]\022\226\236\362:\301\375{\037~\210\003\031\320r\263#"
  }
}
signatures {
  algorithm {
    type: BCPKI
    version: "0.4"
  }
  value: "fooproject"
}

B verifies the signature in the blockchain:

@onlineB: ./bitcoind -testnet verify fooproject
{
    "fSigned" : true,
    "txid" : "76755b27e14bf737a418ab2891ebf0414b8643996aa23c38873b66d9ae9e9b9f",
    "confirmations" : 2,
    "strTime" : "2013-02-02T16:56:06"
}

Now the project can start.

Receiving payments

A and B both add the receiving base address in their wallet:

@onlineA|B: b addmultisigaddress 2 '["0285b2eb2c0f2e4a12646dbcf38d08c29ef557b5616048575b133a2084a56bb84a","03ba3137ddbee4e164390b7b67e0975d12969ef23ac1fd7b1f7e880319d072b323"]' fooproj_recv
2NAM5kqrMNAVUFtwN9cQeTJyMJ5mSukorvH

Suppose the certificate was uploaded to a server:

@onlineB: HEX=`cat ~/.bitcoin/testnet3/bcerts/933e81f136834fafe8aafe05feef13e9f17249ad.bcrt | xxd -p | tr -d "\n"`
@onlineB: wget -O log.html "http://btcrypt.org/cgi-bin/transfer.cgi?hexcert=${HEX}"

A third party C downloads the certificate and stores it:

@onlineC: wget -O fooproject.bcrt "http://btcrypt.org/cgi-bin/retrieve.cgi?alias=fooproject"
@onlineC: TODO derive filename or have wget generate it automatically
@onlineC: mv fooproject.bcrt ~/.bitcoin/testnet3/bcerts

C pays directly to fooproject via the P2CMULTI method (pay-to-contract with multiple base keys). Say the chosen ticket is 4febe382ed164145bf248b448444b807.

@onlineC: ./bitcoind -testnet sendtoalias fooproject '[2,"4febe382ed164145bf248b448444b807"]' 0.5
{
    "nConfirmations" : 112,
    "dest" : "2N4uqgTeYypZZWFrsx2TcsPrTMr23JUwKZX",
    "txid" : "f77446016d4b7eec4ffb0be4daf3183d4fb02baa1e850bbf7e59c7a9b7a3b581"
    "vout" : 1
}
This tells us that the certificate for fooproject has 112 confirmations at the time of sending.
The derived destination is the P2SH address that we see.

Look at the transaction:

@onlineC: ./bitcoind -testnet gettransaction 
{
    "p2cmulti" : "0285b2eb2c0f2e4a12646dbcf38d08c29ef557b5616048575b133a2084a56bb84a 03ba3137ddbee4e164390b7b67e0975d12969ef23ac1fd7b1f7e880319d072b323 ",
    "ticket" : "4febe382ed164145bf248b448444b807",
    "to" : "BCSIG_v0.4_F0PR0JECT<P2CMULTI:4febe382ed164145bf248b448444b807> = 2 0370c6b83811d57e7267cd835bfeb941d553111789e38cf0c43d0ca52624c0cad6 028324aacef85fcbe199d03126cec6c1a3a51b4a1f4b8a18a15bd193737059fa5a 2 OP_CHECKMULTISIG",
        "vout" : [
            ,
            {
                "value" : 0.50000000,
                "n" : 1,
                "scriptPubKey" : {
                    "asm" : "OP_HASH160 7ff6fc246c62c89dde14ac3d965c5fa018bc6d8e OP_EQUAL",
                    "hex" : "a9147ff6fc246c62c89dde14ac3d965c5fa018bc6d8e87",
                    "reqSigs" : 1,
                    "type" : "scripthash",
                    "addresses" : [
                        "2N4uqgTeYypZZWFrsx2TcsPrTMr23JUwKZX"
                    ]
                }
            }
        ]
}

We see A and B's base receiving pubkeys in the field p2cmulti and the derived pubkeys in the script under to. The output is the P2SH of that script.

Spending

A and B import the ticket

@onlineA|B: b importticket 2NAM5kqrMNAVUFtwN9cQeTJyMJ5mSukorvH 4febe382ed164145bf248b448444b807 
{
    "ticket" : "4febe382ed164145bf248b448444b807",
    "derived" : "2N4uqgTeYypZZWFrsx2TcsPrTMr23JUwKZX"
}

TODO why is this slow? This has created an account:

@onlineA|B: b getaccount  2N4uqgTeYypZZWFrsx2TcsPrTMr23JUwKZX
fooproj_recv<4febe382ed164145bf248b448444b807>

Unfortunately, bitcoind does not allow to watch arbitrary addresses without having the private key at hand, nor to watch non-wallet transactions. So A and B have to use a different client or an online service to watch for the incoming payment on 2N98AF5e5ck3WnEcNEWfuyxFi7K8txja5St and see the confirmations.

A creates a transaction that spends the coin received for 2N4uqgTeYypZZWFrsx2TcsPrTMr23JUwKZX, and partially signs it:

@onlineA: b getnewaddress
msFrMcXFB4R8vHQJAMXZa8H3RAD6BJkPD8

@onlineA: b createrawtransaction '[{"txid":"f77446016d4b7eec4ffb0be4daf3183d4fb02baa1e850bbf7e59c7a9b7a3b581","vout":1}]' '{"msFrMcXFB4R8vHQJAMXZa8H3RAD6BJkPD8":0.45}'
010000000181b5a3b7a9c7597ebf0b851eaa2bb04f3d18f3dae40bfb4fec7e4b6d014674f70100000000ffffffff0140a5ae02000000001976a91480c6500a42d6b7281f18ff544c339396aa60a11b88ac00000000

@onlineA: b signrawtransaction 010000000181b5a3b7a9c7597ebf0b851eaa2bb04f3d18f3dae40bfb4fec7e4b6d014674f70100000000ffffffff0140a5ae02000000001976a91480c6500a42d6b7281f18ff544c339396aa60a11b88ac00000000
{
    "hex" : "010000000181b5a3b7a9c7597ebf0b851eaa2bb04f3d18f3dae40bfb4fec7e4b6d014674f70100000091004730440220158ddf61d8628bdd8e6cf073428e5fce7e137aebd08390cfe5e5234158bf7449022014fe0e4366f4f7c785780441f85d4bbf0a7a1872bbd98090c81cf705b7825cfd014752210370c6b83811d57e7267cd835bfeb941d553111789e38cf0c43d0ca52624c0cad621028324aacef85fcbe199d03126cec6c1a3a51b4a1f4b8a18a15bd193737059fa5a52aeffffffff0140a5ae02000000001976a91480c6500a42d6b7281f18ff544c339396aa60a11b88ac00000000",
    "complete" : false
}

B signs it too and commits it:

@onlineB: b signrawtransaction 010000000181b5a3b7a9c7597ebf0b851eaa2bb04f3d18f3dae40bfb4fec7e4b6d014674f70100000091004730440220158ddf61d8628bdd8e6cf073428e5fce7e137aebd08390cfe5e5234158bf7449022014fe0e4366f4f7c785780441f85d4bbf0a7a1872bbd98090c81cf705b7825cfd014752210370c6b83811d57e7267cd835bfeb941d553111789e38cf0c43d0ca52624c0cad621028324aacef85fcbe199d03126cec6c1a3a51b4a1f4b8a18a15bd193737059fa5a52aeffffffff0140a5ae02000000001976a91480c6500a42d6b7281f18ff544c339396aa60a11b88ac00000000
{
    "hex" : "010000000181b5a3b7a9c7597ebf0b851eaa2bb04f3d18f3dae40bfb4fec7e4b6d014674f701000000db004730440220158ddf61d8628bdd8e6cf073428e5fce7e137aebd08390cfe5e5234158bf7449022014fe0e4366f4f7c785780441f85d4bbf0a7a1872bbd98090c81cf705b7825cfd01493046022100ac34c2f7bb07f416ff5ddd1a7275ec2843bfb0315236c0982ced4dd8b666bd7102210085e08d5f02e1dd8a810c8185be403301b1744899042439980463faab587ec785014752210370c6b83811d57e7267cd835bfeb941d553111789e38cf0c43d0ca52624c0cad621028324aacef85fcbe199d03126cec6c1a3a51b4a1f4b8a18a15bd193737059fa5a52aeffffffff0140a5ae02000000001976a91480c6500a42d6b7281f18ff544c339396aa60a11b88ac00000000",
    "complete" : true
}

@onlineB: b sendrawtransaction 010000000181b5a3b7a9c7597ebf0b851eaa2bb04f3d18f3dae40bfb4fec7e4b6d014674f701000000db004730440220158ddf61d8628bdd8e6cf073428e5fce7e137aebd08390cfe5e5234158bf7449022014fe0e4366f4f7c785780441f85d4bbf0a7a1872bbd98090c81cf705b7825cfd01493046022100ac34c2f7bb07f416ff5ddd1a7275ec2843bfb0315236c0982ced4dd8b666bd7102210085e08d5f02e1dd8a810c8185be403301b1744899042439980463faab587ec785014752210370c6b83811d57e7267cd835bfeb941d553111789e38cf0c43d0ca52624c0cad621028324aacef85fcbe199d03126cec6c1a3a51b4a1f4b8a18a15bd193737059fa5a52aeffffffff0140a5ae02000000001976a91480c6500a42d6b7281f18ff544c339396aa60a11b88ac00000000
7dc48b2931d44746955c98165c8e7700521bdb26536109d59699f2d3c4535f9b

Revoking

A imports the private key corresponding to alias:

@onlineA: b aliasdump fooproject
{
    "normalized" : "BCSIG_v0.4_F0PR0JECT",
    "bcvalue" : "3c66a8afea592deb11d7d40ee07ec2b48d0e4256",
    "privkey" : "cMahea7zqjxrtgAbB7w9MkKbuTqT4fW1g4M5TZ8SeyyvNauBdrXX",
    "pubkey" : "03a1af5122a7c8711d59df6e99f7242b3a35808c17b66a8d6966db5a1a1d7c5f1a",
    "id" : "933e81f136834fafe8aafe05feef13e9f17249ad",
    "addr" : "mtwWWMd5L3mpLipudYXQbXWDp6ofc96gt5"
}

@onlineA: b importprivkey cMahea7zqjxrtgAbB7w9MkKbuTqT4fW1g4M5TZ8SeyyvNauBdrXX

A looks us the relevant outpoint of the signing transaction, creates a revokation transaction, and partially signs it:

@onlineA: b bclist fooproject
{
    "fRegistered" : true,
    "txid" : "76755b27e14bf737a418ab2891ebf0414b8643996aa23c38873b66d9ae9e9b9f",
    "confirmations" : 115,
    "strTime" : "2013-02-02T16:56:06",
    "values" : [
        {
            "vout" : 0,
            "value" : "933e81f136834fafe8aafe05feef13e9f17249ad"
        },
        {
            "vout" : 1,
            "value" : "0fdd656a062751d4a3e8dd4f7a5b2cdccb4e5ce9"
        }
    ]
}

@onlineA: b createrawtransaction '[{"txid":"76755b27e14bf737a418ab2891ebf0414b8643996aa23c38873b66d9ae9e9b9f","vout":1}]' '{"mgZL8xBMo2kpVeJHSSEi2x14pCJw5wndfp":0.0495}'
01000000019f9b9eaed9663b87383ca26a9943864b41f0eb9128ab18a437f74be1275b75760100000000ffffffff01f0874b00000000001976a9140b6b30fe9fc8b5023dbecd403a336434b87c1a9688ac00000000

@onlineA: b signrawtransaction 01000000019f9b9eaed9663b87383ca26a9943864b41f0eb9128ab18a437f74be1275b75760100000000ffffffff01f0874b00000000001976a9140b6b30fe9fc8b5023dbecd403a336434b87c1a9688ac00000000
{
    "hex" : "01000000019f9b9eaed9663b87383ca26a9943864b41f0eb9128ab18a437f74be1275b7576010000009300483045022100ee130074ef491b7cb1035f14a1bfb5aa2cad75218f0702f3e5a8e2d10146c30902200f0501da268d305982a703eab6b4da72d08f1029368d5bee71232bb1f3469f02014730440220740e86f3e884b6f10d077afd75f82233285a29211f1b2a97321216fba117d18c0220385e4ce49082374d324bc8a3dcb4fbfecc8ac53747a5e8eb316634755241e75b0100ffffffff01f0874b00000000001976a9140b6b30fe9fc8b5023dbecd403a336434b87c1a9688ac00000000",
    "complete" : false
}

B also signs and commits:

@onlineB: b signrawtransaction 01000000019f9b9eaed9663b87383ca26a9943864b41f0eb9128ab18a437f74be1275b7576010000009300483045022100ee130074ef491b7cb1035f14a1bfb5aa2cad75218f0702f3e5a8e2d10146c30902200f0501da268d305982a703eab6b4da72d08f1029368d5bee71232bb1f3469f02014730440220740e86f3e884b6f10d077afd75f82233285a29211f1b2a97321216fba117d18c0220385e4ce49082374d324bc8a3dcb4fbfecc8ac53747a5e8eb316634755241e75b0100ffffffff01f0874b00000000001976a9140b6b30fe9fc8b5023dbecd403a336434b87c1a9688ac00000000
{
    "hex" : "01000000019f9b9eaed9663b87383ca26a9943864b41f0eb9128ab18a437f74be1275b757601000000da00483045022100ee130074ef491b7cb1035f14a1bfb5aa2cad75218f0702f3e5a8e2d10146c30902200f0501da268d305982a703eab6b4da72d08f1029368d5bee71232bb1f3469f02014730440220740e86f3e884b6f10d077afd75f82233285a29211f1b2a97321216fba117d18c0220385e4ce49082374d324bc8a3dcb4fbfecc8ac53747a5e8eb316634755241e75b0147304402202ce650c4f2c694a6ced44d9752b55077e973bca7e53f9f5c2f77a15fe8b2553d022029bd70bb08e76f25a9a6aa59488b8a05c61b05cb97771093cf806ec3605aabae01ffffffff01f0874b00000000001976a9140b6b30fe9fc8b5023dbecd403a336434b87c1a9688ac00000000",
    "complete" : true
}

@onlineB: b sendrawtransaction 01000000019f9b9eaed9663b87383ca26a9943864b41f0eb9128ab18a437f74be1275b757601000000da00483045022100ee130074ef491b7cb1035f14a1bfb5aa2cad75218f0702f3e5a8e2d10146c30902200f0501da268d305982a703eab6b4da72d08f1029368d5bee71232bb1f3469f02014730440220740e86f3e884b6f10d077afd75f82233285a29211f1b2a97321216fba117d18c0220385e4ce49082374d324bc8a3dcb4fbfecc8ac53747a5e8eb316634755241e75b0147304402202ce650c4f2c694a6ced44d9752b55077e973bca7e53f9f5c2f77a15fe8b2553d022029bd70bb08e76f25a9a6aa59488b8a05c61b05cb97771093cf806ec3605aabae01ffffffff01f0874b00000000001976a9140b6b30fe9fc8b5023dbecd403a336434b87c1a9688ac00000000
bc40bf91f86427fe9a0338f3cb45c3b12c9ce5ea2507aecbad3ad4205480d168
Clone this wiki locally