Accounts & Runtimes
Account interfaces
| Interface | Capabilities | Properties |
|---|---|---|
ZkpReadAccount | decrypt(ciphertext) | zkpAddress |
ZkpProvingAccount | Above + prove(request) | |
ZkpSigningAccount | signControllerAuth(typedData) | controllerAddress |
ZkpAccount | All of the above | zkpAddress, 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
- Create a runtime (backends are built internally)
- Create accounts from the runtime (multiple accounts can share one runtime)
- Use accounts with clients
- 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