Migrating to Sui 0.29 Addresses
Upcoming Sui 0.29 will change how wallet addresses are generated
Sui 0.29
will change the way that user wallet addresses are generated from their public keys, therefore, projects which rely on persisting data across network wipes will have to make changes accordingly to accomodate this change.
Persistence across wipes is generally achieved by airdropping persisted objects into a list of saved addresses. After these changes, any saved addresses will no longer be valid, necessitating that they are updated.
This article aims to outline the changes in address generation mechanism and provides a library implementation for generating the pre-0.29
and 0.29
addresses from user public keys for comparison. Firstly we will cover the basics of public-key cryptography followed by outlining the algorithms used to generate the addresses. Some wallets may not expose user public keys, therefore, we will introduce a small tool to derive a public key from your private key.
You can find all the code in this article in the following repository: key-migration: Library for migrating Sui addresses to new version from user public keys
Public-key Cryptography
When a user creates a cryptocurrency wallet, the wallet generates a pair of keys: a public key and a private key. The public key is used to receive transactions, and it is shared with other users who want to send cryptocurrency to the wallet. The private key, on the other hand, is kept secret and used to sign transactions to prove ownership of the digital assets.
The transaction is broadcast to the network, and other nodes on the network use the public key of the sender's wallet to verify the signature and ensure that the sender is the rightful owner of the digital assets being sent. Once the transaction is confirmed and added to the blockchain, the digital assets are transferred from the sender's wallet to the recipient's wallet.
In the following section we will outline the pre-0.29
algorithm to generate wallet addresses.
Address Generation
There are two public-key encryption methods available for wallets on Sui
, ED25519
and Secp256k1
, this section outlines how an address can be generated from a public key from either method.
Pre-0.29 Sui
addresses were generated using a truncated hash of the public key concatenated with an encryption scheme flag.
address = truncate(sha256(SIGNATURE_SCHEME_TO_FLAG | publicKey), 20)
We can now write a JS
function to generate pre-0.29 Sui
addresses from a given public key.
const SIGNATURE_SCHEME_TO_FLAG = {
ED25519: 0x00,
Secp256k1: 0x01,
};
function oldAddress(flag, publicKey) {
let tmp = new Uint8Array(publicKey.data.length + 1);
tmp.set([SIGNATURE_SCHEME_TO_FLAG[flag]]);
tmp.set(publicKey.toBytes(), 1);
return bytesToHex(sha3_256(tmp)).slice(0, 40);
}
After 0.29 Sui
addresses will be generated using the following formula:
address = truncate(blake2b(SIGNATURE_SCHEME_TO_FLAG | publicKey), 32)
With the corresponding JS
implementation:
function newAddress(flag, publicKey) {
let tmp = new Uint8Array(publicKey.data.length + 1);
tmp.set([SIGNATURE_SCHEME_TO_FLAG[flag]]);
tmp.set(publicKey.toBytes(), 1);
return bytesToHex(blake2b(tmp, { dkLen: 32 })).slice(0, 64);
}
These functions will generate a raw hex representation of the address, however we still need to normalize the address for compatibility. To do this we create a helper function:
function normalize(value, addressLength) {
let address = value.toLowerCase();
return `0x${address.padStart(addressLength * 2, '0')}`;
}
We can now write functions for both signature schemes that will simultaneously generate the old and new addesses:
export function generateEd25519Address(publicKey) {
return [
normalize(oldAddress('ED25519', publicKey), 20),
normalize(newAddress('ED25519', publicKey), 32),
];
}
export function generateSecp256k1Address(publicKey) {
return [
normalize(oldAddress('Secp256k1', publicKey), 20),
normalize(newAddress('Secp256k1', publicKey), 30),
];
}
You can find the complete code in the following repository: key-migration. The repository also contains unit tests to verify correctness on test cases used by the Sui codebase.
Now that we have the functions to generate addresses based on user public keys, in the following section we will cover the migration process and
Migrating User Addresses
The main motivation behind this article are the projects working with OriginByte that persist data across wipes, these projects generally restore data by airdropping objects into a list of saved addresses. This section covers a suggested method for a safe migration of these addresses to the new version.
The keen eyed readers may have noticed that because public keys are hashed in order to generate an address, this means that it is impossible to compute the original public key given the address.
The key to any migration effort will be to provide a way for users to submit their public key and have the backend update their address to the new one if it exists.
Public keys are safe to share, therefore, the user does not incur a security risk by sharing the public key associated with their address with marketplaces or other projects (this is guaranteed by the fundamental properties of public-key cryptography).
Finding your Public Key
If you are a user registered with a project which needs your public key to migrate your address you may be left asking: Where can I find my public key?
We will address two cases, extracting your public key from the Sui Wallet, but also extracting it from the Sui CLI client.
Extract Public Key from Sui Wallet
If you are using a wallet, the wallet may offer you a way to export your public key directly, in which case you will have no problem obtaining it. However, in the case of the official Sui wallet, you are only able to export your private key, how do you find your public key from this?
Marketplaces should not, under any circumstance, provide an API to which you can paste your private key due to the danger of it being stolen. OriginByte has prepared a small JS
CLI which you can use to obtain your public key from the private key.
The CLI is available under: key-migration. Make sure to familiarize yourself with the code to ensure that you trust the implementation.
To install the CLI you will first need to install Node then use the following commands:
$ git clone https://github.com/Origin-Byte/key-migration.git
$ cd key-migration
$ npm i
You will now be able to call the CLI to obtain your public key, ED25519
and Secp256k1
keys are supported.
$ node public-key.js {PRIVATE_KEY} ED25519
publicKey: A8Q0tTFHAYiY/vaK5GPofI5ZvG23cOP5MpntItGtIopn
oldAddress: 0xd9016586630399177da976d89709961e986da005
newAddress: 0x8d526d4574e6d5ddce686e6deb8c96c343701a85c099526f7d09a69b21f6804d
Extract Public Key from Sui CLI Client
Extracting your key from the Sui CLI client is even easier than from the Sui Wallet.
You will be able to find your private keys in the sui.keystore
file, found under: ~/.sui/sui_config/sui.keystore
on Linux systems.
The private keys in this file have the SIGNATURE_SCHEME_TO_FLAG
prepended to them so you will not have to provide an extra scheme argument (ED25519
or Secp256k1)
. You can call the CLI to obtain your public key:
$ node public-key.js {PRIVATE_KEY}
publicKey: A8Q0tTFHAYiY/vaK5GPofI5ZvG23cOP5MpntItGtIopn
oldAddress: 0xd9016586630399177da976d89709961e986da005
newAddress: 0x8d526d4574e6d5ddce686e6deb8c96c343701a85c099526f7d09a69b21f6804d
Closing thoughts
Hopefully this article provided some insight into the upcoming changes and helped plan potential migration strategies. This migration will be critical for marketplaces and wallets to perform if they are persisting any data across network wipes. Sui is changing everyday and we have to work hard to keep up!