Prerequisites. Direct starred prerequisites: none. No later core chapter depends on this route.
Preservation and progress cannot distinguish the following command from an ordinary well-typed conditional: 𝐢𝐟 ℎ=0 𝐭𝐡𝐞𝐧 𝑙:=0 𝐞𝐥𝐬𝐞 𝑙:=1.(𝖫𝖾𝖺𝗄) Both branches assign integers. Nevertheless, an observer who may read the public variable 𝑙 learns whether the secret ℎ was zero. The missing invariant relates two runs: changing only secret inputs must not change public outputs. For the imperative language below, that relation is the exact termination-insensitive noninterference property to establish.
Stores, observations, and the security lattice
Fix a finite lattice (L, ⊑𝗌𝖾𝖼, ⊔,⊥). A security environment Γ :𝖵𝖺𝗋 →L assigns a fixed label to every mutable variable. Expressions and commands are 𝑒::=𝑘∣𝑥∣𝑒+𝑒,𝑏::=𝑒≤𝑒∣𝑒=𝑒,𝑐::=𝐬𝐤𝐢𝐩∣𝑥:=𝑒∣𝑐;𝑐∣𝐢𝐟 𝑏 𝐭𝐡𝐞𝐧 𝑐 𝐞𝐥𝐬𝐞 𝑐∣𝐰𝐡𝐢𝐥𝐞 𝑏 𝐝𝐨 𝑐. Stores map variables to integers. The deterministic big-step relation is ⟨𝑐,𝑠⟩ ⇓𝖨𝖥𝑠′; its assignment, sequence, conditional, and terminating-loop rules appear in appendix A. The theorem will quantify only over pairs of terminating derivations.
An observer at level 𝑜 sees the variables labelled at most 𝑜.
𝑠1≈𝑜Γ𝑠2⟺∀𝑥. Γ(𝑥)⊑𝗌𝖾𝖼𝑜⟹𝑠1(𝑥)=𝑠2(𝑥).
Referenced from 2 locations
On the two-point lattice 𝐿 ⊑𝗌𝖾𝖼𝐻, stores agreeing on 𝑙 :𝐿 are low-equivalent at 𝐿, regardless of their values at ℎ :𝐻. Taking 𝑠0(ℎ) =0 and 𝑠1(ℎ) =7 in (Leak) yields outputs with 𝑙 =0 and 𝑙 =1, so the command fails the relation.
Expression labels and command typing
The expression judgment Γ ⊢𝑒 :ℓ assigns an upper bound to every variable read by 𝑒: constants have label ⊥, a variable has label Γ(𝑥), and a compound expression joins the labels of its operands. Boolean guards use the same join.
Commands are checked under a program-counter label: Γ ⊢𝖨𝖥𝑝𝑐. The label 𝑝 records the information already revealed by control flow. Γ⊢𝑒:ℓ𝑝⊔ℓ⊑𝗌𝖾𝖼Γ(𝑥)Γ⊢𝖨𝖥𝑝𝑥:=𝑒IF−AssignΓ⊢𝖨𝖥𝑝𝑐1Γ⊢𝖨𝖥𝑝𝑐2Γ⊢𝖨𝖥𝑝𝑐1;𝑐2IF−Seq Γ⊢𝑏:ℓΓ⊢𝖨𝖥𝑝⊔ℓ𝑐1Γ⊢𝖨𝖥𝑝⊔ℓ𝑐2Γ⊢𝖨𝖥𝑝𝐢𝐟 𝑏 𝐭𝐡𝐞𝐧 𝑐1 𝐞𝐥𝐬𝐞 𝑐2IF−IfΓ⊢𝑏:ℓΓ⊢𝖨𝖥𝑝⊔ℓ𝑐Γ⊢𝖨𝖥𝑝𝐰𝐡𝐢𝐥𝐞 𝑏 𝐝𝐨 𝑐IF−While. The skip rule has no premise. In 𝖫𝖾𝖺𝗄, the branches are checked under 𝐻, but IF-Assign would require 𝐻 ⊑𝗌𝖾𝖼𝐿. The rejected derivation pinpoints the implicit flow.
If 𝑝 ⊑𝗌𝖾𝖼𝑝′ and Γ ⊢𝖨𝖥𝑝′𝑐, then Γ ⊢𝖨𝖥𝑝𝑐.
Referenced from 4 locations
Proof of Lemma 70.2 — Program-counter monotonicity
Proof. Induct on the typing derivation. In IF-Assign, 𝑝 ⊔ℓ ⊑𝗌𝖾𝖼𝑝′ ⊔ℓ ⊑𝗌𝖾𝖼Γ(𝑥). In IF-If and IF-While, monotonicity of join gives 𝑝 ⊔ℓ ⊑𝗌𝖾𝖼𝑝′ ⊔ℓ; apply the induction hypothesis to the premises. Sequence and skip are immediate. ◻
Write ⟨𝑐,𝑠⟩ ⟶𝖨𝖥⟨𝑐′,𝑠′⟩ for the deterministic small-step rules in appendix A. A conditional step removes a guard and thereby lowers the dynamic program counter. The preceding lemma supplies exactly the needed weakening.
If Γ ⊢𝖨𝖥𝑝𝑐 and ⟨𝑐,𝑠⟩ ⟶𝖨𝖥⟨𝑐′,𝑠′⟩, then Γ ⊢𝖨𝖥𝑝𝑐′.
Referenced from 2 locations
Proof of Proposition 70.3 — Subject reduction
Proof. By cases on the step. Assignment produces skip. A conditional selects a branch typed at 𝑝 ⊔ℓ; since 𝑝 ⊑𝗌𝖾𝖼𝑝 ⊔ℓ, apply lemma 70.2. While unfolds to a conditional followed by the loop, whose premises follow from IF-While. Sequence uses the induction hypothesis for its left component and retains the right premise. ◻
★☆☆ Erase 𝑝 from IF-Assign while leaving the branch rule unchanged. Construct a derivation for 𝖫𝖾𝖺𝗄, then calculate the two low-equivalent runs that refute noninterference.
Referenced from 4 locations
Agreement and confinement
Two lemmas divide the proof according to whether observed data are read or written.
If Γ ⊢𝑒 :ℓ, ℓ ⊑𝗌𝖾𝖼𝑜, and 𝑠1 ≈𝑜Γ𝑠2, then [[𝑒]]𝑠1 =[[𝑒]]𝑠2. The same holds for guards.
Referenced from 3 locations
Proof of Lemma 70.4 — Expression agreement, or simple security
Proof. Induct on 𝑒. In the variable case, Γ(𝑥) ⊑𝗌𝖾𝖼ℓ ⊑𝗌𝖾𝖼𝑜, so low equivalence gives the equality. Constants agree. For addition, each operand label flows to their join and therefore to 𝑜; apply both induction hypotheses. Guard evaluation follows from the two expression cases. ◻
If 𝑝⧸ ⊑𝗌𝖾𝖼𝑜, Γ ⊢𝖨𝖥𝑝𝑐, and ⟨𝑐,𝑠⟩ ⇓𝖨𝖥𝑠′, then 𝑠 ≈𝑜Γ𝑠′.
Referenced from 3 locations
Proof of Lemma 70.5 — High-context confinement
Proof. Induct on the evaluation derivation. For assignment to 𝑥, IF-Assign gives 𝑝 ⊑𝗌𝖾𝖼𝑝 ⊔ℓ ⊑𝗌𝖾𝖼Γ(𝑥). If Γ(𝑥) ⊑𝗌𝖾𝖼𝑜, transitivity would contradict 𝑝⧸ ⊑𝗌𝖾𝖼𝑜. Hence no observed variable changes. Sequence composes the two low-equivalences.
For a conditional, each selected branch is typed at 𝑝 ⊔ℓ. Since 𝑝 ⊑𝗌𝖾𝖼𝑝 ⊔ℓ, that label also fails to flow to 𝑜; apply the induction hypothesis to the selected branch. The false-loop rule changes no store. In the true-loop rule, apply the induction hypothesis first to the body and then to the recursive loop derivation, and use transitivity of low equivalence. ◻
The original Volpano–Irvine–Smith calculus phrases these facts as simple security, confinement, and a two-store soundness theorem [VIS96]. Its printed syntax-directed system uses command security types rather than our explicit program-counter judgment. The proof above belongs to the book’s stated calculus; the historical theorem is comparison evidence, not an implementation transfer.
★★☆ Prove that 𝑝 ⊑𝗌𝖾𝖼𝑝′ implies 𝑝 ⊔ℓ ⊑𝗌𝖾𝖼𝑝′ ⊔ℓ in any lattice. Use it to derive lemma 70.2 for IF-While in full.
Referenced from 3 locations
Two runs
The central argument is an unwinding proof over two terminating derivations. The low-guard case synchronizes their control choices; the high-guard case allows different choices but confines both.
Suppose Γ ⊢𝖨𝖥⊥𝑐, 𝑠1 ≈𝑜Γ𝑠2, and both runs terminate: ⟨𝑐,𝑠1⟩⇓𝖨𝖥𝑠′1,⟨𝑐,𝑠2⟩⇓𝖨𝖥𝑠′2. Then 𝑠′1 ≈𝑜Γ𝑠′2.
Referenced from 7 locations
Proof of Theorem 70.6 — Termination-insensitive noninterference
Proof. Prove the stronger statement for Γ ⊢𝖨𝖥𝑝𝑐, by induction on the first evaluation and case analysis on the second.
For 𝑥 :=𝑒, consider an observed target Γ(𝑥) ⊑𝗌𝖾𝖼𝑜. IF-Assign gives 𝑝 ⊔ℓ ⊑𝗌𝖾𝖼Γ(𝑥), hence ℓ ⊑𝗌𝖾𝖼𝑜. By lemma 70.4, both assignments store the same integer. Unobserved targets do not affect low equivalence. Sequence applies the induction hypothesis to the first commands and then to the second commands.
For a conditional with guard label ℓ, there are two cases. If ℓ ⊑𝗌𝖾𝖼𝑜, expression agreement makes both guards select the same branch. Apply the induction hypothesis to that branch, whose typing premise is at 𝑝 ⊔ℓ. If ℓ⧸ ⊑𝗌𝖾𝖼𝑜, then 𝑝 ⊔ℓ⧸ ⊑𝗌𝖾𝖼𝑜. Each run may select a different branch, but lemma 70.5 shows that each selected branch preserves its own initial low store. Transitivity through 𝑠1 ≈𝑜Γ𝑠2 relates the results.
For while with a low guard, expression agreement synchronizes zero iterations or one iteration. In the latter case, apply the induction hypothesis to the body and then to the two residual loop derivations. For a high guard, the whole terminating loop is confined: every body is typed at 𝑝 ⊔ℓ⧸ ⊑𝗌𝖾𝖼𝑜, so each finite iteration preserves its run’s low projection. The runs may execute different numbers of iterations; their final low projections still equal their respective initial ones. Skip is immediate. Instantiate the stronger statement with 𝑝 =⊥. ◻
The theorem deliberately assumes that both evaluations terminate. A program may loop exactly when ℎ =0; an observer who can detect termination learns a secret bit even though no low store cell changes. That is a termination-sensitive observation and is not covered by theorem 70.6.
★★☆ Repair 𝖫𝖾𝖺𝗄 in two ways: first by relabelling its destination, then by making the public result constant. Give the first typing derivation. Explain why the second program is semantically secure but still rejected by the syntax-directed rules when its assignments remain under a high guard.
Referenced from 3 locations
A complete password calculation
Let Γ(𝑝𝑤𝑑) =Γ(𝑔𝑢𝑒𝑠𝑠) =Γ(𝑎𝑢𝑑𝑖𝑡) =𝐻 and Γ(𝑠𝑡𝑎𝑡𝑢𝑠) =𝐿. Consider 𝐢𝐟 𝑝𝑤𝑑=𝑔𝑢𝑒𝑠𝑠 𝐭𝐡𝐞𝐧 𝑎𝑢𝑑𝑖𝑡:=1 𝐞𝐥𝐬𝐞 𝑎𝑢𝑑𝑖𝑡:=0;𝑠𝑡𝑎𝑡𝑢𝑠:=1.(𝖯𝖺𝗌𝗌𝗐𝗈𝗋𝖽𝖠𝗎𝖽𝗂𝗍) The guard has label 𝐻. Both branch assignments satisfy 𝐻 ⊔𝐿 =𝐻 ⊑𝗌𝖾𝖼𝐻 =Γ(𝑎𝑢𝑑𝑖𝑡). The final assignment is checked after the conditional, at program counter ⊥, so ⊥ ⊔⊥ ⊑𝗌𝖾𝖼𝐿. For any two initial stores agreeing on 𝑠𝑡𝑎𝑡𝑢𝑠, the branches may disagree on 𝑎𝑢𝑑𝑖𝑡, but confinement preserves the low projection; both final assignments then write 1 to 𝑠𝑡𝑎𝑡𝑢𝑠. Thus the complete two-run result is 𝑠1≈𝐿Γ𝑠2⟹𝑠′1[𝑠𝑡𝑎𝑡𝑢𝑠↦1]≈𝐿Γ𝑠′2[𝑠𝑡𝑎𝑡𝑢𝑠↦1]. Moving 𝑠𝑡𝑎𝑡𝑢𝑠 :=1 into only the successful branch would make the program rejected and genuinely leaking when the initial status differs from 1.
The checker as a finite abstract interpretation
Only after fixing the two-run semantics can we compare the type checker to an analysis. For a finite set of variables, abstract an expression to the join of labels of variables it reads. Abstract a command at program point 𝑝 to the predicate that every assignment 𝑥 :=𝑒 on a control path satisfies 𝑝 ⊔ℓ𝑒 ⊑𝗌𝖾𝖼Γ(𝑥), joining the guard label into 𝑝 below conditionals and loop bodies. Structural recursion computes this finite predicate; IF-Assign, IF-If, and IF-While are exactly its local transfer conditions.
Soundness of this analysis is theorem 70.6, not merely termination of the checker. It is incomplete: the constant-branch program 𝐢𝐟 ℎ=0 𝐭𝐡𝐞𝐧 𝑙:=0 𝐞𝐥𝐬𝐞 𝑙:=0 is noninterfering but rejected because the abstraction retains the high control dependency and does not prove equality of branch results. The more flow- and path-sensitive analysis of Li and Zhang and the ownership-oriented Flowistry system refine different components of this abstraction [LZ17, CPAH22]. Neither paper’s theorem transfers to this fixed-variable calculus without an explicit translation.
★★★ For each program below, decide whether it is accepted, semantically noninterfering, both, or neither. Justify each semantic answer with two runs or an unwinding argument. (𝑎)𝑙:=0;(𝑏)𝐢𝐟 ℎ=0 𝐭𝐡𝐞𝐧 𝑙:=0 𝐞𝐥𝐬𝐞 𝑙:=0;(𝑐)𝐢𝐟 ℎ=0 𝐭𝐡𝐞𝐧 𝑙:=0 𝐞𝐥𝐬𝐞 𝑙:=1;(𝑑)ℎ:=𝑙+1.
Referenced from 3 locations
A bounded DCC comparison
The Dependency Core Calculus protects a value at label ℓ with a type 𝑇ℓ𝐴. This is a separate, functional theorem card. It does not replace the imperative two-run proof.
Algehed and Bernardy first prove a shallow relational-parametricity theorem. For their shallow DCC module 𝑑𝑐𝑐, a type 𝐴, observer ̂ℓ, and protected label ℓ⧸ ⊑𝗌𝖾𝖼̂ℓ, every 𝑓:(𝑑𝑐𝑐:𝖣𝖢𝖢)→(𝑇 𝑑𝑐𝑐 ℓ 𝐴)→(𝑇 𝑑𝑐𝑐 ̂ℓ 𝖡𝗈𝗈𝗅) returns equal results on any two protected inputs. This is their Theorem 3.
Their Definition 4 interprets deep DCC types and terms in the shallow module. Theorem 5 says the translation preserves typing. Theorem 6 says one deep DCC step translates to definitional equality; its bind-return case assumes the right-unit law for the selected DCC module. Strong normalization and confluence then reflect equality at protected Boolean values.
Let 𝐴 be a DCC type, let ℓ⧸ ⊑𝗌𝖾𝖼̂ℓ, and let 𝑒:𝑇ℓ𝐴→𝑇̂ℓ𝖡𝗈𝗈𝗅 be a closed deep DCC term. For closed 𝑎0,𝑎1 :𝐴, 𝑒(𝗋𝖾𝗍𝗎𝗋𝗇ℓ𝑎0)=𝛽𝑒(𝗋𝖾𝗍𝗎𝗋𝗇ℓ𝑎1).
Referenced from 2 locations
Proof of Theorem 70.7 — Original-DCC noninterference
Proof. By translation type preservation, [[𝑒]] has the shallow type needed by Theorem 3. Apply that theorem to [[𝑎0]] and [[𝑎1]]: [[𝑒]](𝗋𝖾𝗍𝗎𝗋𝗇ℓ[[𝑎0]])≡[[𝑒]](𝗋𝖾𝗍𝗎𝗋𝗇ℓ[[𝑎1]]). Definition 4 identifies these terms with the translations of the two deep applications. Theorem 6 carries each deep reduction to definitional equality. Strong normalization and confluence put the closed protected Booleans in canonical return forms; the Boolean reflection corollary makes their deep normal forms equal. One beta expansion on each side yields the displayed equation. This is precisely the route through Theorems 3, 5, and 6 used to derive Algehed–Bernardy Theorem 8 [AB19]. ◻
The pinned Agda fixture exposes its assumptions rather than hiding them: lattice structure is postulated in Definitions.agda; function extensionality, strong normalization of deep DCC, a separating observer, and shallow noninterference appear as named postulates in Translation.agda. The artifact is hole-free at its pinned commit, but the local environment used for this edition has no Agda executable, so Appendix E records hashes and a static hole scan rather than claiming a fresh typecheck.
This comparison covers the original DCC Boolean-observation theorem only. It does not establish termination-sensitive security, declassification, term-sensitive relations, quantitative leakage, or results for other DCC variants. The Haskell adaptation in the paper explicitly remains termination-insensitive because partiality exposes a termination channel.
Chapter seminar
The Kappa companion at artifacts/ch70-tini-checker/ implements the two-point instance, the syntax-directed checker, a fuel-bounded evaluator, and finite two-run tests. The finite enumeration tests the implementation; the proof of theorem 70.6 quantifies over every terminating derivation.
The first two tasks form the practical route. Later tasks change the observation and therefore require a new theorem statement.
Suggested first pass.
Run the leak and audit examples, then inspect why the secure constant-branch program is rejected before modifying the checker.
★★★ Practical project.imperative-tini-checker Run the accepted corpus. Remove the program-counter join from conditional checking and confirm that the unchanged leak oracle fails. Add a third lattice point 𝑀 with 𝐿 ⊑𝗌𝖾𝖼𝑀 ⊑𝗌𝖾𝖼𝐻, and test one permitted 𝐿-to-𝑀 assignment and one rejected 𝐻-to-𝑀 assignment.
Referenced from 4 locations
★★★ Write the complete high-guard while case of theorem 70.6, including the induction on each finite evaluation and the two transitivity steps for low equivalence.
Referenced from 3 locations
★★★ Give two low-equivalent stores for a program that terminates exactly when ℎ =0. Define an observation that includes termination, and show precisely which premise or conclusion of theorem 70.6 must change.
Referenced from 3 locations
★★★ Design a command that intentionally releases the parity of ℎ. State a declassification policy and a corresponding two-run relation. Explain why the original low-equivalence theorem cannot certify the program.
Referenced from 3 locations
The principal result is termination-insensitive two-run noninterference for a sequential, deterministic, fixed-label store language. Concurrency, declassification, probabilistic observations, quantitative leakage, and termination-sensitive security require different observations and proof relations; they are not variants silently covered by the theorem above.