Skip to content

Rekeying accounts

Rekeying is a powerful protocol feature that enables an Algorand account holder to maintain a static public address while dynamically rotating the authoritative private spending key(s). This is accomplished by issuing a transaction with the rekey-to field set the authorized address field within the account object. Future transaction authorization using the account’s public address must be provided by the spending key(s) associated with the authorized address, which may be a single key address, multisignature address, or logic signature program address. Rekeying an account only affects the authorizing address for that account. An account is distinct from an address, so several essential points may not be obvious:

  • If an account is closed (balance to 0), the rekey setting is lost.
  • Rekeys are not recursively resolved. If A is rekeyed to B and B rekeyed to C, B will authorize A’s transactions, not C.
  • Rekeying members of a multisignature does not affect the multisignature authorization since it’s composed of Addresses, not accounts. If necessary, the multisignature account would need to be rekeyed.

The result of a confirmed rekey-to transaction will be the auth-addr field of the account object is defined, modified, or removed. Defining or modifying means only the corresponding authorized address’s private spending key(s) may authorize future transactions for this public address. Removing the auth-addr field is an explicit assignment of the authorized address back to the “addr” field of the account object (observed implicitly because the field is not displayed).

To provide maximum flexibility in key management options, the auth-addr may be specified within a rekey-to transaction as a distinct foreign address representing a single key address, multisignature address, or logic signature program address. The protocol does not validate control of the required spending key(s) associated with the authorized address defined by --rekey-to parameter when the rekey-to transaction is sent. This is by design and affords additional privacy features to the new authorized address. It is incumbent upon the user to ensure proper key management practices and --rekey-to assignments.

Authorized Addresses

The balance record of every account includes the auth-addr field, which, when populated, defines the required authorized address to be evaluated during transaction validation. Initially, the auth-addr field is implicitly set to the account’s address field, and the only valid private spending key is created during account generation. The auth-addr field is only stored and displayed to conserve resources after the network confirms an authorized rekey-to transaction.

A standard account uses its private spending key to authorize from its public address. A rekeyed account defines the authorized address that references a distinct foreign address and thus requires the private spending key(s) thereof to authorize future transactions.

Let’s consider a scenario where a single-key account with address A rekeys to a different single-key account with address B. This requires two single key accounts at time t0. The result from time t1 is that transactions for address A must be authorized by address B.

Figure: Rekeying to a Single Address
Figure: Rekeying to a Single Address

Refer to Creating Accounts to generate two accounts and Funding Accounts to fund their addresses using the faucet. This example utilizes the following public addresses:

ADDR_A="UGAGADYHIUGFGRBEPHXRFI6Z73HUFZ25QP32P5FV4H6B3H3DS2JII5ZF3Q"
ADDR_B="LOWE5DE25WOXZB643JSNWPE6MGIJNBLRPU2RBAVUNI4ZU22E3N7PHYYHSY"

Use the following code sample to view initial authorized address for Account A using goal:

goal account dump --address $ADDR_A

Response:

{
"addr": "UGAGADYHIUGFGRBEPHXRFI6Z73HUFZ25QP32P5FV4H6B3H3DS2JII5ZF3Q",
"algo": 100000,
[...]
}

The response includes the addr field, which is the public address. Only the spending key associated with this address may authorize transactions for this account.

Now lets consider another scenario wherein a single key account with public address A rekeys to a multi signature address BC_T1. This scenario reuses both Accounts A and B, adds a third Account C and creates a multisignature Account BC_T1 comprised of addresses B and C with a threshold of 1. The result will be the private spending key for $ADDR_B or $ADDR_C may authorize transaction from $ADDR_A.

Rekey to multisignature Address

To create a new multisignature account, refer to Generate a Multisignature Account. Ensure it uses both $ADDR_B and the new $ADDR_C with a threshold of 1 (so either B or C may authorize). Set the resulting account address to the $ADDR_BC_T1 environment variable for use below.

Rekey-to Transaction

A rekey-to transaction allows an account holder to change the spending authority of their account without changing the account’s public address. A rekey-to transaction enables an account owner to delegate their spending authority to a different private key while maintaining the same public address. This means the original account can transfer its authorization to sign and approve transactions to a new key without creating a new account or changing the account’s address. The existing authorized address must provide authorization for this transaction.

Account A intends to rekey its authorized address to $ADDR_B, which is the public address of Account B. This can be accomplished in a single goal command:

goal clerk send --from $ADDR_A --to $ADDR_A --amount 0 --rekey-to $ADDR_B

Now, if we view account A using the command:

goal account dump --address $ADDR_A

Response:

{
"addr": "UGAGADYHIUGFGRBEPHXRFI6Z73HUFZ25QP32P5FV4H6B3H3DS2JII5ZF3Q",
"algo": 199000,
[...]
"spend": "LOWE5DE25WOXZB643JSNWPE6MGIJNBLRPU2RBAVUNI4ZU22E3N7PHYYHSY"
}

The populated spend field instructs the validation protocol to only approve transactions for this account object when authorized by that address’s spending key(s). Validators will ignore all other attempted authorizations, including those from the public address defined in the addr field.

The following transaction will fail because, by default, goal attempts to add the authorization using the --from parameter. However, the protocol will reject this because it is expecting the authorization from $ADDR_B due to the confirmed rekeying transaction above.

goal clerk send --from $ADDR_A --to $ADDR_B --amount 100000

The rekey-to transaction workflow is as follows:

  • Construct a transaction that specifies an address for the rekey-to parameter
  • Add the required signature(s) from the current authorized address
  • Send and confirm the transaction on the network

Construct an Unsigned Transaction

We will construct an unsigned transaction using goal with the --outfile flag to write the unsigned transaction to a file:

goal clerk send --from $ADDR_A --to $ADDR_B --amount 100000 --out send-single.txn

For multisignature account, the rekey transaction constructed requires authorization from $ADDR_B.

goal clerk send --from $ADDR_A --to $ADDR_A --amount 0 --rekey-to $ADDR_BC_T1 --out rekey-multisig.txn

Add Authorized Signature(s)

Next, locate the wallet containing the private spending key for Account B. The goal clerk sign command provides the flag --signer, which specifies the proper required authorized address $ADDR_B. Notice the infile flag reads in the unsigned transaction file from above and the --outfile flag writes the signed transaction to a separate file.

goal clerk sign --signer $ADDR_B --infile send-single.txn --outfile send-single.stxn

Use the following command to sign rekey transaction in multisignature account:

goal clerk sign --signer $ADDR_B --infile rekey-multisig.txn --outfile rekey-multisig.stxn

Send and Confirm

We will send the signed transaction file using the following command:

goal clerk rawsend --filename send-single.stxn

This will succeed, sending the 100000 microAlgos from $ADDR_A to $ADDR_B using the private spending key of Account B.

Next, send and Confirm Rekey to multisignature account using the following command:

goal clerk rawsend --filename rekey-multisig.stxn
goal account dump --address $ADDR_A

The rekey transaction will confirm, resulting in the spend field update within the account object:

{
"addr": "UGAGADYHIUGFGRBEPHXRFI6Z73HUFZ25QP32P5FV4H6B3H3DS2JII5ZF3Q",
"algo": 199000,
[...]
"spend": "NEWMULTISIGADDRESSBCT1..."
}

Now we will send with Auth BC_T1 using the following command:

goal clerk send --from $ADDR_A --to $ADDR_B --amount 100000 --msig-params="1 $ADDR_B $ADDR_C" --out send-multisig-bct1.txn
goal clerk multisig sign --tx send-multisig-bct1.txn --address $ADDR_C
goal clerk rawsend --filename send-multisig-bct1.txn

This transaction will succeed as a private spending key for $ADDR_C provided the authorization and meets the threshold requirement for the multisignature account.

Utils Example

Rekeying can also be acheived using Algokit Utils. In the following example, account_a is rekeyed to account_b. The code then illustrates that signing a transaction from account_a will fail if signed with account_a’s private key and succeed if signed with account_b’s private key.

/**
* Rekey an account to use a different address for signing.
* This allows account A to be controlled by account B's private key.
*/
await algorand.account.rekeyAccount(randomAccountA, randomAccountB)
// Send a payment transaction from account A
// which will automatically sign the transaction with account B's private key
await algorand.send.payment({
sender: randomAccountA,
receiver: randomAccountC,
amount: algo(1),
})