File size: 7,794 Bytes
518343a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
// SPDX-License-Identifier: Apache-2.0
// © 2026 Lutar, Stephen P. — SZL Holdings
// ORCID: 0009-0001-0110-4173
//
// Layer 6 — a11oy policy gate for GaussianMechanismDP (G36)
//
// Policy rationale:
//   A DSSE receipt asserting differential privacy via the Gaussian mechanism
//   is accepted only if the declared noise scale σ_claimed satisfies the
//   calibration formula:
//     σ_claimed ≥ Δ₂f · √(2 ln(1.25/δ)) / ε
//   for the declared (ε, δ, Δ₂f) in the receipt header.
//   If σ_claimed is too small, the DP guarantee is void and the receipt is denied.
//
//   Lean theorem cited: `gaussianNoiseSufficiency`
//   Lean file: Lutar/DP/GaussianMechanism.lean
//   Lean commit SHA: 1dca00032dfc9aa8559cc6c2e4b63192fcf52371
//   Lean status: theorem (2 sorries in broader measure-theoretic proof;
//                gate-level arithmetic theorem has 0 sorries)
//   Severity: ENFORCED (calibration violation is a hard deny)
//
// References:
//   Dwork & Roth (2014). Algorithmic Foundations of DP.
//   DOI: https://doi.org/10.1561/0400000042
//   Balle & Wang (2018). arXiv:1805.06530

// ── Inline formula ─────────────────────────────────────────────────────────────
// G36: σ_min = Δ₂f · √(2 · ln(1.25 / δ)) / ε
// Gate passes iff σ_claimed ≥ σ_min

export interface GaussianMechanismDPGateConfig {
  /**
   * Minimum epsilon allowed (rejects receipts with ε below this floor).
   * Default: 1e-6 (no practical floor).
   */
  minEpsilon?: number;
  /**
   * Maximum delta allowed.
   * Default: 1e-3.
   */
  maxDelta?: number;
}

export interface GaussianMechanismDPGateOpts {
  /** Declared ε privacy parameter. Must be in (0, 1). */
  dp_epsilon: number;
  /** Declared δ failure probability. Must be in (0, 1). */
  dp_delta: number;
  /** Declared ℓ₂-sensitivity of the query Δ₂f. Must be > 0. */
  l2_sensitivity: number;
  /** Asserted noise scale σ used in the Gaussian mechanism. Must be > 0. */
  sigma_claimed: number;
}

export interface GaussianMechanismDPDecision {
  allow:                 boolean;
  rationale:             string;
  formula:               string;
  leanTheorem:           string;
  leanFile:              string;
  leanCommitSha:         string;
  dp_epsilon:            number;
  dp_delta:              number;
  l2_sensitivity:        number;
  sigma_claimed:         number;
  sigma_required:        number;
  dp_calibration_valid:  boolean;
  /** DSSE receipt extension fields for in-toto payload. */
  dsse_extension: {
    dp: {
      epsilon:           number;
      delta:             number;
      l2_sensitivity:    number;
      sigma_claimed:     number;
      sigma_required:    number;
      calibration_valid: boolean;
      lean_theorem_sha:  string;
    };
  };
}

const LEAN_THEOREM  = "gaussianNoiseSufficiency";
const LEAN_FILE     = "Lutar/DP/GaussianMechanism.lean";
const LEAN_COMMIT   = "1dca00032dfc9aa8559cc6c2e4b63192fcf52371";
const FORMULA_STR   =
  "σ_min = Δ₂f · √(2 · ln(1.25/δ)) / ε  [Dwork-Roth 2014, §A.1; DOI:10.1561/0400000042]";

/** Compute σ_min = Δ₂f · √(2 · ln(1.25/δ)) / ε. */
function computeSigmaRequired(l2_sensitivity: number, epsilon: number, delta: number): number {
  const logTerm = Math.log(1.25 / delta);        // ln(1.25/δ) > 0 for δ < 1.25
  const sqrtTerm = Math.sqrt(2 * logTerm);        // √(2 ln(1.25/δ))
  return (l2_sensitivity * sqrtTerm) / epsilon;   // Δ₂f · √… / ε
}

/**
 * GaussianMechanismDP (G36) policy gate.
 *
 * Accepts a DSSE receipt asserting Gaussian mechanism DP only if the claimed
 * noise scale satisfies the calibration formula from Dwork-Roth 2014.
 *
 * Lean theorem: `gaussianNoiseSufficiency` (Lutar/DP/GaussianMechanism.lean)
 * Commit: 1dca00032dfc9aa8559cc6c2e4b63192fcf52371
 * References:
 *   Dwork & Roth (2014) DOI:10.1561/0400000042
 *   Balle & Wang (2018) arXiv:1805.06530
 */
export function gaussianMechanismDPGate(
  config: GaussianMechanismDPGateConfig = {}
): (opts: GaussianMechanismDPGateOpts) => GaussianMechanismDPDecision {
  const minEpsilon = config.minEpsilon ?? 1e-6;
  const maxDelta   = config.maxDelta   ?? 1e-3;

  return (opts: GaussianMechanismDPGateOpts): GaussianMechanismDPDecision => {
    const { dp_epsilon, dp_delta, l2_sensitivity, sigma_claimed } = opts;

    // --- Input validation ---
    if (!Number.isFinite(dp_epsilon) || dp_epsilon <= 0 || dp_epsilon >= 1) {
      throw new Error(`GaussianMechanismDPGate: dp_epsilon must be in (0,1); got ${dp_epsilon}`);
    }
    if (!Number.isFinite(dp_delta) || dp_delta <= 0 || dp_delta >= 1) {
      throw new Error(`GaussianMechanismDPGate: dp_delta must be in (0,1); got ${dp_delta}`);
    }
    if (!Number.isFinite(l2_sensitivity) || l2_sensitivity <= 0) {
      throw new Error(`GaussianMechanismDPGate: l2_sensitivity must be > 0; got ${l2_sensitivity}`);
    }
    if (!Number.isFinite(sigma_claimed) || sigma_claimed <= 0) {
      throw new Error(`GaussianMechanismDPGate: sigma_claimed must be > 0; got ${sigma_claimed}`);
    }

    // --- Config bound checks ---
    if (dp_epsilon < minEpsilon) {
      return deny(opts, 0,
        `dp_epsilon ${dp_epsilon} below configured minEpsilon ${minEpsilon}`);
    }
    if (dp_delta > maxDelta) {
      return deny(opts, 0,
        `dp_delta ${dp_delta} exceeds configured maxDelta ${maxDelta}`);
    }

    // --- Core calibration check ---
    const sigma_required = computeSigmaRequired(l2_sensitivity, dp_epsilon, dp_delta);
    const dp_calibration_valid = sigma_claimed >= sigma_required;

    const allow = dp_calibration_valid;
    const rationale = allow
      ? `Lean:${LEAN_THEOREM} — σ_claimed (${sigma_claimed.toFixed(4)}) ≥ σ_required (${sigma_required.toFixed(4)}). Gaussian mechanism (ε=${dp_epsilon}, δ=${dp_delta}) calibration satisfied.`
      : `Lean:${LEAN_THEOREM} — DENY: σ_claimed (${sigma_claimed.toFixed(4)}) < σ_required (${sigma_required.toFixed(4)}). DP guarantee void for (ε=${dp_epsilon}, δ=${dp_delta}).`;

    return {
      allow,
      rationale,
      formula: FORMULA_STR,
      leanTheorem:          LEAN_THEOREM,
      leanFile:             LEAN_FILE,
      leanCommitSha:        LEAN_COMMIT,
      dp_epsilon,
      dp_delta,
      l2_sensitivity,
      sigma_claimed,
      sigma_required,
      dp_calibration_valid,
      dsse_extension: {
        dp: {
          epsilon:           dp_epsilon,
          delta:             dp_delta,
          l2_sensitivity,
          sigma_claimed,
          sigma_required,
          calibration_valid: dp_calibration_valid,
          lean_theorem_sha:  LEAN_COMMIT,  // gate uses commit SHA; CI replaces with file hash
        },
      },
    };
  };
}

/** Helper: build a deny decision. */
function deny(
  opts: GaussianMechanismDPGateOpts,
  sigma_required: number,
  reason: string
): GaussianMechanismDPDecision {
  return {
    allow: false,
    rationale: `Lean:${LEAN_THEOREM} — DENY: ${reason}`,
    formula: FORMULA_STR,
    leanTheorem:          LEAN_THEOREM,
    leanFile:             LEAN_FILE,
    leanCommitSha:        LEAN_COMMIT,
    dp_epsilon:           opts.dp_epsilon,
    dp_delta:             opts.dp_delta,
    l2_sensitivity:       opts.l2_sensitivity,
    sigma_claimed:        opts.sigma_claimed,
    sigma_required,
    dp_calibration_valid: false,
    dsse_extension: {
      dp: {
        epsilon:           opts.dp_epsilon,
        delta:             opts.dp_delta,
        l2_sensitivity:    opts.l2_sensitivity,
        sigma_claimed:     opts.sigma_claimed,
        sigma_required,
        calibration_valid: false,
        lean_theorem_sha:  LEAN_COMMIT,
      },
    },
  };
}