Multisig
IOTA supports multi-signature (multisig) transactions, which require multiple keys for authorization rather than a single, one-key signature. In technical terms, IOTA supports k
out of n
multisig transactions, where k
is the threshold and n
is the total weights of all participating parties. The maximum number of parties is 10. To learn more about the single key signatures that IOTA supports, see Signatures.
Valid participating keys for multisig are Pure Ed25519, ECDSA Secp256k1, and ECDSA Secp256r1. A (u8) weight is set for each participating keys and the threshold can be set as u16. If the serialized multisig contains enough valid signatures of which the sum of weights passes the threshold, IOTA considers the multisig valid and the transaction executes.
Applications of multisig
IOTA allows you to mix and match key schemes in a single multisig account. For example, you can pick a single Ed25519 mnemonic-based key and two ECDSA secp256r1 keys to create a multisig account that always requires the Ed25519 key, but also one of the ECDSA secp256r1 keys to sign. You could use this structure for mobile secure enclave stored keys as two-factor authentication.
Currently, iPhone and high-end Android devices support only ECDSA secp256r1 enclave-stored keys.
Compared to threshold signatures, a multisig account is generally more flexible and straightforward to implement and use, without requiring complex multi-party computation (MPC) account setup ceremonies and related software, and any dependency in threshold crypto providers. Additionally, apart from the ability to mix and match key schemes and setting different weights for each key (which is complex in threshold cryptography), multisig accounts are "accountable" and "transparent" by design because both participating parties and observers can see who signed each transaction. On the other hand, threshold signatures provide the benefits of hiding the threshold policy, but also resulting in a single signature payload, making it indistinguishable from a single-key account.
Multisig structures supported in IOTA.
Example workflow
The following steps demonstrate how to create a multisig transaction and then submit it against a local network using the IOTA CLI. A transaction can be the transfer of an object, the publish or upgrade of a package, the payment of IOTA, and so on. To learn how to set up a local network, see Connect to a Local Network.
Step 1: Create keys
Use the following command to generate a IOTA address and key for each supported key scheme and add it to the iota.keystore
, then list the keys.
Use iota client
to create IOTA addresses of different key schemes.
iota client new-address ed25519
iota client new-address secp256k1
iota client new-address secp256r1
Step 2: Add keys to IOTA keystore
Use iota keytool
to list the signatures you created in the previous step.
iota keytool list
The response resembles the following, but displays actual addresses, keys, and peer IDs:
╭────────────────────────────────────────────────────────────────────────────────────────────╮
│ ╭─────────────────┬──────────────────────────────────────────────────────────────────────╮ │
│ │ iotaAddress │ <IOTA-ADDRESS> │ │
│ │ publicBase64Key │ <PUBLIC-KEY> │ │
│ │ keyScheme │ ed25519 │ │
│ │ flag │ 0 │ │
│ │ peerId │ <PEER-ID> │ │
│ ╰─────────────────┴──────────────────────────────────────────────────────────────────────╯ │
│ ╭─────────────────┬──────────────────────────────────────────────────────────────────────╮ │
│ │ iotaAddress │ <IOTA-ADDRESS> │ │
│ │ publicBase64Key │ <PUBLIC-KEY> │ │
│ │ keyScheme │ secp256k1 │ │
│ │ flag │ 0 │ │
│ │ peerId │ <PEER-ID> │ │
│ ╰─ ────────────────┴──────────────────────────────────────────────────────────────────────╯ │
│ ╭─────────────────┬──────────────────────────────────────────────────────────────────────╮ │
│ │ iotaAddress │ <IOTA-ADDRESS> │ │
│ │ publicBase64Key │ <PUBLIC-KEY> │ │
│ │ keyScheme │ secp256r1 │ │
│ │ flag │ 0 │ │
│ │ peerId │ <PEER-ID> │ │
│ ╰─────────────────┴──────────────────────────────────────────────────────────────────────╯ │
╰────────────────────────────────────────────────────────────────────────────────────────────╯
Step 3: Create a multisig address
To create a multisig address, input a list of public keys to use for the multisig address and a list of their corresponding weights and the threshold (replacing <VARIABLES>
with actual values).
iota keytool multi-sig-address --pks <PUBLIC-KEY-ED25519> <PUBLIC-KEY-SECPK1> <PUBLIC-KEY-SECP256R1> --weights 1 2 3 --threshold 3
The response resembles the following:
╭─────────────────┬────────────────────────────────────────────────────────────────────────────────────╮
│ multisigAddress │ <MULTISIG-ADDRESS> │
│ multisig │ ╭────────────────────────────────────────────────────────────────────────────────╮ │
│ │ │ ╭ ─────────────────┬──────────────────────────────────────────────────────────╮ │ │
│ │ │ │ address │ <IOTA-ADDRESS> │ │ │
│ │ │ │ publicBase64Key │ <PUBLIC-KEY> │ │ │
│ │ │ │ weight │ 1 │ │ │
│ │ │ ╰─────────────────┴──────────────────────────────────────────────────────────╯ │ │
│ │ │ ╭─────────────────┬──────────────────────────────────────────────────────────╮ │ │
│ │ │ │ address │ <IOTA-ADDRESS> │ │ │
│ │ │ │ publicBase64Key │ <PUBLIC-KEY> │ │ │
│ │ │ │ weight │ 2 │ │ │
│ │ │ ╰─────────────────┴──────────────────────────────────────────────────────────╯ │ │
│ │ │ ╭─────────────────┬──────────────────────────────────────────────────────────╮ │ │
│ │ │ │ address │ <IOTA-ADDRESS> │ │ │
│ │ │ │ publicBase64Key │ <PUBLIC-KEY> │ │ │
│ │ │ │ weight │ 3 │ │ │
│ │ │ ╰─────────────────┴──────────────────────────────────────────────────────────╯ │ │
│ │ ╰────────────────────────────────────────────────────────────────────────────────╯ │
╰─────────────────┴────────────────────────────────────────────────────────────────────────────────────╯
Step 4: Send objects to a multisig address
This example requests gas from a local network using the default URL following the guidance in Connect to a Local Network. If following along, be sure to replace <MULTISIG-ADDR>
with the address you receive in the previous step.
curl --location --request POST 'http://127.0.0.1:9123/gas' --header 'Content-Type: application/json' --data-raw "{ \"FixedAmountRequest\": { \"recipient\": \"<MULTISIG-ADDR>\" } }"
The response resembles the following:
{"transferred_gas_objects":[{"amount":200000,"id":"<OBJECT-ID>", ...}]}
Step 5: Serialize any transaction
This section demonstrates how to use an object that belongs to a multisig address and serialize a transfer to be signed. The tx_bytes
value can be any serialized transaction data where the sender is the multisig address. Use the --serialize-unsigned-transaction
flag for supported commands in iota client -h
(publish
, upgrade
, call
, transfer
, transfer-iota
, pay
, pay-all-iota
, pay-iota
, split
, merge-coin
) to output the Base64 encoded transaction bytes.
iota client transfer --to <IOTA-ADDRESS> --object-id <OBJECT-ID> --serialize-unsigned-transaction
Raw tx_bytes to execute: <TX_BYTES>
Step 6: Sign the transaction with two keys
Use the following code sample to sign the transaction with two keys in iota.keystore
. You can do this with other tools as long as you serialize it to flag || sig || pk
.
iota keytool sign --address <IOTA-ADDRESS> --data <TX_BYTES>
Raw tx_bytes to execute: <TX_BYTES>
Serialized signature (`flag || sig || pk` in Base64): $SIG_1
iota keytool sign --address <IOTA-ADDRESS> --data <TX_BYTES>
Raw tx_bytes to execute: <TX_BYTES>
Serialized signature (`flag || sig || pk` in Base64): $SIG_2
Step 7: Combine individual signatures into a multisig
This sample demonstrates how to combine the two signatures:
iota keytool multi-sig-combine-partial-sig --pks <PUBLIC-KEY-1> <PUBLIC-KEY-2> <PUBLIC-KEY-3> --weights 1 2 3 --threshold 3 --sigs <SIGNATURE-1> <SIGNATURE-2>
multisig address: <MULTISIG-ADDRESS> # Informational
multisig parsed: <HUMAN-READABLE-STRUCT> # Informational
multisig serialized: <SERIALIZED-MULTISIG>
You need only the signatures of the participating signers whose sum of weights >=k
. You must provide all public keys and their weights, and the threshold that defined the multisig address.
Step 8: Execute a transaction with multisig
Use iota client
to execute a transaction using multisig:
iota client execute-signed-tx --tx-bytes <TX_BYTES> --signatures <SERIALIZED-MULTISIG>