Spaces:
Running
Running
File size: 7,185 Bytes
518343a e956545 518343a e956545 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 | // SPDX-License-Identifier: Apache-2.0
// © 2026 Lutar, Stephen P. — SZL Holdings
// ORCID: 0009-0001-0110-4173
//
// Layer 6 — a11oy policy gate for RDPSequentialComposition (G38)
//
// Policy rationale:
// For a pipeline of k steps each satisfying (α, εᵢ)-RDP, the sequential
// composition is (α, Σεᵢ)-RDP (Mironov 2017, Proposition 1).
// Converting to (ε_dp, δ)-DP: ε_dp = Σεᵢ + ln(1/δ)/(α-1).
// The gate accepts a chained receipt only if ε_dp ≤ declared budget ceiling.
//
// Lean theorem cited: `rdpSequentialCompositionAdditivity`
// Lean file: Lutar/DP/RDPComposition.lean
// Lean commit SHA: b675cd84caa17080671570c153484c817f8769ac
// Lean status: theorem (2 sorries for measure-theoretic Rényi divergence;
// budget arithmetic predicate `rdpBudgetValid` has 0 sorries)
// Severity: ENFORCED
//
// References:
// Mironov (2017). "Rényi Differential Privacy."
// IEEE CSF 2017. arXiv:1702.07476. DOI:10.1109/CSF.2017.11
// Rényi (1961). Proc. 4th Berkeley Symposium 1, 547–561.
// https://projecteuclid.org/euclid.bsmsp/1200512181
// ── Inline formula ─────────────────────────────────────────────────────────────
// G38: ε_total = Σᵢ εᵢ (composition, same α)
// ε_dp = ε_total + ln(1/δ) / (α - 1) (conversion to (ε,δ)-DP)
// Gate passes iff ε_dp ≤ budget_threshold.
export interface RDPCompositionGateConfig {
/**
* Default Rényi order α if not declared per-receipt.
* Must be > 1. Default: 8.0 (common choice for Gaussian mechanism).
*/
defaultAlpha?: number;
/**
* Default δ for RDP → DP conversion if not declared.
* Default: 1e-5.
*/
defaultDelta?: number;
}
export interface RDPCompositionGateOpts {
/** Rényi order α > 1. */
rdp_alpha: number;
/** Per-step RDP ε values (one per sequential mechanism call). */
rdp_epsilon_steps: number[];
/** δ for the (ε, δ)-DP conversion. */
dp_delta: number;
/** Declared ε budget ceiling. */
budget_epsilon_threshold: number;
}
export interface RDPCompositionDecision {
allow: boolean;
rationale: string;
formula: string;
leanTheorem: string;
leanFile: string;
leanCommitSha: string;
rdp_alpha: number;
rdp_epsilon_total: number;
dp_epsilon_converted: number;
dp_delta: number;
budget_epsilon_threshold: number;
rdp_budget_valid: boolean;
step_count: number;
dsse_extension: {
rdp_accounting: {
alpha: number;
steps: number[];
epsilon_total_rdp: number;
delta: number;
epsilon_dp_converted: number;
budget_threshold: number;
budget_valid: boolean;
lean_theorem_sha: string;
};
};
}
const LEAN_THEOREM = "rdpSequentialCompositionAdditivity";
const LEAN_FILE = "Lutar/DP/RDPComposition.lean";
const LEAN_COMMIT = "b675cd84caa17080671570c153484c817f8769ac";
const FORMULA_STR =
"ε_dp = Σᵢεᵢ + ln(1/δ)/(α−1) [Mironov 2017 Prop.1+3; arXiv:1702.07476; DOI:10.1109/CSF.2017.11]";
/**
* Compute total (α, Σεᵢ)-RDP cost from steps, then convert to (ε_dp, δ)-DP.
* Mironov 2017 Proposition 1 (composition) and Proposition 3 (conversion).
*/
function computeRDPBudget(
alpha: number,
epsilonSteps: number[],
delta: number
): { epsilon_total_rdp: number; epsilon_dp_converted: number } {
// Composition: (α, ε₁)-RDP + (α, ε₂)-RDP = (α, ε₁+ε₂)-RDP
const epsilon_total_rdp = epsilonSteps.reduce((s, e) => s + e, 0);
// Conversion: (α, ε_rdp)-RDP → (ε_rdp + ln(1/δ)/(α-1), δ)-DP
const epsilon_dp_converted = epsilon_total_rdp + Math.log(1 / delta) / (alpha - 1);
return { epsilon_total_rdp, epsilon_dp_converted };
}
/**
* RDPSequentialComposition (G38) policy gate.
*
* Verifies that the cumulative RDP privacy budget across k sequential
* mechanism calls, converted to (ε, δ)-DP, does not exceed the declared ceiling.
*
* Lean theorem: `rdpSequentialCompositionAdditivity` (Lutar/DP/RDPComposition.lean)
* Reference: Mironov (2017) arXiv:1702.07476.
*/
export function rdpCompositionGate(
config: RDPCompositionGateConfig = {}
): (opts: RDPCompositionGateOpts) => RDPCompositionDecision {
const defaultAlpha = config.defaultAlpha ?? 8.0;
const defaultDelta = config.defaultDelta ?? 1e-5;
return (opts: RDPCompositionGateOpts): RDPCompositionDecision => {
const {
rdp_alpha,
rdp_epsilon_steps,
dp_delta,
budget_epsilon_threshold,
} = opts;
// --- Input validation ---
if (!Number.isFinite(rdp_alpha) || rdp_alpha <= 1) {
throw new Error(`RDPCompositionGate: rdp_alpha must be > 1; got ${rdp_alpha}`);
}
if (!Array.isArray(rdp_epsilon_steps) || rdp_epsilon_steps.length === 0) {
throw new Error("RDPCompositionGate: rdp_epsilon_steps must be a non-empty array");
}
for (const e of rdp_epsilon_steps) {
if (!Number.isFinite(e) || e < 0) {
throw new Error(`RDPCompositionGate: all RDP ε steps must be ≥ 0; got ${e}`);
}
}
if (!Number.isFinite(dp_delta) || dp_delta <= 0 || dp_delta >= 1) {
throw new Error(`RDPCompositionGate: dp_delta must be in (0,1); got ${dp_delta}`);
}
// --- Core accounting ---
const { epsilon_total_rdp, epsilon_dp_converted } = computeRDPBudget(
rdp_alpha, rdp_epsilon_steps, dp_delta
);
const rdp_budget_valid = epsilon_dp_converted <= budget_epsilon_threshold;
const rationale = rdp_budget_valid
? `Lean:${LEAN_THEOREM} — RDP budget valid. ε_rdp=${epsilon_total_rdp.toFixed(6)}, ε_dp=${epsilon_dp_converted.toFixed(6)} ≤ budget=${budget_epsilon_threshold}. α=${rdp_alpha}, k=${rdp_epsilon_steps.length} steps.`
: `Lean:${LEAN_THEOREM} — DENY: ε_dp=${epsilon_dp_converted.toFixed(6)} exceeds budget=${budget_epsilon_threshold}. (α=${rdp_alpha}, Σεᵢ=${epsilon_total_rdp.toFixed(6)}, δ=${dp_delta})`;
return {
allow: rdp_budget_valid,
rationale,
formula: FORMULA_STR,
leanTheorem: LEAN_THEOREM,
leanFile: LEAN_FILE,
leanCommitSha: LEAN_COMMIT,
rdp_alpha,
rdp_epsilon_total: epsilon_total_rdp,
dp_epsilon_converted: epsilon_dp_converted,
dp_delta,
budget_epsilon_threshold,
rdp_budget_valid,
step_count: rdp_epsilon_steps.length,
dsse_extension: {
rdp_accounting: {
alpha: rdp_alpha,
steps: rdp_epsilon_steps,
epsilon_total_rdp,
delta: dp_delta,
epsilon_dp_converted,
budget_threshold: budget_epsilon_threshold,
budget_valid: rdp_budget_valid,
lean_theorem_sha: LEAN_COMMIT,
},
},
};
};
}
|