yakmesh 2.8.2 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +637 -0
- package/CONTRIBUTING.md +42 -0
- package/Caddyfile +77 -0
- package/README.md +119 -29
- package/adapters/adapter-mlv-bible/README.md +124 -0
- package/adapters/adapter-mlv-bible/index.js +400 -0
- package/adapters/chat-mod-adapter.js +532 -0
- package/adapters/content-adapter.js +273 -0
- package/content/api.js +50 -41
- package/content/index.js +2 -2
- package/content/store.js +355 -173
- package/dashboard/index.html +19 -3
- package/database/replication.js +117 -37
- package/docs/CRYPTO-AGILITY.md +204 -0
- package/docs/MTLS-RESEARCH.md +367 -0
- package/docs/NAMCHE-SPEC.md +681 -0
- package/docs/PEERQUANTA-YAKMESH-INTEGRATION.md +407 -0
- package/docs/PRECISION-DISCLOSURE.md +96 -0
- package/docs/README.md +76 -0
- package/docs/ROADMAP-2.4.0.md +447 -0
- package/docs/ROADMAP-2.5.0.md +244 -0
- package/docs/SECURITY-AUDIT-REPORT.md +306 -0
- package/docs/SST-INTEGRATION.md +712 -0
- package/docs/STEADYWATCH-IMPLEMENTATION.md +303 -0
- package/docs/TERNARY-AUDIT-REPORT.md +247 -0
- package/docs/TME-FAQ.md +221 -0
- package/docs/WHITEPAPER.md +623 -0
- package/docs/adapters.html +1001 -0
- package/docs/advanced-systems.html +1045 -0
- package/docs/annex.html +1046 -0
- package/docs/api.html +970 -0
- package/docs/business/response-templates.md +160 -0
- package/docs/c2c.html +1225 -0
- package/docs/cli.html +1332 -0
- package/docs/configuration.html +1248 -0
- package/docs/darshan.html +1085 -0
- package/docs/dharma.html +966 -0
- package/docs/docs-bundle.html +1075 -0
- package/docs/docs.css +3120 -0
- package/docs/docs.js +556 -0
- package/docs/doko.html +969 -0
- package/docs/geo-proof.html +858 -0
- package/docs/getting-started.html +840 -0
- package/docs/gumba-tutorial.html +1144 -0
- package/docs/gumba.html +1098 -0
- package/docs/index.html +914 -0
- package/docs/jhilke.html +1312 -0
- package/docs/karma.html +1100 -0
- package/docs/katha.html +1037 -0
- package/docs/lama.html +978 -0
- package/docs/mandala.html +1067 -0
- package/docs/mani.html +964 -0
- package/docs/mantra.html +967 -0
- package/docs/mesh.html +1409 -0
- package/docs/nakpak.html +869 -0
- package/docs/namche.html +928 -0
- package/docs/nav-order.json +53 -0
- package/docs/prahari.html +1043 -0
- package/docs/prism-bash.min.js +1 -0
- package/docs/prism-javascript.min.js +1 -0
- package/docs/prism-json.min.js +1 -0
- package/docs/prism-tomorrow.min.css +1 -0
- package/docs/prism.min.js +1 -0
- package/docs/privacy.html +699 -0
- package/docs/quick-reference.html +1181 -0
- package/docs/sakshi.html +1402 -0
- package/docs/sandboxing.md +386 -0
- package/docs/seva.html +911 -0
- package/docs/sherpa.html +871 -0
- package/docs/studio.html +860 -0
- package/docs/stupa.html +995 -0
- package/docs/tailwind.min.css +2 -0
- package/docs/tattva.html +1332 -0
- package/docs/terms.html +686 -0
- package/docs/time-server-deployment.md +166 -0
- package/docs/time-sources.html +1392 -0
- package/docs/tivra.html +1127 -0
- package/docs/trademark-policy.html +686 -0
- package/docs/tribhuj.html +1183 -0
- package/docs/trust-security.html +1029 -0
- package/docs/tutorials/backup-recovery.html +654 -0
- package/docs/tutorials/dashboard.html +604 -0
- package/docs/tutorials/domain-setup.html +605 -0
- package/docs/tutorials/host-website.html +456 -0
- package/docs/tutorials/mesh-network.html +505 -0
- package/docs/tutorials/mobile-access.html +445 -0
- package/docs/tutorials/privacy.html +467 -0
- package/docs/tutorials/raspberry-pi.html +600 -0
- package/docs/tutorials/security-basics.html +539 -0
- package/docs/tutorials/share-files.html +431 -0
- package/docs/tutorials/troubleshooting.html +637 -0
- package/docs/tutorials/trust-karma.html +419 -0
- package/docs/tutorials/yak-protocol.html +456 -0
- package/docs/tutorials.html +1034 -0
- package/docs/vani.html +1270 -0
- package/docs/webserver.html +809 -0
- package/docs/yak-protocol.html +940 -0
- package/docs/yak-timeserver-design.md +475 -0
- package/docs/yakapp.html +1015 -0
- package/docs/ypc27.html +1069 -0
- package/docs/yurt.html +1344 -0
- package/embedded-docs/bundle.js +334 -74
- package/gossip/protocol.js +247 -27
- package/identity/key-resolver.js +262 -0
- package/identity/machine-seed.js +632 -0
- package/identity/node-key.js +669 -368
- package/identity/tribhuj-ratchet.js +506 -0
- package/knowledge-base.js +37 -8
- package/launcher/yakmesh.bat +62 -0
- package/launcher/yakmesh.sh +70 -0
- package/mesh/annex.js +462 -108
- package/mesh/beacon-broadcast.js +113 -1
- package/mesh/darshan.js +1718 -0
- package/mesh/gumba.js +1567 -0
- package/mesh/jhilke.js +651 -0
- package/mesh/katha.js +1012 -0
- package/mesh/nakpak-routing.js +8 -5
- package/mesh/network.js +724 -34
- package/mesh/pulse-sync.js +4 -1
- package/mesh/rate-limiter.js +127 -15
- package/mesh/seva.js +526 -0
- package/mesh/sherpa-discovery.js +89 -8
- package/mesh/sybil-defense.js +19 -5
- package/mesh/temporal-encoder.js +4 -3
- package/mesh/vani.js +1364 -0
- package/mesh/yurt.js +1340 -0
- package/models/entropy-sentinel.onnx +0 -0
- package/models/karma-trust.onnx +0 -0
- package/models/manifest.json +43 -0
- package/models/sakshi-anomaly.onnx +0 -0
- package/oracle/code-proof-protocol.js +7 -6
- package/oracle/codebase-lock.js +257 -28
- package/oracle/index.js +74 -15
- package/oracle/ma902-snmp.js +678 -0
- package/oracle/module-sealer.js +5 -3
- package/oracle/network-identity.js +16 -0
- package/oracle/packet-checksum.js +201 -0
- package/oracle/sst.js +579 -0
- package/oracle/ternary-144t.js +714 -0
- package/oracle/ternary-ml.js +481 -0
- package/oracle/time-api.js +239 -0
- package/oracle/time-source.js +137 -47
- package/oracle/validation-oracle-hardened.js +1111 -1071
- package/oracle/validation-oracle.js +4 -2
- package/oracle/ypc27.js +211 -0
- package/package.json +20 -3
- package/protocol/yak-handler.js +35 -9
- package/protocol/yak-protocol.js +28 -13
- package/reference/cpp/yakmesh_mceliece_shard.cpp +168 -0
- package/reference/cpp/yakmesh_ypc27.cpp +179 -0
- package/sbom.json +87 -0
- package/scripts/security-audit.mjs +264 -0
- package/scripts/update-docs-nav.js +194 -0
- package/scripts/update-docs-sidebar.cjs +164 -0
- package/security/crypto-config.js +4 -3
- package/security/dharma-moderation.js +517 -0
- package/security/doko-identity.js +193 -143
- package/security/domain-consensus.js +86 -85
- package/security/fs-hardening.js +620 -0
- package/security/hardware-attestation.js +5 -3
- package/security/hybrid-trust.js +227 -87
- package/security/karma-rate-limiter.js +692 -0
- package/security/khata-protocol.js +22 -21
- package/security/khata-trust-integration.js +277 -150
- package/security/memory-safety.js +635 -0
- package/security/mesh-auth.js +11 -10
- package/security/mesh-revocation.js +373 -5
- package/security/namche-gateway.js +298 -69
- package/security/sakshi.js +460 -3
- package/security/sangha.js +770 -0
- package/security/secure-config.js +473 -0
- package/security/silicon-parity.js +13 -10
- package/security/steadywatch.js +1142 -0
- package/security/strike-system.js +32 -3
- package/security/temporal-signing.js +488 -0
- package/security/trit-commitment.js +464 -0
- package/server/crypto/annex.js +247 -0
- package/server/darshan-api.js +343 -0
- package/server/index.js +3259 -362
- package/server/komm-api.js +668 -0
- package/utils/accel.js +2273 -0
- package/utils/ternary-id.js +79 -0
- package/utils/verify-worker.js +57 -0
- package/webserver/index.js +95 -5
- package/assets/yakmesh-logo.png +0 -0
- package/assets/yakmesh-logo.svg +0 -80
- package/assets/yakmesh-logo2.png +0 -0
- package/assets/yakmesh-logo2sm.png +0 -0
- package/assets/ymsm.png +0 -0
- package/website/assets/silhouettes/adapters.svg +0 -107
- package/website/assets/silhouettes/api-endpoints.svg +0 -115
- package/website/assets/silhouettes/atomic-clock.svg +0 -83
- package/website/assets/silhouettes/base-camp.svg +0 -81
- package/website/assets/silhouettes/bridge.svg +0 -69
- package/website/assets/silhouettes/docs-bundle.svg +0 -113
- package/website/assets/silhouettes/doko-basket.svg +0 -70
- package/website/assets/silhouettes/fortress.svg +0 -93
- package/website/assets/silhouettes/gateway.svg +0 -54
- package/website/assets/silhouettes/gears.svg +0 -93
- package/website/assets/silhouettes/globe-satellite.svg +0 -67
- package/website/assets/silhouettes/karma-wheel.svg +0 -137
- package/website/assets/silhouettes/lama-council.svg +0 -141
- package/website/assets/silhouettes/mandala-network.svg +0 -169
- package/website/assets/silhouettes/mani-stones.svg +0 -149
- package/website/assets/silhouettes/mantra-wheel.svg +0 -116
- package/website/assets/silhouettes/mesh-nodes.svg +0 -113
- package/website/assets/silhouettes/nakpak.svg +0 -56
- package/website/assets/silhouettes/peak-lightning.svg +0 -73
- package/website/assets/silhouettes/sherpa.svg +0 -69
- package/website/assets/silhouettes/stupa-tower.svg +0 -119
- package/website/assets/silhouettes/tattva-eye.svg +0 -78
- package/website/assets/silhouettes/terminal.svg +0 -74
- package/website/assets/silhouettes/webserver.svg +0 -145
- package/website/assets/silhouettes/yak.svg +0 -78
- package/website/assets/yakmesh-logo.png +0 -0
- package/website/assets/yakmesh-logo.webp +0 -0
- package/website/assets/yakmesh-logo128x140.webp +0 -0
- package/website/assets/yakmesh-logo2.png +0 -0
- package/website/assets/yakmesh-logo2.svg +0 -51
- package/website/assets/yakmesh-logo40x44.webp +0 -0
- package/website/assets/yakmesh.gif +0 -0
- package/website/assets/yakmesh.ico +0 -0
- package/website/assets/yakmesh.jpg +0 -0
- package/website/assets/yakmesh.pdf +0 -0
- package/website/assets/yakmesh.png +0 -0
- package/website/assets/yakmesh.svg +0 -70
- package/website/assets/yakmesh128.webp +0 -0
- package/website/assets/yakmesh32.png +0 -0
- package/website/assets/yakmesh32.svg +0 -65
- package/website/assets/yakmesh32o.ico +0 -2
- package/website/assets/yakmesh32o.svg +0 -65
- package/website/assets/yakmesh32o.svgz +0 -0
package/security/sakshi.js
CHANGED
|
@@ -1440,7 +1440,7 @@ export function assessComputationTrust(computation, computedBy, options = {}) {
|
|
|
1440
1440
|
}))
|
|
1441
1441
|
);
|
|
1442
1442
|
|
|
1443
|
-
if (verificationAgreement.agreed && verificationAgreement.value === 'VALID') {
|
|
1443
|
+
if (verificationAgreement.agreed && verificationAgreement.data?.value === 'VALID') {
|
|
1444
1444
|
return {
|
|
1445
1445
|
trusted: true,
|
|
1446
1446
|
basis: 'VERIFIED',
|
|
@@ -1449,7 +1449,7 @@ export function assessComputationTrust(computation, computedBy, options = {}) {
|
|
|
1449
1449
|
};
|
|
1450
1450
|
}
|
|
1451
1451
|
|
|
1452
|
-
if (verificationAgreement.agreed && verificationAgreement.value === 'INVALID') {
|
|
1452
|
+
if (verificationAgreement.agreed && verificationAgreement.data?.value === 'INVALID') {
|
|
1453
1453
|
return {
|
|
1454
1454
|
trusted: false,
|
|
1455
1455
|
basis: 'VERIFICATION_FAILED',
|
|
@@ -1462,11 +1462,462 @@ export function assessComputationTrust(computation, computedBy, options = {}) {
|
|
|
1462
1462
|
return {
|
|
1463
1463
|
trusted: false,
|
|
1464
1464
|
basis: 'VERIFIERS_DISAGREE',
|
|
1465
|
-
action: verificationAgreement.action,
|
|
1465
|
+
action: verificationAgreement.data?.action,
|
|
1466
1466
|
suggestion: 'Need more verifiers or investigate disagreement',
|
|
1467
1467
|
};
|
|
1468
1468
|
}
|
|
1469
1469
|
|
|
1470
|
+
// =============================================================================
|
|
1471
|
+
// BEHAVIOR VELOCITY MONITORING
|
|
1472
|
+
// =============================================================================
|
|
1473
|
+
|
|
1474
|
+
/**
|
|
1475
|
+
* VEGATI - Velocity-based Behavior Change Detection
|
|
1476
|
+
* वेगति (Sanskrit: "velocity, momentum")
|
|
1477
|
+
*
|
|
1478
|
+
* Monitors nodes for sudden behavioral changes that may indicate:
|
|
1479
|
+
* - Compromised hardware/keys
|
|
1480
|
+
* - Reputation farming then abuse
|
|
1481
|
+
* - Insider threat activation
|
|
1482
|
+
*
|
|
1483
|
+
* Uses exponential moving average to establish behavioral baselines,
|
|
1484
|
+
* then triggers alerts when current behavior deviates significantly.
|
|
1485
|
+
*/
|
|
1486
|
+
|
|
1487
|
+
/**
|
|
1488
|
+
* Velocity alert severity levels
|
|
1489
|
+
*/
|
|
1490
|
+
export const VELOCITY_ALERT = Object.freeze({
|
|
1491
|
+
NORMAL: 'normal', // Within expected variance
|
|
1492
|
+
ELEVATED: 'elevated', // Notable change, monitor closely
|
|
1493
|
+
WARNING: 'warning', // Significant deviation
|
|
1494
|
+
CRITICAL: 'critical', // Dramatic behavioral shift
|
|
1495
|
+
});
|
|
1496
|
+
|
|
1497
|
+
/**
|
|
1498
|
+
* Behavior dimensions tracked for velocity detection
|
|
1499
|
+
*/
|
|
1500
|
+
export const BEHAVIOR_DIMENSION = Object.freeze({
|
|
1501
|
+
MESSAGE_RATE: 'message_rate', // Messages per minute
|
|
1502
|
+
GOSSIP_RATIO: 'gossip_ratio', // Gossip vs direct messages
|
|
1503
|
+
ERROR_RATE: 'error_rate', // Invalid messages/signatures
|
|
1504
|
+
ATTESTATION_RATE: 'attestation_rate', // Revocation attestations filed
|
|
1505
|
+
CONNECTION_CHURN: 'connection_churn', // Connect/disconnect frequency
|
|
1506
|
+
RESPONSE_LATENCY: 'response_latency', // Average response time
|
|
1507
|
+
});
|
|
1508
|
+
|
|
1509
|
+
/**
|
|
1510
|
+
* BehaviorVelocityMonitor - Tracks behavioral baselines and detects anomalies
|
|
1511
|
+
*
|
|
1512
|
+
* Each node builds a behavioral "fingerprint" over time.
|
|
1513
|
+
* Sudden changes from this fingerprint trigger velocity alerts.
|
|
1514
|
+
*/
|
|
1515
|
+
export class BehaviorVelocityMonitor {
|
|
1516
|
+
constructor(options = {}) {
|
|
1517
|
+
this.profiles = new Map(); // nodeId -> BehaviorProfile
|
|
1518
|
+
this._inferenceEngine = options.inferenceEngine || null;
|
|
1519
|
+
this._modelName = 'sakshi-anomaly';
|
|
1520
|
+
|
|
1521
|
+
// Configuration
|
|
1522
|
+
this.config = {
|
|
1523
|
+
// EMA smoothing factor (0-1, lower = slower adaptation)
|
|
1524
|
+
emaSmoothingFactor: options.emaSmoothingFactor || 0.1,
|
|
1525
|
+
|
|
1526
|
+
// Minimum observations before establishing baseline
|
|
1527
|
+
minObservationsForBaseline: options.minObservationsForBaseline || 50,
|
|
1528
|
+
|
|
1529
|
+
// Standard deviation thresholds for alerts
|
|
1530
|
+
thresholds: {
|
|
1531
|
+
elevated: options.elevatedThreshold || 2.0, // 2 sigma
|
|
1532
|
+
warning: options.warningThreshold || 3.0, // 3 sigma
|
|
1533
|
+
critical: options.criticalThreshold || 4.0, // 4 sigma
|
|
1534
|
+
},
|
|
1535
|
+
|
|
1536
|
+
// Cooldown period after alert before re-alerting (ms)
|
|
1537
|
+
alertCooldown: options.alertCooldown || 60000,
|
|
1538
|
+
|
|
1539
|
+
// Profile retention (ms)
|
|
1540
|
+
profileTTL: options.profileTTL || 7 * 24 * 60 * 60 * 1000, // 7 days
|
|
1541
|
+
};
|
|
1542
|
+
|
|
1543
|
+
// Alert callbacks
|
|
1544
|
+
this.alertCallbacks = [];
|
|
1545
|
+
|
|
1546
|
+
log.info('vegati', 'Behavior velocity monitor initialized');
|
|
1547
|
+
}
|
|
1548
|
+
|
|
1549
|
+
/**
|
|
1550
|
+
* Register a callback for velocity alerts
|
|
1551
|
+
*/
|
|
1552
|
+
onAlert(callback) {
|
|
1553
|
+
this.alertCallbacks.push(callback);
|
|
1554
|
+
}
|
|
1555
|
+
|
|
1556
|
+
/**
|
|
1557
|
+
* Record an observation for a node
|
|
1558
|
+
*
|
|
1559
|
+
* @param {string} nodeId - Node identifier
|
|
1560
|
+
* @param {string} dimension - Which behavior dimension (from BEHAVIOR_DIMENSION)
|
|
1561
|
+
* @param {number} value - Observed value
|
|
1562
|
+
* @returns {Object} Current velocity status for this dimension
|
|
1563
|
+
*/
|
|
1564
|
+
observe(nodeId, dimension, value) {
|
|
1565
|
+
let profile = this.profiles.get(nodeId);
|
|
1566
|
+
|
|
1567
|
+
if (!profile) {
|
|
1568
|
+
profile = this._createProfile(nodeId);
|
|
1569
|
+
this.profiles.set(nodeId, profile);
|
|
1570
|
+
}
|
|
1571
|
+
|
|
1572
|
+
profile.lastSeen = Date.now();
|
|
1573
|
+
|
|
1574
|
+
// Get or create dimension stats
|
|
1575
|
+
let stats = profile.dimensions.get(dimension);
|
|
1576
|
+
if (!stats) {
|
|
1577
|
+
stats = {
|
|
1578
|
+
count: 0,
|
|
1579
|
+
ema: value, // Exponential moving average
|
|
1580
|
+
emVar: 0, // Exponential moving variance
|
|
1581
|
+
lastValue: value,
|
|
1582
|
+
lastAlert: 0,
|
|
1583
|
+
alertCount: 0,
|
|
1584
|
+
};
|
|
1585
|
+
profile.dimensions.set(dimension, stats);
|
|
1586
|
+
}
|
|
1587
|
+
|
|
1588
|
+
stats.count++;
|
|
1589
|
+
stats.lastValue = value;
|
|
1590
|
+
|
|
1591
|
+
// Update EMA (baseline)
|
|
1592
|
+
const alpha = this.config.emaSmoothingFactor;
|
|
1593
|
+
const delta = value - stats.ema;
|
|
1594
|
+
stats.ema = stats.ema + alpha * delta;
|
|
1595
|
+
|
|
1596
|
+
// Update exponential moving variance (for std dev calculation)
|
|
1597
|
+
stats.emVar = (1 - alpha) * (stats.emVar + alpha * delta * delta);
|
|
1598
|
+
|
|
1599
|
+
// Only check velocity once we have baseline
|
|
1600
|
+
if (stats.count < this.config.minObservationsForBaseline) {
|
|
1601
|
+
return {
|
|
1602
|
+
status: VELOCITY_ALERT.NORMAL,
|
|
1603
|
+
reason: 'BUILDING_BASELINE',
|
|
1604
|
+
progress: stats.count / this.config.minObservationsForBaseline,
|
|
1605
|
+
};
|
|
1606
|
+
}
|
|
1607
|
+
|
|
1608
|
+
// Calculate z-score (standard deviations from mean)
|
|
1609
|
+
const stdDev = Math.sqrt(stats.emVar);
|
|
1610
|
+
const zScore = stdDev > 0 ? Math.abs(delta) / stdDev : 0;
|
|
1611
|
+
|
|
1612
|
+
// Determine alert level
|
|
1613
|
+
let alertLevel = VELOCITY_ALERT.NORMAL;
|
|
1614
|
+
if (zScore >= this.config.thresholds.critical) {
|
|
1615
|
+
alertLevel = VELOCITY_ALERT.CRITICAL;
|
|
1616
|
+
} else if (zScore >= this.config.thresholds.warning) {
|
|
1617
|
+
alertLevel = VELOCITY_ALERT.WARNING;
|
|
1618
|
+
} else if (zScore >= this.config.thresholds.elevated) {
|
|
1619
|
+
alertLevel = VELOCITY_ALERT.ELEVATED;
|
|
1620
|
+
}
|
|
1621
|
+
|
|
1622
|
+
// Emit alert if significant and not in cooldown
|
|
1623
|
+
const now = Date.now();
|
|
1624
|
+
if (alertLevel !== VELOCITY_ALERT.NORMAL &&
|
|
1625
|
+
now - stats.lastAlert > this.config.alertCooldown) {
|
|
1626
|
+
stats.lastAlert = now;
|
|
1627
|
+
stats.alertCount++;
|
|
1628
|
+
|
|
1629
|
+
const alert = {
|
|
1630
|
+
nodeId,
|
|
1631
|
+
dimension,
|
|
1632
|
+
level: alertLevel,
|
|
1633
|
+
zScore,
|
|
1634
|
+
currentValue: value,
|
|
1635
|
+
baselineEma: stats.ema,
|
|
1636
|
+
baselineStdDev: stdDev,
|
|
1637
|
+
deviation: delta,
|
|
1638
|
+
alertCount: stats.alertCount,
|
|
1639
|
+
timestamp: now,
|
|
1640
|
+
};
|
|
1641
|
+
|
|
1642
|
+
// Emit to callbacks
|
|
1643
|
+
for (const callback of this.alertCallbacks) {
|
|
1644
|
+
try {
|
|
1645
|
+
callback(alert);
|
|
1646
|
+
} catch (e) {
|
|
1647
|
+
log.error('vegati', 'Alert callback error', { error: e.message });
|
|
1648
|
+
}
|
|
1649
|
+
}
|
|
1650
|
+
|
|
1651
|
+
log.warn('vegati', `Velocity alert: ${alertLevel}`, {
|
|
1652
|
+
nodeId,
|
|
1653
|
+
dimension,
|
|
1654
|
+
zScore: zScore.toFixed(2),
|
|
1655
|
+
deviation: delta.toFixed(4),
|
|
1656
|
+
});
|
|
1657
|
+
}
|
|
1658
|
+
|
|
1659
|
+
return {
|
|
1660
|
+
status: alertLevel,
|
|
1661
|
+
zScore,
|
|
1662
|
+
deviation: delta,
|
|
1663
|
+
baseline: stats.ema,
|
|
1664
|
+
stdDev,
|
|
1665
|
+
};
|
|
1666
|
+
}
|
|
1667
|
+
|
|
1668
|
+
/**
|
|
1669
|
+
* Get the current behavioral profile for a node
|
|
1670
|
+
*/
|
|
1671
|
+
getProfile(nodeId) {
|
|
1672
|
+
const profile = this.profiles.get(nodeId);
|
|
1673
|
+
if (!profile) return null;
|
|
1674
|
+
|
|
1675
|
+
const dimensions = {};
|
|
1676
|
+
for (const [dim, stats] of profile.dimensions) {
|
|
1677
|
+
dimensions[dim] = {
|
|
1678
|
+
baseline: stats.ema,
|
|
1679
|
+
stdDev: Math.sqrt(stats.emVar),
|
|
1680
|
+
observations: stats.count,
|
|
1681
|
+
lastValue: stats.lastValue,
|
|
1682
|
+
alertCount: stats.alertCount,
|
|
1683
|
+
hasBaseline: stats.count >= this.config.minObservationsForBaseline,
|
|
1684
|
+
};
|
|
1685
|
+
}
|
|
1686
|
+
|
|
1687
|
+
return {
|
|
1688
|
+
nodeId: profile.nodeId,
|
|
1689
|
+
createdAt: profile.createdAt,
|
|
1690
|
+
lastSeen: profile.lastSeen,
|
|
1691
|
+
dimensions,
|
|
1692
|
+
};
|
|
1693
|
+
}
|
|
1694
|
+
|
|
1695
|
+
/**
|
|
1696
|
+
* Get nodes with active alerts
|
|
1697
|
+
*/
|
|
1698
|
+
getActiveAlerts() {
|
|
1699
|
+
const alerts = [];
|
|
1700
|
+
const now = Date.now();
|
|
1701
|
+
|
|
1702
|
+
for (const profile of this.profiles.values()) {
|
|
1703
|
+
for (const [dim, stats] of profile.dimensions) {
|
|
1704
|
+
if (stats.alertCount > 0 && now - stats.lastAlert < this.config.alertCooldown * 2) {
|
|
1705
|
+
const stdDev = Math.sqrt(stats.emVar);
|
|
1706
|
+
const zScore = stdDev > 0 ? Math.abs(stats.lastValue - stats.ema) / stdDev : 0;
|
|
1707
|
+
|
|
1708
|
+
let level = VELOCITY_ALERT.NORMAL;
|
|
1709
|
+
if (zScore >= this.config.thresholds.critical) level = VELOCITY_ALERT.CRITICAL;
|
|
1710
|
+
else if (zScore >= this.config.thresholds.warning) level = VELOCITY_ALERT.WARNING;
|
|
1711
|
+
else if (zScore >= this.config.thresholds.elevated) level = VELOCITY_ALERT.ELEVATED;
|
|
1712
|
+
|
|
1713
|
+
if (level !== VELOCITY_ALERT.NORMAL) {
|
|
1714
|
+
alerts.push({
|
|
1715
|
+
nodeId: profile.nodeId,
|
|
1716
|
+
dimension: dim,
|
|
1717
|
+
level,
|
|
1718
|
+
zScore,
|
|
1719
|
+
totalAlerts: stats.alertCount,
|
|
1720
|
+
lastAlert: stats.lastAlert,
|
|
1721
|
+
});
|
|
1722
|
+
}
|
|
1723
|
+
}
|
|
1724
|
+
}
|
|
1725
|
+
}
|
|
1726
|
+
|
|
1727
|
+
return alerts;
|
|
1728
|
+
}
|
|
1729
|
+
|
|
1730
|
+
/**
|
|
1731
|
+
* Get aggregate velocity statistics
|
|
1732
|
+
*/
|
|
1733
|
+
getStats() {
|
|
1734
|
+
let totalProfiles = 0;
|
|
1735
|
+
let profilesWithBaseline = 0;
|
|
1736
|
+
let activeAlerts = 0;
|
|
1737
|
+
const alertsByLevel = {
|
|
1738
|
+
[VELOCITY_ALERT.ELEVATED]: 0,
|
|
1739
|
+
[VELOCITY_ALERT.WARNING]: 0,
|
|
1740
|
+
[VELOCITY_ALERT.CRITICAL]: 0,
|
|
1741
|
+
};
|
|
1742
|
+
|
|
1743
|
+
for (const profile of this.profiles.values()) {
|
|
1744
|
+
totalProfiles++;
|
|
1745
|
+
let hasAnyBaseline = false;
|
|
1746
|
+
|
|
1747
|
+
for (const [dim, stats] of profile.dimensions) {
|
|
1748
|
+
if (stats.count >= this.config.minObservationsForBaseline) {
|
|
1749
|
+
hasAnyBaseline = true;
|
|
1750
|
+
}
|
|
1751
|
+
|
|
1752
|
+
if (stats.alertCount > 0) {
|
|
1753
|
+
const stdDev = Math.sqrt(stats.emVar);
|
|
1754
|
+
const zScore = stdDev > 0 ? Math.abs(stats.lastValue - stats.ema) / stdDev : 0;
|
|
1755
|
+
|
|
1756
|
+
if (zScore >= this.config.thresholds.critical) {
|
|
1757
|
+
activeAlerts++;
|
|
1758
|
+
alertsByLevel[VELOCITY_ALERT.CRITICAL]++;
|
|
1759
|
+
} else if (zScore >= this.config.thresholds.warning) {
|
|
1760
|
+
activeAlerts++;
|
|
1761
|
+
alertsByLevel[VELOCITY_ALERT.WARNING]++;
|
|
1762
|
+
} else if (zScore >= this.config.thresholds.elevated) {
|
|
1763
|
+
activeAlerts++;
|
|
1764
|
+
alertsByLevel[VELOCITY_ALERT.ELEVATED]++;
|
|
1765
|
+
}
|
|
1766
|
+
}
|
|
1767
|
+
}
|
|
1768
|
+
|
|
1769
|
+
if (hasAnyBaseline) profilesWithBaseline++;
|
|
1770
|
+
}
|
|
1771
|
+
|
|
1772
|
+
return {
|
|
1773
|
+
totalProfiles,
|
|
1774
|
+
profilesWithBaseline,
|
|
1775
|
+
activeAlerts,
|
|
1776
|
+
alertsByLevel,
|
|
1777
|
+
};
|
|
1778
|
+
}
|
|
1779
|
+
|
|
1780
|
+
/**
|
|
1781
|
+
* NPU-accelerated anomaly assessment for a node.
|
|
1782
|
+
* Feeds all behavioral dimensions + contextual features into the
|
|
1783
|
+
* sakshi-anomaly ONNX model for multi-class attack detection.
|
|
1784
|
+
*
|
|
1785
|
+
* Falls back to CPU heuristic (z-score based) if ONNX Runtime is unavailable.
|
|
1786
|
+
*
|
|
1787
|
+
* @param {string} nodeId - Node to assess
|
|
1788
|
+
* @param {Object} context - Additional context features
|
|
1789
|
+
* @param {number} [context.uptimePercent=0.5] - Node uptime (0-1)
|
|
1790
|
+
* @param {number} [context.networkAgeDays=0] - Days on network
|
|
1791
|
+
* @param {number} [context.karmaScore=0.5] - Current KARMA score (0-1)
|
|
1792
|
+
* @param {boolean} [context.hasAesni=false] - Hardware AES-NI attestation
|
|
1793
|
+
* @param {number} [context.timeSourceQuality=0] - Time source quality (0=system, 0.5=ntp, 1=ptp)
|
|
1794
|
+
* @param {number} [context.observationCount=0] - Total observations recorded
|
|
1795
|
+
* @returns {Promise<Object>} Anomaly assessment with scores per threat type
|
|
1796
|
+
*/
|
|
1797
|
+
async assessNode(nodeId, context = {}) {
|
|
1798
|
+
const profile = this.profiles.get(nodeId);
|
|
1799
|
+
|
|
1800
|
+
// Default feature values (zero-filled if no profile)
|
|
1801
|
+
const getDimValue = (dim) => {
|
|
1802
|
+
if (!profile) return 0;
|
|
1803
|
+
const stats = profile.dimensions.get(dim);
|
|
1804
|
+
return stats ? stats.lastValue : 0;
|
|
1805
|
+
};
|
|
1806
|
+
|
|
1807
|
+
// Build 12-feature input vector (must match training data order)
|
|
1808
|
+
const features = new Float32Array([
|
|
1809
|
+
getDimValue(BEHAVIOR_DIMENSION.MESSAGE_RATE),
|
|
1810
|
+
getDimValue(BEHAVIOR_DIMENSION.GOSSIP_RATIO),
|
|
1811
|
+
getDimValue(BEHAVIOR_DIMENSION.ERROR_RATE),
|
|
1812
|
+
getDimValue(BEHAVIOR_DIMENSION.ATTESTATION_RATE),
|
|
1813
|
+
getDimValue(BEHAVIOR_DIMENSION.CONNECTION_CHURN),
|
|
1814
|
+
getDimValue(BEHAVIOR_DIMENSION.RESPONSE_LATENCY),
|
|
1815
|
+
Math.min(1.0, context.uptimePercent ?? 0.5),
|
|
1816
|
+
Math.min(1.0, (context.networkAgeDays ?? 0) / 365),
|
|
1817
|
+
Math.min(1.0, context.karmaScore ?? 0.5),
|
|
1818
|
+
context.hasAesni ? 1.0 : 0.0,
|
|
1819
|
+
Math.min(1.0, context.timeSourceQuality ?? 0),
|
|
1820
|
+
Math.min(1.0, (context.observationCount ?? 0) / 1000),
|
|
1821
|
+
]);
|
|
1822
|
+
|
|
1823
|
+
// NPU path: use ONNX model if available
|
|
1824
|
+
const engine = this._inferenceEngine;
|
|
1825
|
+
if (engine && engine.hasModel(this._modelName)) {
|
|
1826
|
+
try {
|
|
1827
|
+
const result = await engine.infer(this._modelName, {
|
|
1828
|
+
behavior_features: features,
|
|
1829
|
+
});
|
|
1830
|
+
if (result && result.anomaly_scores) {
|
|
1831
|
+
const scores = result.anomaly_scores;
|
|
1832
|
+
return {
|
|
1833
|
+
source: 'NPU',
|
|
1834
|
+
nodeId,
|
|
1835
|
+
anomalyScore: scores[0],
|
|
1836
|
+
sybilScore: scores[1],
|
|
1837
|
+
eclipseScore: scores[2],
|
|
1838
|
+
floodScore: scores[3],
|
|
1839
|
+
features,
|
|
1840
|
+
};
|
|
1841
|
+
}
|
|
1842
|
+
} catch (err) {
|
|
1843
|
+
log.warn('vegati', `NPU assessment failed for ${nodeId}: ${err.message}`);
|
|
1844
|
+
}
|
|
1845
|
+
}
|
|
1846
|
+
|
|
1847
|
+
// CPU fallback: aggregate z-scores across dimensions
|
|
1848
|
+
let maxZScore = 0;
|
|
1849
|
+
let anomalySum = 0;
|
|
1850
|
+
let dimCount = 0;
|
|
1851
|
+
|
|
1852
|
+
if (profile) {
|
|
1853
|
+
for (const [, stats] of profile.dimensions) {
|
|
1854
|
+
if (stats.count >= this.config.minObservationsForBaseline) {
|
|
1855
|
+
const stdDev = Math.sqrt(stats.emVar);
|
|
1856
|
+
const zScore = stdDev > 0 ? Math.abs(stats.lastValue - stats.ema) / stdDev : 0;
|
|
1857
|
+
maxZScore = Math.max(maxZScore, zScore);
|
|
1858
|
+
anomalySum += Math.min(1.0, zScore / this.config.thresholds.critical);
|
|
1859
|
+
dimCount++;
|
|
1860
|
+
}
|
|
1861
|
+
}
|
|
1862
|
+
}
|
|
1863
|
+
|
|
1864
|
+
const anomalyScore = dimCount > 0 ? anomalySum / dimCount : 0;
|
|
1865
|
+
return {
|
|
1866
|
+
source: 'CPU',
|
|
1867
|
+
nodeId,
|
|
1868
|
+
anomalyScore,
|
|
1869
|
+
sybilScore: 0, // CPU fallback cannot distinguish attack types
|
|
1870
|
+
eclipseScore: 0,
|
|
1871
|
+
floodScore: 0,
|
|
1872
|
+
maxZScore,
|
|
1873
|
+
features,
|
|
1874
|
+
};
|
|
1875
|
+
}
|
|
1876
|
+
|
|
1877
|
+
/**
|
|
1878
|
+
* Cleanup old profiles
|
|
1879
|
+
*/
|
|
1880
|
+
cleanup() {
|
|
1881
|
+
const now = Date.now();
|
|
1882
|
+
let removed = 0;
|
|
1883
|
+
|
|
1884
|
+
for (const [nodeId, profile] of this.profiles) {
|
|
1885
|
+
if (now - profile.lastSeen > this.config.profileTTL) {
|
|
1886
|
+
this.profiles.delete(nodeId);
|
|
1887
|
+
removed++;
|
|
1888
|
+
}
|
|
1889
|
+
}
|
|
1890
|
+
|
|
1891
|
+
if (removed > 0) {
|
|
1892
|
+
log.info('vegati', `Cleaned up ${removed} stale profiles`);
|
|
1893
|
+
}
|
|
1894
|
+
|
|
1895
|
+
return removed;
|
|
1896
|
+
}
|
|
1897
|
+
|
|
1898
|
+
_createProfile(nodeId) {
|
|
1899
|
+
return {
|
|
1900
|
+
nodeId,
|
|
1901
|
+
createdAt: Date.now(),
|
|
1902
|
+
lastSeen: Date.now(),
|
|
1903
|
+
dimensions: new Map(),
|
|
1904
|
+
};
|
|
1905
|
+
}
|
|
1906
|
+
}
|
|
1907
|
+
|
|
1908
|
+
// Singleton instance
|
|
1909
|
+
let _velocityMonitor = null;
|
|
1910
|
+
|
|
1911
|
+
/**
|
|
1912
|
+
* Get the singleton velocity monitor instance
|
|
1913
|
+
*/
|
|
1914
|
+
export function getVelocityMonitor(options) {
|
|
1915
|
+
if (!_velocityMonitor) {
|
|
1916
|
+
_velocityMonitor = new BehaviorVelocityMonitor(options);
|
|
1917
|
+
}
|
|
1918
|
+
return _velocityMonitor;
|
|
1919
|
+
}
|
|
1920
|
+
|
|
1470
1921
|
// =============================================================================
|
|
1471
1922
|
// EXPORTS
|
|
1472
1923
|
// =============================================================================
|
|
@@ -1506,4 +1957,10 @@ export default {
|
|
|
1506
1957
|
checkRevocationAgreement,
|
|
1507
1958
|
aggregateAttestations,
|
|
1508
1959
|
assessComputationTrust,
|
|
1960
|
+
|
|
1961
|
+
// Velocity detection (VEGATI)
|
|
1962
|
+
VELOCITY_ALERT,
|
|
1963
|
+
BEHAVIOR_DIMENSION,
|
|
1964
|
+
BehaviorVelocityMonitor,
|
|
1965
|
+
getVelocityMonitor,
|
|
1509
1966
|
};
|