Skip to main content

Apertures: Partial Evaluation with Holes for Distributed Computation

The idea behind apertures is simple. You have a computation with holes in it (denoted ?variable). You can partially evaluate the parts you know, optimize the result, and fill in the holes later when the data arrives.

This is not a cryptographic protocol. Apertures make no security claims. They leak information through program structure, evaluation patterns, and algebraic relationships. But many real-world coordination problems do not need cryptographic privacy. They need a way for multiple parties to share computation structure while controlling when and where data enters.

The Core Mechanism

An aperture is an unknown expression, a hole in a computation. Programs with apertures can be partially evaluated by parties who do not know the aperture values, optimized and transformed without seeing the data, and resumed when apertures are eventually filled.

The most useful pattern is local computation:

;; Server optimizes without seeing data or results
(let ((plan (server-optimize ?query)))
  (client-execute plan ?local-data))
;; Results stay local

The server provides optimization expertise without seeing actual query parameters, the local data being processed, or query results. But the server does learn the query structure and patterns. That is the tradeoff.

Language and Evaluation

Apertures extend a Lisp-like language with holes:

e ::= v | x | ?h | (e e*) | (λ (x*) e)
    | (let ((x e)*) e) | (if e e e)

Evaluation proceeds until it gets blocked by an aperture:

E[(+ n1 n2)] → n1 + n2           (arithmetic)
E[(+ ?h n)]  →p (+ ?h n)         (partial - blocked)
E[?h]        →p E[?h]            (aperture blocks)

Algebraic simplification happens during partial evaluation:

(* 0 ?x) →p 0
(+ 0 ?x) →p ?x
(* 1 ?x) →p ?x

These simplifications improve performance. They also leak information. If (* 0 ?x) reduces to 0, an observer learns the multiplier was zero without seeing ?x.

Coordination Patterns

Progressive refinement. Multiple parties fill apertures incrementally:

;; Initial query with holes
(select ?table
  (where (and (> ?col1 ?val1)
              (< ?col2 ?val2))))

;; Party A knows table structure
(fill query {table: "users", col1: "age", col2: "salary"})

;; Party B knows constraints
(fill query {val1: 18, val2: 100000})

Speculative compilation. The server compiles multiple code paths without knowing which will be used:

(case ?config
  [(fast) (quick-process data)]
  [(accurate) (slow-process data)]
  [(balanced) (hybrid-process data)])

Performance

Overhead compared to direct evaluation is 2-5%:

OperationDirect (us)With Apertures (us)Overhead
Arithmetic1271313.1%
List processing89934.5%
Lambda application1561645.1%

The overhead comes from hole checking and maintaining partial evaluation state. It is small because the mechanism is simple.

When Not to Use Apertures

I want to be clear about the limitations.

Adversarial settings: an adversary can infer values from structure and exploit evaluation patterns. High-sensitivity data: medical records, financial data, personal information. Apertures leak too much. Regulatory compliance: GDPR, HIPAA, financial regulations require stronger guarantees.

Here is a concrete example of leakage:

(if (> ?age 65)
    (discount 0.2)
    (if (< ?age 18)
        (discount 0.1)
        (no-discount)))

Even without seeing ?age, an observer learns that age-based discount tiers exist, the exact discount amounts, and the full business logic structure. If that matters, do not use apertures.

When Apertures Fit

They work when the computation structure is not sensitive, parties are honest-but-curious rather than adversarial, and performance matters more than perfect privacy. Scientific computing with public algorithms, optimization of non-sensitive business logic, collaborative debugging, educational systems.

The C++ implementation provides an S-expression parser with aperture syntax, a partial evaluator with algebraic simplification, hole tracking and filling, and stack-based evaluation with continuation frames.

The Point

Not every distributed computation needs cryptographic security. But all of them need honest accounting of their tradeoffs. Apertures fill the gap between “no coordination” and “full cryptographic protocol” with minimal overhead and no pretense about what they protect.

View the full workshop paper (PDF)

  • Partial Evaluation: Apertures extend partial evaluation with explicit holes for multi-party coordination
  • Homomorphic Encryption: Provides strong privacy with 1000-10000x overhead
  • Secure Multi-Party Computation: Cryptographic guarantees for adversarial settings
  • Staged Computation: Multi-stage programming for performance optimization

Discussion