Key pairs
The Sui TypeScript SDK provides Keypair
classes that handle logic for signing and verification
using the cryptographic key pairs associated with a Sui address.
The Sui TypeScript SDK supports three signing schemes:
Sign scheme | Class name | Import folder |
---|---|---|
Ed25519 | Ed25519Keypair | @mysten/sui/keypairs/ed25519 |
ECDSA Secp256k1 | Secp256k1Keypair | @mysten/sui/keypairs/secp256k1 |
ECDSA Secp256r1 | Secp256r1Keypair | @mysten/sui/keypairs/secp256r1 |
For information on these schemes, see the Signatures (opens in a new tab) topic.
To use, import the key pair class your project uses from the @mysten/sui/keypairs
folder. For
example, to use the Ed25519 scheme, import the Ed25519Keypair
class from
@mysten/sui/keypairs/ed25519
.
import { Ed25519Keypair } from '@mysten/sui/keypairs/ed25519';
To create a random key pair (which identifies a Sui address), instantiate a new Keypair
class. To
reference a key pair from an existing secret key, pass the secret to the fromSecretKey
function.
// random Keypair
const keypair = new Ed25519Keypair();
// Keypair from an existing secret key (Uint8Array)
const keypair = Ed25519Keypair.fromSecretKey(secretKey);
With your key pair created, you can reference it when performing actions on the network. For example, you can use it to sign transactions, like the following code that creates and signs a personal message using the public key from the key pair created in the previous code:
const publicKey = keypair.getPublicKey();
const message = new TextEncoder().encode('hello world');
const { signature } = await keypair.signPersonalMessage(message);
const isValid = await publicKey.verifyPersonalMessage(message, signature);
Public keys
Each Keypair
has an associated PublicKey
class. You use the public key to verify signatures or
to retrieve its associated Sui address. You can access a Keypair
from its PublicKey
or construct
it from the bytes (as a Uint8Array
) of the PublicKey
, as in the following code:
import { Ed25519Keypair, Ed25519PublicKey } from '@mysten/sui/keypairs/ed25519';
const keypair = new Ed25519Keypair();
// method 1
const bytes = keypair.getPublicKey().toRawBytes();
const publicKey = new Ed25519PublicKey(bytes);
const address = publicKey.toSuiAddress();
// method 2
const address = keypair.getPublicKey().toSuiAddress();
Verifying signatures without a key pair
When you have an existing public key, you can use it to verify a signature. Verification ensures the signature is valid for the provided message and is signed with the appropriate secret key.
The following code creates a key pair in the Ed25519 scheme, creates and signs a message with it,
then verifies the message to retrieve the public key. The code then uses toSuiAddress()
to check
if the address associated with the public key matches the address that the key pair defines.
import { Ed25519Keypair } from '@mysten/sui/keypairs/ed25519';
import { verifyPersonalMessageSignature } from '@mysten/sui/verify';
const keypair = new Ed25519Keypair();
const message = new TextEncoder().encode('hello world');
const { signature } = await keypair.signPersonalMessage(message);
const publicKey = await verifyPersonalMessageSignature(message, signature);
if (publicKey.verifyAddress(keypair.getPublicKey().toSuiAddress())) {
throw new Error('Signature was valid, but was signed by a different key pair');
}
Verifying that a signature is valid for a specific address
verifyPersonalMessageSignature
and verifyTransactionSignature
accept an optional address
, and
will throw an error if the signature is not valid for the provided address.
import { Ed25519Keypair } from '@mysten/sui/keypairs/ed25519';
import { verifyPersonalMessageSignature } from '@mysten/sui/verify';
const keypair = new Ed25519Keypair();
const message = new TextEncoder().encode('hello world');
const { signature } = await keypair.signPersonalMessage(message);
await verifyPersonalMessageSignature(message, signature, {
address: keypair.getPublicKey().toSuiAddress(),
});
Verifying transaction signatures
Verifying transaction signatures is similar to personal message signature verification, except you
use verifyTransactionSignature
:
// import SuiClient to create a network client and the getFullnodeUrl helper function
import { getFullnodeUrl, SuiClient } from '@mysten/sui/client';
import { Ed25519Keypair } from '@mysten/sui/keypairs/ed25519';
import { verifyTransactionSignature } from '@mysten/sui/verify';
// see Network Interactions with SuiClient for more info on creating clients
const client = new SuiClient({ url: getFullnodeUrl('testnet') });
const tx = new Transaction();
// ... add some transactions...
const bytes = await tx.build({ client });
const keypair = new Ed25519Keypair();
const { signature } = await keypair.signTransaction(bytes);
await verifyTransactionSignature(bytes, signature, {
// optionally verify that the signature is valid for a specific address
address: keypair.getPublicKey().toSuiAddress(),
});
Verifying zkLogin signatures
ZkLogin signatures can't be verified purely on the client. When verifying a zkLogin signature, the SDK uses the GraphQL API to verify the signature. This will work for mainnet signatures without any additional configuration.
For testnet signatures, you will need to provide a testnet GraphQL Client:
import { SuiGraphQLClient } from '@mysten/sui/graphql';
import { verifyPersonalMessageSignature } from '@mysten/sui/verify';
const publicKey = await verifyPersonalMessageSignature(message, zkSignature, {
client: new SuiGraphQLClient({
url: 'https://sui-testnet.mystenlabs.com/graphql',
}),
});
For some zklogin accounts, there are 2 valid addresses for a given set of inputs. This means you may
run into issues if you try to compare the address returned by publicKey.toSuiAddress()
directly
with an expected address.
Instead, you can either pass in the expected address during verification, or use the
publicKey.verifyAddress(address)
method:
import { SuiGraphQLClient } from '@mysten/sui/graphql';
import { verifyPersonalMessageSignature } from '@mysten/sui/verify';
const publicKey = await verifyPersonalMessageSignature(message, zkSignature, {
client: new SuiGraphQLClient({
url: 'https://sui-testnet.mystenlabs.com/graphql',
}),
// Pass in the expected address, and the verification method will throw an error if the signature is not valid for the provided address
address: '0x...expectedAddress',
});
// or
if (!publicKey.verifyAddress('0x...expectedAddress')) {
throw new Error('Signature was valid, but was signed by a different key pair');
}
Both of these methods will check the signature against both the standard and legacy versions of the zklogin address (opens in a new tab).
Deriving a key pair from a mnemonic
The Sui TypeScript SDK supports deriving a key pair from a mnemonic phrase. This can be useful when building wallets or other tools that allow a user to import their private keys.
const exampleMnemonic = 'result crisp session latin ...';
const keyPair = Ed25519Keypair.deriveKeypair(exampleMnemonic);
Deriving a Keypair
from a Bech32 encoded secret key
You can derive a Keypair
by converting the 33-byte secret key encoded in Bech32 string to a
Uint8Array
and passing it to the fromSecretKey
method of a Keypair
class.
import { decodeSuiPrivateKey, encodeSuiPrivateKey } from '@mysten/sui/cryptography';
import { Ed25519Keypair } from '@mysten/sui/keypairs/ed25519';
const encoded = encodeSuiPrivateKey(
[
59, 148, 11, 85, 134, 130, 61, 253, 2, 174, 59, 70, 27, 180, 51, 107, 94, 203, 174, 253, 102,
39, 170, 146, 46, 252, 4, 143, 236, 12, 136, 28,
],
'ED25519',
);
const { schema, secretKey } = decodeSuiPrivateKey(encoded);
// use schema to choose the correct key pair
const keypair = Ed25519Keypair.fromSecretKey(secretKey);
See SIP-15 (opens in a new tab) for additional context and motivation.
If you know your keypair schema, you can use the fromSecretKey
method of the appropriate keypair
to directly derive the keypair from the secret key.
const secretKey = 'suiprivkey1qzse89atw7d3zum8ujep76d2cxmgduyuast0y9fu23xcl0mpafgkktllhyc';
const keypair = Ed25519Keypair.fromSecretKey(secretKey);
You can also export a keypair to a Bech32 encoded secret key using the getSecretKey
method.
const secretKey = keypair.getSecretKey();
Deriving a Keypair
from a hex encoded secret key
If you have an existing secret key formatted as a hex encoded string, you can derive a Keypair
by
converting the secret key to a Uint8Array
and passing it to the fromSecretKey
method of a
Keypair
class.
import { Ed25519Keypair } from '@mysten/sui/keypairs/ed25519';
import { fromHex } from '@mysten/sui/utils';
const secret = '0x...';
const keypair = Ed25519Keypair.fromSecretKey(fromHex(secret));