Skip to content

Mode A — Stateful Session Caching

Mode A registers a hardware-attested Ed25519 key once. Later consumer transactions treat that key as a session signer.

Use Mode A for high-frequency work: quotes, heartbeats, streaming oracles.

  1. The enclave generates an ephemeral Ed25519 key in encrypted RAM.
  2. Hardware signs a report with REPORT_DATA[0..32] = pubkey and REPORT_DATA[32..64] = slot_hash.
  3. The client submits verify_and_register.
  4. The verifier checks VCEK (or Nitro COSE), measurement, TCB, SlotHashes age ≤ 150, and burns a UsedNonceAccount.
  5. The verifier writes AttestedSignerAccount with expires_slot = clock.slot + 216_000.
  6. The consumer calls assert_attested_signer (or AttestedSignerAccount::validate_session_signer). Subsequent transactions use native Ed25519 and skip P-384.

Stage 2 stays under 550,000 CUs (@spec TETON-PERF-001). Mock-crypto SBF harness: verify_and_register ≈ 62,734 CUs. The consumer PDA check is bounded at 1,500 CUs (@spec TETON-CONSUMER-001).

ATTESTATION_TTL_SLOTS = 216_000 (~24 hours at 400 ms slots). The verifier writes expiry from Clock. Clients pass expiresSlot only as bookkeeping.

Re-attestation of a live PDA is allowed when current_slot > expires_slot, or when the stored pubkey matches and a fresh unused nonce verifies (@spec TETON-VERIFY-004).

Discriminator sha256("global:verify_and_register")[..8]:

[246, 249, 100, 14, 102, 116, 92, 145]

Offset Size Field
0 8 Discriminator
8 8 nonce_slot (u64 LE)
16 1184 SNP report (zero-copy borrow, @spec TETON-ARCH-002)

Total instruction data: 1,200 bytes.

Accounts: payer, policy_registry, vcek, attested_signer, used_nonce, SlotHashes, Clock, system_program.

Nitro Mode A uses verify_nitro_attestation with mode = 0. See the instruction matrix.

PDA seeds: [b"attested_signer", signer_pubkey]. Size 146 bytes. Discriminator [97, 156, 233, 39, 50, 169, 179, 13].

Offset Size Field
0 8 Discriminator
8 32 signer_pubkey
40 1 enclave_type
41 48 measurement
89 32 chip_id_hash
121 8 tcb_version LE
129 8 registered_slot LE
137 8 expires_slot LE
145 1 bump

tcb_version and slot fields sit at unaligned offsets, so the CPI type stores them as [u8; 8] (bytemuck::Pod, align 1).

let attested = teton_cpi::AttestedSignerAccount::try_from_account_info(attested_info)?;
attested.validate_session_signer(workload_signer, &EXPECTED_MEASUREMENT)?;

validate_session_signer requires workload_signer.is_signer, pubkey equality, measurement match, and Clock::get()?.slot <= expires_slot (@spec TETON-SEC-004). Owner plus discriminator authenticate the record. PDA re-derivation is optional defense-in-depth and costs 1,500 CUs.

The helper teton_cpi::assert_attested_signer also re-derives the PDA.

New PDAs allocate through System Program create_account, funded by payer. The program asserts owner == program_id and is_writable on writable accounts. Stage 2 prefers client-supplied bumps and create_program_address over find_program_address.