Version: next

This documentation is for an unreleased version of Taquito. Features and APIs may change before the final release. View the latest stable version.

In Memory Signer

Written by Simon Boissonneault-Robert

Caution

Storing private keys in memory is suitable for development workflows but risky for production use-cases! Use the InMemorySigner appropriately given your risk profile.

More information on why can be found here.

InMemorySigner is a local signer implementation that allows you to directly use a private key in your browser or your NodeJS app and is intended for development workflows.

Using the InMemorySigner for operations on mainnet where your system uses tokens of real value is discouraged.

If you require the server-side signing of operations on the mainnet, we recommend exploring the use of the Remote Signer package in conjunction with an HSM remote signer such as Signatory or TacoInfra’s Remote Signer.

Usage

Loading an unencrypted private key

If you configure Taquito this way, you will now be able to use every function that needs signing support.

import { InMemorySigner } from '@taquito/signer';
import { TezosToolkit } from '@taquito/taquito';

const Tezos = new TezosToolkit('https://YOUR_PREFERRED_RPC_URL');

Tezos.setProvider({ signer: await InMemorySigner.fromSecretKey('your_private_key') });
Note

The operation will be signed automatically using the signer (no prompt)

The fromSecretKey method takes a secret that is base58 encoded as a parameter. Here are three examples with unencrypted private keys:

try {
  const theSigner = await InMemorySigner.fromSecretKey('edsk2rKA8YEExg9Zo2qNPiQnnYheF1DhqjLVmfKdxiFfu5GyGRZRnb');
  Tezos.setProvider({ signer: theSigner });
  const publicKeyHash = await Tezos.signer.publicKeyHash();
  console.log(`The public key hash associated is: ${publicKeyHash}.`);
} catch (error) {
  console.log(`Error: ${error} ${JSON.stringify(error, null, 2)}`);
}
try {
  const theSigner = await InMemorySigner.fromSecretKey('spsk2Fiz7sGP5fNMJrokp6ynTa4bcFbsRhw58FHXbNf5ProDNFJ5Xq');
  Tezos.setProvider({ signer: theSigner });
  const publicKeyHash = await Tezos.signer.publicKeyHash();
  console.log(`The public key hash associated is: ${publicKeyHash}.`);
} catch (error) {
  console.log(`Error: ${error} ${JSON.stringify(error, null, 2)}`);
}

When required, Taquito offers the b58Encode function allowing to encode the secret in base58. The parameters of the function are the secret that can be a hex string or an Uint8Array, and the desired prefix. Here is an example with a hex string:

// import { b58Encode, PrefixV2 } from '@taquito/utils';

try {
  const b58encodedSecret = b58Encode(
    '7c842c15c8b0c8fd228e6cb5302a50201f41642dd36b699003fb3c857920bc9d',
    PrefixV2.P256SecretKey
  );
  console.log(
    `The secret is encoded in base58 and the prefix "p2sk" is added to it: ${b58encodedSecret}.`
  );

  const theSigner = await InMemorySigner.fromSecretKey(b58encodedSecret);
  Tezos.setProvider({ signer: theSigner });
  const publicKeyHash = await Tezos.signer.publicKeyHash();
  console.log(`The public key hash associated is: ${publicKeyHash}.`);
} catch (error) {
  console.log(`Error: ${error} ${JSON.stringify(error, null, 2)}`);
}

Loading an encrypted private key with a passphrase

If your private key is encrypted, you can specify a passphrase to decrypt it. Doing so will automatically decrypt the key and allow you to use the signer to sign transactions.

import { InMemorySigner } from '@taquito/signer';
import { TezosToolkit } from '@taquito/taquito';

const Tezos = new TezosToolkit('https://YOUR_PREFERRED_RPC_URL');
Tezos.setProvider({
  signer: await InMemorySigner.fromSecretKey('your_private_key', 'your_passphrase'),
});

Here are three examples with encrypted private keys where the passphrase used is test:

try {
  const theSigner = await InMemorySigner.fromSecretKey(
    'edesk1GXwWmGjXiLHBKxGBxwmNvG21vKBh6FBxc4CyJ8adQQE2avP5vBB57ZUZ93Anm7i4k8RmsHaPzVAvpnHkFF',
    'test'
  );
  Tezos.setProvider({ signer: theSigner });
  const publicKeyHash = await Tezos.signer.publicKeyHash();
  console.log(`The public key hash associated is: ${publicKeyHash}.`);
} catch (error) {
  console.log(`Error: ${error} ${JSON.stringify(error, null, 2)}`);
}
try {
  const theSigner = await InMemorySigner.fromSecretKey(
    'spesk24UQkAiJk8X6AufNtRv1WWPp2BAssEgmijCTQPMgUXweSKPmLdbyAjPmCG1pR2dC9P5UZZVeZcb7zVodUHZ',
    'test'
  );
  Tezos.setProvider({ signer: theSigner });
  const publicKeyHash = await Tezos.signer.publicKeyHash();
  console.log(`The public key hash associated is: ${publicKeyHash}.`);
} catch (error) {
  console.log(`Error: ${error} ${JSON.stringify(error, null, 2)}`);
}
try {
  const theSigner = await InMemorySigner.fromSecretKey(
    'p2esk28hoUE2J88QNFj2aDX2pjzL7wcVh2g8tkEwtWWguby9M3FHUgSbzvF2Sd7wQ4Kd8crFwvto6gF3otcBuo4T',
    'test'
  );
  Tezos.setProvider({ signer: theSigner });
  const publicKeyHash = await Tezos.signer.publicKeyHash();
  console.log(`The public key hash associated is: ${publicKeyHash}.`);
} catch (error) {
  console.log(`Error: ${error} ${JSON.stringify(error, null, 2)}`);
}

Loading a mnemonic

The fromMnemonic method takes the mnemonic, password, derivationPath, and curve as parameters. Here is an example of an instantiation of an InMemorySigner.fromMnemonic

The default derivation path is "44'/1729'/0'/0'". Select a path for the account you want to derive.

With ed25519 default derivation path (must be hardened with either h or ')

// ed25519 must have all hardened paths
// using all default values password = '' curve = 'ed25519' and derivationPath "44'/1729'/0'/0'"
try {
  const params = {
    mnemonic: 'author crumble medal dose ribbon permit ankle sport final hood shadow vessel horn hawk enter zebra prefer devote captain during fly found despair business'
  };

  const signer = InMemorySigner.fromMnemonic(params);
  Tezos.setSignerProvider(signer);
  const publicKeyHash = await Tezos.signer.publicKeyHash();
  console.log(`The public key hash associated is: ${publicKeyHash}`);
} catch (error) {
  console.log(error);
}

With a non-default derivation path non-hardened with a tz2 address

try {
  const params = {
    mnemonic: 'author crumble medal dose ribbon permit ankle sport final hood shadow vessel horn hawk enter zebra prefer devote captain during fly found despair business',
    password: '',
    derivationPath: '44h/1729h/1/0', // h or ' specify hardened derivation path
    curve: 'secp256k1'
  };

  const signer = InMemorySigner.fromMnemonic(params);
  Tezos.setSignerProvider(signer);
  const publicKeyHash = await Tezos.signer.publicKeyHash();
  console.log(`The public key hash associated is: ${publicKeyHash}`);
} catch (error) {
  console.log(error);
}

Generate and restore a mnemonic

The generateMnemonic function creates an English BIP39 mnemonic. Its default strength is 128 bits, which produces 12 words. You can also select 160, 192, 224, or 256 bits.

import {
  generateMnemonic,
  mnemonicToEntropy,
  entropyToMnemonic,
} from '@taquito/signer';

const mnemonic = generateMnemonic();
const entropy = mnemonicToEntropy(mnemonic);
const restoredMnemonic = entropyToMnemonic(entropy);
console.log(restoredMnemonic === mnemonic); // true

mnemonicToEntropy returns a Uint8Array. entropyToMnemonic accepts 16, 20, 24, 28, or 32 bytes. It also accepts an even-length hexadecimal string without a 0x prefix. Leading zero bytes are preserved. An invalid mnemonic throws an InvalidMnemonicError without including the phrase in the error.

Byte input must be a Uint8Array, such as a Node.js Buffer or a subarray view. The helper uses only the bytes in that view and leaves the input unchanged. Plain number arrays and other typed-array kinds are not accepted.

Derive keys without a signer

Use deriveKeyFromMnemonic to obtain account details without constructing an InMemorySigner. The function is synchronous and returns publicKey, publicKeyHash, and secretKey.

import { generateMnemonic, deriveKeyFromMnemonic } from '@taquito/signer';

const mnemonic = generateMnemonic();
const account = deriveKeyFromMnemonic({
  mnemonic,
  password: '',
  derivationPath: "44'/1729'/1'/0'",
  curve: 'ed25519',
});
console.log(account.publicKeyHash);

The options match InMemorySigner.fromMnemonic. The defaults are an empty password, the path "44'/1729'/0'/0'", and the ed25519 curve. password is the BIP39 passphrase. Supported curves are ed25519, secp256k1, and p256. Ed25519 paths must be hardened. BLS and ML-DSA mnemonic derivation are not supported.

The returned secretKey is unencrypted. Avoid logging or sharing the account object. Ed25519 uses the expanded secret-key form returned by InMemorySigner.secretKey().

A simple factory multiple keys/wallets

If you require to sign operations with many different keys, then implementing a factory function can be useful.

The signerFactory function example creates a new Tezos instance, uses it for signing, and then discards it when complete.

import { InMemorySigner } from '@taquito/signer';
import { TezosToolkit } from '@taquito/taquito';

const signerFactory = async (rpcUrl: string, pk: string) => {
  const Tezos = new TezosToolkit(rpcUrl);
  await Tezos.setProvider({ signer: await InMemorySigner.fromSecretKey(pk) });
  return Tezos;
};

const bob = await signerFactory('bobs_secret_key');
const alice = await signerFactory('alice_secret_key');

Aggregate-key BLS proofs

InMemorySigner.provePossession() still creates a proof over its own BLS public key. For the N-of-N native multisig reveal flow, provePossession(aggregatePublicKey) creates a proof share over the raw aggregate key instead. It uses the proof-of-possession domain, without an operation watermark or message prehash.

There are two proof stages. First, each participant supplies its public key and its ordinary self proof. The coordinator calls RpcClient.aggregatePublicKeys to check those proofs before constructing the aggregate key. This check protects against rogue-key inputs.

Each participant must verify the agreed participant list and aggregate key before creating an override proof with its own signer:

const share = await signer.provePossession(approvedAggregatePublicKey);
const publicProofShare = share.prefixSig;

The coordinator collects those public proof shares and calls:

const proof = await rpc.aggregateProofs({
  public_key: approvedAggregatePublicKey,
  proofs: approvedProofShares,
});
if (proof === null) {
  throw new Error('The aggregate proof did not verify');
}

Use the resulting proof in the aggregate account’s reveal workflow. Aggregating the original self proofs does not produce this reveal proof because those proofs sign different keys. Participants keep their private keys; this API does not coordinate or store them.

The override is a concrete InMemorySigner feature. The generic Signer interface retains its zero-argument proof method, so do not assume an external signer accepts an aggregate key. Existing non-BLS rejection and ordinary signing are unchanged.

The RPC follows Octez 25.3’s root /bls/aggregate_proofs endpoint. Invalid proof combinations can return null; malformed encodings can produce HTTP errors. RpcClientCache forwards each request without caching. Older custom RPC clients may omit the optional capability and receive UnsupportedActionError if it is invoked through the cache.

These helpers prepare proof setup for N-of-N accounts. They do not provide participant transport, consent, threshold key generation, secure custody or a funded reveal test. See the native multisig reference.