createLazyKeyPairSignerFromBytes

function createLazyKeyPairSignerFromBytes<TAddress>(
    bytes,
    extractable?,
): Readonly<{
    address: Address<TAddress>;
    signMessages: Promise<
        readonly Readonly<Record<Address, SignatureBytes>>[]
    >;
}> &
    Readonly<{
        address: Address<TAddress>;
        signTransactions: Promise<
            readonly Readonly<Record<Address, SignatureBytes>>[]
        >;
    }>;

Creates a signer from a 64-bytes Uint8Array secret key (private key and public key) synchronously.

Unlike createKeyPairSignerFromBytes, this helper returns without awaiting. It derives the signer's MessagePartialSigner#address | address directly from the public key half of the secret key (the last 32 bytes) and defers the asynchronous CryptoKey import until the first time a message or transaction is signed. The imported key pair is memoised so the import only happens once, no matter how many times the signer is used.

This is useful when a signer must be created in a synchronous context — for instance, when registering signers up front — whilst the actual signing can remain asynchronous.

Type Parameters

Type ParameterDefault typeDescription
TAddress extends stringstringSupply a string literal to define a signer having a particular address.

Parameters

ParameterTypeDescription
bytesReadonlyUint8ArrayA 64-bytes secret key, the first 32 of which represent the private key and the last 32 of which represent its associated public key.
extractable?booleanSetting this to true makes it possible to extract the bytes of the private key using the crypto.subtle.exportKey() API. Defaults to false. Note that, because the import is deferred, this helper keeps a copy of the secret key bytes in memory until the first signing call completes, regardless of this setting.

Returns

Readonly<{ address: Address<TAddress>; signMessages: Promise<readonly Readonly<Record<Address, SignatureBytes>>[]>; }> & Readonly<{ address: Address<TAddress>; signTransactions: Promise<readonly Readonly<Record<Address, SignatureBytes>>[]>; }>

A signer implementing both the MessagePartialSigner and TransactionPartialSigner interfaces. Note that, because the CryptoKeyPair is imported lazily, this signer does not expose a keyPair property and is therefore not a full KeyPairSigner.

Throws

SolanaError with code SOLANA_ERROR__KEYS__INVALID_KEY_PAIR_BYTE_LENGTH if the provided bytes are not exactly 64 bytes long. This check is performed synchronously.

Example

import fs from 'fs';
import { createLazyKeyPairSignerFromBytes } from '@solana/signers';
 
// Get bytes from local keypair file.
const keypairFile = fs.readFileSync('~/.config/solana/id.json');
const keypairBytes = new Uint8Array(JSON.parse(keypairFile.toString()));
 
// Create a signer from the bytes synchronously.
const signer = createLazyKeyPairSignerFromBytes(keypairBytes);
signer.address; // Available immediately, no `await` required.
const [transactionSignatures] = await signer.signTransactions([transaction]);

Remarks

Because the CryptoKey import is deferred, the cryptographic check that the public key half of the secret key matches its private key half — which createKeyPairSignerFromBytes performs eagerly — is also deferred. A mismatched or corrupt secret key therefore throws on the first signing attempt rather than at creation time. Only the 64-bytes length is validated synchronously.

Since the import is deferred, the provided bytes are copied on creation so that the signer keeps working even if the caller mutates or zeroes their buffer before the first signing attempt. This internal copy is zeroed as soon as the import succeeds, so the plaintext secret key does not linger in memory beyond the first signing call.

If the deferred import fails, the failure is not cached: the next signing call will attempt the import again. This means a transient failure can be retried, whilst a genuinely mismatched or corrupt secret key will fail on every attempt.

See

createKeyPairSignerFromBytes for the asynchronous variant that eagerly validates the secret key and exposes the CryptoKeyPair via a keyPair property.

On this page