AURA

Confidential Guardrails

How EUint64 FHE ciphertexts keep spending limits private while still being enforced on-chain via Ika Encrypt.

The Problem

A naive treasury stores daily_limit_usd = 10_000 in a public Solana account. Any observer can read it, infer the agent's strategy, and front-run or manipulate it. AURA solves this with Fully Homomorphic Encryption (FHE) via the Ika Encrypt network — the limit value is stored as an EUint64 ciphertext and never decrypted during evaluation.

What Gets Encrypted

The core confidential path attaches three scalar EUint64 ciphertext accounts to a treasury via configure_confidential_guardrails:

Ciphertext accountWhat it holds
daily_limit_ciphertextEncrypted daily spending limit in USD cents
per_tx_limit_ciphertextEncrypted per-transaction limit in USD cents
spent_today_ciphertextEncrypted running total spent today in USD cents

These are Solana accounts owned by the Ika Encrypt program. Their addresses are stored in the TreasuryAccount and passed as accounts to every confidential instruction.

The newer ConfidentialGuardrailsAccount sidecar adds an epoch marker, an enabled flag, and optional expanded ciphertext pointers. Current proposal execution uses that sidecar for the extended weekly-limit path when both weekly_limit_ciphertext and weekly_spent_ciphertext are supplied.

Instruction Flow

CPI Accounts for propose_confidential_transaction

The instruction requires these accounts beyond the standard treasury/AI authority pair:

AccountSeed / SourcePurpose
daily_limit_ciphertextstored in TreasuryAccountEncrypted daily limit
per_tx_limit_ciphertextstored in TreasuryAccountEncrypted per-tx limit
spent_today_ciphertextstored in TreasuryAccountEncrypted running counter
amount_ciphertextfreshly createdEncrypted proposal amount
policy_output_ciphertextfreshly createdOutput — encrypted verdict
weekly_limit_ciphertextoptional sidecar pointerExtended graph weekly limit
weekly_spent_ciphertextoptional sidecar pointerExtended graph weekly counter
confidential_guardrails["confidential_guardrails", treasury]Optional sidecar required for extended weekly path
encrypt_program4ebfzWdKnrnGseuQpezXdG8yCdHqwQ1SSBHD3bWArND8Ika Encrypt program
configEncrypt program global configEncrypt network config
depositpayer-fundedPays for FHE compute
caller_programaura-core program IDCPI caller identity
cpi_authority["__encrypt_cpi_authority"] on aura-coreSigns the CPI
network_encryption_keyEncrypt program accountNetwork's public key
event_authority["__event_authority"] on Encrypt programEmit Encrypt events
system_program11111111111111111111111111111111Account creation

What the FHE Circuit Does

The default Ika Encrypt graph evaluates a circuit over the four core ciphertexts:

verdict = if (amount > per_tx_limit) → PerTransactionLimit
          else if (spent_today + amount > daily_limit) → DailyLimit
          else → None (approved)

When the weekly ciphertext accounts and sidecar are supplied, aura-core submits the extended graph:

verdict = if (amount > per_tx_limit) → PerTransactionLimit
          else if (spent_today + amount > daily_limit) → DailyLimit
          else if (weekly_spent + amount > weekly_limit) → WeeklyLimit
          else → None (approved)

The output carries an encrypted violation code and update lanes for the encrypted counters. Only the small violation code and validated counter update are consumed on-chain; the limit values remain encrypted.

What Stays Private

DataOn-chain visibility
Daily limit valuePrivate — EUint64 ciphertext only
Per-tx limit valuePrivate — EUint64 ciphertext only
Running spent-today totalPrivate — EUint64 ciphertext only
Weekly limit / weekly spentPrivate when the extended sidecar path is used
Proposal amountPublic — in PendingTransaction.amount_usd
Violation code (0 or N)Public — decrypted on-chain
Recipient / chainPublic — in PendingTransaction

Public Precheck Before FHE

evaluate_public_precheck runs before the FHE CPI. Current source evaluates the public subset: scoped pauses, budget envelopes, Bitcoin manual-review threshold, time window, protocol allowlist, slippage, quote freshness, counterparty risk, shared pool, velocity, and approval ladder. It skips direct per-transaction, daily, weekly, monthly, and recipient cap checks; encrypted per-tx/daily checks are always deferred to Encrypt, and the weekly check is included only in the extended sidecar path. If any public rule fails, the proposal is rejected immediately — no FHE call is made, saving compute and cost.

Decryption Accounts for request_policy_decryption

AccountPurpose
request_accountFreshly created — tracks the decryption request
ciphertextThe policy_output_ciphertext from the pending proposal
encrypt_programIka Encrypt program
configEncrypt global config
depositPays for decryption
caller_programaura-core program ID
cpi_authority["__encrypt_cpi_authority"] on aura-core
network_encryption_keyEncrypt network's public key
event_authority["__event_authority"] on Encrypt program
system_programAccount creation

SDK Usage

import { instructions } from "@aura-protocol/sdk-ts";

// Configure confidential guardrails (owner signs)
await instructions.confidential.sendConfigureConfidentialGuardrails(client, owner, {
  accounts: {
    owner: owner.publicKey,
    treasury,
    dailyLimitCiphertext,
    perTxLimitCiphertext,
    spentTodayCiphertext,
  },
  args: { now },
});

// Propose a confidential transaction (AI authority signs)
await instructions.confidential.sendProposeConfidentialTransaction(
  client,
  aiAuthority,
  {
    accounts: {
      aiAuthority: aiAuthority.publicKey,
      treasury,
      dailyLimitCiphertext,
      perTxLimitCiphertext,
      spentTodayCiphertext,
      amountCiphertext,
      policyOutputCiphertext,
      weeklyLimitCiphertext: null,
      weeklySpentCiphertext: null,
      confidentialGuardrails: null,
      encryptProgram: ENCRYPT_DEVNET_PROGRAM_ID,
      config: encryptConfig,
      deposit: depositAccount,
      callerProgram: AURA_PROGRAM_ID,
      cpiAuthority: deriveEncryptCpiAuthorityAddress()[0],
      networkEncryptionKey,
      eventAuthority: deriveEncryptEventAuthorityAddress(ENCRYPT_DEVNET_PROGRAM_ID)[0],
      systemProgram: SystemProgram.programId,
    },
    args,
  },
);

On this page