Skip to main content
Version: develop

Accounts & Runtimes

Account interfaces

InterfaceCapabilitiesProperties
ZkpReadAccountdecrypt(ciphertext)zkpAddress
ZkpProvingAccountAbove + prove(request)
ZkpSigningAccountsignControllerAuth(typedData)controllerAddress
ZkpAccountAll of the abovezkpAddress, controllerAddress

ZkpAccount extends both ZkpProvingAccount and ZkpSigningAccount.

Account factories

createReadAccount

import { createReadAccount } from '@cardinal-cryptography/core'

const account = createReadAccount({
esk: EncryptionSecretKey,
solver: Solver,
})
// Returns: ZkpReadAccount

createAccount

Creates a full account with a local controller spending key (CSK):

import { createAccount } from '@cardinal-cryptography/core'

const account = createAccount({
esk: EncryptionSecretKey,
solver: Solver,
prover: Prover,
csk: ControllerSpendingKey,
})
// Returns: ZkpAccount

createAccountWithSigner

Creates a full account with an external signer (MetaMask, hardware wallet):

import { createAccountWithSigner } from '@cardinal-cryptography/core'

const account = createAccountWithSigner({
esk: EncryptionSecretKey,
solver: Solver,
prover: Prover,
signer: ExternalSigner,
})
// Returns: ZkpAccount

ExternalSigner interface

Any object with these two methods:

interface ExternalSigner {
getAddress(): EvmAddress
signTypedData(args: {
domain: TypedDataToSign['domain']
types: TypedDataToSign['types']
primaryType: string
message: Record<string, unknown>
}): Promise<HexSignature>
}

viem's WalletClient satisfies this interface.

Runtime interfaces

ReadRuntime

Solver only. For decryption without proving.

interface ReadRuntime {
readonly solver: Solver

createReadAccount(esk): ZkpReadAccount
createReadAccountFromMnemonic(mnemonic, accountIndex?): ZkpReadAccount
createReadAccountFromSeed(seed, accountIndex?): ZkpReadAccount

destroy(): void
}

ZkpRuntime

Solver + prover. Full capability.

interface ZkpRuntime extends ReadRuntime {
readonly prover: Prover

createAccount(esk, signer): ZkpAccount
createAccountFromMnemonic(mnemonic, accountIndex?): ZkpAccount
createAccountFromSeed(seed, accountIndex?): ZkpAccount

prewarmProver(): Promise<void>
destroy(): void
}

Runtime factories

Node (ergonomic — preferred)

@cardinal-cryptography/sdk factories build the solver and prover internally:

import { createReadRuntime, createRuntime } from '@cardinal-cryptography/sdk'

const readOnly = createReadRuntime() // solver only
const full = createRuntime() // solver + prover (threads auto-detected)

Both accept an optional config:

const readOnly = createReadRuntime({ solver: { tiers: [...] } })
const full = createRuntime({ solver: { tiers: [...] }, prover: { threads: 4 } })

Core (low-level, platform-agnostic)

@cardinal-cryptography/core exposes assembleRuntime / assembleReadRuntime for callers who supply their own pre-built backends (useful in tests or custom environments):

import { assembleReadRuntime, assembleRuntime } from '@cardinal-cryptography/core'

const readOnly = assembleReadRuntime(solver)
const full = assembleRuntime(solver, prover)

Lifecycle

  1. Create a runtime (backends are built internally)
  2. Create accounts from the runtime (multiple accounts can share one runtime)
  3. Use accounts with clients
  4. Destroy the runtime when done (frees WASM resources)
const runtime = createRuntime()
const account = runtime.createAccountFromMnemonic('...')

// ... use account with clients ...

runtime.destroy() // Frees solver + prover WASM