Skip to main content

Intent

Define a four-layer privacy architecture where Data, Execution, Settlement, and Disclosure are distinct concerns, each addressable by different technologies. This enables institutions to select best-fit components per layer while maintaining interoperability and upgrade paths.
Best for: Different privacy requirements exist for different transaction phases, or organization needs flexibility to swap components without full redesign.
Avoid when: Uniform end-to-end privacy is mandatory with single-vendor solution, or tight latency requirements preclude layer coordination overhead.

Architecture Overview

Ingredients

Standards

  • ERC-7573: Atomic DvP settlement across networks
  • ERC-3643: Compliant security tokens with identity hooks
  • EAS: Ethereum Attestation Service for disclosure proofs
  • EIP-4844: Blob transactions for data availability

Infrastructure by Layer

LayerResponsibilityOptions
DataStore/retrieve encrypted dataOff-chain encrypted storage, DA layers (EigenDA, Celestia), L2 blobs (EIP-4844), IPFS+encryption
ExecutionPrivate computationZK (Aztec, Miden), FHE (Zama, Fhenix), TEE enclaves (Flashbots SUAVE)
SettlementFinality, atomicityEthereum L1, Arbitrum, Optimism, ZKsync, Polygon
DisclosureRegulatory accessView keys, ZK proofs, threshold KMS, EAS attestations

Off-chain Services

  • Key management systems per layer (data encryption keys, proving keys, signing keys)
  • Cross-layer routing and orchestration (transaction coordinator)
  • Audit log aggregation (unified view across layers)

Protocol

1

Define Layer Boundaries

Map each transaction phase to a layer:Example: Private bond issuance
PhaseLayerTechnology
Store bond termsDataEncrypted off-chain storage
Verify investor eligibilityExecutionZK proof on Aztec
Transfer ownershipSettlementERC-7573 on Ethereum L1
Regulator accessDisclosureView keys via threshold KMS
2

Configure Layer Interfaces

Establish standardized APIs between layers:
// Data Layer Interface
interface DataLayer {
  store(data: EncryptedBlob): Promise<ContentHash>;
  retrieve(hash: ContentHash, key: DecryptionKey): Promise<Blob>;
  anchor(hashes: ContentHash[]): Promise<MerkleRoot>;
}

// Execution Layer Interface
interface ExecutionLayer {
  compute(input: DataReference, circuit: Circuit): Promise<Proof>;
  verify(proof: Proof): Promise<boolean>;
  getStateTransition(proof: Proof): Promise<StateTransition>;
}

// Settlement Layer Interface
interface SettlementLayer {
  escrow(asset: Asset, conditions: Outcome[]): Promise<EscrowId>;
  settle(escrowId: EscrowId, proof: Proof): Promise<TxHash>;
  revert(escrowId: EscrowId): Promise<TxHash>;
}

// Disclosure Layer Interface
interface DisclosureLayer {
  generateViewKey(scope: Scope, expiry: Timestamp): Promise<ViewKey>;
  attest(event: DisclosureEvent): Promise<AttestationId>;
  verify(viewKey: ViewKey, scope: Scope): Promise<boolean>;
}
3

Route Data to Storage

Encrypt sensitive transaction data and store via the Data layer:
// Encrypt bond terms
const bondData = {
  issuer: 'Bank A',
  isin: 'XS1234567890',
  principal: 10_000_000, // €10M
  coupon: 3.5,
  maturity: '2030-12-31'
};

// Generate symmetric key
const dataKey = crypto.randomBytes(32);

// Encrypt data
const encryptedBlob = await encrypt(bondData, dataKey);

// Store in Data layer
const contentHash = await dataLayer.store(encryptedBlob);

// Wrap key to threshold authorities
const wrappedKey = await thresholdKMS.wrap(dataKey, [
  authority1_pubkey,
  authority2_pubkey,
  authority3_pubkey
]);

// Store metadata on-chain
await dataCommitContract.commit(contentHash, wrappedKey);
Returns content-addressed reference (contentHash) for downstream layers.
4

Execute Private Computation

The Execution layer retrieves encrypted data references, performs computation, and outputs verifiable state transition:
// Investor eligibility check via ZK proof
const eligibilityCircuit = {
  inputs: {
    investorKYC: privateInput,  // Not revealed
    jurisdiction: 'DE',
    accreditedStatus: true
  },
  outputs: {
    isEligible: publicOutput  // Only this is revealed
  }
};

// Generate proof
const proof = await executionLayer.compute(
  contentHash,  // Reference to encrypted data
  eligibilityCircuit
);

// Proof attests: "Investor meets eligibility criteria"
// without revealing investor identity or KYC details
5

Settle on Target Chain

Submit execution proof to Settlement layer:
// Settlement contract verifies proof and executes transfer
function settleWithProof(
  bytes32 tradeId,
  bytes32 contentHash,
  bytes calldata executionProof
) external {
  // Verify execution proof
  require(
    executionLayer.verify(executionProof),
    "Invalid execution proof"
  );
  
  // Extract state transition
  StateTransition memory transition = 
    executionLayer.getStateTransition(executionProof);
  
  // Execute atomic DvP via ERC-7573
  bondToken.transferFrom(
    transition.from,
    transition.to,
    transition.bondAmount
  );
  
  cashToken.settleConditional(
    transition.cashOutcomeKey
  );
  
  emit SettledWithProof(tradeId, contentHash);
}
Settlement may be on L1 for maximum security or L2 for lower cost.
6

Generate Disclosure Artifacts

Produce disclosure proofs, view keys, or attestations for authorized parties:
// Regulator requests access to bond terms
const disclosureRequest = {
  requestor: 'BaFin',
  scope: {
    isin: 'XS1234567890',
    dateRange: ['2026-01-01', '2026-01-31']
  },
  expiry: Date.now() + 24 * 60 * 60 * 1000  // 24 hours
};

// Policy engine verifies mandate
const approved = await policyEngine.evaluate(disclosureRequest);

if (approved) {
  // Generate time-limited view key
  const viewKey = await disclosureLayer.generateViewKey(
    disclosureRequest.scope,
    disclosureRequest.expiry
  );
  
  // Log disclosure via EAS
  const attestation = await disclosureLayer.attest({
    requestor: 'BaFin',
    dataHash: contentHash,
    viewKeyHash: hash(viewKey),
    timestamp: Date.now(),
    expiry: disclosureRequest.expiry
  });
  
  // Deliver view key to regulator
  await sendToRegulator(viewKey, attestation);
}
7

Log Cross-Layer Audit Trail

Record layer transitions and references in unified audit log:
const auditEntry = {
  tradeId: '0xabc123...',
  layers: {
    data: {
      contentHash: '0x7f3a...',
      storageBackend: 'IPFS',
      encryptionAlgo: 'AES-256-GCM'
    },
    execution: {
      proofHash: '0x9c2e...',
      backend: 'Aztec',
      circuitId: 'eligibility-v1.2'
    },
    settlement: {
      txHash: '0xdef456...',
      chain: 'Ethereum L1',
      blockNumber: 18_456_789
    },
    disclosure: {
      attestationId: '0x3b7f...',
      requestor: 'BaFin',
      viewKeyExpiry: 1735689600
    }
  },
  timestamp: Date.now()
};

await auditLog.append(auditEntry);
Each layer contributes its own audit data, enabling full transaction reconstruction.

Guarantees

Compromise or failure in one layer does not expose data in others:
  • Data layer breach: Encrypted blobs remain secure; attacker cannot decrypt without keys
  • Execution layer failure: Settlement layer can revert; stored data unaffected
  • Settlement layer censorship: Can migrate to alternative settlement chain without re-encrypting data
  • Disclosure layer key leak: Only affects scoped disclosures; does not compromise execution or data encryption
Layers can be independently upgraded or swapped:Example upgrade paths:
  • Migrate from TEE execution → ZK execution without changing settlement
  • Move from L1 settlement → L2 settlement without changing data storage
  • Add new disclosure mechanism (e.g., FHE-based queries) alongside existing view keys
  • Switch from IPFS → Arweave for data storage without re-generating proofs
Cross-layer audit trail enables reconstruction of transaction flow:
// Reconstruct full transaction history
async function auditTransaction(tradeId: string) {
  const entry = await auditLog.get(tradeId);
  
  // Retrieve original data (if authorized)
  const encryptedData = await dataLayer.retrieve(
    entry.layers.data.contentHash
  );
  
  // Verify execution proof
  const proofValid = await executionLayer.verify(
    entry.layers.execution.proofHash
  );
  
  // Check settlement finality
  const settlement = await settlementLayer.getTransaction(
    entry.layers.settlement.txHash
  );
  
  // List all disclosures
  const disclosures = await disclosureLayer.getAttestations(
    entry.layers.data.contentHash
  );
  
  return {
    data: encryptedData,
    proofValid,
    settlement,
    disclosures
  };
}
Settlement layer defines atomicity boundary. If execution fails, settlement reverts without affecting stored data:
function settleWithFailureHandling(
  bytes32 tradeId,
  bytes calldata proof
) external {
  try executionLayer.verify(proof) returns (bool valid) {
    require(valid, "Invalid proof");
    
    // Attempt settlement
    _executeSettlement(tradeId);
  } catch Error(string memory reason) {
    // Settlement failed; revert escrow
    _revertEscrow(tradeId);
    
    // Data layer unaffected; can retry later
    emit SettlementFailed(tradeId, reason);
  }
}

Trade-offs

Coordination complexity: Multiple layers require orchestration logic, increasing system complexity and operational overhead.

Latency Accumulation

Each layer adds processing time:
LayerTypical LatencyCumulative
Data100-500ms (storage write)100-500ms
Execution5-30s (proof generation)5.1-30.5s
Settlement12-180s (block confirmation)17-210s
Disclosure1-5s (key generation)18-215s
Total latency: ~18 seconds to ~3.5 minutes. Compare to monolithic solutions: ~30 seconds to 2 minutes.

Interface Rigidity

Standardized interfaces may constrain layer-specific optimizations:
  • Data layer: Generic encryption interface may not support FHE-specific optimizations
  • Execution layer: Abstraction over ZK/FHE/TEE may limit access to advanced features
  • Settlement layer: ERC-7573 may not cover all atomic settlement patterns
Mitigation: Provide “escape hatches” for advanced use cases requiring direct layer access.

Tooling Fragmentation

Different vendors per layer means multiple SDKs, monitoring tools, and support relationships:
// Multiple SDK imports
import { AztecClient } from '@aztec/sdk';  // Execution
import { IPFSClient } from 'ipfs-http-client';  // Data
import { ethers } from 'ethers';  // Settlement
import { EAS } from '@ethereum-attestation-service/sdk';  // Disclosure
import { ThresholdKMS } from '@lit-protocol/sdk';  // Keys

// Different authentication methods
aztecClient.authenticate(aztecPrivateKey);
ipfsClient.authenticate(ipfsProjectId, ipfsSecret);
ethersProvider.getSigner(ethereumPrivateKey);
easClient.connect(easContractAddress);
thresholdKMS.connect(litNodeUrls);

Metadata Leakage

Even with encrypted data, cross-layer routing can reveal timing, access patterns, and transaction graph:
  • Timing correlation: Data write → execution proof → settlement transaction reveals trade flow
  • Size leakage: Encrypted blob sizes may hint at transaction complexity
  • Access patterns: Frequent retrieval from specific content hashes reveals hot data
Mitigation:
  • Add random delays between layer transitions
  • Pad encrypted blobs to fixed sizes
  • Use mixing services or batch processing to obscure individual transactions

Example: Institutional Bond Settlement

1

Data Layer: Store Bond Terms

Bond terms and investor details encrypted with AES-256, stored in off-chain encrypted storage:
{
  "isin": "XS1234567890",
  "issuer": "Bank A",
  "principal": 10000000,
  "investors": [
    {"id": "investor-1", "allocation": 5000000},
    {"id": "investor-2", "allocation": 5000000}
  ]
}
Content hash 0x7f3a... published to Celestia DA layer for availability guarantees.
2

Execution Layer: Compute Allocation

Aztec private contracts compute allocation and verify investor eligibility via ZK proofs:
fn allocate_bonds(
  bond_data: EncryptedData,
  investor_kyc: PrivateInput
) -> pub AllocationProof {
  // Verify investor eligibility (private)
  assert(investor_kyc.accredited == true);
  assert(investor_kyc.jurisdiction == "DE");
  
  // Compute allocation (private)
  let allocation = calculate_pro_rata(bond_data, investor_kyc.id);
  
  // Output proof of valid allocation
  AllocationProof {
    is_eligible: true,
    allocation_valid: true
    // Amounts and identities remain private
  }
}
Execution produces settlement instruction with proof of valid state transition.
3

Settlement Layer: Atomic DvP on L1

ERC-7573 atomic DvP on Ethereum L1:
// Bond tokens transfer to buyer
bondToken.transferFrom(issuer, buyer, bondAmount);

// Payment token transfers to seller
cashToken.transferFrom(buyer, issuer, paymentAmount);

// Both succeed or both revert
Transaction hash 0xdef456... recorded on Ethereum L1 at block 18,456,789.
4

Disclosure Layer: Regulator Access

Issuer provides view keys to BaFin via EAS attestation:
// Generate view key for specific bond issuance
const viewKey = await thresholdKMS.generateViewKey({
  scope: { isin: 'XS1234567890' },
  expiry: Date.now() + 24 * 60 * 60 * 1000
});

// Attest disclosure event via EAS
const attestation = await eas.attest({
  schema: DISCLOSURE_SCHEMA,
  data: {
    dataHash: '0x7f3a...',
    requestor: 'BaFin',
    viewKeyHash: hash(viewKey),
    expiry: viewKey.expiry
  }
});
Regulator can:
  • Decrypt bond terms and investor details using view key
  • Verify investor eligibility proofs from execution layer
  • Confirm settlement on L1 block explorer
Regulator cannot access:
  • Other bond issuances (scoped view key)
  • Full transaction graph (only specific trade)
  • Investor details in other trades

Upgrade Scenario

This modular configuration allows the issuer to:
Migrate from Aztec to Miden for execution without changing settlement:
  • Replace Aztec client with Miden VM client
  • Rewrite circuits in Miden assembly
  • Data layer, settlement layer, disclosure layer unchanged
  • Zero downtime migration via parallel deployment

Implementation Checklist

1

Define Layer Requirements

  • Identify data sensitivity levels
  • Determine execution privacy needs (ZK/FHE/TEE)
  • Select settlement finality requirements (L1/L2)
  • Define disclosure scope and authorized parties
2

Select Layer Technologies

  • Choose data storage backend (IPFS/Arweave/Celestia)
  • Choose execution environment (Aztec/Zama/Flashbots)
  • Choose settlement chain (Ethereum/Arbitrum/Polygon)
  • Choose disclosure mechanism (view keys/ZK proofs/EAS)
3

Implement Layer Interfaces

  • Standardize API contracts between layers
  • Implement cross-layer orchestration logic
  • Add error handling and retry mechanisms
  • Build unified audit logging
4

Test Integration

  • Unit test each layer independently
  • Integration test cross-layer flows
  • Stress test coordination under load
  • Security audit layer boundaries
5

Deploy and Monitor

  • Deploy layers in staging environment
  • Perform end-to-end transaction tests
  • Set up monitoring and alerting per layer
  • Plan upgrade and rollback procedures

See Also

Private L2s

Execution layer options: Aztec, Miden, Scroll

Commit and Prove

Cross-layer coordination pattern

Atomic DvP via ERC-7573

Settlement layer standard

Regulatory Disclosure

Disclosure layer mechanisms

L2 Encrypted Off-chain Audit

Data + disclosure combination pattern

TEE-based Privacy

Execution layer option using trusted hardware

Vendor Implementations

Aztec

ZK execution layer

Zama

FHE execution layer

Miden

ZK VM execution layer

Railgun

Privacy infrastructure

EigenDA

Data availability layer

Celestia

Modular DA network

Build docs developers (and LLMs) love