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
|
@@ -0,0 +1,678 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ╔═══════════════════════════════════════════════════════════════════════════════╗
|
|
3
|
+
* ║ 📡 MA-902 SNMP MONITOR — CELESTIAL STONE TELEMETRY 📡 ║
|
|
4
|
+
* ╠═══════════════════════════════════════════════════════════════════════════════╣
|
|
5
|
+
* ║ ║
|
|
6
|
+
* ║ The MA-902/S-C1 GPS Gigabit Time Server is a hardware MANI stone — ║
|
|
7
|
+
* ║ a celestial marker receiving signals from satellite constellations. ║
|
|
8
|
+
* ║ ║
|
|
9
|
+
* ║ This module queries the MA-902 via SNMP v2c to extract: ║
|
|
10
|
+
* ║ - GPS time (Unix epoch) with sub-second precision ║
|
|
11
|
+
* ║ - Satellite lock status and constellation info ║
|
|
12
|
+
* ║ - Visible/tracked/used satellite counts ║
|
|
13
|
+
* ║ - Alarm and quality indicators ║
|
|
14
|
+
* ║ ║
|
|
15
|
+
* ║ Enterprise OID: 1.3.6.1.4.1.26381 (Chongqing Miaoan / MA-902) ║
|
|
16
|
+
* ║ ║
|
|
17
|
+
* ║ SNMP data feeds directly into ManiTimeDetector for real-time trust ║
|
|
18
|
+
* ║ assessment — if satellites degrade, trust level adjusts automatically. ║
|
|
19
|
+
* ║ ║
|
|
20
|
+
* ╚═══════════════════════════════════════════════════════════════════════════════╝
|
|
21
|
+
*
|
|
22
|
+
* @module mani/ma902-snmp
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
import { EventEmitter } from 'events';
|
|
26
|
+
import { createLogger } from '../utils/logger.js';
|
|
27
|
+
|
|
28
|
+
const log = createLogger('mani:ma902');
|
|
29
|
+
|
|
30
|
+
// ============================================================
|
|
31
|
+
// MA-902 ENTERPRISE OID MAP
|
|
32
|
+
// ============================================================
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Enterprise OID prefix for the MA-902/S-C1 time server
|
|
36
|
+
* Vendor: Chongqing Miaoan Technology (重庆妙安科技有限公司)
|
|
37
|
+
* IANA Enterprise Number: 26381
|
|
38
|
+
*/
|
|
39
|
+
const MA902_ENTERPRISE_OID = '1.3.6.1.4.1.26381';
|
|
40
|
+
const MA902_DATA_PREFIX = `${MA902_ENTERPRISE_OID}.1.1`;
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* MA-902 proprietary SNMP OID definitions
|
|
44
|
+
* Discovered via SNMP walk on 2026-02-19
|
|
45
|
+
*/
|
|
46
|
+
const MA902_OIDS = {
|
|
47
|
+
GPS_TIME: `${MA902_DATA_PREFIX}.1.0`, // Unix timestamp (seconds)
|
|
48
|
+
SUB_SECONDS: `${MA902_DATA_PREFIX}.2.0`, // Sub-second counter (nanosecond-scale)
|
|
49
|
+
LOCK_STATUS: `${MA902_DATA_PREFIX}.3.0`, // 1 = locked to satellites, 0 = unlocked
|
|
50
|
+
REF_SOURCE: `${MA902_DATA_PREFIX}.4.0`, // Reference source type (1 = GPS)
|
|
51
|
+
CONSTELLATION_MASK: `${MA902_DATA_PREFIX}.5.0`, // Bitmask of active constellations
|
|
52
|
+
SATS_VISIBLE: `${MA902_DATA_PREFIX}.6.0`, // Number of satellites visible
|
|
53
|
+
SATS_USED: `${MA902_DATA_PREFIX}.7.0`, // Number of satellites in fix solution
|
|
54
|
+
SATS_TRACKING: `${MA902_DATA_PREFIX}.8.0`, // Number of satellites being tracked
|
|
55
|
+
ALARM_STATUS: `${MA902_DATA_PREFIX}.9.0`, // 0 = no alarms
|
|
56
|
+
QUALITY: `${MA902_DATA_PREFIX}.10.0`, // Timing quality indicator
|
|
57
|
+
OFFSET: `${MA902_DATA_PREFIX}.11.0`, // Clock offset
|
|
58
|
+
RESERVED: `${MA902_DATA_PREFIX}.12.0`, // Reserved (0xFFFFFFFF sentinel)
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Standard MIB-II OIDs for basic system info
|
|
63
|
+
*/
|
|
64
|
+
const SYSTEM_OIDS = {
|
|
65
|
+
SYS_DESCR: '1.3.6.1.2.1.1.1.0',
|
|
66
|
+
SYS_UPTIME: '1.3.6.1.2.1.1.3.0',
|
|
67
|
+
SYS_NAME: '1.3.6.1.2.1.1.5.0',
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Constellation bitmask mapping
|
|
72
|
+
* Based on observed values: GPS=1, BeiDou=2, GLONASS=4, Galileo=8, QZSS=16
|
|
73
|
+
*/
|
|
74
|
+
const CONSTELLATION_FLAGS = {
|
|
75
|
+
GPS: 0x01,
|
|
76
|
+
BEIDOU: 0x02,
|
|
77
|
+
GLONASS: 0x04,
|
|
78
|
+
GALILEO: 0x08,
|
|
79
|
+
QZSS: 0x10,
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Minimum satellite thresholds for trust assessment
|
|
84
|
+
*/
|
|
85
|
+
const SAT_THRESHOLDS = {
|
|
86
|
+
EXCELLENT: 8, // >=8 sats = excellent fix
|
|
87
|
+
GOOD: 5, // >=5 sats = good fix
|
|
88
|
+
MARGINAL: 3, // >=3 sats = marginal fix (3D requires minimum 4)
|
|
89
|
+
DEGRADED: 1, // 1-2 sats = degraded, likely no valid fix
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
// ============================================================
|
|
93
|
+
// MA-902 SNMP MONITOR
|
|
94
|
+
// ============================================================
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* MA-902 GPS Time Server SNMP Monitor
|
|
98
|
+
*
|
|
99
|
+
* Queries the MA-902 via SNMP v2c to extract real-time satellite
|
|
100
|
+
* and timing telemetry. Emits events when status changes.
|
|
101
|
+
*
|
|
102
|
+
* @example
|
|
103
|
+
* const monitor = new MA902Monitor({ host: '192.168.1.30' });
|
|
104
|
+
* monitor.on('telemetry', (data) => console.log(data));
|
|
105
|
+
* await monitor.start();
|
|
106
|
+
*/
|
|
107
|
+
export class MA902Monitor extends EventEmitter {
|
|
108
|
+
constructor(options = {}) {
|
|
109
|
+
super();
|
|
110
|
+
|
|
111
|
+
this.options = {
|
|
112
|
+
host: options.host || '192.168.1.30',
|
|
113
|
+
port: options.port || 161,
|
|
114
|
+
community: options.community || 'public',
|
|
115
|
+
pollInterval: options.pollInterval || 10000, // 10s default
|
|
116
|
+
retries: options.retries || 2,
|
|
117
|
+
timeout: options.timeout || 3000, // 3s SNMP timeout
|
|
118
|
+
minSatellites: options.minSatellites || SAT_THRESHOLDS.MARGINAL,
|
|
119
|
+
verbose: options.verbose || false,
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
this.snmpSession = null;
|
|
123
|
+
this.snmpLib = null;
|
|
124
|
+
this.pollTimer = null;
|
|
125
|
+
this.available = false;
|
|
126
|
+
this.lastTelemetry = null;
|
|
127
|
+
this.consecutiveFailures = 0;
|
|
128
|
+
this.maxConsecutiveFailures = 5;
|
|
129
|
+
this.systemInfo = null;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Initialize the SNMP library (lazy-loaded to avoid hard dependency)
|
|
134
|
+
* @returns {boolean} Whether SNMP is available
|
|
135
|
+
*/
|
|
136
|
+
async _initSnmp() {
|
|
137
|
+
if (this.snmpLib) return true;
|
|
138
|
+
|
|
139
|
+
try {
|
|
140
|
+
this.snmpLib = await import('net-snmp');
|
|
141
|
+
// Handle both default and named export patterns
|
|
142
|
+
if (this.snmpLib.default) {
|
|
143
|
+
this.snmpLib = this.snmpLib.default;
|
|
144
|
+
}
|
|
145
|
+
return true;
|
|
146
|
+
} catch (err) {
|
|
147
|
+
log.warn('net-snmp not available - MA-902 SNMP monitoring disabled', {
|
|
148
|
+
hint: 'npm install net-snmp',
|
|
149
|
+
error: err.message,
|
|
150
|
+
});
|
|
151
|
+
return false;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Create or recreate the SNMP session
|
|
157
|
+
*/
|
|
158
|
+
_createSession() {
|
|
159
|
+
if (this.snmpSession) {
|
|
160
|
+
try { this.snmpSession.close(); } catch (e) { /* ignore */ }
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
this.snmpSession = this.snmpLib.createSession(this.options.host, this.options.community, {
|
|
164
|
+
port: this.options.port,
|
|
165
|
+
retries: this.options.retries,
|
|
166
|
+
timeout: this.options.timeout,
|
|
167
|
+
version: this.snmpLib.Version2c,
|
|
168
|
+
transport: 'udp4',
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
this.snmpSession.on('error', (err) => {
|
|
172
|
+
log.debug('SNMP session error', { error: err.message });
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Start monitoring the MA-902
|
|
178
|
+
* @returns {boolean} Whether monitoring started successfully
|
|
179
|
+
*/
|
|
180
|
+
async start() {
|
|
181
|
+
const snmpAvailable = await this._initSnmp();
|
|
182
|
+
if (!snmpAvailable) {
|
|
183
|
+
this.available = false;
|
|
184
|
+
return false;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
this._createSession();
|
|
188
|
+
|
|
189
|
+
// Initial probe - verify the device responds
|
|
190
|
+
const probe = await this._querySystemInfo();
|
|
191
|
+
if (!probe) {
|
|
192
|
+
log.warn('MA-902 not responding at ' + this.options.host, {
|
|
193
|
+
action: 'Will retry on next poll cycle',
|
|
194
|
+
});
|
|
195
|
+
} else {
|
|
196
|
+
this.systemInfo = probe;
|
|
197
|
+
this.available = true;
|
|
198
|
+
log.info('MA-902 GPS Time Server connected via SNMP', {
|
|
199
|
+
host: this.options.host,
|
|
200
|
+
description: probe.description,
|
|
201
|
+
uptime: Math.round(probe.uptimeSeconds) + 's',
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// Start polling
|
|
206
|
+
await this.poll();
|
|
207
|
+
|
|
208
|
+
if (this.options.pollInterval > 0) {
|
|
209
|
+
this.pollTimer = setInterval(() => this.poll(), this.options.pollInterval);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
return this.available;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Stop monitoring
|
|
217
|
+
*/
|
|
218
|
+
stop() {
|
|
219
|
+
if (this.pollTimer) {
|
|
220
|
+
clearInterval(this.pollTimer);
|
|
221
|
+
this.pollTimer = null;
|
|
222
|
+
}
|
|
223
|
+
if (this.snmpSession) {
|
|
224
|
+
try { this.snmpSession.close(); } catch (e) { /* ignore */ }
|
|
225
|
+
this.snmpSession = null;
|
|
226
|
+
}
|
|
227
|
+
this.available = false;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Query basic system info (sysDescr, sysUptime, sysName)
|
|
232
|
+
* @returns {Object|null} System info or null on failure
|
|
233
|
+
*/
|
|
234
|
+
async _querySystemInfo() {
|
|
235
|
+
return new Promise((resolve) => {
|
|
236
|
+
const oids = [SYSTEM_OIDS.SYS_DESCR, SYSTEM_OIDS.SYS_UPTIME, SYSTEM_OIDS.SYS_NAME];
|
|
237
|
+
|
|
238
|
+
this.snmpSession.get(oids, (err, varbinds) => {
|
|
239
|
+
if (err) {
|
|
240
|
+
resolve(null);
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
try {
|
|
245
|
+
resolve({
|
|
246
|
+
description: varbinds[0].value.toString(),
|
|
247
|
+
uptimeSeconds: parseInt(varbinds[1].value) / 100,
|
|
248
|
+
name: varbinds[2].value.toString(),
|
|
249
|
+
});
|
|
250
|
+
} catch (e) {
|
|
251
|
+
resolve(null);
|
|
252
|
+
}
|
|
253
|
+
});
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* Poll the MA-902 for current telemetry
|
|
259
|
+
* @returns {Object|null} Telemetry data or null on failure
|
|
260
|
+
*/
|
|
261
|
+
async poll() {
|
|
262
|
+
if (!this.snmpSession) return null;
|
|
263
|
+
|
|
264
|
+
const telemetry = await this._queryTelemetry();
|
|
265
|
+
|
|
266
|
+
if (!telemetry) {
|
|
267
|
+
this.consecutiveFailures++;
|
|
268
|
+
|
|
269
|
+
if (this.consecutiveFailures >= this.maxConsecutiveFailures) {
|
|
270
|
+
if (this.available) {
|
|
271
|
+
this.available = false;
|
|
272
|
+
log.warn('MA-902 connection lost after ' + this.consecutiveFailures + ' failures', {
|
|
273
|
+
host: this.options.host,
|
|
274
|
+
});
|
|
275
|
+
this.emit('connectionLost', { host: this.options.host });
|
|
276
|
+
}
|
|
277
|
+
// Recreate session on next attempt
|
|
278
|
+
this._createSession();
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
return null;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
// Success - reset failure counter
|
|
285
|
+
if (!this.available) {
|
|
286
|
+
this.available = true;
|
|
287
|
+
log.info('MA-902 connection restored', { host: this.options.host });
|
|
288
|
+
this.emit('connectionRestored', { host: this.options.host });
|
|
289
|
+
}
|
|
290
|
+
this.consecutiveFailures = 0;
|
|
291
|
+
|
|
292
|
+
// Detect changes
|
|
293
|
+
const previousTelemetry = this.lastTelemetry;
|
|
294
|
+
this.lastTelemetry = telemetry;
|
|
295
|
+
|
|
296
|
+
// Emit telemetry event
|
|
297
|
+
this.emit('telemetry', telemetry);
|
|
298
|
+
|
|
299
|
+
// Detect significant state changes
|
|
300
|
+
if (previousTelemetry) {
|
|
301
|
+
this._checkStateChanges(previousTelemetry, telemetry);
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
return telemetry;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
/**
|
|
308
|
+
* Query enterprise OIDs for MA-902 telemetry
|
|
309
|
+
* @returns {Object|null} Parsed telemetry or null on failure
|
|
310
|
+
*/
|
|
311
|
+
async _queryTelemetry() {
|
|
312
|
+
return new Promise((resolve) => {
|
|
313
|
+
const oids = Object.values(MA902_OIDS);
|
|
314
|
+
|
|
315
|
+
this.snmpSession.get(oids, (err, varbinds) => {
|
|
316
|
+
if (err) {
|
|
317
|
+
log.debug('SNMP query failed', { error: err.message });
|
|
318
|
+
resolve(null);
|
|
319
|
+
return;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
try {
|
|
323
|
+
const keys = Object.keys(MA902_OIDS);
|
|
324
|
+
const raw = {};
|
|
325
|
+
varbinds.forEach((vb, i) => {
|
|
326
|
+
if (this.snmpLib.isVarbindError(vb)) {
|
|
327
|
+
raw[keys[i]] = null;
|
|
328
|
+
} else {
|
|
329
|
+
raw[keys[i]] = typeof vb.value === 'object' && Buffer.isBuffer(vb.value)
|
|
330
|
+
? parseInt(vb.value.toString('hex'), 16)
|
|
331
|
+
: parseInt(vb.value.toString());
|
|
332
|
+
}
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
resolve(this._parseTelemetry(raw));
|
|
336
|
+
} catch (e) {
|
|
337
|
+
log.debug('Telemetry parse error', { error: e.message });
|
|
338
|
+
resolve(null);
|
|
339
|
+
}
|
|
340
|
+
});
|
|
341
|
+
});
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
/**
|
|
345
|
+
* Parse raw SNMP values into structured telemetry
|
|
346
|
+
* @param {Object} raw - Raw OID values keyed by MA902_OIDS names
|
|
347
|
+
* @returns {Object} Structured telemetry
|
|
348
|
+
*/
|
|
349
|
+
_parseTelemetry(raw) {
|
|
350
|
+
const gpsTimeUnix = raw.GPS_TIME;
|
|
351
|
+
const systemTimeUnix = Math.floor(Date.now() / 1000);
|
|
352
|
+
const clockDelta = gpsTimeUnix ? Math.abs(systemTimeUnix - gpsTimeUnix) : null;
|
|
353
|
+
|
|
354
|
+
const locked = raw.LOCK_STATUS === 1;
|
|
355
|
+
const satsVisible = raw.SATS_VISIBLE || 0;
|
|
356
|
+
const satsUsed = raw.SATS_USED || 0;
|
|
357
|
+
const satsTracking = raw.SATS_TRACKING || 0;
|
|
358
|
+
const alarmActive = raw.ALARM_STATUS !== 0;
|
|
359
|
+
|
|
360
|
+
// Decode constellation bitmask
|
|
361
|
+
const constellationMask = raw.CONSTELLATION_MASK || 0;
|
|
362
|
+
const constellations = [];
|
|
363
|
+
if (constellationMask & CONSTELLATION_FLAGS.GPS) constellations.push('GPS');
|
|
364
|
+
if (constellationMask & CONSTELLATION_FLAGS.BEIDOU) constellations.push('BeiDou');
|
|
365
|
+
if (constellationMask & CONSTELLATION_FLAGS.GLONASS) constellations.push('GLONASS');
|
|
366
|
+
if (constellationMask & CONSTELLATION_FLAGS.GALILEO) constellations.push('Galileo');
|
|
367
|
+
if (constellationMask & CONSTELLATION_FLAGS.QZSS) constellations.push('QZSS');
|
|
368
|
+
|
|
369
|
+
// Assess satellite quality
|
|
370
|
+
let satQuality;
|
|
371
|
+
if (satsUsed >= SAT_THRESHOLDS.EXCELLENT) satQuality = 'excellent';
|
|
372
|
+
else if (satsUsed >= SAT_THRESHOLDS.GOOD) satQuality = 'good';
|
|
373
|
+
else if (satsUsed >= SAT_THRESHOLDS.MARGINAL) satQuality = 'marginal';
|
|
374
|
+
else if (satsUsed >= SAT_THRESHOLDS.DEGRADED) satQuality = 'degraded';
|
|
375
|
+
else satQuality = 'none';
|
|
376
|
+
|
|
377
|
+
// Determine if GPS time source is trustworthy
|
|
378
|
+
const synchronized = locked && satsUsed >= this.options.minSatellites && !alarmActive;
|
|
379
|
+
|
|
380
|
+
// Build telemetry object
|
|
381
|
+
const telemetry = {
|
|
382
|
+
timestamp: Date.now(),
|
|
383
|
+
host: this.options.host,
|
|
384
|
+
|
|
385
|
+
// Time data
|
|
386
|
+
gpsTime: gpsTimeUnix,
|
|
387
|
+
gpsTimeISO: gpsTimeUnix ? new Date(gpsTimeUnix * 1000).toISOString() : null,
|
|
388
|
+
subSeconds: raw.SUB_SECONDS,
|
|
389
|
+
systemTime: systemTimeUnix,
|
|
390
|
+
clockDeltaSeconds: clockDelta,
|
|
391
|
+
|
|
392
|
+
// Lock & sync
|
|
393
|
+
locked,
|
|
394
|
+
synchronized,
|
|
395
|
+
refSource: raw.REF_SOURCE,
|
|
396
|
+
|
|
397
|
+
// Satellite data
|
|
398
|
+
satellites: {
|
|
399
|
+
visible: satsVisible,
|
|
400
|
+
used: satsUsed,
|
|
401
|
+
tracking: satsTracking,
|
|
402
|
+
quality: satQuality,
|
|
403
|
+
constellations,
|
|
404
|
+
constellationMask,
|
|
405
|
+
},
|
|
406
|
+
|
|
407
|
+
// Health
|
|
408
|
+
alarm: alarmActive,
|
|
409
|
+
alarmCode: raw.ALARM_STATUS,
|
|
410
|
+
qualityIndicator: raw.QUALITY,
|
|
411
|
+
offset: raw.OFFSET,
|
|
412
|
+
|
|
413
|
+
// Trust assessment for MANI integration
|
|
414
|
+
maniTrust: this._assessManiTrust(locked, satsUsed, alarmActive, clockDelta),
|
|
415
|
+
};
|
|
416
|
+
|
|
417
|
+
if (this.options.verbose) {
|
|
418
|
+
log.info('MA-902 telemetry', {
|
|
419
|
+
locked,
|
|
420
|
+
sats: `${satsUsed}/${satsTracking}/${satsVisible}`,
|
|
421
|
+
quality: satQuality,
|
|
422
|
+
constellations: constellations.join('+'),
|
|
423
|
+
delta: clockDelta !== null ? clockDelta + 's' : 'unknown',
|
|
424
|
+
});
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
return telemetry;
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
/**
|
|
431
|
+
* Assess MANI trust level based on MA-902 telemetry
|
|
432
|
+
*
|
|
433
|
+
* This is the key integration point - translating hardware telemetry
|
|
434
|
+
* into the MANI trust hierarchy.
|
|
435
|
+
*
|
|
436
|
+
* @param {boolean} locked - Satellite lock status
|
|
437
|
+
* @param {number} satsUsed - Satellites used in fix
|
|
438
|
+
* @param {boolean} alarm - Alarm active
|
|
439
|
+
* @param {number|null} clockDelta - Seconds between GPS and system time
|
|
440
|
+
* @returns {Object} Trust assessment
|
|
441
|
+
*/
|
|
442
|
+
_assessManiTrust(locked, satsUsed, alarm, clockDelta) {
|
|
443
|
+
// GPS trust requires: locked, sufficient satellites, no alarms
|
|
444
|
+
if (!locked || alarm) {
|
|
445
|
+
return {
|
|
446
|
+
trustworthy: false,
|
|
447
|
+
level: 'degraded',
|
|
448
|
+
reason: !locked ? 'No satellite lock' : 'Alarm active',
|
|
449
|
+
confidence: 0,
|
|
450
|
+
};
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
if (satsUsed < SAT_THRESHOLDS.MARGINAL) {
|
|
454
|
+
return {
|
|
455
|
+
trustworthy: false,
|
|
456
|
+
level: 'degraded',
|
|
457
|
+
reason: `Insufficient satellites (${satsUsed} < ${SAT_THRESHOLDS.MARGINAL})`,
|
|
458
|
+
confidence: 0.2,
|
|
459
|
+
};
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
// Clock delta sanity check - GPS leap seconds can cause up to ~37s offset
|
|
463
|
+
// but anything beyond 120s suggests something is wrong
|
|
464
|
+
if (clockDelta !== null && clockDelta > 120) {
|
|
465
|
+
return {
|
|
466
|
+
trustworthy: false,
|
|
467
|
+
level: 'suspect',
|
|
468
|
+
reason: `Clock delta too large (${clockDelta}s)`,
|
|
469
|
+
confidence: 0.1,
|
|
470
|
+
};
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
// Calculate confidence based on satellite count
|
|
474
|
+
const satConfidence = Math.min(1.0, satsUsed / SAT_THRESHOLDS.EXCELLENT);
|
|
475
|
+
|
|
476
|
+
if (satsUsed >= SAT_THRESHOLDS.EXCELLENT) {
|
|
477
|
+
return {
|
|
478
|
+
trustworthy: true,
|
|
479
|
+
level: 'excellent',
|
|
480
|
+
reason: `${satsUsed} satellites, locked, no alarms`,
|
|
481
|
+
confidence: 1.0,
|
|
482
|
+
};
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
if (satsUsed >= SAT_THRESHOLDS.GOOD) {
|
|
486
|
+
return {
|
|
487
|
+
trustworthy: true,
|
|
488
|
+
level: 'good',
|
|
489
|
+
reason: `${satsUsed} satellites, locked`,
|
|
490
|
+
confidence: satConfidence,
|
|
491
|
+
};
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
// Marginal (3-4 sats)
|
|
495
|
+
return {
|
|
496
|
+
trustworthy: true,
|
|
497
|
+
level: 'marginal',
|
|
498
|
+
reason: `${satsUsed} satellites (marginal fix)`,
|
|
499
|
+
confidence: satConfidence,
|
|
500
|
+
};
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
/**
|
|
504
|
+
* Check for significant state changes between polls
|
|
505
|
+
*/
|
|
506
|
+
_checkStateChanges(prev, curr) {
|
|
507
|
+
// Lock lost
|
|
508
|
+
if (prev.locked && !curr.locked) {
|
|
509
|
+
log.warn('MA-902: Satellite lock LOST');
|
|
510
|
+
this.emit('lockLost', curr);
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
// Lock acquired
|
|
514
|
+
if (!prev.locked && curr.locked) {
|
|
515
|
+
log.info('MA-902: Satellite lock acquired');
|
|
516
|
+
this.emit('lockAcquired', curr);
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
// Alarm triggered
|
|
520
|
+
if (!prev.alarm && curr.alarm) {
|
|
521
|
+
log.warn('MA-902: Alarm triggered', { code: curr.alarmCode });
|
|
522
|
+
this.emit('alarm', curr);
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
// Alarm cleared
|
|
526
|
+
if (prev.alarm && !curr.alarm) {
|
|
527
|
+
log.info('MA-902: Alarm cleared');
|
|
528
|
+
this.emit('alarmCleared', curr);
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
// Satellite degradation (significant drop)
|
|
532
|
+
if (prev.satellites.used - curr.satellites.used >= 3) {
|
|
533
|
+
log.warn('MA-902: Significant satellite degradation', {
|
|
534
|
+
before: prev.satellites.used,
|
|
535
|
+
after: curr.satellites.used,
|
|
536
|
+
});
|
|
537
|
+
this.emit('satelliteDegradation', {
|
|
538
|
+
before: prev.satellites.used,
|
|
539
|
+
after: curr.satellites.used,
|
|
540
|
+
telemetry: curr,
|
|
541
|
+
});
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
// Trust level change
|
|
545
|
+
if (prev.maniTrust.level !== curr.maniTrust.level) {
|
|
546
|
+
log.info('MA-902: Trust level changed', {
|
|
547
|
+
from: prev.maniTrust.level,
|
|
548
|
+
to: curr.maniTrust.level,
|
|
549
|
+
});
|
|
550
|
+
this.emit('trustChanged', {
|
|
551
|
+
from: prev.maniTrust.level,
|
|
552
|
+
to: curr.maniTrust.level,
|
|
553
|
+
telemetry: curr,
|
|
554
|
+
});
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
/**
|
|
559
|
+
* Get current telemetry (last polled values)
|
|
560
|
+
* @returns {Object|null} Latest telemetry or null if unavailable
|
|
561
|
+
*/
|
|
562
|
+
getTelemetry() {
|
|
563
|
+
return this.lastTelemetry;
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
/**
|
|
567
|
+
* Check if the MA-902 is available and responding
|
|
568
|
+
* @returns {boolean}
|
|
569
|
+
*/
|
|
570
|
+
isAvailable() {
|
|
571
|
+
return this.available;
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
/**
|
|
575
|
+
* Check if the MA-902 has a valid satellite lock
|
|
576
|
+
* @returns {boolean}
|
|
577
|
+
*/
|
|
578
|
+
isLocked() {
|
|
579
|
+
return this.lastTelemetry?.locked ?? false;
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
/**
|
|
583
|
+
* Check if the MA-902 is synchronized (locked + sufficient sats + no alarms)
|
|
584
|
+
* @returns {boolean}
|
|
585
|
+
*/
|
|
586
|
+
isSynchronized() {
|
|
587
|
+
return this.lastTelemetry?.synchronized ?? false;
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
/**
|
|
591
|
+
* Get satellite count (used in fix)
|
|
592
|
+
* @returns {number}
|
|
593
|
+
*/
|
|
594
|
+
getSatelliteCount() {
|
|
595
|
+
return this.lastTelemetry?.satellites?.used ?? 0;
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
/**
|
|
599
|
+
* Get the MANI trust assessment from latest telemetry
|
|
600
|
+
* @returns {Object} Trust assessment
|
|
601
|
+
*/
|
|
602
|
+
getManiTrust() {
|
|
603
|
+
return this.lastTelemetry?.maniTrust ?? {
|
|
604
|
+
trustworthy: false,
|
|
605
|
+
level: 'unavailable',
|
|
606
|
+
reason: 'No telemetry data',
|
|
607
|
+
confidence: 0,
|
|
608
|
+
};
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
/**
|
|
612
|
+
* Get status summary for API responses
|
|
613
|
+
* @returns {Object} Status object
|
|
614
|
+
*/
|
|
615
|
+
getStatus() {
|
|
616
|
+
if (!this.available || !this.lastTelemetry) {
|
|
617
|
+
return {
|
|
618
|
+
available: false,
|
|
619
|
+
host: this.options.host,
|
|
620
|
+
reason: 'MA-902 not responding or SNMP disabled',
|
|
621
|
+
};
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
const t = this.lastTelemetry;
|
|
625
|
+
return {
|
|
626
|
+
available: true,
|
|
627
|
+
host: this.options.host,
|
|
628
|
+
locked: t.locked,
|
|
629
|
+
synchronized: t.synchronized,
|
|
630
|
+
satellites: t.satellites,
|
|
631
|
+
gpsTime: t.gpsTimeISO,
|
|
632
|
+
clockDelta: t.clockDeltaSeconds,
|
|
633
|
+
alarm: t.alarm,
|
|
634
|
+
quality: t.qualityIndicator,
|
|
635
|
+
trust: t.maniTrust,
|
|
636
|
+
uptime: this.systemInfo?.uptimeSeconds ?? null,
|
|
637
|
+
lastPoll: t.timestamp,
|
|
638
|
+
};
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
// ============================================================
|
|
643
|
+
// SINGLETON INSTANCE
|
|
644
|
+
// ============================================================
|
|
645
|
+
|
|
646
|
+
let globalMonitor = null;
|
|
647
|
+
|
|
648
|
+
/**
|
|
649
|
+
* Get or create the global MA-902 monitor instance
|
|
650
|
+
* @param {Object} options - Monitor options
|
|
651
|
+
* @returns {MA902Monitor}
|
|
652
|
+
*/
|
|
653
|
+
export function getMA902Monitor(options = {}) {
|
|
654
|
+
if (!globalMonitor) {
|
|
655
|
+
globalMonitor = new MA902Monitor(options);
|
|
656
|
+
}
|
|
657
|
+
return globalMonitor;
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
// ============================================================
|
|
661
|
+
// EXPORTS
|
|
662
|
+
// ============================================================
|
|
663
|
+
|
|
664
|
+
export {
|
|
665
|
+
MA902_OIDS,
|
|
666
|
+
MA902_ENTERPRISE_OID,
|
|
667
|
+
CONSTELLATION_FLAGS,
|
|
668
|
+
SAT_THRESHOLDS,
|
|
669
|
+
};
|
|
670
|
+
|
|
671
|
+
export default {
|
|
672
|
+
MA902Monitor,
|
|
673
|
+
getMA902Monitor,
|
|
674
|
+
MA902_OIDS,
|
|
675
|
+
MA902_ENTERPRISE_OID,
|
|
676
|
+
CONSTELLATION_FLAGS,
|
|
677
|
+
SAT_THRESHOLDS,
|
|
678
|
+
};
|
package/oracle/module-sealer.js
CHANGED
|
@@ -14,9 +14,11 @@
|
|
|
14
14
|
* @module ModuleSealer
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
-
import { sha3_256, sha3_512 } from '@noble/hashes/sha3.js';
|
|
17
|
+
import { sha3_256 as _nobleSha3, sha3_512 } from '@noble/hashes/sha3.js';
|
|
18
18
|
import { bytesToHex, utf8ToBytes } from '@noble/hashes/utils.js';
|
|
19
19
|
import { ml_dsa65 } from '@noble/post-quantum/ml-dsa.js';
|
|
20
|
+
// ACCEL: Hardware-accelerated crypto
|
|
21
|
+
import { sha3_256, mlDsa65Sign, mlDsa65Verify } from '../utils/accel.js';
|
|
20
22
|
import { readFileSync, writeFileSync, existsSync } from 'fs';
|
|
21
23
|
import { join, dirname } from 'path';
|
|
22
24
|
import { fileURLToPath } from 'url';
|
|
@@ -74,7 +76,7 @@ export class SealedModule {
|
|
|
74
76
|
const pubKeyBytes = hexToBytes(attestation.publicKey);
|
|
75
77
|
|
|
76
78
|
// IMPORTANT: ml_dsa65.verify(signature, message, publicKey) - signature FIRST!
|
|
77
|
-
return
|
|
79
|
+
return mlDsa65Verify(sigBytes, messageBytes, pubKeyBytes);
|
|
78
80
|
} catch (e) {
|
|
79
81
|
return false;
|
|
80
82
|
}
|
|
@@ -243,7 +245,7 @@ export class ModuleSealer {
|
|
|
243
245
|
const privKeyBytes = hexToBytes(this.privateKey);
|
|
244
246
|
|
|
245
247
|
// IMPORTANT: ml_dsa65.sign(message, secretKey) - message FIRST!
|
|
246
|
-
const signature =
|
|
248
|
+
const signature = mlDsa65Sign(messageBytes, privKeyBytes);
|
|
247
249
|
|
|
248
250
|
return {
|
|
249
251
|
publicKey: this.publicKey,
|