Arcium LogoArcium TS SDK Docs

Quick Start

Get started with the Arcium TypeScript SDK for encrypted Solana computations

Introduction

Arcium is a decentralized confidential computing network that enables secure processing of encrypted data through Multi-Party Computation (MPC) on Solana. Unlike traditional computation that requires data to be decrypted, Arcium allows computations to run on fully encrypted data, maintaining privacy throughout the entire process.

The SDK provides client-side libraries for interacting with encrypted Solana programs and the Arcium network. The SDK works seamlessly with Anchor and Solana's existing tooling.

Whether you're building private DeFi applications, secure AI systems, or confidential gaming experiences, the Arcium TypeScript SDK gives you the tools to process sensitive data without compromising its confidentiality.

Installation

Install the Arcium client SDK for encryption, PDA helpers, and computation management:

npm install @arcium-hq/client
pnpm add @arcium-hq/client
yarn add @arcium-hq/client
bun add @arcium-hq/client

Overview

This guide will walk you through the complete flow of using the Arcium TypeScript SDK to submit and process encrypted computations:

  1. Setup: Configure your Anchor provider and Arcium cluster connection
  2. Encrypt: Establish encryption keys and encrypt your computation inputs
  3. Submit: Send encrypted computations to the Arcium network
  4. Monitor: Track computation finalization on-chain
  5. Decrypt: Retrieve and decrypt computation results

Prerequisites

Complete the Arcium Installation Guide to set up your development environment. This Quick Start guide assumes you have a Solana program with Arcium integration and are familiar with Arcium and Solana concepts.

Setup Anchor Provider

Configure your Anchor provider and get your MXE program ID. This establishes the connection to Solana and identifies your encrypted computation program.

import * as  from "@coral-xyz/anchor";

// Initialize Anchor provider from environment variables
.setProvider(.AnchorProvider.env());
const  = .getProvider();

// Your MXE program ID
const  = new .web3.PublicKey("YourProgramIdHere");

Configure Cluster Account

Get the Arcium cluster account address. The cluster account represents a group of ARX nodes that will execute your encrypted computations.

import { ,  } from "@arcium-hq/client";

// For localnet: null (reads ARCIUM_CLUSTER_PUBKEY from environment)
// For devnet/testnet: your cluster offset (see callout below)
const : number | null = null;

const  =
   !== null
    ? ()
    : ().arciumClusterPubkey;

Getting started:

  • For local testing (recommended): Leave CLUSTER_OFFSET = null

    • Set ARCIUM_CLUSTER_PUBKEY in your .env file
    • Requires running a local ARX node
  • For devnet/testnet: Set your cluster offset

    • Get your cluster offset from the deployment guide
    • Example: const CLUSTER_OFFSET = 1078779259; (v0.3.0 devnet)

Most developers start with local testing before moving to deployed networks.

Generate Keys and Derive Shared Secret

Perform x25519 key exchange with the MXE to derive a shared secret. This shared secret enables you to encrypt data that the MXE can then compute on.

import * as  from "@coral-xyz/anchor";
import { , ,  } from "@arcium-hq/client";
import {  } from "@solana/web3.js";

// Generate client keypair for encryption/decryption
// Note: In production, consider deriving this from your user keypair using signed message-based derivation
const  = ..();
const  = .();

// Fetch MXE public key with retry logic
// → Expand "Helper Functions" accordion below for full implementation
const  = await getMXEPublicKeyWithRetry(
  provider as .,
  programId
);

// Derive shared secret and create cipher instance
const  = .(, );
const  = new ();

Important

Security: Keep clientPrivateKey in memory until decryption completes. Never log or persist private keys.

Local Testing: ARX nodes generate MXE keys on startup, so getMXEPublicKey may initially return null. The getMXEPublicKeyWithRetry helper function below handles this with configurable retry logic (default: 20 retries × 500ms).

Helper Functions

Encrypt Input Data

Encrypt your computation inputs using the cipher from Step 3. Your sensitive data will remain encrypted throughout the entire computation process.

import {  } from "crypto";
import * as  from "@coral-xyz/anchor";
import {  } from "@arcium-hq/client";

// Prepare your computation inputs
const  = [(42), (100)];

// Generate a 16-byte nonce (required)
const  = (16); // Must be exactly 16 bytes

// Encrypt inputs - returns number[][] where each element is a 32-byte ciphertext
const  = cipher.encrypt(, );

// Generate computation offset and convert nonce to BN for transaction
const  = new .BN((8), "hex");
const  = new .BN(().());
  • Input values must be < 2^252 (Curve25519 scalar field limit)
  • encrypt() returns number[][] where each element is a 32-byte ciphertext
  • computationOffset is a unique 8-byte identifier to track each computation on-chain (must be unique per computation) - generate a random value as shown above

Set Up Event Listener

Load your Anchor program and set up the event listener before submitting the transaction. This ensures you can receive the encrypted computation results when they're ready.

import * as  from "@coral-xyz/anchor";

// Load your Anchor program
const  = new .Program(
  YourProgramIdl, // Your program's IDL
  programId,
  provider
);

// Type-safe event listener helper
// → Expand "Helper Functions" accordion below for full implementation
type  = .<typeof .idl>;

// Set up event listener BEFORE submitting transaction
const  = awaitEvent("yourResultEvent");

The awaitEvent helper creates a Promise that resolves when your event is emitted. Set up the listener before transaction submission to avoid race conditions. The helper automatically cleans up the listener and provides full type safety from your program's IDL.

Helper Functions

Submit Computation Transaction

Submit the encrypted computation for execution. The Arcium network will process your encrypted data without ever decrypting it.

import * as  from "@coral-xyz/anchor";
import {
  ,
  ,
  ,
  ,
  ,
  ,
} from "@arcium-hq/client";

// From previous steps:
// - provider, programId (Step 1)
// - clusterAccount (Step 2)
// - clusterOffset (Step 2)
// - clientPublicKey (Step 3)
// - computationOffset, ciphertext, nonceBN (Step 4)
// - program, resultEventPromise (Step 5)

// Get computation definition offset for your encrypted instruction
// The instruction name must match the function name in your Rust MXE program
// (e.g., if your function is `add_together`, use "add_together")
const  = ("your_instruction_name");
const  = .().();

// Submit the computation transaction
const  = await program.methods
  .yourComputationMethod(
    computationOffset,
    .(ciphertext[0]),
    .(ciphertext[1]),
    .(clientPublicKey),
    nonceBN
  )
  .accountsPartial({
    : (clusterOffset, computationOffset),
    ,
    : (programId),
    : (clusterOffset),
    : (clusterOffset),
    : (programId, ),
    // ... your program-specific accounts
  })
  .rpc({ : true, : "confirmed" });

.("Computation submitted:", );
  • Replace yourComputationMethod with your program's instruction name (must match your MXE function name) - Add your program-specific accounts to accountsPartial alongside required Arcium accounts - clientPublicKey is required for ECDH key exchange: we fetch the MXE public key using getMXEPublicKey, and send clientPublicKey to the MXE so it can derive the same shared secret. See encryption documentation for more details

Await Computation Finalization

Wait for the computation to finalize on-chain. This confirms that the MPC nodes have completed processing your encrypted computation.

import * as  from "@coral-xyz/anchor";
import {  } from "@arcium-hq/client";

// Wait for computation finalization
const  = await (
  provider as .,
  computationOffset,
  programId,
  "confirmed"
);

.("Computation finalized:", );

Decrypt Results

After finalization completes, retrieve the event and decrypt the result. Use the same cipher instance from Step 3 to decrypt the encrypted computation output.

import * as  from "@coral-xyz/anchor";

// Await the event (listener was set up in Step 5)
const  = await resultEventPromise;

// Decrypt the result using the cipher and event nonce
const [] = cipher.decrypt(
  [.encryptedResult],
  new (.nonce)
);

.("Decrypted result:", );

Event structure: The resultEvent structure shown here (encryptedResult, nonce) is a generic example. Your actual event structure depends on your program's implementation and IDL definition.

Nonce handling: The MXE includes the nonce used for encryption in the result event. Always use the nonce from the event for decryption.

If your event doesn't include a nonce field, use the supplied nonce + 1 for decryption (the MXE increments the nonce when encrypting results).


Complete Example

For a complete working example showing all steps together, see the Hello World guide which includes a full test file demonstrating the entire flow from encryption to decryption.

You can also explore the example programs repository:

GitHubarcium-hq/examples

20


What's Next

Explore the API

  • Client API Reference: Detailed docs for encryption, PDA helpers, and encrypted instruction management.

Dive Deeper