For the complete documentation index, see llms.txt. This page is also available as Markdown.

Monero

Multisignature

In cryptocurrencies, multisig allows one to sign a transaction with more than one private key. Funds protected with multisig can only be spent by signing with M-of-N keys.

Example use cases:

  • shared account (1-of-2; both husband and wife individually have full access to their funds)

  • consensus account (2-of-2; both husband and wife must agree to spend their funds)

  • threshold account (2-of-3; an escrow service is involved as an independent 3rd party, to co-sign with either the seller, or with the buyer, if seller and buyer do not agree)

  • secure account (2-of-3; a single owner controls all 3 keys but secures them via different means to diversify risks)

  • arbitrary threshold account (M-of-N; some cryptocurrencies provide full flexibility on the number of signers)

Monero's multisig design

Monero doesn't directly implement multisignatures (at least not in a classical sense). Monero emulates the feature by secret splitting.

Transactions are still signed with a single spend key. The spend key is a sum of all N private keys. The rationale for such a design is to decouple multisig from ring signatures.

Let's consider the 2-of-3 scheme. We have 3 participants. Each participant is granted exactly 2 private keys in a way that pairs do not repeat between participants. This way any 2 participants together have all 3 private keys required to create the private spend key.

Multi-signing is a wallet-level feature, and there is no separate multisig address type. This means there is no way to learn from the blockchain which transactions were created using multiple signatures.

After multisig wallet setup every participant ends up knowing the public address and private view key. This is necessary for participants to recognize and decipher transactions they are supposed to co-sign.

Multisig wallet setup

Multisig is currently only available via the Command Line Interface (CLI). This tutorial will assume you have some familiarity with the CLI before beginning.

In this example we will use a 2-of-3 multisig scheme, as it generalizes well.

Initially, while you're becoming familiar with multisig, it's suggested you begin by using stagenet, such that no valuable Monero are lost.

If you're not already familiar with stagenet, it is a separate, but functionally identical instance of the Monero network, created for testing purposes. To use it you simply add the --stagenet flag when creating and running your stagenet wallet.

1: Create a new wallet

To begin you will need to create a new wallet. Multisig cannot be applied to a wallet that has previously received funds.

First you create a new wallet. The below the code assumes you're using a remote node, but using a local node is ideal:

In the above, replace address-URL with the actual URL that you want to connect to. At the time of writing, a list of remote nodes can be found at: monero.fail. The default view shows mainnet servers, so make sure to filter by stagenet servers first.

Next, enable multisig via:

If you try to issue the first command without first setting this flag, you will see:

This warning message is there to let people know that Multisig is still an experimental feature and may have bugs. You can read more about this message below.

Recommendation: By default the CLI applies a screen timeout of 90 seconds. After which, you will be asked to input your password to continue using the wallet. Unfortunately, once the wallet times out, it interrupts the multisig creation process.

To extend the timeout to 10 minutes, use the command:

To disable the timeout entirely (for this session only), use the command:

2: prepare_multisig

To begin, every participant independently generates initialization data, which is not an address.

Participants then send their initialization data manually to all other participants over a secure channel.

However, if you're creating the multisig wallet without external participants, then you simply transfer the data between terminal windows.

Begin by using the command:

Note: if you try to use this command on a wallet that has already been used, you will see the error message:

After prepare_multisig you will see a message that looks similar to the below:

The long string that begins Multisig is important, and will be shared with the other wallets in the next step.

Before you move to the next step, you'll want to run the prepare_multisig command on the rest of the wallets you want to use in your multisig setup. For example, 2 more if you're doing a 2/3 multisig.

3: make_multisig

This command is where you set the threshold for your multisig wallet and then pass the initialization data from the other participants. The initialization data is the long string beginning Multisig mentioned above.

For example, if you're doing a 2 of 2 multisig, then your threshold is 2 and you'll pass 1 piece of data. If you're doing a 3 of 5 multisig, then your threshold is 3 and you'll pass 4 pieces of data.

Continuing with our 2/3 multisig example, you would then type into your CLI:

Which in practice would look similar to:

If you were doing a 3/5 multisig, you'd instead run:

Once this command is run on each wallet, you will then receive a second round of initialization data, that looks similar to:

Side note: If you make a mistake, such as inputting the wrong threshold or missing out some initialization data, there isn't an undo function. That individual wallet will get created incorrectly, and you will need to re-do it.

4: exchange_multisig_keys

With the threshold established in the prior command, the exchange_multisig_keys command simply takes the init data from the other participants, no threshold parameter needed.

For example:

It is either run once or twice in total.

Once if your wallet has the same threshold as the total number of participants, e.g. 2 of 2.

Twice if you have a different threshold, e.g. 2 of 3.

Continuing our 2/3 multisig example, after inputting the above exchange_multisig_keys command, we would then see:

Then for a second, and last time, we input:

And we receive back:

This results in a wallet public address and private view key to be known for all participants.

So if you're the sole participant in the multisig setup, you'll know it has worked when you see the same multisig address across all the wallets.

Receiving funds

1: Funding the Multisig Account

Addresses created by a multisig wallet operate the same as normal, non-multisig addresses. This means:

  • Each wallet can create subaddresses independently, no collaboration needed.

  • All participants can see incoming funds as they share the private view key.

The main difference comes when trying to spend funds from a multisig wallet. See the Spending Funds section below for how to do this.

2: Check Account Balance

To check the account balance, open one of the multisig wallets and type the refresh command.

This will refresh the wallet and display your balance. The output will look similar to the below, but with a different amount:

If you see that last sentence:

This means that you haven't synchronized your wallet with the threshold amount of wallets needed (1 other in the case of 2/3 multisig) for the outputs to become spendable.

You can also use the command show_transfers to display a list of funds received and the transfer date, with the output looking similar to:

Spending funds

Prior to explaining the process for spending multisig funds, it may help to have a high level overview of the process. There are two core steps:

1) First, the sharing of partial key-images - At minimum, the spender needs to get a partial key image from the people (1 or more) who will sign the transaction with him later. They need to export a file and share it with the future spender, who then imports the file to their wallet.

2) Second, creating, signing & submitting the transaction - A transfer is created, written to file, and then this file needs to be signed by the co-signers, before it can lastly be submitted to the network.

Preparation for spending

Preparation Step 1: Export partial key image

Prior to constructing a transaction, the spender will need to get a partial key image from the wallet or wallets which will later co-sign the transaction.

In our 2/3 multisig example, the spender needs to get 1 partial key image, because the threshold is 2.

The wallet that will provide the partial key image needs to enter the command:

Where key1 can be any filename. The output will then be:

The file will be saved to the present working directory in the terminal.

It then needs to be shared with the wallet which will create the spending transaction.

Preparation Step 2: Import partial key image

Now that the spending wallet has the partial key image it can import it. Assuming the file is in the present working directory, the command would be:

If two or more key images were being imported, you would specify them side by side, such as:

After issuing that command, the wallet will display how many new inputs it has verified, for example if 1 output is verified:

Spending

Spending Step 1 - Create Unsigned Transaction

Creating a new transaction can be done by any of the multisig wallets. However, to avoid weird things from happening, only do it for 1 transaction at a time. If anything weird happens, re-do steps 1 & 2 again to fix.

The wallet initiating the transfer should create a transfer, as per the normal CLI transfer process:

So for example:

The output will look like:

The present working directory will now contain a file named multisig_monero_tx, which should then be shared with the co-signer.

Spending Step 2 - Sign Transaction

The wallet that has been chosen to co-sign the transaction now needs to run the command:

Which will result in an output similar to:

Note: Once you synchronize the partial key images, there is a certain time window by which you can create and send your transaction. I'm unsure exactly how long the time window is. If you leave it too long you will see the output:

The solution is to re-do steps 1 and 2 of the preparation for sending. Once that's completed, you can return to the sending steps.

Spending Step 3 - Submit Transaction

Now that your transaction has been co-signed, it is possible to submit it. You can do this from any of the wallets, as long as they have the co-signed multisig_monero_tx file. Using the command:

You will then see an output similar to:

The transaction has now been broadcast to the network. If you want to create another one, you will need to go back to the preparation stage and re-sync the partial key images.

Spending concerns

In a multisig wallet constructed between untrusted parties, it is possible for a single malicious signer to trick other signers into sending a payment twice. For most uses this is not a concern; common exempt uses include a single person controlling a multisig, or a 2 of 2 multisig in a decentralized exchange which only has to send all funds once. If you are operating a multisig with other holders for repeat transfer of funds, however, you should be aware of the following issue, illustrated by example (no fees for simplicity):

  • A 3 of 3 multisig is created between signers 1, 2, and 3

  • The multisig owns two outputs A and B, both size 1 XMR

  • Signer 1: "I want to withdraw 1 XMR to my address X". 2 and 3 agree

  • Signer 2 is selected to begin signing the transaction. 2 constructs the transaction sending output A -> X

  • Signer 3 signs, the transaction now has 2/3 signatures

  • Signer 1 signs, the transaction has 3/3 signatures and is valid and can be broadcasted to the network

  • Signer 1 does not broadcast the A -> X transaction. 1 lies and says he could not sign. He claims he got the error This signature was made with stale data.

  • Signer 1 says "We should do it again, it didn't work"

  • Signer 1 constructs the transaction sending B -> X

  • Signer 2 and 3 sign, 3 broadcasts B -> X

  • Signer 1 broadcasts the withheld A -> X transaction

  • Signer 1 has drained all the funds!

The withheld transaction will succeed because it does not conflict with the B -> X transaction as it spends a different input. As a holder, you should only ever sign for a given transfer once in normal multisig operation. If the signature fails due to the stale data error or any other reason, you must re-check the inputs of the transaction and make sure they are the same, which prevents a hidden transaction being respent. Viewing the inputs is not currently possible in any user wallet, but can be done with the wallet RPC method describe_transfer. If the inputs do not match the first transaction, do not sign the second transaction.

This is possible in other cryptocurrencies, but is more feasible in Monero because of the stale data error mentioned earlier, which provides an excuse for why the transaction failed. Work is in progress to reduce the chance of encountering the stale data error and remove this excuse. Other cryptocurrencies' technical user wallets sometimes display inputs, which can help you examine transactions more easily, but for Monero this is not yet the case, and you have to use the wallet RPC.

Mnemonic Seeds

With a regular wallet is it possible to create a mnemonic seed that you can back up, and later use to recreate the wallet.

Fortunately, multisig wallets have the same feature. The only difference is that the seed is a long string of letters and numbers, rather than a set of dictionary words. Unfortunately, it needs to encode too much data to fit neatly into the regular mnemonic seed dictionary output.

To access your wallet seed, open the wallet within the CLI and type seed. You will see an output similar to this:

Note: This seed will only recreate the individual wallet it is created from. Each wallet would need to be backed up separately.

About the experimental feature warning message

Prior to a pull request in mid 2022 (PR #8149) Monero's multisig feature had some known bugs.

PR #8149 fixed these issues, including findings identified by an independent audit of multisig.

However, there is still a possibility of a yet unknown bug that would allow a malicious group member, in a worst-case scenario, to acquire all funds within the multisig wallet.

Two potential steps to get Monero's multisig implementation further tested and more secure would be the completion of a formal specification and a third-party audit. However, there is currently no timeline for this.

It's worth noting that the risks implied by this unknown bug scenario depend upon the individual use-case. For example:

a) If one planned to use multisig in collaboration with other people, then this risk is there.

b) If one planned to use multisig solely to shard a cold wallet, and store it in multiple locations, then this risk may be lessened. On the basis that it requires two coincidences to come together:

i) A malicious actor who has the capability to exploit an unknown bug in Monero's multisig.

ii) This malicious actor is then able to access one of the, presumably secured, multisig wallets.

However, if an exploit was made public knowledge, then the risk increases, because the attacker no longer needs to figure out the exploit, they simply need to locate your wallet and then implement the public exploit.

Thus, if one took the risk to use multisig in method b), they would be prudent to stay up to date on multisig development. Such that they would learn quickly if such an exploit was discovered.

References

The below guides are very detailed, and were formative in the creation of this document. Note that they are both a little out of date, as a few of the CLI commands have been updated in the interim.

Last updated