Using multiple keys for extra security
Public key encryption, also known as asymmetric cryptography, is a key underlying technology of blockchains. Participants in the chain generate their own pairs of private keys and public addresses. They keep the private keys secret, but freely distribute the associated addresses. A blockchain transaction which performs an action for a particular address (e.g. spending its funds) must be signed by the corresponding private key. All participants on the chain can then verify these signatures, using public addresses only, without needing to see each others’ private keys.
Multisignature (“multisig” for short) addresses and transactions broaden this model by creating identities on the chain which are managed collectively by multiple parties. MultiChain uses “m-of-n” bitcoin-style multisignatures, in which a multisig address A is defined as: Given n regular addresses, at least m of the private keys corresponding to those addresses must sign a transaction to perform an action for A.
Some common values of m and n are given below, with practical examples:
- 1-of-n: Any one of n different parties can approve the transaction. For example, one of three employees can spend some funds, but we want the blockchain to contain a record of who did so.
- 2-of-2: Each of two separate parties must approve the transaction. For example, two departments in a company must sign off before some data is published on a blockchain on behalf of that company.
- 2-of-3: Any two out of three parties can approve the transaction. This is commonly used for escrow purposes, where the two counterparties to an agreement engage a third party to act as an arbitrator in the event of dispute.
In this tutorial, we will focus on 2-of-2 multisignatures, but the same techniques can be applied for any m and n. The tutorial requires two servers running Linux, both of which should have a multichaind
node up and running on the same blockchain, with no native currency or other unusual parameters. Both servers should be running multichain-cli
for that chain in interactive mode. If you don’t yet have this, follow the instructions in sections 1 and 2 of the Getting Started guide and then run multichain-cli chain1
on both servers. The first server’s node should also have an address with admin
, issue
and create
permissions – this will automatically be the case if it started the chain.
Creating the multisignature address
On the first server, run the following command:
getaddresses true
Choose any address with "ismine" : true
, which means that this node’s wallet contains the private key for the address.
Copy and paste the pubkey
shown:
Now run the same getaddresses true
command on the second server, again choosing an address with "ismine" : true
.
Copy and paste the pubkey
shown:
Now run the following command on either server to create the 2-of-2 multisig address and add it to the node’s wallet:
addmultisigaddress 2 '["", ""]'
The response contains the multisignature address. Copy and paste it here:
The response should be empty. Now run the same command on the other server, to add the address to the wallet and start tracking its balance:
addmultisigaddress 2 '["", ""]'
Issuing an asset to the multisig address
For most blockchain actions, a multisig address requires its own permissions, independent of the permissions of the individual regular addresses that were combined to create it (more details here). Let’s grant these permissions on the first server:
grant receive,send
The txid of the grant transaction should be displayed in the response. Now let’s issue a new asset directly to the multisig address:
issue asset9 10000 0.01
And now let’s check the multisig address has received the funds successfully:
getaddressbalances 0
A balance of 10000
units of asset9
should be displayed.
Spending funds from the multisig address
Still on the first server, let’s create a new regular address to receive some funds from the multisig:
getnewaddress
Copy and paste the new address here:
Now let’s grant this address receive
permissions, so it can be sent some funds:
grant receive
Now we begin the process of building the transaction which sends funds from the multisig address to this new address. Because this is a 2-of-2 multisig, the process will require a signature from both servers. Let’s begin on the first server:
createrawsendfrom '{"":{"asset9":500}}' '[]' sign
The response should contain a complete
field with value false
, along with a large hexadecimal blob in the hex
field. This hexadecimal blob is the raw transaction, which has been partially signed, and should be copied to the clipboard.
Now switch to the second server and run the following, pasting the raw transaction from the clipboard where shown:
signrawtransaction [paste-hex-blob]
The response should contain a complete
field with value true
, along with an even larger hexadecimal blob in the hex
field. This means that the transaction has enough signatures to be valid, and is ready for broadcasting to the blockchain. Copy the new hexadecimal blob, and run:
sendrawtransaction [paste-bigger-hex-blob]
The response should contain the 64-character hexadecimal txid of the sent transaction. Now let’s check that the 500 units of asset9
have been successfully transferred. On either server:
getaddressbalances 0
And on the first server only, check the new address’s balance (including unconfirmed transactions):
getaddressbalances 0
Creating a multisig-only stream
Now let’s create a stream to which only this multisignature address can write. On the first server:
create stream stream9 false
This automatically grants per-stream write
permissions to its creator, which can be seen here:
listpermissions stream9.write
Copy and paste the address
shown:
Now we’ll revoke the write
permissions for this address and grant them only to the multisig address:
revoke stream9.write
grant stream9.write
Let’s verify the outcome, in which only the multisig address should be shown:
listpermissions stream9.write
Publishing from the multisig address
Now let’s prepare to publish something to the stream from the multisignature address. Still on the first server:
createrawsendfrom '{}' '[{"for":"stream9","key":"key1","data":"48656c6c6f2066726f6d206d756c746973696721"}]' sign
The response should contain a complete
field containing false
, and a large hexadecimal blob in the hex
field, which should be copied to the clipboard.
Now switch to the second server and paste from the clipboard where shown:
signrawtransaction [paste-hex-blob]
The response should contain a complete
field containing true
, along with an even larger blob in the hex
field. Copy the new blob, and run:
sendrawtransaction [paste-bigger-hex-blob]
The response should contain the txid of the sent transaction. Finally let’s check that the item was published successfully. On either server:
subscribe stream9
liststreamitems stream9
You should see the item listed with the multisig address shown in the publishers
field, as well as the key
and data
entered above.
Where to go from here
Congratulations! You have now learned how to send assets and publish to a stream using a 2-of-2 multisignature address.
A similar technique can be used to perform any other action for a multisig address – issuing or reissuing assets, creating streams, and granting/revoking permissions for other addresses. In each case, examples of the appropriate createrawsendfrom
parameters can be found on the raw transactions page. Pass sign
instead of send
as the final parameter to createrawsendfrom
, then complete the process on the second node using signrawtransaction
and sendrawtransaction
as above.
For transactions that must be signed by more than 2 nodes, such as those using 3-of-3 multisigs, pass the raw transaction through signrawtransaction
on each node in turn, taking the new hex
output before transferring to the next node. Once the complete
field of the response is true
, the final raw transaction can be sent from any node using sendrawtransaction
.