Shuya Feng
commited on
Commit
·
6264b1a
1
Parent(s):
7bfe1af
Enhanced privacy attack visualizations and DP-SGD defense explanations
Browse filesMajor improvements:
- Replaced digit 7 with realistic medical patient records in membership inference
- Fixed tab overlap with responsive flex layout
- Added concrete 4x4 grid visualization for data reconstruction with varying privacy levels
- Implemented dynamic Model Inversion attack with privacy-based noise/blur
- Added privacy sliders and real-time feedback for Property Inference
- Fixed linkage attack logic (correct epsilon to success rate mapping)
- Removed redundant privacy indicator bars for cleaner UI
- Added personalized DP-SGD defense cards within each attack section
- Each defense explanation is specific to its attack type with unique analogies
- app/static/js/attacks.js +697 -30
- app/templates/attacks.html +689 -91
app/static/js/attacks.js
CHANGED
|
@@ -336,8 +336,8 @@ class AttackSimulator {
|
|
| 336 |
const successRate = successRates[privacyLevel - 1];
|
| 337 |
|
| 338 |
// Update confidence differences based on privacy
|
| 339 |
-
const confidenceDiffs = [
|
| 340 |
-
const trainingConf = [
|
| 341 |
const testConf = trainingConf.map((tc, i) => tc - confidenceDiffs[i]); // Test confidence
|
| 342 |
|
| 343 |
const currentTrainingConf = trainingConf[privacyLevel - 1];
|
|
@@ -382,35 +382,156 @@ class AttackSimulator {
|
|
| 382 |
const clipping = parseFloat(document.getElementById('recon-clipping-slider').value);
|
| 383 |
const noise = parseFloat(document.getElementById('recon-noise-slider').value);
|
| 384 |
|
| 385 |
-
// Calculate reconstruction quality
|
| 386 |
const baseQuality = 0.95;
|
| 387 |
-
const clippingReduction = (5 - clipping) * 0.
|
| 388 |
-
const noiseReduction = noise * 0.
|
| 389 |
|
| 390 |
-
const quality = Math.max(0.
|
|
|
|
| 391 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 392 |
const qualityElement = document.getElementById('recon-quality');
|
| 393 |
-
if (
|
| 394 |
-
|
| 395 |
-
|
| 396 |
-
|
| 397 |
-
|
| 398 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 399 |
} else {
|
| 400 |
-
|
| 401 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 402 |
}
|
| 403 |
}
|
| 404 |
|
| 405 |
updateLinkageAttack() {
|
| 406 |
const quality = parseInt(document.getElementById('linkage-quality-slider').value);
|
| 407 |
-
const
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 408 |
|
| 409 |
// Calculate linkage success
|
| 410 |
-
|
| 411 |
-
|
|
|
|
|
|
|
| 412 |
|
| 413 |
-
|
|
|
|
| 414 |
|
| 415 |
document.getElementById('linkage-success').textContent = `${Math.round(successRate)}%`;
|
| 416 |
|
|
@@ -447,6 +568,9 @@ function runReconstructionAttack() {
|
|
| 447 |
const simulator = window.attackSimulator;
|
| 448 |
simulator.updateReconstructionAttack();
|
| 449 |
|
|
|
|
|
|
|
|
|
|
| 450 |
// Add visual feedback
|
| 451 |
const button = event.target;
|
| 452 |
const originalText = button.textContent;
|
|
@@ -464,15 +588,42 @@ function runInversionAttack() {
|
|
| 464 |
const privacySlider = document.getElementById('inversion-privacy-slider');
|
| 465 |
|
| 466 |
const selectedClass = classSelect.value;
|
| 467 |
-
const
|
| 468 |
|
| 469 |
-
//
|
| 470 |
-
const
|
| 471 |
-
|
|
|
|
| 472 |
|
| 473 |
-
// Update
|
|
|
|
| 474 |
document.getElementById('inversion-class').textContent = classSelect.options[classSelect.selectedIndex].text;
|
| 475 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 476 |
// Add visual feedback
|
| 477 |
const button = event.target;
|
| 478 |
const originalText = button.textContent;
|
|
@@ -485,20 +636,119 @@ function runInversionAttack() {
|
|
| 485 |
}, 1800);
|
| 486 |
}
|
| 487 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 488 |
function runPropertyAttack() {
|
| 489 |
const propertyType = document.getElementById('property-type').value;
|
| 490 |
const accessLevel = parseInt(document.getElementById('property-access-slider').value);
|
|
|
|
|
|
|
| 491 |
|
| 492 |
-
// Calculate property inference accuracy
|
| 493 |
-
|
|
|
|
| 494 |
const accessBonus = accessLevel * 8;
|
| 495 |
-
const
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 496 |
|
| 497 |
-
// Update
|
| 498 |
-
const
|
|
|
|
| 499 |
|
| 500 |
-
|
| 501 |
-
document.getElementById('property-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 502 |
|
| 503 |
// Add visual feedback
|
| 504 |
const button = event.target;
|
|
@@ -512,6 +762,10 @@ function runPropertyAttack() {
|
|
| 512 |
}, 2200);
|
| 513 |
}
|
| 514 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 515 |
function runLinkageAttack() {
|
| 516 |
const simulator = window.attackSimulator;
|
| 517 |
simulator.updateLinkageAttack();
|
|
@@ -528,6 +782,303 @@ function runLinkageAttack() {
|
|
| 528 |
}, 2500);
|
| 529 |
}
|
| 530 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 531 |
// Initialize when page loads
|
| 532 |
document.addEventListener('DOMContentLoaded', function() {
|
| 533 |
window.attackSimulator = new AttackSimulator();
|
|
@@ -536,4 +1087,120 @@ document.addEventListener('DOMContentLoaded', function() {
|
|
| 536 |
window.attackSimulator.updateMembershipDemo();
|
| 537 |
window.attackSimulator.updateReconstructionAttack();
|
| 538 |
window.attackSimulator.updateLinkageAttack();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 539 |
});
|
|
|
|
| 336 |
const successRate = successRates[privacyLevel - 1];
|
| 337 |
|
| 338 |
// Update confidence differences based on privacy
|
| 339 |
+
const confidenceDiffs = [8, 12, 18, 24, 28]; // Confidence differences
|
| 340 |
+
const trainingConf = [76, 80, 86, 92, 96]; // Training confidence
|
| 341 |
const testConf = trainingConf.map((tc, i) => tc - confidenceDiffs[i]); // Test confidence
|
| 342 |
|
| 343 |
const currentTrainingConf = trainingConf[privacyLevel - 1];
|
|
|
|
| 382 |
const clipping = parseFloat(document.getElementById('recon-clipping-slider').value);
|
| 383 |
const noise = parseFloat(document.getElementById('recon-noise-slider').value);
|
| 384 |
|
| 385 |
+
// Calculate reconstruction quality (SSIM score)
|
| 386 |
const baseQuality = 0.95;
|
| 387 |
+
const clippingReduction = (5 - clipping) * 0.08;
|
| 388 |
+
const noiseReduction = noise * 0.22;
|
| 389 |
|
| 390 |
+
const quality = Math.max(0.05, baseQuality - clippingReduction - noiseReduction);
|
| 391 |
+
const ssimScore = quality.toFixed(2);
|
| 392 |
|
| 393 |
+
// Update SSIM score display
|
| 394 |
+
const ssimElement = document.getElementById('ssim-score');
|
| 395 |
+
if (ssimElement) {
|
| 396 |
+
ssimElement.textContent = ssimScore;
|
| 397 |
+
ssimElement.style.color = quality > 0.7 ? '#dc3545' : quality > 0.4 ? '#f57c00' : '#28a745';
|
| 398 |
+
}
|
| 399 |
+
|
| 400 |
+
// Update quality badge
|
| 401 |
const qualityElement = document.getElementById('recon-quality');
|
| 402 |
+
if (qualityElement) {
|
| 403 |
+
if (quality > 0.7) {
|
| 404 |
+
qualityElement.textContent = '❌ High Quality (Vulnerable!)';
|
| 405 |
+
qualityElement.className = 'reconstruction-quality quality-high';
|
| 406 |
+
} else if (quality > 0.4) {
|
| 407 |
+
qualityElement.textContent = '⚠️ Medium Quality';
|
| 408 |
+
qualityElement.className = 'reconstruction-quality quality-medium';
|
| 409 |
+
} else {
|
| 410 |
+
qualityElement.textContent = '✅ Low Quality (Protected!)';
|
| 411 |
+
qualityElement.className = 'reconstruction-quality quality-low';
|
| 412 |
+
}
|
| 413 |
+
}
|
| 414 |
+
|
| 415 |
+
// Calculate privacy level
|
| 416 |
+
const epsilon = Math.max(0.5, 10 - (clipping * 0.5 + noise * 2));
|
| 417 |
+
const privacyStatus = document.getElementById('privacy-status');
|
| 418 |
+
if (privacyStatus) {
|
| 419 |
+
if (epsilon > 6) {
|
| 420 |
+
privacyStatus.textContent = `❌ Low (ε ≈ ${epsilon.toFixed(1)})`;
|
| 421 |
+
privacyStatus.style.color = '#dc3545';
|
| 422 |
+
} else if (epsilon > 3) {
|
| 423 |
+
privacyStatus.textContent = `⚠️ Medium (ε ≈ ${epsilon.toFixed(1)})`;
|
| 424 |
+
privacyStatus.style.color = '#f57c00';
|
| 425 |
+
} else {
|
| 426 |
+
privacyStatus.textContent = `✅ High (ε ≈ ${epsilon.toFixed(1)})`;
|
| 427 |
+
privacyStatus.style.color = '#28a745';
|
| 428 |
+
}
|
| 429 |
+
}
|
| 430 |
+
|
| 431 |
+
// Update attack success rate
|
| 432 |
+
const attackSuccess = Math.round(quality * 100);
|
| 433 |
+
const attackSuccessElement = document.getElementById('attack-success');
|
| 434 |
+
if (attackSuccessElement) {
|
| 435 |
+
attackSuccessElement.textContent = `${attackSuccess}%`;
|
| 436 |
+
attackSuccessElement.style.color = attackSuccess > 70 ? '#dc3545' : attackSuccess > 40 ? '#f57c00' : '#28a745';
|
| 437 |
+
}
|
| 438 |
+
|
| 439 |
+
// Update reconstructed image visualization
|
| 440 |
+
this.updateReconstructedImage(quality, noise);
|
| 441 |
+
|
| 442 |
+
// Update explanation
|
| 443 |
+
const explanationElement = document.getElementById('recon-explanation');
|
| 444 |
+
if (explanationElement) {
|
| 445 |
+
if (quality > 0.7) {
|
| 446 |
+
explanationElement.textContent = '⚠️ Without sufficient privacy protection, attackers can reconstruct training images with high fidelity from gradient information alone!';
|
| 447 |
+
explanationElement.style.background = '#fff3cd';
|
| 448 |
+
explanationElement.style.borderLeft = '4px solid #ffc107';
|
| 449 |
+
} else if (quality > 0.4) {
|
| 450 |
+
explanationElement.textContent = '🛡️ Medium privacy protection degrades reconstruction quality, but some features may still be visible. Consider increasing noise level.';
|
| 451 |
+
explanationElement.style.background = '#fff3e0';
|
| 452 |
+
explanationElement.style.borderLeft = '4px solid #f57c00';
|
| 453 |
+
} else {
|
| 454 |
+
explanationElement.textContent = '✅ Excellent! With strong differential privacy, reconstructed images are too noisy to reveal sensitive information. Training data is well protected!';
|
| 455 |
+
explanationElement.style.background = '#e8f5e9';
|
| 456 |
+
explanationElement.style.borderLeft = '4px solid #28a745';
|
| 457 |
+
}
|
| 458 |
+
}
|
| 459 |
+
}
|
| 460 |
+
|
| 461 |
+
updateReconstructedImage(quality, noise) {
|
| 462 |
+
const reconstructedImg = document.getElementById('reconstructed-img');
|
| 463 |
+
const privacyOverlay = document.getElementById('privacy-overlay');
|
| 464 |
+
const leakStatus = document.getElementById('leak-status');
|
| 465 |
+
const modelPrivacyLevel = document.getElementById('model-privacy-level');
|
| 466 |
+
|
| 467 |
+
if (!reconstructedImg) return;
|
| 468 |
+
|
| 469 |
+
// Calculate epsilon for display
|
| 470 |
+
const epsilon = Math.max(0.5, 10 - (parseFloat(document.getElementById('recon-clipping-slider').value) * 0.5 + noise * 2));
|
| 471 |
+
if (modelPrivacyLevel) {
|
| 472 |
+
modelPrivacyLevel.textContent = `ε = ${epsilon.toFixed(1)}`;
|
| 473 |
+
}
|
| 474 |
+
|
| 475 |
+
if (quality < 0.4) {
|
| 476 |
+
// High privacy - show heavily obscured/protected image with overlay
|
| 477 |
+
const svg = `data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 400 500'%3E%3Cdefs%3E%3Cfilter id='heavynoise'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='${1.5 + noise * 0.5}' numOctaves='8' /%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3ClinearGradient id='protectgrad' x1='0%25' y1='0%25' x2='100%25' y2='100%25'%3E%3Cstop offset='0%25' style='stop-color:%23e8f5e9;stop-opacity:1' /%3E%3Cstop offset='100%25' style='stop-color:%23c8e6c9;stop-opacity:1' /%3E%3C/linearGradient%3E%3C/defs%3E%3Crect width='400' height='500' fill='url(%23protectgrad)'/%3E%3Crect width='400' height='500' fill='gray' opacity='0.95' filter='url(%23heavynoise)'/%3E%3C/svg%3E`;
|
| 478 |
+
reconstructedImg.src = svg;
|
| 479 |
+
|
| 480 |
+
if (privacyOverlay) {
|
| 481 |
+
privacyOverlay.style.display = 'flex';
|
| 482 |
+
privacyOverlay.innerHTML = '<div style="font-size: 3rem;">🔒</div><div>PROTECTED</div>';
|
| 483 |
+
}
|
| 484 |
+
|
| 485 |
+
if (leakStatus) {
|
| 486 |
+
leakStatus.innerHTML = '✅ ATTACK<br/>FAILED!';
|
| 487 |
+
leakStatus.style.color = '#28a745';
|
| 488 |
+
}
|
| 489 |
+
} else if (quality < 0.7) {
|
| 490 |
+
// Medium privacy - show partially obscured image
|
| 491 |
+
const svg = `data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 400 500'%3E%3Cdefs%3E%3Cfilter id='mednoise'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='${0.8 + noise * 0.3}' numOctaves='5' /%3E%3CfeColorMatrix type='saturate' values='0.2'/%3E%3C/filter%3E%3ClinearGradient id='medgrad' x1='0%25' y1='0%25' x2='100%25' y2='100%25'%3E%3Cstop offset='0%25' style='stop-color:%23fff3e0;stop-opacity:1' /%3E%3Cstop offset='100%25' style='stop-color:%23ffe0b2;stop-opacity:1' /%3E%3C/linearGradient%3E%3C/defs%3E%3Crect width='400' height='500' fill='url(%23medgrad)'/%3E%3Crect width='400' height='500' fill='gray' opacity='${0.5 + noise * 0.15}' filter='url(%23mednoise)'/%3E%3Cellipse cx='200' cy='180' rx='80' ry='90' fill='%238b6f47' opacity='0.25'/%3E%3Crect x='140' y='260' width='120' height='160' fill='%236b8e6b' opacity='0.2' rx='8'/%3E%3C/svg%3E`;
|
| 492 |
+
reconstructedImg.src = svg;
|
| 493 |
+
|
| 494 |
+
if (privacyOverlay) {
|
| 495 |
+
privacyOverlay.style.display = 'none';
|
| 496 |
+
}
|
| 497 |
+
|
| 498 |
+
if (leakStatus) {
|
| 499 |
+
leakStatus.innerHTML = '⚠️ PARTIAL<br/>LEAK';
|
| 500 |
+
leakStatus.style.color = '#f57c00';
|
| 501 |
+
}
|
| 502 |
} else {
|
| 503 |
+
// Low privacy - show clear reconstruction (vulnerable)
|
| 504 |
+
const svg = `data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 400 500'%3E%3Cdefs%3E%3Cfilter id='lightnoise'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='${0.3 + noise * 0.1}' numOctaves='2' /%3E%3CfeColorMatrix type='saturate' values='0.4'/%3E%3C/filter%3E%3ClinearGradient id='vulngrad' x1='0%25' y1='0%25' x2='100%25' y2='100%25'%3E%3Cstop offset='0%25' style='stop-color:%23e8b4b8;stop-opacity:1' /%3E%3Cstop offset='100%25' style='stop-color:%23d4a5a8;stop-opacity:1' /%3E%3C/linearGradient%3E%3C/defs%3E%3Crect width='400' height='500' fill='url(%23vulngrad)'/%3E%3Crect width='400' height='500' fill='gray' opacity='${0.15 + noise * 0.05}' filter='url(%23lightnoise)'/%3E%3Cellipse cx='200' cy='180' rx='80' ry='90' fill='%238b6f47' opacity='0.5'/%3E%3Crect x='140' y='260' width='120' height='160' fill='%236b8e6b' opacity='0.4' rx='8'/%3E%3Ccircle cx='280' cy='140' r='35' fill='%23fff' opacity='0.2'/%3E%3Crect x='80' y='350' width='240' height='100' fill='%23a0826d' opacity='0.3' rx='6'/%3E%3C/svg%3E`;
|
| 505 |
+
reconstructedImg.src = svg;
|
| 506 |
+
|
| 507 |
+
if (privacyOverlay) {
|
| 508 |
+
privacyOverlay.style.display = 'none';
|
| 509 |
+
}
|
| 510 |
+
|
| 511 |
+
if (leakStatus) {
|
| 512 |
+
leakStatus.innerHTML = '🚨 LEAKED<br/>PRIVATE DATA!';
|
| 513 |
+
leakStatus.style.color = '#c1272d';
|
| 514 |
+
}
|
| 515 |
}
|
| 516 |
}
|
| 517 |
|
| 518 |
updateLinkageAttack() {
|
| 519 |
const quality = parseInt(document.getElementById('linkage-quality-slider').value);
|
| 520 |
+
const privacySlider = parseInt(document.getElementById('linkage-privacy-slider').value);
|
| 521 |
+
|
| 522 |
+
// Calculate epsilon: epsilon = 11 - privacySlider
|
| 523 |
+
// privacySlider = 1 → ε = 10.0 (LOW privacy, HIGH success)
|
| 524 |
+
// privacySlider = 10 → ε = 1.0 (HIGH privacy, LOW success)
|
| 525 |
+
const epsilon = 11 - privacySlider;
|
| 526 |
|
| 527 |
// Calculate linkage success
|
| 528 |
+
// Higher quality = easier to link (increases success)
|
| 529 |
+
// Higher epsilon (lower privacy) = easier to link (increases success)
|
| 530 |
+
const qualityBonus = quality * 10; // Quality factor (0-60)
|
| 531 |
+
const epsilonBonus = epsilon * 4; // Epsilon: 1.0 (high privacy) = 4, 10.0 (low privacy) = 40
|
| 532 |
|
| 533 |
+
// Base success is 20%, add quality scaled by epsilon influence
|
| 534 |
+
const successRate = Math.max(15, Math.min(95, 20 + qualityBonus * (epsilon / 10)));
|
| 535 |
|
| 536 |
document.getElementById('linkage-success').textContent = `${Math.round(successRate)}%`;
|
| 537 |
|
|
|
|
| 568 |
const simulator = window.attackSimulator;
|
| 569 |
simulator.updateReconstructionAttack();
|
| 570 |
|
| 571 |
+
// Update the canvas examples
|
| 572 |
+
updateCurrentReconstructionExamples();
|
| 573 |
+
|
| 574 |
// Add visual feedback
|
| 575 |
const button = event.target;
|
| 576 |
const originalText = button.textContent;
|
|
|
|
| 588 |
const privacySlider = document.getElementById('inversion-privacy-slider');
|
| 589 |
|
| 590 |
const selectedClass = classSelect.value;
|
| 591 |
+
const sliderValue = parseInt(privacySlider.value);
|
| 592 |
|
| 593 |
+
// Invert the slider: slider 1 = high privacy (ε=1), slider 10 = low privacy (ε=10)
|
| 594 |
+
const privacyLevel = 11 - sliderValue; // For drawing function
|
| 595 |
+
const epsilon = sliderValue; // epsilon matches slider position now
|
| 596 |
+
const confidence = Math.max(30, 35 + (sliderValue * 6)); // Higher slider = higher confidence
|
| 597 |
|
| 598 |
+
// Update displays
|
| 599 |
+
document.getElementById('inversion-confidence').textContent = `${confidence}%`;
|
| 600 |
document.getElementById('inversion-class').textContent = classSelect.options[classSelect.selectedIndex].text;
|
| 601 |
|
| 602 |
+
// Update privacy bar
|
| 603 |
+
const privacyLevels = ['Very High', 'Very High', 'High', 'High', 'Medium', 'Medium', 'Low', 'Low', 'Very Low', 'Very Low'];
|
| 604 |
+
updateInversionPrivacyBar(sliderValue, privacyLevels[sliderValue - 1]);
|
| 605 |
+
|
| 606 |
+
// Update explanation based on slider value (1=high privacy, 10=low privacy)
|
| 607 |
+
const explanation = document.getElementById('inversion-explanation');
|
| 608 |
+
if (explanation) {
|
| 609 |
+
if (sliderValue <= 3) {
|
| 610 |
+
explanation.textContent = '✅ High privacy! The inverted features are very noisy and don\'t reveal clear class characteristics. Training data is well protected!';
|
| 611 |
+
explanation.style.background = '#e8f5e9';
|
| 612 |
+
explanation.style.borderLeft = '4px solid #4caf50';
|
| 613 |
+
} else if (sliderValue <= 6) {
|
| 614 |
+
explanation.textContent = '⚠️ Medium privacy. Some class features are visible but degraded. Consider increasing privacy for sensitive data.';
|
| 615 |
+
explanation.style.background = '#fff3e0';
|
| 616 |
+
explanation.style.borderLeft = '4px solid #ff9800';
|
| 617 |
+
} else {
|
| 618 |
+
explanation.textContent = '❌ Low privacy! The model reveals clear, detailed class features. An attacker can learn what the model associates with this class.';
|
| 619 |
+
explanation.style.background = '#ffebee';
|
| 620 |
+
explanation.style.borderLeft = '4px solid #f44336';
|
| 621 |
+
}
|
| 622 |
+
}
|
| 623 |
+
|
| 624 |
+
// Draw the inverted features on canvas
|
| 625 |
+
drawInvertedFeatures(selectedClass, privacyLevel);
|
| 626 |
+
|
| 627 |
// Add visual feedback
|
| 628 |
const button = event.target;
|
| 629 |
const originalText = button.textContent;
|
|
|
|
| 636 |
}, 1800);
|
| 637 |
}
|
| 638 |
|
| 639 |
+
function getPrivacyLevelText(level) {
|
| 640 |
+
if (level <= 2) return 'Very High';
|
| 641 |
+
if (level <= 4) return 'High';
|
| 642 |
+
if (level <= 6) return 'Medium';
|
| 643 |
+
if (level <= 8) return 'Low';
|
| 644 |
+
return 'Very Low';
|
| 645 |
+
}
|
| 646 |
+
|
| 647 |
+
function updateInversionPrivacyBar(sliderValue, privacyText) {
|
| 648 |
+
// Privacy bar has been removed - function kept for compatibility
|
| 649 |
+
}
|
| 650 |
+
|
| 651 |
+
function drawInvertedFeatures(classDigit, privacyLevel) {
|
| 652 |
+
const canvas = document.getElementById('inversion-canvas');
|
| 653 |
+
if (!canvas) return;
|
| 654 |
+
|
| 655 |
+
const ctx = canvas.getContext('2d');
|
| 656 |
+
const width = canvas.width;
|
| 657 |
+
const height = canvas.height;
|
| 658 |
+
|
| 659 |
+
ctx.clearRect(0, 0, width, height);
|
| 660 |
+
|
| 661 |
+
// Background
|
| 662 |
+
ctx.fillStyle = '#e3f2fd';
|
| 663 |
+
ctx.fillRect(0, 0, width, height);
|
| 664 |
+
|
| 665 |
+
// Calculate noise level based on privacy (1=high privacy/more noise, 10=low privacy/less noise)
|
| 666 |
+
const noiseLevel = (privacyLevel - 1) / 9; // 0 to 1, where 0 = most noise
|
| 667 |
+
const clarity = 1 - noiseLevel; // Inverted: high privacy = low clarity
|
| 668 |
+
|
| 669 |
+
// Draw the digit with varying clarity
|
| 670 |
+
ctx.save();
|
| 671 |
+
ctx.globalAlpha = Math.max(0.3, clarity);
|
| 672 |
+
|
| 673 |
+
// Draw digit based on selected class - scale font size based on canvas size
|
| 674 |
+
ctx.fillStyle = '#1976d2';
|
| 675 |
+
ctx.font = `bold ${Math.floor(width * 0.6)}px Arial`;
|
| 676 |
+
ctx.textAlign = 'center';
|
| 677 |
+
ctx.textBaseline = 'middle';
|
| 678 |
+
ctx.fillText(classDigit, width / 2, height / 2);
|
| 679 |
+
|
| 680 |
+
ctx.restore();
|
| 681 |
+
|
| 682 |
+
// Add noise based on privacy level
|
| 683 |
+
if (privacyLevel <= 7) {
|
| 684 |
+
const noiseIntensity = (7 - privacyLevel) / 7; // More noise for higher privacy
|
| 685 |
+
addCanvasNoise(ctx, noiseIntensity, width, height);
|
| 686 |
+
}
|
| 687 |
+
|
| 688 |
+
// For very high privacy, add blur effect
|
| 689 |
+
if (privacyLevel <= 3) {
|
| 690 |
+
ctx.filter = `blur(${(4 - privacyLevel) * 4}px)`;
|
| 691 |
+
ctx.drawImage(canvas, 0, 0);
|
| 692 |
+
ctx.filter = 'none';
|
| 693 |
+
}
|
| 694 |
+
}
|
| 695 |
+
|
| 696 |
+
function addCanvasNoise(ctx, intensity, width, height) {
|
| 697 |
+
if (intensity < 0.1) return;
|
| 698 |
+
|
| 699 |
+
const imageData = ctx.getImageData(0, 0, width, height);
|
| 700 |
+
const data = imageData.data;
|
| 701 |
+
|
| 702 |
+
for (let i = 0; i < data.length; i += 4) {
|
| 703 |
+
const noise = (Math.random() - 0.5) * intensity * 200;
|
| 704 |
+
data[i] += noise; // R
|
| 705 |
+
data[i + 1] += noise; // G
|
| 706 |
+
data[i + 2] += noise; // B
|
| 707 |
+
}
|
| 708 |
+
|
| 709 |
+
ctx.putImageData(imageData, 0, 0);
|
| 710 |
+
}
|
| 711 |
+
|
| 712 |
function runPropertyAttack() {
|
| 713 |
const propertyType = document.getElementById('property-type').value;
|
| 714 |
const accessLevel = parseInt(document.getElementById('property-access-slider').value);
|
| 715 |
+
const privacySlider = document.getElementById('property-privacy-slider');
|
| 716 |
+
const sliderValue = privacySlider ? parseInt(privacySlider.value) : 5;
|
| 717 |
|
| 718 |
+
// Calculate property inference accuracy based on privacy and access
|
| 719 |
+
// Lower privacy (higher slider value) = more accurate inference
|
| 720 |
+
const privacyPenalty = (11 - sliderValue) * 5; // High privacy reduces accuracy
|
| 721 |
const accessBonus = accessLevel * 8;
|
| 722 |
+
const baseAccuracy = 50;
|
| 723 |
+
const accuracy = Math.min(95, baseAccuracy + accessBonus + (sliderValue * 3));
|
| 724 |
+
|
| 725 |
+
// Update uncertainty based on privacy (high privacy = high uncertainty)
|
| 726 |
+
const uncertainty = Math.max(2, 20 - sliderValue * 1.5 - accessLevel * 2);
|
| 727 |
+
|
| 728 |
+
document.getElementById('property-male').textContent = `${52}% ± ${Math.round(uncertainty)}%`;
|
| 729 |
+
document.getElementById('property-female').textContent = `${48}% ± ${Math.round(uncertainty)}%`;
|
| 730 |
|
| 731 |
+
// Update privacy bar
|
| 732 |
+
const privacyLevels = ['Very High', 'Very High', 'High', 'High', 'Medium', 'Medium', 'Low', 'Low', 'Very Low', 'Very Low'];
|
| 733 |
+
updatePropertyPrivacyBar(sliderValue, privacyLevels[sliderValue - 1]);
|
| 734 |
|
| 735 |
+
// Update explanation
|
| 736 |
+
const explanation = document.getElementById('property-explanation');
|
| 737 |
+
if (explanation) {
|
| 738 |
+
if (sliderValue <= 3) {
|
| 739 |
+
explanation.textContent = '✅ High privacy! The attacker cannot accurately infer dataset properties. Large confidence intervals show high uncertainty.';
|
| 740 |
+
explanation.style.background = '#e8f5e9';
|
| 741 |
+
explanation.style.borderLeft = '4px solid #4caf50';
|
| 742 |
+
} else if (sliderValue <= 6) {
|
| 743 |
+
explanation.textContent = '⚠️ Medium privacy. The attacker can infer properties with moderate accuracy. Consider increasing privacy for sensitive datasets.';
|
| 744 |
+
explanation.style.background = '#fff3e0';
|
| 745 |
+
explanation.style.borderLeft = '4px solid #ff9800';
|
| 746 |
+
} else {
|
| 747 |
+
explanation.textContent = '❌ Low privacy! The attacker can accurately infer sensitive dataset properties like demographic distributions. Privacy breach risk!';
|
| 748 |
+
explanation.style.background = '#ffebee';
|
| 749 |
+
explanation.style.borderLeft = '4px solid #f44336';
|
| 750 |
+
}
|
| 751 |
+
}
|
| 752 |
|
| 753 |
// Add visual feedback
|
| 754 |
const button = event.target;
|
|
|
|
| 762 |
}, 2200);
|
| 763 |
}
|
| 764 |
|
| 765 |
+
function updatePropertyPrivacyBar(sliderValue, privacyText) {
|
| 766 |
+
// Privacy bar has been removed - function kept for compatibility
|
| 767 |
+
}
|
| 768 |
+
|
| 769 |
function runLinkageAttack() {
|
| 770 |
const simulator = window.attackSimulator;
|
| 771 |
simulator.updateLinkageAttack();
|
|
|
|
| 782 |
}, 2500);
|
| 783 |
}
|
| 784 |
|
| 785 |
+
// Draw reconstruction examples on canvases
|
| 786 |
+
function drawReconstructionExamples() {
|
| 787 |
+
// Example data patterns
|
| 788 |
+
const examples = [
|
| 789 |
+
{ // Face-like
|
| 790 |
+
draw: (ctx, noise) => {
|
| 791 |
+
// Head
|
| 792 |
+
ctx.fillStyle = `rgba(139, 111, 71, ${1 - noise * 0.8})`;
|
| 793 |
+
ctx.beginPath();
|
| 794 |
+
ctx.ellipse(60, 45, 30, 35, 0, 0, Math.PI * 2);
|
| 795 |
+
ctx.fill();
|
| 796 |
+
|
| 797 |
+
// Eyes
|
| 798 |
+
ctx.fillStyle = `rgba(50, 50, 50, ${1 - noise * 0.9})`;
|
| 799 |
+
ctx.fillRect(45 + Math.random() * noise * 5, 35, 8, 8);
|
| 800 |
+
ctx.fillRect(67 + Math.random() * noise * 5, 35, 8, 8);
|
| 801 |
+
|
| 802 |
+
// Nose
|
| 803 |
+
ctx.fillStyle = `rgba(100, 80, 60, ${1 - noise * 0.85})`;
|
| 804 |
+
ctx.fillRect(57, 50, 6, 12);
|
| 805 |
+
|
| 806 |
+
// Mouth
|
| 807 |
+
ctx.fillStyle = `rgba(80, 60, 50, ${1 - noise * 0.9})`;
|
| 808 |
+
ctx.fillRect(48, 70, 24, 5);
|
| 809 |
+
|
| 810 |
+
// Body
|
| 811 |
+
ctx.fillStyle = `rgba(107, 142, 107, ${1 - noise * 0.8})`;
|
| 812 |
+
ctx.fillRect(35, 85, 50, 30);
|
| 813 |
+
}
|
| 814 |
+
},
|
| 815 |
+
{ // Eye-like medical scan
|
| 816 |
+
draw: (ctx, noise) => {
|
| 817 |
+
// Dark background
|
| 818 |
+
ctx.fillStyle = '#1a1a1a';
|
| 819 |
+
ctx.fillRect(0, 0, 120, 120);
|
| 820 |
+
|
| 821 |
+
// Eye socket (bright)
|
| 822 |
+
ctx.fillStyle = `rgba(255, 200, 100, ${0.9 - noise * 0.7})`;
|
| 823 |
+
ctx.beginPath();
|
| 824 |
+
ctx.ellipse(60, 60, 35, 30, 0, 0, Math.PI * 2);
|
| 825 |
+
ctx.fill();
|
| 826 |
+
|
| 827 |
+
// Pupil (dark)
|
| 828 |
+
ctx.fillStyle = `rgba(20, 20, 20, ${1 - noise * 0.8})`;
|
| 829 |
+
ctx.beginPath();
|
| 830 |
+
ctx.ellipse(60, 60, 15, 15, 0, 0, Math.PI * 2);
|
| 831 |
+
ctx.fill();
|
| 832 |
+
|
| 833 |
+
// Highlight
|
| 834 |
+
ctx.fillStyle = `rgba(255, 255, 255, ${0.8 - noise * 0.7})`;
|
| 835 |
+
ctx.beginPath();
|
| 836 |
+
ctx.arc(55, 52, 5, 0, Math.PI * 2);
|
| 837 |
+
ctx.fill();
|
| 838 |
+
}
|
| 839 |
+
},
|
| 840 |
+
{ // Medical scan with bright center
|
| 841 |
+
draw: (ctx, noise) => {
|
| 842 |
+
// Dark background
|
| 843 |
+
ctx.fillStyle = '#0a0a0a';
|
| 844 |
+
ctx.fillRect(0, 0, 120, 120);
|
| 845 |
+
|
| 846 |
+
// Bright center (hot spot)
|
| 847 |
+
const gradient = ctx.createRadialGradient(60, 60, 5, 60, 60, 40);
|
| 848 |
+
gradient.addColorStop(0, `rgba(255, 100, 50, ${1 - noise * 0.6})`);
|
| 849 |
+
gradient.addColorStop(0.5, `rgba(200, 80, 40, ${0.8 - noise * 0.6})`);
|
| 850 |
+
gradient.addColorStop(1, `rgba(100, 40, 20, ${0.3 - noise * 0.3})`);
|
| 851 |
+
ctx.fillStyle = gradient;
|
| 852 |
+
ctx.fillRect(0, 0, 120, 120);
|
| 853 |
+
|
| 854 |
+
// Green markers
|
| 855 |
+
ctx.fillStyle = `rgba(100, 255, 100, ${0.7 - noise * 0.6})`;
|
| 856 |
+
ctx.fillRect(20, 20, 8, 8);
|
| 857 |
+
ctx.fillRect(92, 20, 8, 8);
|
| 858 |
+
ctx.fillRect(20, 92, 8, 8);
|
| 859 |
+
ctx.fillRect(92, 92, 8, 8);
|
| 860 |
+
}
|
| 861 |
+
},
|
| 862 |
+
{ // Computer/object
|
| 863 |
+
draw: (ctx, noise) => {
|
| 864 |
+
// Screen
|
| 865 |
+
ctx.fillStyle = `rgba(100, 150, 255, ${0.9 - noise * 0.7})`;
|
| 866 |
+
ctx.fillRect(30, 20, 60, 45);
|
| 867 |
+
|
| 868 |
+
// Screen content
|
| 869 |
+
ctx.fillStyle = `rgba(200, 220, 255, ${0.8 - noise * 0.7})`;
|
| 870 |
+
ctx.fillRect(35, 25, 50, 35);
|
| 871 |
+
|
| 872 |
+
// Base
|
| 873 |
+
ctx.fillStyle = `rgba(80, 80, 80, ${1 - noise * 0.8})`;
|
| 874 |
+
ctx.fillRect(40, 70, 40, 8);
|
| 875 |
+
|
| 876 |
+
// Stand
|
| 877 |
+
ctx.fillStyle = `rgba(100, 100, 100, ${1 - noise * 0.8})`;
|
| 878 |
+
ctx.fillRect(55, 65, 10, 15);
|
| 879 |
+
|
| 880 |
+
// Keyboard
|
| 881 |
+
ctx.fillStyle = `rgba(60, 60, 60, ${0.9 - noise * 0.7})`;
|
| 882 |
+
ctx.fillRect(20, 85, 80, 25);
|
| 883 |
+
}
|
| 884 |
+
}
|
| 885 |
+
];
|
| 886 |
+
|
| 887 |
+
// Draw each example at different privacy levels
|
| 888 |
+
examples.forEach((example, idx) => {
|
| 889 |
+
const exampleNum = idx + 1;
|
| 890 |
+
|
| 891 |
+
// Ground truth (original)
|
| 892 |
+
const originalCanvas = document.getElementById(`original-${exampleNum}`);
|
| 893 |
+
if (originalCanvas) {
|
| 894 |
+
const ctx = originalCanvas.getContext('2d');
|
| 895 |
+
ctx.clearRect(0, 0, 120, 120);
|
| 896 |
+
example.draw(ctx, 0);
|
| 897 |
+
}
|
| 898 |
+
|
| 899 |
+
// No privacy (nearly perfect reconstruction - privacy breach!)
|
| 900 |
+
const noPrivacyCanvas = document.getElementById(`no-privacy-${exampleNum}`);
|
| 901 |
+
if (noPrivacyCanvas) {
|
| 902 |
+
const ctx = noPrivacyCanvas.getContext('2d');
|
| 903 |
+
ctx.clearRect(0, 0, 120, 120);
|
| 904 |
+
example.draw(ctx, 0.02); // Almost no degradation
|
| 905 |
+
addNoise(ctx, 0.01, 120, 120); // Minimal noise
|
| 906 |
+
}
|
| 907 |
+
|
| 908 |
+
// High privacy (ε = 0.1) - complete noise/static
|
| 909 |
+
const highPrivacyCanvas = document.getElementById(`high-privacy-${exampleNum}`);
|
| 910 |
+
if (highPrivacyCanvas) {
|
| 911 |
+
const ctx = highPrivacyCanvas.getContext('2d');
|
| 912 |
+
ctx.clearRect(0, 0, 120, 120);
|
| 913 |
+
// Draw pure random noise - no original features visible
|
| 914 |
+
drawCompleteNoise(ctx, 120, 120);
|
| 915 |
+
}
|
| 916 |
+
});
|
| 917 |
+
|
| 918 |
+
// Update current setting examples
|
| 919 |
+
updateCurrentReconstructionExamples();
|
| 920 |
+
}
|
| 921 |
+
|
| 922 |
+
function updateCurrentReconstructionExamples() {
|
| 923 |
+
const clipping = parseFloat(document.getElementById('recon-clipping-slider')?.value || 1.0);
|
| 924 |
+
const noise = parseFloat(document.getElementById('recon-noise-slider')?.value || 1.0);
|
| 925 |
+
|
| 926 |
+
// Calculate quality/noise level
|
| 927 |
+
const quality = Math.max(0.05, 0.95 - (5 - clipping) * 0.08 - noise * 0.22);
|
| 928 |
+
const noiseLevel = 1 - quality;
|
| 929 |
+
|
| 930 |
+
// Calculate epsilon
|
| 931 |
+
const epsilon = Math.max(0.5, 10 - (clipping * 0.5 + noise * 2));
|
| 932 |
+
|
| 933 |
+
// Update epsilon display
|
| 934 |
+
const epsilonDisplay = document.getElementById('current-epsilon');
|
| 935 |
+
if (epsilonDisplay) {
|
| 936 |
+
epsilonDisplay.textContent = `(ε = ${epsilon.toFixed(1)})`;
|
| 937 |
+
}
|
| 938 |
+
|
| 939 |
+
// Example patterns (same as above)
|
| 940 |
+
const examples = [
|
| 941 |
+
{ // Face-like
|
| 942 |
+
draw: (ctx, noise) => {
|
| 943 |
+
ctx.fillStyle = `rgba(139, 111, 71, ${1 - noise * 0.8})`;
|
| 944 |
+
ctx.beginPath();
|
| 945 |
+
ctx.ellipse(60, 45, 30, 35, 0, 0, Math.PI * 2);
|
| 946 |
+
ctx.fill();
|
| 947 |
+
ctx.fillStyle = `rgba(50, 50, 50, ${1 - noise * 0.9})`;
|
| 948 |
+
ctx.fillRect(45 + Math.random() * noise * 5, 35, 8, 8);
|
| 949 |
+
ctx.fillRect(67 + Math.random() * noise * 5, 35, 8, 8);
|
| 950 |
+
ctx.fillStyle = `rgba(100, 80, 60, ${1 - noise * 0.85})`;
|
| 951 |
+
ctx.fillRect(57, 50, 6, 12);
|
| 952 |
+
ctx.fillStyle = `rgba(80, 60, 50, ${1 - noise * 0.9})`;
|
| 953 |
+
ctx.fillRect(48, 70, 24, 5);
|
| 954 |
+
ctx.fillStyle = `rgba(107, 142, 107, ${1 - noise * 0.8})`;
|
| 955 |
+
ctx.fillRect(35, 85, 50, 30);
|
| 956 |
+
}
|
| 957 |
+
},
|
| 958 |
+
{ // Eye-like
|
| 959 |
+
draw: (ctx, noise) => {
|
| 960 |
+
ctx.fillStyle = '#1a1a1a';
|
| 961 |
+
ctx.fillRect(0, 0, 120, 120);
|
| 962 |
+
ctx.fillStyle = `rgba(255, 200, 100, ${0.9 - noise * 0.7})`;
|
| 963 |
+
ctx.beginPath();
|
| 964 |
+
ctx.ellipse(60, 60, 35, 30, 0, 0, Math.PI * 2);
|
| 965 |
+
ctx.fill();
|
| 966 |
+
ctx.fillStyle = `rgba(20, 20, 20, ${1 - noise * 0.8})`;
|
| 967 |
+
ctx.beginPath();
|
| 968 |
+
ctx.ellipse(60, 60, 15, 15, 0, 0, Math.PI * 2);
|
| 969 |
+
ctx.fill();
|
| 970 |
+
ctx.fillStyle = `rgba(255, 255, 255, ${0.8 - noise * 0.7})`;
|
| 971 |
+
ctx.beginPath();
|
| 972 |
+
ctx.arc(55, 52, 5, 0, Math.PI * 2);
|
| 973 |
+
ctx.fill();
|
| 974 |
+
}
|
| 975 |
+
},
|
| 976 |
+
{ // Medical scan
|
| 977 |
+
draw: (ctx, noise) => {
|
| 978 |
+
ctx.fillStyle = '#0a0a0a';
|
| 979 |
+
ctx.fillRect(0, 0, 120, 120);
|
| 980 |
+
const gradient = ctx.createRadialGradient(60, 60, 5, 60, 60, 40);
|
| 981 |
+
gradient.addColorStop(0, `rgba(255, 100, 50, ${1 - noise * 0.6})`);
|
| 982 |
+
gradient.addColorStop(0.5, `rgba(200, 80, 40, ${0.8 - noise * 0.6})`);
|
| 983 |
+
gradient.addColorStop(1, `rgba(100, 40, 20, ${0.3 - noise * 0.3})`);
|
| 984 |
+
ctx.fillStyle = gradient;
|
| 985 |
+
ctx.fillRect(0, 0, 120, 120);
|
| 986 |
+
ctx.fillStyle = `rgba(100, 255, 100, ${0.7 - noise * 0.6})`;
|
| 987 |
+
ctx.fillRect(20, 20, 8, 8);
|
| 988 |
+
ctx.fillRect(92, 20, 8, 8);
|
| 989 |
+
ctx.fillRect(20, 92, 8, 8);
|
| 990 |
+
ctx.fillRect(92, 92, 8, 8);
|
| 991 |
+
}
|
| 992 |
+
},
|
| 993 |
+
{ // Computer
|
| 994 |
+
draw: (ctx, noise) => {
|
| 995 |
+
ctx.fillStyle = `rgba(100, 150, 255, ${0.9 - noise * 0.7})`;
|
| 996 |
+
ctx.fillRect(30, 20, 60, 45);
|
| 997 |
+
ctx.fillStyle = `rgba(200, 220, 255, ${0.8 - noise * 0.7})`;
|
| 998 |
+
ctx.fillRect(35, 25, 50, 35);
|
| 999 |
+
ctx.fillStyle = `rgba(80, 80, 80, ${1 - noise * 0.8})`;
|
| 1000 |
+
ctx.fillRect(40, 70, 40, 8);
|
| 1001 |
+
ctx.fillStyle = `rgba(100, 100, 100, ${1 - noise * 0.8})`;
|
| 1002 |
+
ctx.fillRect(55, 65, 10, 15);
|
| 1003 |
+
ctx.fillStyle = `rgba(60, 60, 60, ${0.9 - noise * 0.7})`;
|
| 1004 |
+
ctx.fillRect(20, 85, 80, 25);
|
| 1005 |
+
}
|
| 1006 |
+
}
|
| 1007 |
+
];
|
| 1008 |
+
|
| 1009 |
+
// Draw current setting for each example
|
| 1010 |
+
examples.forEach((example, idx) => {
|
| 1011 |
+
const currentCanvas = document.getElementById(`current-${idx + 1}`);
|
| 1012 |
+
if (currentCanvas) {
|
| 1013 |
+
const ctx = currentCanvas.getContext('2d');
|
| 1014 |
+
ctx.clearRect(0, 0, 120, 120);
|
| 1015 |
+
|
| 1016 |
+
// If very high privacy (epsilon < 1.0), show mostly noise
|
| 1017 |
+
if (epsilon < 1.0) {
|
| 1018 |
+
// Draw mostly random noise with tiny hint of original
|
| 1019 |
+
example.draw(ctx, 0.98);
|
| 1020 |
+
drawCompleteNoise(ctx, 120, 120);
|
| 1021 |
+
} else if (epsilon < 3.0) {
|
| 1022 |
+
// High privacy - heavy noise
|
| 1023 |
+
example.draw(ctx, noiseLevel);
|
| 1024 |
+
addNoise(ctx, Math.min(0.85, noiseLevel * 1.2), 120, 120);
|
| 1025 |
+
} else if (epsilon < 6.0) {
|
| 1026 |
+
// Medium privacy - moderate noise
|
| 1027 |
+
example.draw(ctx, noiseLevel * 0.7);
|
| 1028 |
+
addNoise(ctx, noiseLevel * 0.8, 120, 120);
|
| 1029 |
+
} else {
|
| 1030 |
+
// Low privacy - more visible noise (increased from 0.4 to 0.6)
|
| 1031 |
+
example.draw(ctx, noiseLevel * 0.4);
|
| 1032 |
+
addNoise(ctx, Math.max(0.3, noiseLevel * 0.6), 120, 120);
|
| 1033 |
+
}
|
| 1034 |
+
}
|
| 1035 |
+
});
|
| 1036 |
+
}
|
| 1037 |
+
|
| 1038 |
+
function addNoise(ctx, intensity, width, height) {
|
| 1039 |
+
if (intensity < 0.05) return;
|
| 1040 |
+
|
| 1041 |
+
const imageData = ctx.getImageData(0, 0, width, height);
|
| 1042 |
+
const data = imageData.data;
|
| 1043 |
+
|
| 1044 |
+
// For high intensity, make it more aggressive
|
| 1045 |
+
if (intensity > 0.7) {
|
| 1046 |
+
// Very high noise - almost complete randomization
|
| 1047 |
+
for (let i = 0; i < data.length; i += 4) {
|
| 1048 |
+
const randomness = intensity * 1.5;
|
| 1049 |
+
data[i] = Math.random() * 255 * randomness + data[i] * (1 - randomness); // R
|
| 1050 |
+
data[i + 1] = Math.random() * 255 * randomness + data[i + 1] * (1 - randomness); // G
|
| 1051 |
+
data[i + 2] = Math.random() * 255 * randomness + data[i + 2] * (1 - randomness); // B
|
| 1052 |
+
}
|
| 1053 |
+
} else {
|
| 1054 |
+
// Normal noise addition
|
| 1055 |
+
for (let i = 0; i < data.length; i += 4) {
|
| 1056 |
+
const noise = (Math.random() - 0.5) * intensity * 300;
|
| 1057 |
+
data[i] += noise; // R
|
| 1058 |
+
data[i + 1] += noise; // G
|
| 1059 |
+
data[i + 2] += noise; // B
|
| 1060 |
+
}
|
| 1061 |
+
}
|
| 1062 |
+
|
| 1063 |
+
ctx.putImageData(imageData, 0, 0);
|
| 1064 |
+
}
|
| 1065 |
+
|
| 1066 |
+
function drawCompleteNoise(ctx, width, height) {
|
| 1067 |
+
// Draw pure random static - complete privacy protection
|
| 1068 |
+
const imageData = ctx.createImageData(width, height);
|
| 1069 |
+
const data = imageData.data;
|
| 1070 |
+
|
| 1071 |
+
for (let i = 0; i < data.length; i += 4) {
|
| 1072 |
+
// Random RGB values - pure noise
|
| 1073 |
+
data[i] = Math.random() * 255; // R
|
| 1074 |
+
data[i + 1] = Math.random() * 255; // G
|
| 1075 |
+
data[i + 2] = Math.random() * 255; // B
|
| 1076 |
+
data[i + 3] = 255; // A (fully opaque)
|
| 1077 |
+
}
|
| 1078 |
+
|
| 1079 |
+
ctx.putImageData(imageData, 0, 0);
|
| 1080 |
+
}
|
| 1081 |
+
|
| 1082 |
// Initialize when page loads
|
| 1083 |
document.addEventListener('DOMContentLoaded', function() {
|
| 1084 |
window.attackSimulator = new AttackSimulator();
|
|
|
|
| 1087 |
window.attackSimulator.updateMembershipDemo();
|
| 1088 |
window.attackSimulator.updateReconstructionAttack();
|
| 1089 |
window.attackSimulator.updateLinkageAttack();
|
| 1090 |
+
|
| 1091 |
+
// Draw reconstruction examples
|
| 1092 |
+
setTimeout(() => {
|
| 1093 |
+
drawReconstructionExamples();
|
| 1094 |
+
}, 100);
|
| 1095 |
+
|
| 1096 |
+
// Initialize inversion canvas and privacy bar with default values
|
| 1097 |
+
setTimeout(() => {
|
| 1098 |
+
drawInvertedFeatures('7', 6); // Default: digit 7, privacy level 6 (slider=5, inverted to 6)
|
| 1099 |
+
updateInversionPrivacyBar(5, 'Medium'); // Initialize privacy bar at slider position 5
|
| 1100 |
+
updatePropertyPrivacyBar(5, 'Medium'); // Initialize property privacy bar
|
| 1101 |
+
}, 100);
|
| 1102 |
+
|
| 1103 |
+
// Add event listeners for inversion attack controls
|
| 1104 |
+
const inversionPrivacySlider = document.getElementById('inversion-privacy-slider');
|
| 1105 |
+
if (inversionPrivacySlider) {
|
| 1106 |
+
inversionPrivacySlider.addEventListener('input', function() {
|
| 1107 |
+
const sliderValue = parseInt(this.value);
|
| 1108 |
+
// Invert the slider: slider 1 = high privacy, slider 10 = low privacy
|
| 1109 |
+
const privacyLevel = 11 - sliderValue;
|
| 1110 |
+
const privacyLevels = ['Very High', 'Very High', 'High', 'High', 'Medium', 'Medium', 'Low', 'Low', 'Very Low', 'Very Low'];
|
| 1111 |
+
document.getElementById('inversion-privacy').textContent = privacyLevels[sliderValue - 1];
|
| 1112 |
+
|
| 1113 |
+
// Update visualization in real-time
|
| 1114 |
+
const classSelect = document.getElementById('inversion-class-select');
|
| 1115 |
+
const selectedClass = classSelect ? classSelect.value : '7';
|
| 1116 |
+
drawInvertedFeatures(selectedClass, privacyLevel);
|
| 1117 |
+
|
| 1118 |
+
// Update privacy bar indicator
|
| 1119 |
+
updateInversionPrivacyBar(sliderValue, privacyLevels[sliderValue - 1]);
|
| 1120 |
+
|
| 1121 |
+
// Update explanation based on slider value (1=high privacy, 10=low privacy)
|
| 1122 |
+
const explanation = document.getElementById('inversion-explanation');
|
| 1123 |
+
if (explanation) {
|
| 1124 |
+
if (sliderValue <= 3) {
|
| 1125 |
+
explanation.textContent = '✅ High privacy! The inverted features are very noisy and don\'t reveal clear class characteristics. Training data is well protected!';
|
| 1126 |
+
explanation.style.background = '#e8f5e9';
|
| 1127 |
+
explanation.style.borderLeft = '4px solid #4caf50';
|
| 1128 |
+
} else if (sliderValue <= 6) {
|
| 1129 |
+
explanation.textContent = '⚠️ Medium privacy. Some class features are visible but degraded. Consider increasing privacy for sensitive data.';
|
| 1130 |
+
explanation.style.background = '#fff3e0';
|
| 1131 |
+
explanation.style.borderLeft = '4px solid #ff9800';
|
| 1132 |
+
} else {
|
| 1133 |
+
explanation.textContent = '❌ Low privacy! The model reveals clear, detailed class features. An attacker can learn what the model associates with this class.';
|
| 1134 |
+
explanation.style.background = '#ffebee';
|
| 1135 |
+
explanation.style.borderLeft = '4px solid #f44336';
|
| 1136 |
+
}
|
| 1137 |
+
}
|
| 1138 |
+
});
|
| 1139 |
+
}
|
| 1140 |
+
|
| 1141 |
+
// Add event listener for class selection
|
| 1142 |
+
const inversionClassSelect = document.getElementById('inversion-class-select');
|
| 1143 |
+
if (inversionClassSelect) {
|
| 1144 |
+
inversionClassSelect.addEventListener('change', function() {
|
| 1145 |
+
const privacySlider = document.getElementById('inversion-privacy-slider');
|
| 1146 |
+
const sliderValue = privacySlider ? parseInt(privacySlider.value) : 5;
|
| 1147 |
+
const privacyLevel = 11 - sliderValue; // Invert for drawing
|
| 1148 |
+
drawInvertedFeatures(this.value, privacyLevel);
|
| 1149 |
+
document.getElementById('inversion-class').textContent = this.options[this.selectedIndex].text;
|
| 1150 |
+
});
|
| 1151 |
+
}
|
| 1152 |
+
|
| 1153 |
+
// Add event listeners for property inference attack controls
|
| 1154 |
+
const propertyPrivacySlider = document.getElementById('property-privacy-slider');
|
| 1155 |
+
if (propertyPrivacySlider) {
|
| 1156 |
+
propertyPrivacySlider.addEventListener('input', function() {
|
| 1157 |
+
const sliderValue = parseInt(this.value);
|
| 1158 |
+
const privacyLevels = ['Very High', 'Very High', 'High', 'High', 'Medium', 'Medium', 'Low', 'Low', 'Very Low', 'Very Low'];
|
| 1159 |
+
document.getElementById('property-privacy').textContent = privacyLevels[sliderValue - 1];
|
| 1160 |
+
|
| 1161 |
+
// Update privacy bar in real-time
|
| 1162 |
+
updatePropertyPrivacyBar(sliderValue, privacyLevels[sliderValue - 1]);
|
| 1163 |
+
|
| 1164 |
+
// Update uncertainty display in real-time
|
| 1165 |
+
const accessLevel = parseInt(document.getElementById('property-access-slider').value);
|
| 1166 |
+
const uncertainty = Math.max(2, 20 - sliderValue * 1.5 - accessLevel * 2);
|
| 1167 |
+
document.getElementById('property-male').textContent = `${52}% ± ${Math.round(uncertainty)}%`;
|
| 1168 |
+
document.getElementById('property-female').textContent = `${48}% ± ${Math.round(uncertainty)}%`;
|
| 1169 |
+
|
| 1170 |
+
// Update explanation
|
| 1171 |
+
const explanation = document.getElementById('property-explanation');
|
| 1172 |
+
if (explanation) {
|
| 1173 |
+
if (sliderValue <= 3) {
|
| 1174 |
+
explanation.textContent = '✅ High privacy! The attacker cannot accurately infer dataset properties. Large confidence intervals show high uncertainty.';
|
| 1175 |
+
explanation.style.background = '#e8f5e9';
|
| 1176 |
+
explanation.style.borderLeft = '4px solid #4caf50';
|
| 1177 |
+
} else if (sliderValue <= 6) {
|
| 1178 |
+
explanation.textContent = '⚠️ Medium privacy. The attacker can infer properties with moderate accuracy. Consider increasing privacy for sensitive datasets.';
|
| 1179 |
+
explanation.style.background = '#fff3e0';
|
| 1180 |
+
explanation.style.borderLeft = '4px solid #ff9800';
|
| 1181 |
+
} else {
|
| 1182 |
+
explanation.textContent = '❌ Low privacy! The attacker can accurately infer sensitive dataset properties like demographic distributions. Privacy breach risk!';
|
| 1183 |
+
explanation.style.background = '#ffebee';
|
| 1184 |
+
explanation.style.borderLeft = '4px solid #f44336';
|
| 1185 |
+
}
|
| 1186 |
+
}
|
| 1187 |
+
});
|
| 1188 |
+
}
|
| 1189 |
+
|
| 1190 |
+
// Add event listener for model access slider
|
| 1191 |
+
const propertyAccessSlider = document.getElementById('property-access-slider');
|
| 1192 |
+
if (propertyAccessSlider) {
|
| 1193 |
+
propertyAccessSlider.addEventListener('input', function() {
|
| 1194 |
+
const accessLevel = parseInt(this.value);
|
| 1195 |
+
const accessLevels = ['Black-box', 'Gray-box', 'White-box'];
|
| 1196 |
+
document.getElementById('property-access').textContent = accessLevels[accessLevel - 1];
|
| 1197 |
+
|
| 1198 |
+
// Update uncertainty display when access changes
|
| 1199 |
+
const privacySlider = document.getElementById('property-privacy-slider');
|
| 1200 |
+
const sliderValue = privacySlider ? parseInt(privacySlider.value) : 5;
|
| 1201 |
+
const uncertainty = Math.max(2, 20 - sliderValue * 1.5 - accessLevel * 2);
|
| 1202 |
+
document.getElementById('property-male').textContent = `${52}% ± ${Math.round(uncertainty)}%`;
|
| 1203 |
+
document.getElementById('property-female').textContent = `${48}% ± ${Math.round(uncertainty)}%`;
|
| 1204 |
+
});
|
| 1205 |
+
}
|
| 1206 |
});
|
app/templates/attacks.html
CHANGED
|
@@ -17,11 +17,13 @@
|
|
| 17 |
padding: 4px;
|
| 18 |
margin-bottom: 2rem;
|
| 19 |
overflow-x: auto;
|
|
|
|
|
|
|
| 20 |
}
|
| 21 |
|
| 22 |
.attack-tab {
|
| 23 |
-
flex: 1;
|
| 24 |
-
min-width:
|
| 25 |
padding: 0.75rem 1rem;
|
| 26 |
text-align: center;
|
| 27 |
background: transparent;
|
|
@@ -31,6 +33,7 @@
|
|
| 31 |
font-weight: 500;
|
| 32 |
transition: all 0.3s ease;
|
| 33 |
white-space: nowrap;
|
|
|
|
| 34 |
}
|
| 35 |
|
| 36 |
.attack-tab:hover {
|
|
@@ -332,8 +335,28 @@
|
|
| 332 |
flex-shrink: 0;
|
| 333 |
}
|
| 334 |
|
| 335 |
-
/*
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 336 |
@media (max-width: 768px) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 337 |
.story-flow {
|
| 338 |
flex-direction: column;
|
| 339 |
}
|
|
@@ -348,6 +371,13 @@
|
|
| 348 |
}
|
| 349 |
}
|
| 350 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 351 |
.interactive-demo {
|
| 352 |
background: #f8f9fa;
|
| 353 |
padding: 2rem;
|
|
@@ -590,6 +620,374 @@
|
|
| 590 |
color: #666;
|
| 591 |
line-height: 1.5;
|
| 592 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 593 |
</style>
|
| 594 |
{% endblock %}
|
| 595 |
|
|
@@ -672,7 +1070,7 @@
|
|
| 672 |
<div class="demo-scenario">
|
| 673 |
<div class="scenario-setup">
|
| 674 |
<h4>The Setup</h4>
|
| 675 |
-
<p>
|
| 676 |
</div>
|
| 677 |
|
| 678 |
<div class="confidence-comparison">
|
|
@@ -682,12 +1080,16 @@
|
|
| 682 |
<span class="sample-status training">✓ Was in training</span>
|
| 683 |
</div>
|
| 684 |
<div class="sample-image">
|
| 685 |
-
<div class="digit-display">
|
|
|
|
|
|
|
|
|
|
|
|
|
| 686 |
</div>
|
| 687 |
<div class="confidence-bar">
|
| 688 |
<div class="confidence-label">Model Confidence:</div>
|
| 689 |
<div class="confidence-meter">
|
| 690 |
-
<div class="confidence-fill training-confidence" id="training-confidence" style="width:
|
| 691 |
</div>
|
| 692 |
</div>
|
| 693 |
</div>
|
|
@@ -700,12 +1102,16 @@
|
|
| 700 |
<span class="sample-status test">✗ Not in training</span>
|
| 701 |
</div>
|
| 702 |
<div class="sample-image">
|
| 703 |
-
<div class="digit-display">
|
|
|
|
|
|
|
|
|
|
|
|
|
| 704 |
</div>
|
| 705 |
<div class="confidence-bar">
|
| 706 |
<div class="confidence-label">Model Confidence:</div>
|
| 707 |
<div class="confidence-meter">
|
| 708 |
-
<div class="confidence-fill test-confidence" id="test-confidence" style="width:
|
| 709 |
</div>
|
| 710 |
</div>
|
| 711 |
</div>
|
|
@@ -713,8 +1119,8 @@
|
|
| 713 |
|
| 714 |
<div class="attack-insight">
|
| 715 |
<div class="insight-box">
|
| 716 |
-
<strong>🔍 The Attack Insight:</strong> The model is <span id="confidence-diff">
|
| 717 |
-
An attacker can use this difference to
|
| 718 |
</div>
|
| 719 |
</div>
|
| 720 |
</div>
|
|
@@ -777,6 +1183,16 @@
|
|
| 777 |
<div class="chart-container">
|
| 778 |
<canvas id="membership-chart"></canvas>
|
| 779 |
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 780 |
</div>
|
| 781 |
</div>
|
| 782 |
|
|
@@ -795,41 +1211,173 @@
|
|
| 795 |
<strong>Threat:</strong> Attackers with access to gradients can potentially reconstruct original training images, especially in federated learning scenarios.
|
| 796 |
</div>
|
| 797 |
|
| 798 |
-
<div class="attack-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 799 |
<div class="demo-panel">
|
| 800 |
-
<h3
|
| 801 |
<div class="demo-controls">
|
| 802 |
-
<label>Clipping Norm: <span id="recon-clipping">1.0</span></label>
|
| 803 |
<input type="range" class="demo-slider" id="recon-clipping-slider" min="0.1" max="5" step="0.1" value="1.0">
|
|
|
|
|
|
|
|
|
|
|
|
|
| 804 |
|
| 805 |
-
<label>Noise
|
| 806 |
<input type="range" class="demo-slider" id="recon-noise-slider" min="0" max="3" step="0.1" value="1.0">
|
|
|
|
|
|
|
|
|
|
|
|
|
| 807 |
</div>
|
| 808 |
-
<button class="control-button" onclick="runReconstructionAttack()"
|
| 809 |
</div>
|
| 810 |
|
| 811 |
<div class="demo-panel">
|
| 812 |
-
<h3
|
| 813 |
-
<div class="
|
| 814 |
-
<div
|
| 815 |
-
<
|
| 816 |
-
|
|
|
|
|
|
|
| 817 |
</div>
|
| 818 |
-
<div>Ground Truth</div>
|
| 819 |
</div>
|
| 820 |
-
|
| 821 |
-
|
| 822 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 823 |
</div>
|
| 824 |
-
<div class="reconstruction-quality quality-high" id="recon-quality">High Quality</div>
|
| 825 |
</div>
|
| 826 |
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
| 827 |
</div>
|
| 828 |
</div>
|
| 829 |
|
| 830 |
<div class="chart-container">
|
| 831 |
<canvas id="reconstruction-chart"></canvas>
|
| 832 |
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 833 |
</div>
|
| 834 |
</div>
|
| 835 |
|
|
@@ -849,38 +1397,64 @@
|
|
| 849 |
</div>
|
| 850 |
|
| 851 |
<div class="attack-demo">
|
| 852 |
-
<div class="demo-panel">
|
| 853 |
-
<h3>Inversion Parameters</h3>
|
| 854 |
-
<div class="demo-controls">
|
| 855 |
-
<
|
| 856 |
-
|
| 857 |
-
|
| 858 |
-
|
| 859 |
-
<
|
| 860 |
-
|
| 861 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 862 |
|
| 863 |
-
<
|
| 864 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 865 |
</div>
|
| 866 |
-
<button class="control-button" onclick="runInversionAttack()">Generate Class Representative</button>
|
| 867 |
</div>
|
| 868 |
|
| 869 |
-
<div class="demo-panel">
|
| 870 |
-
<h3>Generated Features</h3>
|
| 871 |
<div class="visual-demo">
|
| 872 |
<div class="visual-item">
|
| 873 |
-
<
|
| 874 |
-
|
| 875 |
-
|
| 876 |
-
|
| 877 |
-
<div style="font-size: 0.8rem; color: #666; margin-top: 0.5rem;">
|
| 878 |
-
Confidence: <span id="inversion-confidence">87%</span>
|
| 879 |
</div>
|
| 880 |
</div>
|
| 881 |
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 882 |
</div>
|
| 883 |
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 884 |
</div>
|
| 885 |
</div>
|
| 886 |
|
|
@@ -900,44 +1474,82 @@
|
|
| 900 |
</div>
|
| 901 |
|
| 902 |
<div class="attack-demo">
|
| 903 |
-
<div class="demo-panel">
|
| 904 |
-
<h3>Target Properties</h3>
|
| 905 |
-
<div class="demo-controls">
|
| 906 |
-
<
|
| 907 |
-
|
| 908 |
-
<
|
| 909 |
-
|
| 910 |
-
|
| 911 |
-
|
|
|
|
|
|
|
| 912 |
|
| 913 |
-
<
|
| 914 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 915 |
</div>
|
| 916 |
-
<button class="control-button" onclick="runPropertyAttack()">Infer Properties</button>
|
| 917 |
</div>
|
| 918 |
|
| 919 |
-
<div class="demo-panel">
|
| 920 |
-
<h3>Inferred Properties</h3>
|
| 921 |
<div class="demo-result">
|
| 922 |
-
<div>Inferred Distribution:</div>
|
| 923 |
-
<div style="margin:
|
| 924 |
-
<div style="display: flex; justify-content: space-between; margin: 0.
|
| 925 |
-
<span>Male:</span> <span id="property-male">52% ± 8%</span>
|
| 926 |
</div>
|
| 927 |
-
<div style="display: flex; justify-content: space-between; margin: 0.
|
| 928 |
-
<span>Female:</span> <span id="property-female">48% ± 8%</span>
|
| 929 |
</div>
|
| 930 |
</div>
|
| 931 |
-
<div style="font-size: 0.
|
| 932 |
Confidence intervals show attack uncertainty
|
| 933 |
</div>
|
| 934 |
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 935 |
</div>
|
| 936 |
</div>
|
| 937 |
|
| 938 |
<div class="chart-container">
|
| 939 |
<canvas id="property-chart"></canvas>
|
| 940 |
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 941 |
</div>
|
| 942 |
</div>
|
| 943 |
|
|
@@ -1013,6 +1625,16 @@
|
|
| 1013 |
<div class="chart-container">
|
| 1014 |
<canvas id="linkage-chart"></canvas>
|
| 1015 |
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1016 |
</div>
|
| 1017 |
</div>
|
| 1018 |
|
|
@@ -1060,30 +1682,6 @@
|
|
| 1060 |
</div>
|
| 1061 |
</div>
|
| 1062 |
|
| 1063 |
-
<!-- Defense Mechanisms -->
|
| 1064 |
-
<div class="defense-section">
|
| 1065 |
-
<h2>🛡️ How DP-SGD Defends Against These Attacks</h2>
|
| 1066 |
-
<p>Differential privacy provides mathematical guarantees against all these attack types</p>
|
| 1067 |
-
|
| 1068 |
-
<div class="defense-grid">
|
| 1069 |
-
<div class="defense-item">
|
| 1070 |
-
<h3>Gradient Noise</h3>
|
| 1071 |
-
<p>Adds calibrated noise to gradients, making it impossible to perfectly reconstruct training data or infer membership with certainty.</p>
|
| 1072 |
-
</div>
|
| 1073 |
-
<div class="defense-item">
|
| 1074 |
-
<h3>Gradient Clipping</h3>
|
| 1075 |
-
<p>Limits the influence of any single training example, preventing attackers from identifying outliers or high-influence samples.</p>
|
| 1076 |
-
</div>
|
| 1077 |
-
<div class="defense-item">
|
| 1078 |
-
<h3>Privacy Accounting</h3>
|
| 1079 |
-
<p>Tracks cumulative privacy loss across training, ensuring mathematical bounds on what attackers can learn.</p>
|
| 1080 |
-
</div>
|
| 1081 |
-
<div class="defense-item">
|
| 1082 |
-
<h3>Composition Guarantees</h3>
|
| 1083 |
-
<p>Provides formal bounds even when multiple attacks are combined, protecting against sophisticated adversaries.</p>
|
| 1084 |
-
</div>
|
| 1085 |
-
</div>
|
| 1086 |
-
</div>
|
| 1087 |
</div>
|
| 1088 |
{% endblock %}
|
| 1089 |
|
|
|
|
| 17 |
padding: 4px;
|
| 18 |
margin-bottom: 2rem;
|
| 19 |
overflow-x: auto;
|
| 20 |
+
gap: 4px;
|
| 21 |
+
flex-wrap: wrap;
|
| 22 |
}
|
| 23 |
|
| 24 |
.attack-tab {
|
| 25 |
+
flex: 1 1 auto;
|
| 26 |
+
min-width: 160px;
|
| 27 |
padding: 0.75rem 1rem;
|
| 28 |
text-align: center;
|
| 29 |
background: transparent;
|
|
|
|
| 33 |
font-weight: 500;
|
| 34 |
transition: all 0.3s ease;
|
| 35 |
white-space: nowrap;
|
| 36 |
+
font-size: 0.9rem;
|
| 37 |
}
|
| 38 |
|
| 39 |
.attack-tab:hover {
|
|
|
|
| 335 |
flex-shrink: 0;
|
| 336 |
}
|
| 337 |
|
| 338 |
+
/* Responsive design */
|
| 339 |
+
@media (max-width: 1024px) {
|
| 340 |
+
.attack-tab {
|
| 341 |
+
flex: 1 1 calc(33.333% - 4px);
|
| 342 |
+
min-width: 150px;
|
| 343 |
+
font-size: 0.88rem;
|
| 344 |
+
}
|
| 345 |
+
}
|
| 346 |
+
|
| 347 |
@media (max-width: 768px) {
|
| 348 |
+
.attack-tabs {
|
| 349 |
+
gap: 4px;
|
| 350 |
+
padding: 4px;
|
| 351 |
+
}
|
| 352 |
+
|
| 353 |
+
.attack-tab {
|
| 354 |
+
flex: 1 1 calc(50% - 4px);
|
| 355 |
+
min-width: 140px;
|
| 356 |
+
font-size: 0.85rem;
|
| 357 |
+
padding: 0.6rem 0.75rem;
|
| 358 |
+
}
|
| 359 |
+
|
| 360 |
.story-flow {
|
| 361 |
flex-direction: column;
|
| 362 |
}
|
|
|
|
| 371 |
}
|
| 372 |
}
|
| 373 |
|
| 374 |
+
@media (max-width: 480px) {
|
| 375 |
+
.attack-tab {
|
| 376 |
+
flex: 1 1 100%;
|
| 377 |
+
min-width: auto;
|
| 378 |
+
}
|
| 379 |
+
}
|
| 380 |
+
|
| 381 |
.interactive-demo {
|
| 382 |
background: #f8f9fa;
|
| 383 |
padding: 2rem;
|
|
|
|
| 620 |
color: #666;
|
| 621 |
line-height: 1.5;
|
| 622 |
}
|
| 623 |
+
|
| 624 |
+
/* Reconstruction Grid Styles */
|
| 625 |
+
.reconstruction-visual-demo {
|
| 626 |
+
background: white;
|
| 627 |
+
padding: 2rem;
|
| 628 |
+
border-radius: 12px;
|
| 629 |
+
margin: 1.5rem 0;
|
| 630 |
+
}
|
| 631 |
+
|
| 632 |
+
.reconstruction-grid {
|
| 633 |
+
display: grid;
|
| 634 |
+
grid-template-columns: repeat(4, 1fr);
|
| 635 |
+
gap: 1rem;
|
| 636 |
+
margin: 0 auto;
|
| 637 |
+
max-width: 800px;
|
| 638 |
+
}
|
| 639 |
+
|
| 640 |
+
.grid-header {
|
| 641 |
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
| 642 |
+
color: white;
|
| 643 |
+
padding: 0.75rem 0.5rem;
|
| 644 |
+
text-align: center;
|
| 645 |
+
font-weight: bold;
|
| 646 |
+
font-size: 0.9rem;
|
| 647 |
+
border-radius: 8px 8px 0 0;
|
| 648 |
+
line-height: 1.3;
|
| 649 |
+
}
|
| 650 |
+
|
| 651 |
+
.example-cell {
|
| 652 |
+
background: #f8f9fa;
|
| 653 |
+
border: 2px solid #dee2e6;
|
| 654 |
+
border-radius: 8px;
|
| 655 |
+
padding: 0.5rem;
|
| 656 |
+
display: flex;
|
| 657 |
+
align-items: center;
|
| 658 |
+
justify-content: center;
|
| 659 |
+
transition: all 0.3s ease;
|
| 660 |
+
}
|
| 661 |
+
|
| 662 |
+
.example-cell:hover {
|
| 663 |
+
transform: scale(1.05);
|
| 664 |
+
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
|
| 665 |
+
z-index: 10;
|
| 666 |
+
}
|
| 667 |
+
|
| 668 |
+
.example-cell canvas {
|
| 669 |
+
display: block;
|
| 670 |
+
border-radius: 4px;
|
| 671 |
+
image-rendering: pixelated;
|
| 672 |
+
image-rendering: -moz-crisp-edges;
|
| 673 |
+
image-rendering: crisp-edges;
|
| 674 |
+
}
|
| 675 |
+
|
| 676 |
+
.example-cell.current-setting {
|
| 677 |
+
border: 3px solid #ffc107;
|
| 678 |
+
background: #fffbf0;
|
| 679 |
+
box-shadow: 0 0 0 3px rgba(255, 193, 7, 0.2);
|
| 680 |
+
}
|
| 681 |
+
|
| 682 |
+
.reconstruction-legend {
|
| 683 |
+
display: grid;
|
| 684 |
+
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
| 685 |
+
gap: 1rem;
|
| 686 |
+
margin-top: 2rem;
|
| 687 |
+
padding: 1.5rem;
|
| 688 |
+
background: #f8f9fa;
|
| 689 |
+
border-radius: 8px;
|
| 690 |
+
}
|
| 691 |
+
|
| 692 |
+
.legend-item {
|
| 693 |
+
display: flex;
|
| 694 |
+
align-items: center;
|
| 695 |
+
gap: 0.75rem;
|
| 696 |
+
}
|
| 697 |
+
|
| 698 |
+
.legend-box {
|
| 699 |
+
width: 30px;
|
| 700 |
+
height: 30px;
|
| 701 |
+
border-radius: 4px;
|
| 702 |
+
flex-shrink: 0;
|
| 703 |
+
}
|
| 704 |
+
|
| 705 |
+
.current-highlight {
|
| 706 |
+
background: #fffbf0;
|
| 707 |
+
border: 3px solid #ffc107;
|
| 708 |
+
animation: pulse-border 2s infinite;
|
| 709 |
+
}
|
| 710 |
+
|
| 711 |
+
@keyframes pulse-border {
|
| 712 |
+
0%, 100% { border-color: #ffc107; }
|
| 713 |
+
50% { border-color: #ff9800; }
|
| 714 |
+
}
|
| 715 |
+
|
| 716 |
+
.legend-item span {
|
| 717 |
+
font-size: 0.85rem;
|
| 718 |
+
line-height: 1.4;
|
| 719 |
+
}
|
| 720 |
+
|
| 721 |
+
@media (max-width: 768px) {
|
| 722 |
+
.reconstruction-grid {
|
| 723 |
+
grid-template-columns: repeat(2, 1fr);
|
| 724 |
+
gap: 0.5rem;
|
| 725 |
+
}
|
| 726 |
+
|
| 727 |
+
.grid-header {
|
| 728 |
+
font-size: 0.75rem;
|
| 729 |
+
padding: 0.5rem 0.25rem;
|
| 730 |
+
}
|
| 731 |
+
|
| 732 |
+
.example-cell canvas {
|
| 733 |
+
width: 80px;
|
| 734 |
+
height: 80px;
|
| 735 |
+
}
|
| 736 |
+
|
| 737 |
+
.reconstruction-legend {
|
| 738 |
+
grid-template-columns: 1fr;
|
| 739 |
+
gap: 0.75rem;
|
| 740 |
+
}
|
| 741 |
+
}
|
| 742 |
+
|
| 743 |
+
.three-panel-container {
|
| 744 |
+
display: grid;
|
| 745 |
+
grid-template-columns: 1fr auto 1fr auto 1fr;
|
| 746 |
+
gap: 1rem;
|
| 747 |
+
align-items: stretch;
|
| 748 |
+
max-width: 1400px;
|
| 749 |
+
margin: 0 auto;
|
| 750 |
+
}
|
| 751 |
+
|
| 752 |
+
.privacy-panel {
|
| 753 |
+
display: flex;
|
| 754 |
+
flex-direction: column;
|
| 755 |
+
border-radius: 12px;
|
| 756 |
+
overflow: hidden;
|
| 757 |
+
box-shadow: 0 6px 20px rgba(0, 0, 0, 0.15);
|
| 758 |
+
transition: transform 0.3s ease;
|
| 759 |
+
}
|
| 760 |
+
|
| 761 |
+
.privacy-panel:hover {
|
| 762 |
+
transform: translateY(-4px);
|
| 763 |
+
}
|
| 764 |
+
|
| 765 |
+
.panel-header {
|
| 766 |
+
padding: 1.5rem 1rem;
|
| 767 |
+
text-align: center;
|
| 768 |
+
font-weight: bold;
|
| 769 |
+
}
|
| 770 |
+
|
| 771 |
+
.panel-header h3 {
|
| 772 |
+
margin: 0;
|
| 773 |
+
font-size: 1rem;
|
| 774 |
+
line-height: 1.4;
|
| 775 |
+
letter-spacing: 0.5px;
|
| 776 |
+
}
|
| 777 |
+
|
| 778 |
+
.private-panel {
|
| 779 |
+
background: #f5e6d3;
|
| 780 |
+
border: 4px solid #c89968;
|
| 781 |
+
}
|
| 782 |
+
|
| 783 |
+
.private-panel .panel-header {
|
| 784 |
+
background: #f5e6d3;
|
| 785 |
+
color: #8b4513;
|
| 786 |
+
}
|
| 787 |
+
|
| 788 |
+
.safe-panel {
|
| 789 |
+
background: #e8f4f8;
|
| 790 |
+
border: 4px solid #7fb3d5;
|
| 791 |
+
}
|
| 792 |
+
|
| 793 |
+
.safe-panel .panel-header {
|
| 794 |
+
background: #e8f4f8;
|
| 795 |
+
color: #2c5f2d;
|
| 796 |
+
}
|
| 797 |
+
|
| 798 |
+
.attack-panel {
|
| 799 |
+
background: #fce4e4;
|
| 800 |
+
border: 4px solid #d4a5a8;
|
| 801 |
+
}
|
| 802 |
+
|
| 803 |
+
.attack-panel .panel-header {
|
| 804 |
+
background: #fce4e4;
|
| 805 |
+
color: #c1272d;
|
| 806 |
+
}
|
| 807 |
+
|
| 808 |
+
.panel-image-wrapper {
|
| 809 |
+
position: relative;
|
| 810 |
+
flex: 1;
|
| 811 |
+
display: flex;
|
| 812 |
+
align-items: center;
|
| 813 |
+
justify-content: center;
|
| 814 |
+
overflow: hidden;
|
| 815 |
+
background: #f8f9fa;
|
| 816 |
+
}
|
| 817 |
+
|
| 818 |
+
.panel-image {
|
| 819 |
+
width: 100%;
|
| 820 |
+
height: 100%;
|
| 821 |
+
object-fit: cover;
|
| 822 |
+
display: block;
|
| 823 |
+
}
|
| 824 |
+
|
| 825 |
+
.privacy-lock-overlay {
|
| 826 |
+
position: absolute;
|
| 827 |
+
bottom: 20px;
|
| 828 |
+
left: 50%;
|
| 829 |
+
transform: translateX(-50%);
|
| 830 |
+
background: rgba(255, 255, 255, 0.95);
|
| 831 |
+
padding: 0.75rem 1.5rem;
|
| 832 |
+
border-radius: 30px;
|
| 833 |
+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
|
| 834 |
+
}
|
| 835 |
+
|
| 836 |
+
.lock-icon {
|
| 837 |
+
font-size: 2rem;
|
| 838 |
+
text-align: center;
|
| 839 |
+
}
|
| 840 |
+
|
| 841 |
+
.privacy-overlay {
|
| 842 |
+
position: absolute;
|
| 843 |
+
top: 0;
|
| 844 |
+
left: 0;
|
| 845 |
+
width: 100%;
|
| 846 |
+
height: 100%;
|
| 847 |
+
background: rgba(255, 255, 255, 0.95);
|
| 848 |
+
backdrop-filter: blur(30px);
|
| 849 |
+
display: flex;
|
| 850 |
+
align-items: center;
|
| 851 |
+
justify-content: center;
|
| 852 |
+
font-size: 1.5rem;
|
| 853 |
+
font-weight: bold;
|
| 854 |
+
color: #28a745;
|
| 855 |
+
transition: all 0.5s ease;
|
| 856 |
+
flex-direction: column;
|
| 857 |
+
gap: 1rem;
|
| 858 |
+
}
|
| 859 |
+
|
| 860 |
+
.panel-footer {
|
| 861 |
+
padding: 1rem;
|
| 862 |
+
text-align: center;
|
| 863 |
+
font-size: 0.9rem;
|
| 864 |
+
background: rgba(255, 255, 255, 0.5);
|
| 865 |
+
}
|
| 866 |
+
|
| 867 |
+
.safe-footer {
|
| 868 |
+
display: flex;
|
| 869 |
+
align-items: center;
|
| 870 |
+
justify-content: center;
|
| 871 |
+
gap: 0.75rem;
|
| 872 |
+
background: rgba(255, 255, 255, 0.7);
|
| 873 |
+
}
|
| 874 |
+
|
| 875 |
+
.check-icon {
|
| 876 |
+
font-size: 1.5rem;
|
| 877 |
+
color: #28a745;
|
| 878 |
+
background: white;
|
| 879 |
+
width: 35px;
|
| 880 |
+
height: 35px;
|
| 881 |
+
border-radius: 50%;
|
| 882 |
+
display: flex;
|
| 883 |
+
align-items: center;
|
| 884 |
+
justify-content: center;
|
| 885 |
+
font-weight: bold;
|
| 886 |
+
border: 2px solid #28a745;
|
| 887 |
+
}
|
| 888 |
+
|
| 889 |
+
.footer-metrics {
|
| 890 |
+
text-align: left;
|
| 891 |
+
font-size: 0.85rem;
|
| 892 |
+
}
|
| 893 |
+
|
| 894 |
+
.small-text {
|
| 895 |
+
font-size: 0.75rem;
|
| 896 |
+
color: #666;
|
| 897 |
+
margin-top: 0.25rem;
|
| 898 |
+
}
|
| 899 |
+
|
| 900 |
+
.danger-footer {
|
| 901 |
+
display: flex;
|
| 902 |
+
align-items: center;
|
| 903 |
+
justify-content: center;
|
| 904 |
+
gap: 0.75rem;
|
| 905 |
+
background: rgba(255, 255, 255, 0.7);
|
| 906 |
+
padding: 1.25rem;
|
| 907 |
+
}
|
| 908 |
+
|
| 909 |
+
.alert-icon {
|
| 910 |
+
font-size: 2rem;
|
| 911 |
+
animation: pulse 2s infinite;
|
| 912 |
+
}
|
| 913 |
+
|
| 914 |
+
@keyframes pulse {
|
| 915 |
+
0%, 100% { opacity: 1; transform: scale(1); }
|
| 916 |
+
50% { opacity: 0.7; transform: scale(1.1); }
|
| 917 |
+
}
|
| 918 |
+
|
| 919 |
+
.danger-text {
|
| 920 |
+
font-weight: bold;
|
| 921 |
+
color: #c1272d;
|
| 922 |
+
font-size: 1rem;
|
| 923 |
+
line-height: 1.3;
|
| 924 |
+
text-align: center;
|
| 925 |
+
}
|
| 926 |
+
|
| 927 |
+
.footer-text {
|
| 928 |
+
color: #666;
|
| 929 |
+
font-size: 0.9rem;
|
| 930 |
+
}
|
| 931 |
+
|
| 932 |
+
.flow-arrow {
|
| 933 |
+
display: flex;
|
| 934 |
+
flex-direction: column;
|
| 935 |
+
align-items: center;
|
| 936 |
+
justify-content: center;
|
| 937 |
+
gap: 0.5rem;
|
| 938 |
+
}
|
| 939 |
+
|
| 940 |
+
.arrow-symbol {
|
| 941 |
+
font-size: 2.5rem;
|
| 942 |
+
color: #dc3545;
|
| 943 |
+
font-weight: bold;
|
| 944 |
+
}
|
| 945 |
+
|
| 946 |
+
.attack-arrow .arrow-symbol {
|
| 947 |
+
color: #c1272d;
|
| 948 |
+
}
|
| 949 |
+
|
| 950 |
+
.arrow-label {
|
| 951 |
+
font-size: 0.85rem;
|
| 952 |
+
color: #666;
|
| 953 |
+
font-weight: 600;
|
| 954 |
+
text-transform: uppercase;
|
| 955 |
+
letter-spacing: 0.5px;
|
| 956 |
+
}
|
| 957 |
+
|
| 958 |
+
@media (max-width: 1200px) {
|
| 959 |
+
.three-panel-container {
|
| 960 |
+
grid-template-columns: 1fr;
|
| 961 |
+
gap: 1.5rem;
|
| 962 |
+
}
|
| 963 |
+
|
| 964 |
+
.flow-arrow {
|
| 965 |
+
flex-direction: row;
|
| 966 |
+
gap: 1rem;
|
| 967 |
+
}
|
| 968 |
+
|
| 969 |
+
.arrow-symbol {
|
| 970 |
+
transform: rotate(90deg);
|
| 971 |
+
}
|
| 972 |
+
|
| 973 |
+
.panel-header h3 {
|
| 974 |
+
font-size: 0.95rem;
|
| 975 |
+
}
|
| 976 |
+
}
|
| 977 |
+
|
| 978 |
+
@media (max-width: 768px) {
|
| 979 |
+
.panel-header h3 {
|
| 980 |
+
font-size: 0.85rem;
|
| 981 |
+
}
|
| 982 |
+
|
| 983 |
+
.arrow-symbol {
|
| 984 |
+
font-size: 2rem;
|
| 985 |
+
}
|
| 986 |
+
|
| 987 |
+
.reconstruction-visual-demo {
|
| 988 |
+
padding: 1rem;
|
| 989 |
+
}
|
| 990 |
+
}
|
| 991 |
</style>
|
| 992 |
{% endblock %}
|
| 993 |
|
|
|
|
| 1070 |
<div class="demo-scenario">
|
| 1071 |
<div class="scenario-setup">
|
| 1072 |
<h4>The Setup</h4>
|
| 1073 |
+
<p>A hospital trained a model to predict heart disease risk. Let's see if an attacker can tell which patient records were in the training set!</p>
|
| 1074 |
</div>
|
| 1075 |
|
| 1076 |
<div class="confidence-comparison">
|
|
|
|
| 1080 |
<span class="sample-status training">✓ Was in training</span>
|
| 1081 |
</div>
|
| 1082 |
<div class="sample-image">
|
| 1083 |
+
<div class="digit-display" style="font-size: 1rem; flex-direction: column; gap: 0.5rem; height: auto; padding: 1rem;">
|
| 1084 |
+
<div style="font-size: 2.5rem;">🏥</div>
|
| 1085 |
+
<div style="font-size: 0.85rem; color: #666;">Patient #A2847</div>
|
| 1086 |
+
<div style="font-size: 0.8rem; color: #999; line-height: 1.3;">Age: 58 | BP: 145/92<br/>Cholesterol: High</div>
|
| 1087 |
+
</div>
|
| 1088 |
</div>
|
| 1089 |
<div class="confidence-bar">
|
| 1090 |
<div class="confidence-label">Model Confidence:</div>
|
| 1091 |
<div class="confidence-meter">
|
| 1092 |
+
<div class="confidence-fill training-confidence" id="training-confidence" style="width: 96%;">96%</div>
|
| 1093 |
</div>
|
| 1094 |
</div>
|
| 1095 |
</div>
|
|
|
|
| 1102 |
<span class="sample-status test">✗ Not in training</span>
|
| 1103 |
</div>
|
| 1104 |
<div class="sample-image">
|
| 1105 |
+
<div class="digit-display" style="font-size: 1rem; flex-direction: column; gap: 0.5rem; height: auto; padding: 1rem;">
|
| 1106 |
+
<div style="font-size: 2.5rem;">🏥</div>
|
| 1107 |
+
<div style="font-size: 0.85rem; color: #666;">Patient #B3192</div>
|
| 1108 |
+
<div style="font-size: 0.8rem; color: #999; line-height: 1.3;">Age: 56 | BP: 142/90<br/>Cholesterol: High</div>
|
| 1109 |
+
</div>
|
| 1110 |
</div>
|
| 1111 |
<div class="confidence-bar">
|
| 1112 |
<div class="confidence-label">Model Confidence:</div>
|
| 1113 |
<div class="confidence-meter">
|
| 1114 |
+
<div class="confidence-fill test-confidence" id="test-confidence" style="width: 68%;">68%</div>
|
| 1115 |
</div>
|
| 1116 |
</div>
|
| 1117 |
</div>
|
|
|
|
| 1119 |
|
| 1120 |
<div class="attack-insight">
|
| 1121 |
<div class="insight-box">
|
| 1122 |
+
<strong>🔍 The Attack Insight:</strong> The model is <span id="confidence-diff">28%</span> more confident on training data!
|
| 1123 |
+
An attacker can use this difference to infer that Patient A2847 was treated at this hospital - a serious privacy breach.
|
| 1124 |
</div>
|
| 1125 |
</div>
|
| 1126 |
</div>
|
|
|
|
| 1183 |
<div class="chart-container">
|
| 1184 |
<canvas id="membership-chart"></canvas>
|
| 1185 |
</div>
|
| 1186 |
+
|
| 1187 |
+
<!-- Defense against this attack -->
|
| 1188 |
+
<div style="margin-top: 2rem; padding: 1.5rem; background: linear-gradient(135deg, #4caf50 0%, #45a049 100%); border-radius: 8px; color: white;">
|
| 1189 |
+
<h3 style="margin-bottom: 1rem; display: flex; align-items: center; gap: 0.5rem;">
|
| 1190 |
+
<span style="font-size: 1.5rem;">🛡️</span> How DP-SGD Defends Against This Attack
|
| 1191 |
+
</h3>
|
| 1192 |
+
<p style="font-size: 1rem; line-height: 1.6; margin: 0;">
|
| 1193 |
+
<strong>Random noise addition:</strong> DP-SGD adds carefully calibrated noise to model outputs, making Alice's record indistinguishable from any other patient. The model gives similar confidence scores whether or not someone was in the training data - attackers can't tell the difference between training and test examples.
|
| 1194 |
+
</p>
|
| 1195 |
+
</div>
|
| 1196 |
</div>
|
| 1197 |
</div>
|
| 1198 |
|
|
|
|
| 1211 |
<strong>Threat:</strong> Attackers with access to gradients can potentially reconstruct original training images, especially in federated learning scenarios.
|
| 1212 |
</div>
|
| 1213 |
|
| 1214 |
+
<div class="attack-scenario-intro" style="background: #f8f9fa; padding: 1.5rem; border-radius: 8px; margin-bottom: 1.5rem;">
|
| 1215 |
+
<h3>📋 Scenario: Federated Learning Attack</h3>
|
| 1216 |
+
<p style="margin: 0.5rem 0 0 0; color: #666;">
|
| 1217 |
+
In federated learning, a company trains a model using images from users' devices. An attacker with access to
|
| 1218 |
+
gradient updates attempts to reconstruct the original training images. Let's see how differential privacy protects against this!
|
| 1219 |
+
</p>
|
| 1220 |
+
</div>
|
| 1221 |
+
|
| 1222 |
+
<div class="reconstruction-visual-demo">
|
| 1223 |
+
<h3 style="text-align: center; margin-bottom: 1.5rem;">🔍 Reconstruction Quality at Different Privacy Levels</h3>
|
| 1224 |
+
|
| 1225 |
+
<!-- Multi-example comparison grid -->
|
| 1226 |
+
<div class="reconstruction-grid">
|
| 1227 |
+
<!-- Header Row -->
|
| 1228 |
+
<div class="grid-header">Ground Truth</div>
|
| 1229 |
+
<div class="grid-header">No Privacy<br/><span style="font-size: 0.85rem; font-weight: normal;">(ε = ∞)</span></div>
|
| 1230 |
+
<div class="grid-header">Low Privacy<br/><span style="font-size: 0.85rem; font-weight: normal;" id="current-epsilon">(ε = 8.0)</span></div>
|
| 1231 |
+
<div class="grid-header">High Privacy<br/><span style="font-size: 0.85rem; font-weight: normal;">(ε = 0.1)</span></div>
|
| 1232 |
+
|
| 1233 |
+
<!-- Example 1: Face-like -->
|
| 1234 |
+
<div class="example-cell">
|
| 1235 |
+
<canvas id="original-1" width="120" height="120"></canvas>
|
| 1236 |
+
</div>
|
| 1237 |
+
<div class="example-cell">
|
| 1238 |
+
<canvas id="no-privacy-1" width="120" height="120"></canvas>
|
| 1239 |
+
</div>
|
| 1240 |
+
<div class="example-cell current-setting">
|
| 1241 |
+
<canvas id="current-1" width="120" height="120"></canvas>
|
| 1242 |
+
</div>
|
| 1243 |
+
<div class="example-cell">
|
| 1244 |
+
<canvas id="high-privacy-1" width="120" height="120"></canvas>
|
| 1245 |
+
</div>
|
| 1246 |
+
|
| 1247 |
+
<!-- Example 2: Eye-like -->
|
| 1248 |
+
<div class="example-cell">
|
| 1249 |
+
<canvas id="original-2" width="120" height="120"></canvas>
|
| 1250 |
+
</div>
|
| 1251 |
+
<div class="example-cell">
|
| 1252 |
+
<canvas id="no-privacy-2" width="120" height="120"></canvas>
|
| 1253 |
+
</div>
|
| 1254 |
+
<div class="example-cell current-setting">
|
| 1255 |
+
<canvas id="current-2" width="120" height="120"></canvas>
|
| 1256 |
+
</div>
|
| 1257 |
+
<div class="example-cell">
|
| 1258 |
+
<canvas id="high-privacy-2" width="120" height="120"></canvas>
|
| 1259 |
+
</div>
|
| 1260 |
+
|
| 1261 |
+
<!-- Example 3: Medical scan-like -->
|
| 1262 |
+
<div class="example-cell">
|
| 1263 |
+
<canvas id="original-3" width="120" height="120"></canvas>
|
| 1264 |
+
</div>
|
| 1265 |
+
<div class="example-cell">
|
| 1266 |
+
<canvas id="no-privacy-3" width="120" height="120"></canvas>
|
| 1267 |
+
</div>
|
| 1268 |
+
<div class="example-cell current-setting">
|
| 1269 |
+
<canvas id="current-3" width="120" height="120"></canvas>
|
| 1270 |
+
</div>
|
| 1271 |
+
<div class="example-cell">
|
| 1272 |
+
<canvas id="high-privacy-3" width="120" height="120"></canvas>
|
| 1273 |
+
</div>
|
| 1274 |
+
|
| 1275 |
+
<!-- Example 4: Object-like -->
|
| 1276 |
+
<div class="example-cell">
|
| 1277 |
+
<canvas id="original-4" width="120" height="120"></canvas>
|
| 1278 |
+
</div>
|
| 1279 |
+
<div class="example-cell">
|
| 1280 |
+
<canvas id="no-privacy-4" width="120" height="120"></canvas>
|
| 1281 |
+
</div>
|
| 1282 |
+
<div class="example-cell current-setting">
|
| 1283 |
+
<canvas id="current-4" width="120" height="120"></canvas>
|
| 1284 |
+
</div>
|
| 1285 |
+
<div class="example-cell">
|
| 1286 |
+
<canvas id="high-privacy-4" width="120" height="120"></canvas>
|
| 1287 |
+
</div>
|
| 1288 |
+
</div>
|
| 1289 |
+
|
| 1290 |
+
<!-- Legend -->
|
| 1291 |
+
<div class="reconstruction-legend">
|
| 1292 |
+
<div class="legend-item">
|
| 1293 |
+
<div class="legend-box" style="background: #e8f5e9; border: 2px solid #4caf50;"></div>
|
| 1294 |
+
<span><strong>Ground Truth:</strong> Original private training images</span>
|
| 1295 |
+
</div>
|
| 1296 |
+
<div class="legend-item">
|
| 1297 |
+
<div class="legend-box" style="background: #ffebee; border: 2px solid #f44336;"></div>
|
| 1298 |
+
<span><strong>No Privacy:</strong> Perfect reconstruction - privacy breach!</span>
|
| 1299 |
+
</div>
|
| 1300 |
+
<div class="legend-item">
|
| 1301 |
+
<div class="legend-box current-highlight"></div>
|
| 1302 |
+
<span><strong>Your Settings:</strong> Adjust sliders below to see changes</span>
|
| 1303 |
+
</div>
|
| 1304 |
+
<div class="legend-item">
|
| 1305 |
+
<div class="legend-box" style="background: #e3f2fd; border: 2px solid #2196f3;"></div>
|
| 1306 |
+
<span><strong>High Privacy:</strong> Reconstruction fails - data protected!</span>
|
| 1307 |
+
</div>
|
| 1308 |
+
</div>
|
| 1309 |
+
|
| 1310 |
+
<!-- Quality Badge Below -->
|
| 1311 |
+
<div style="text-align: center; margin-top: 1.5rem;">
|
| 1312 |
+
<div class="reconstruction-quality quality-high" id="recon-quality" style="display: inline-block; padding: 0.75rem 1.5rem; font-size: 1.1rem;">
|
| 1313 |
+
⚠️ Medium Quality
|
| 1314 |
+
</div>
|
| 1315 |
+
</div>
|
| 1316 |
+
</div>
|
| 1317 |
+
|
| 1318 |
+
<div class="attack-demo" style="margin-top: 2rem;">
|
| 1319 |
<div class="demo-panel">
|
| 1320 |
+
<h3>🛡️ Differential Privacy Settings</h3>
|
| 1321 |
<div class="demo-controls">
|
| 1322 |
+
<label>Gradient Clipping Norm: <span id="recon-clipping">1.0</span></label>
|
| 1323 |
<input type="range" class="demo-slider" id="recon-clipping-slider" min="0.1" max="5" step="0.1" value="1.0">
|
| 1324 |
+
<div class="privacy-scale">
|
| 1325 |
+
<span style="font-size: 0.75rem;">🔒 Tight Clipping (More Private)</span>
|
| 1326 |
+
<span style="font-size: 0.75rem;">🔓 Loose Clipping (Less Private)</span>
|
| 1327 |
+
</div>
|
| 1328 |
|
| 1329 |
+
<label style="margin-top: 1rem;">Noise Multiplier (σ): <span id="recon-noise-level">1.0</span></label>
|
| 1330 |
<input type="range" class="demo-slider" id="recon-noise-slider" min="0" max="3" step="0.1" value="1.0">
|
| 1331 |
+
<div class="privacy-scale">
|
| 1332 |
+
<span style="font-size: 0.75rem;">🔇 No Noise (Vulnerable)</span>
|
| 1333 |
+
<span style="font-size: 0.75rem;">🔊 High Noise (Protected)</span>
|
| 1334 |
+
</div>
|
| 1335 |
</div>
|
| 1336 |
+
<button class="control-button" onclick="runReconstructionAttack()">🔄 Update Reconstruction</button>
|
| 1337 |
</div>
|
| 1338 |
|
| 1339 |
<div class="demo-panel">
|
| 1340 |
+
<h3>📊 Attack Analysis</h3>
|
| 1341 |
+
<div class="demo-result">
|
| 1342 |
+
<div style="margin-bottom: 1rem;">
|
| 1343 |
+
<strong>Reconstruction SSIM Score:</strong>
|
| 1344 |
+
<div style="font-size: 1.8rem; color: #dc3545; font-weight: bold; margin: 0.5rem 0;" id="ssim-score">0.85</div>
|
| 1345 |
+
<div style="font-size: 0.85rem; color: #666;">
|
| 1346 |
+
(1.0 = perfect reconstruction, 0.0 = completely failed)
|
| 1347 |
</div>
|
|
|
|
| 1348 |
</div>
|
| 1349 |
+
|
| 1350 |
+
<div style="margin-top: 1rem; padding-top: 1rem; border-top: 1px solid #ddd;">
|
| 1351 |
+
<div style="display: flex; justify-content: space-between; margin: 0.5rem 0;">
|
| 1352 |
+
<span>Privacy Level:</span>
|
| 1353 |
+
<span id="privacy-status" style="font-weight: bold; color: #dc3545;">❌ Low (ε ≈ 8.0)</span>
|
| 1354 |
+
</div>
|
| 1355 |
+
<div style="display: flex; justify-content: space-between; margin: 0.5rem 0;">
|
| 1356 |
+
<span>Attack Success:</span>
|
| 1357 |
+
<span id="attack-success" style="font-weight: bold; color: #dc3545;">92%</span>
|
| 1358 |
</div>
|
|
|
|
| 1359 |
</div>
|
| 1360 |
</div>
|
| 1361 |
+
|
| 1362 |
+
<div class="privacy-explanation" id="recon-explanation" style="margin-top: 1rem;">
|
| 1363 |
+
⚠️ Without sufficient privacy protection, attackers can reconstruct training images with high fidelity from gradient information alone!
|
| 1364 |
+
</div>
|
| 1365 |
</div>
|
| 1366 |
</div>
|
| 1367 |
|
| 1368 |
<div class="chart-container">
|
| 1369 |
<canvas id="reconstruction-chart"></canvas>
|
| 1370 |
</div>
|
| 1371 |
+
|
| 1372 |
+
<!-- Defense against this attack -->
|
| 1373 |
+
<div style="margin-top: 2rem; padding: 1.5rem; background: linear-gradient(135deg, #4caf50 0%, #45a049 100%); border-radius: 8px; color: white;">
|
| 1374 |
+
<h3 style="margin-bottom: 1rem; display: flex; align-items: center; gap: 0.5rem;">
|
| 1375 |
+
<span style="font-size: 1.5rem;">🛡️</span> How DP-SGD Defends Against This Attack
|
| 1376 |
+
</h3>
|
| 1377 |
+
<p style="font-size: 1rem; line-height: 1.6; margin: 0;">
|
| 1378 |
+
<strong>Gradient clipping + noise:</strong> DP-SGD clips each person's influence on the model, then drowns it in noise - like taking a photo and adding so much blur that faces become unrecognizable blobs. Attackers cannot reverse-engineer the original training images from the model's outputs.
|
| 1379 |
+
</p>
|
| 1380 |
+
</div>
|
| 1381 |
</div>
|
| 1382 |
</div>
|
| 1383 |
|
|
|
|
| 1397 |
</div>
|
| 1398 |
|
| 1399 |
<div class="attack-demo">
|
| 1400 |
+
<div class="demo-panel" style="padding: 1.5rem;">
|
| 1401 |
+
<h3 style="margin-bottom: 1.5rem;">Inversion Parameters</h3>
|
| 1402 |
+
<div class="demo-controls" style="gap: 1.5rem;">
|
| 1403 |
+
<div style="margin-bottom: 1.5rem;">
|
| 1404 |
+
<label style="display: block; margin-bottom: 0.75rem; font-weight: 500;">
|
| 1405 |
+
Target Class: <span id="inversion-class" style="color: #1976d2; font-weight: 600;">Digit 7</span>
|
| 1406 |
+
</label>
|
| 1407 |
+
<select id="inversion-class-select" class="parameter-select" style="width: 100%; padding: 0.5rem; font-size: 1rem; border-radius: 4px; border: 2px solid #e0e0e0;">
|
| 1408 |
+
<option value="0">Digit 0</option>
|
| 1409 |
+
<option value="1">Digit 1</option>
|
| 1410 |
+
<option value="7" selected>Digit 7</option>
|
| 1411 |
+
<option value="9">Digit 9</option>
|
| 1412 |
+
</select>
|
| 1413 |
+
</div>
|
| 1414 |
|
| 1415 |
+
<div style="margin-bottom: 1.5rem;">
|
| 1416 |
+
<label style="display: block; margin-bottom: 0.75rem; font-weight: 500;">
|
| 1417 |
+
Privacy Level: <span id="inversion-privacy" style="color: #1976d2; font-weight: 600;">Medium</span>
|
| 1418 |
+
</label>
|
| 1419 |
+
<input type="range" class="demo-slider" id="inversion-privacy-slider" min="1" max="10" step="1" value="5" style="width: 100%; margin-top: 0.5rem;">
|
| 1420 |
+
<div style="display: flex; justify-content: space-between; font-size: 0.75rem; color: #999; margin-top: 0.5rem;">
|
| 1421 |
+
<span style="text-align: left;">🔒 High Privacy<br/>(ε = 1.0)</span>
|
| 1422 |
+
<span style="text-align: right;">🔓 Low Privacy<br/>(ε = 10.0)</span>
|
| 1423 |
+
</div>
|
| 1424 |
+
</div>
|
| 1425 |
</div>
|
| 1426 |
+
<button class="control-button" onclick="runInversionAttack()" style="width: 100%; padding: 0.75rem; font-size: 1rem; margin-top: 1rem;">Generate Class Representative</button>
|
| 1427 |
</div>
|
| 1428 |
|
| 1429 |
+
<div class="demo-panel" style="padding: 1.5rem;">
|
| 1430 |
+
<h3 style="margin-bottom: 1.5rem;">Generated Features</h3>
|
| 1431 |
<div class="visual-demo">
|
| 1432 |
<div class="visual-item">
|
| 1433 |
+
<canvas id="inversion-canvas" width="160" height="160" style="border-radius: 8px; margin: 0 auto 1rem; display: block; border: 3px solid #2196f3; box-shadow: 0 2px 8px rgba(0,0,0,0.1);"></canvas>
|
| 1434 |
+
<div style="font-size: 1rem; font-weight: 500; margin-bottom: 0.75rem;">Inverted Features</div>
|
| 1435 |
+
<div style="font-size: 0.9rem; color: #666; margin-bottom: 0.5rem;">
|
| 1436 |
+
Confidence: <span id="inversion-confidence" style="font-weight: 600; color: #1976d2;">87%</span>
|
|
|
|
|
|
|
| 1437 |
</div>
|
| 1438 |
</div>
|
| 1439 |
</div>
|
| 1440 |
+
|
| 1441 |
+
<div class="privacy-explanation" style="margin-top: 1.5rem; padding: 1.25rem; background: #fff3e0; border-radius: 6px; font-size: 0.9rem; line-height: 1.5; border-left: 4px solid #ff9800;">
|
| 1442 |
+
<div id="inversion-explanation">
|
| 1443 |
+
⚠️ Medium privacy. Some class features are visible but degraded. Move the slider left for higher privacy!
|
| 1444 |
+
</div>
|
| 1445 |
+
</div>
|
| 1446 |
</div>
|
| 1447 |
</div>
|
| 1448 |
+
|
| 1449 |
+
<!-- Defense against this attack -->
|
| 1450 |
+
<div style="margin-top: 2rem; padding: 1.5rem; background: linear-gradient(135deg, #4caf50 0%, #45a049 100%); border-radius: 8px; color: white;">
|
| 1451 |
+
<h3 style="margin-bottom: 1rem; display: flex; align-items: center; gap: 0.5rem;">
|
| 1452 |
+
<span style="font-size: 1.5rem;">🛡️</span> How DP-SGD Defends Against This Attack
|
| 1453 |
+
</h3>
|
| 1454 |
+
<p style="font-size: 1rem; line-height: 1.6; margin: 0;">
|
| 1455 |
+
<strong>Feature scrambling:</strong> DP-SGD scrambles what the model "remembers" about each class. Instead of learning "digit 7 looks like this sharp image," it learns "7 is somewhere in this fuzzy cloud." Attackers cannot extract clear class representatives or features.
|
| 1456 |
+
</p>
|
| 1457 |
+
</div>
|
| 1458 |
</div>
|
| 1459 |
</div>
|
| 1460 |
|
|
|
|
| 1474 |
</div>
|
| 1475 |
|
| 1476 |
<div class="attack-demo">
|
| 1477 |
+
<div class="demo-panel" style="padding: 1.5rem;">
|
| 1478 |
+
<h3 style="margin-bottom: 1.5rem;">Target Properties</h3>
|
| 1479 |
+
<div class="demo-controls" style="gap: 1.5rem;">
|
| 1480 |
+
<div style="margin-bottom: 1.5rem;">
|
| 1481 |
+
<label style="display: block; margin-bottom: 0.75rem; font-weight: 500;">Property Type:</label>
|
| 1482 |
+
<select id="property-type" class="parameter-select" style="width: 100%; padding: 0.5rem; font-size: 1rem; border-radius: 4px; border: 2px solid #e0e0e0;">
|
| 1483 |
+
<option value="gender">Gender Distribution</option>
|
| 1484 |
+
<option value="age">Age Distribution</option>
|
| 1485 |
+
<option value="location">Geographic Distribution</option>
|
| 1486 |
+
</select>
|
| 1487 |
+
</div>
|
| 1488 |
|
| 1489 |
+
<div style="margin-bottom: 1.5rem;">
|
| 1490 |
+
<label style="display: block; margin-bottom: 0.75rem; font-weight: 500;">
|
| 1491 |
+
Privacy Level: <span id="property-privacy" style="color: #1976d2; font-weight: 600;">Medium</span>
|
| 1492 |
+
</label>
|
| 1493 |
+
<input type="range" class="demo-slider" id="property-privacy-slider" min="1" max="10" step="1" value="5" style="width: 100%; margin-top: 0.5rem;">
|
| 1494 |
+
<div style="display: flex; justify-content: space-between; font-size: 0.75rem; color: #999; margin-top: 0.5rem;">
|
| 1495 |
+
<span style="text-align: left;">🔒 High Privacy<br/>(ε = 1.0)</span>
|
| 1496 |
+
<span style="text-align: right;">🔓 Low Privacy<br/>(ε = 10.0)</span>
|
| 1497 |
+
</div>
|
| 1498 |
+
</div>
|
| 1499 |
+
|
| 1500 |
+
<div style="margin-bottom: 1.5rem;">
|
| 1501 |
+
<label style="display: block; margin-bottom: 0.75rem; font-weight: 500;">
|
| 1502 |
+
Model Access: <span id="property-access" style="color: #1976d2; font-weight: 600;">Black-box</span>
|
| 1503 |
+
</label>
|
| 1504 |
+
<input type="range" class="demo-slider" id="property-access-slider" min="1" max="3" step="1" value="1" style="width: 100%; margin-top: 0.5rem;">
|
| 1505 |
+
<div style="display: flex; justify-content: space-between; font-size: 0.75rem; color: #999; margin-top: 0.5rem;">
|
| 1506 |
+
<span>Black-box</span>
|
| 1507 |
+
<span>Gray-box</span>
|
| 1508 |
+
<span>White-box</span>
|
| 1509 |
+
</div>
|
| 1510 |
+
</div>
|
| 1511 |
</div>
|
| 1512 |
+
<button class="control-button" onclick="runPropertyAttack()" style="width: 100%; padding: 0.75rem; font-size: 1rem; margin-top: 1rem;">Infer Properties</button>
|
| 1513 |
</div>
|
| 1514 |
|
| 1515 |
+
<div class="demo-panel" style="padding: 1.5rem;">
|
| 1516 |
+
<h3 style="margin-bottom: 1.5rem;">Inferred Properties</h3>
|
| 1517 |
<div class="demo-result">
|
| 1518 |
+
<div style="font-size: 1rem; font-weight: 500; margin-bottom: 1rem;">Inferred Distribution:</div>
|
| 1519 |
+
<div style="margin: 1.5rem 0;">
|
| 1520 |
+
<div style="display: flex; justify-content: space-between; margin: 0.75rem 0; padding: 0.5rem; background: #f5f5f5; border-radius: 4px;">
|
| 1521 |
+
<span style="font-weight: 500;">Male:</span> <span id="property-male" style="font-weight: 600; color: #1976d2;">52% ± 8%</span>
|
| 1522 |
</div>
|
| 1523 |
+
<div style="display: flex; justify-content: space-between; margin: 0.75rem 0; padding: 0.5rem; background: #f5f5f5; border-radius: 4px;">
|
| 1524 |
+
<span style="font-weight: 500;">Female:</span> <span id="property-female" style="font-weight: 600; color: #1976d2;">48% ± 8%</span>
|
| 1525 |
</div>
|
| 1526 |
</div>
|
| 1527 |
+
<div style="font-size: 0.85rem; color: #666; font-style: italic;">
|
| 1528 |
Confidence intervals show attack uncertainty
|
| 1529 |
</div>
|
| 1530 |
</div>
|
| 1531 |
+
|
| 1532 |
+
<div class="privacy-explanation" style="margin-top: 1.5rem; padding: 1.25rem; background: #fff3e0; border-radius: 6px; font-size: 0.9rem; line-height: 1.5; border-left: 4px solid #ff9800;">
|
| 1533 |
+
<div id="property-explanation">
|
| 1534 |
+
⚠️ Medium privacy. The attacker can infer dataset properties with moderate accuracy. Move the slider left for higher privacy!
|
| 1535 |
+
</div>
|
| 1536 |
+
</div>
|
| 1537 |
</div>
|
| 1538 |
</div>
|
| 1539 |
|
| 1540 |
<div class="chart-container">
|
| 1541 |
<canvas id="property-chart"></canvas>
|
| 1542 |
</div>
|
| 1543 |
+
|
| 1544 |
+
<!-- Defense against this attack -->
|
| 1545 |
+
<div style="margin-top: 2rem; padding: 1.5rem; background: linear-gradient(135deg, #4caf50 0%, #45a049 100%); border-radius: 8px; color: white;">
|
| 1546 |
+
<h3 style="margin-bottom: 1rem; display: flex; align-items: center; gap: 0.5rem;">
|
| 1547 |
+
<span style="font-size: 1.5rem;">🛡️</span> How DP-SGD Defends Against This Attack
|
| 1548 |
+
</h3>
|
| 1549 |
+
<p style="font-size: 1rem; line-height: 1.6; margin: 0;">
|
| 1550 |
+
<strong>Privacy budget tracking:</strong> DP-SGD keeps a "privacy budget" (ε) - like a bank account that tracks how much information leaked. When the budget runs low, training stops to prevent dataset statistics (like gender distribution or age ranges) from being exposed.
|
| 1551 |
+
</p>
|
| 1552 |
+
</div>
|
| 1553 |
</div>
|
| 1554 |
</div>
|
| 1555 |
|
|
|
|
| 1625 |
<div class="chart-container">
|
| 1626 |
<canvas id="linkage-chart"></canvas>
|
| 1627 |
</div>
|
| 1628 |
+
|
| 1629 |
+
<!-- Defense against this attack -->
|
| 1630 |
+
<div style="margin-top: 2rem; padding: 1.5rem; background: linear-gradient(135deg, #4caf50 0%, #45a049 100%); border-radius: 8px; color: white;">
|
| 1631 |
+
<h3 style="margin-bottom: 1rem; display: flex; align-items: center; gap: 0.5rem;">
|
| 1632 |
+
<span style="font-size: 1.5rem;">🛡️</span> How DP-SGD Defends Against This Attack
|
| 1633 |
+
</h3>
|
| 1634 |
+
<p style="font-size: 1rem; line-height: 1.6; margin: 0;">
|
| 1635 |
+
<strong>Output noise + bounded leakage:</strong> DP-SGD adds noise to model predictions AND tracks total privacy loss (ε). Even when attackers combine model outputs with external datasets (social media, public records), the mathematical privacy guarantee ensures they cannot reliably link individuals or infer sensitive attributes.
|
| 1636 |
+
</p>
|
| 1637 |
+
</div>
|
| 1638 |
</div>
|
| 1639 |
</div>
|
| 1640 |
|
|
|
|
| 1682 |
</div>
|
| 1683 |
</div>
|
| 1684 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1685 |
</div>
|
| 1686 |
{% endblock %}
|
| 1687 |
|