@svrnsec/pulse 0.7.0 → 0.9.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/LICENSE +21 -21
- package/README.md +883 -782
- package/SECURITY.md +27 -22
- package/bin/svrnsec-pulse.js +7 -7
- package/dist/{pulse.cjs.js → pulse.cjs} +6428 -6413
- package/dist/pulse.cjs.map +1 -0
- package/dist/pulse.esm.js +6429 -6415
- package/dist/pulse.esm.js.map +1 -1
- package/index.d.ts +949 -846
- package/package.json +189 -184
- package/pkg/pulse_core.js +174 -173
- package/src/analysis/audio.js +213 -213
- package/src/analysis/authenticityAudit.js +408 -393
- package/src/analysis/coherence.js +502 -502
- package/src/analysis/coordinatedBehavior.js +825 -804
- package/src/analysis/heuristic.js +428 -428
- package/src/analysis/jitter.js +446 -446
- package/src/analysis/llm.js +473 -472
- package/src/analysis/populationEntropy.js +404 -403
- package/src/analysis/provider.js +248 -248
- package/src/analysis/refraction.js +392 -391
- package/src/analysis/trustScore.js +356 -356
- package/src/cli/args.js +36 -36
- package/src/cli/commands/scan.js +192 -192
- package/src/cli/runner.js +157 -157
- package/src/collector/adaptive.js +200 -200
- package/src/collector/bio.js +297 -287
- package/src/collector/canvas.js +247 -239
- package/src/collector/dram.js +203 -203
- package/src/collector/enf.js +311 -311
- package/src/collector/entropy.js +195 -195
- package/src/collector/gpu.js +248 -245
- package/src/collector/idleAttestation.js +480 -480
- package/src/collector/sabTimer.js +189 -191
- package/src/errors.js +54 -0
- package/src/fingerprint.js +475 -475
- package/src/index.js +345 -342
- package/src/integrations/react-native.js +462 -459
- package/src/integrations/react.js +184 -185
- package/src/middleware/express.js +155 -155
- package/src/middleware/next.js +174 -175
- package/src/proof/challenge.js +249 -249
- package/src/proof/engagementToken.js +426 -394
- package/src/proof/fingerprint.js +268 -268
- package/src/proof/validator.js +82 -142
- package/src/registry/serializer.js +349 -349
- package/src/terminal.js +263 -263
- package/src/update-notifier.js +259 -264
- package/dist/pulse.cjs.js.map +0 -1
package/index.d.ts
CHANGED
|
@@ -1,846 +1,949 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @svrnsec/pulse — TypeScript Declarations
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
// =============================================================================
|
|
6
|
-
// Core pulse() API
|
|
7
|
-
// =============================================================================
|
|
8
|
-
|
|
9
|
-
export interface PulseOptions {
|
|
10
|
-
/**
|
|
11
|
-
* Server-issued challenge nonce — required in self-hosted mode.
|
|
12
|
-
* Omit when using apiKey (hosted API fetches its own nonce).
|
|
13
|
-
*/
|
|
14
|
-
nonce?: string;
|
|
15
|
-
/**
|
|
16
|
-
* Sovereign hosted API key — enables zero-config mode.
|
|
17
|
-
* When set, pulse() handles challenge + verify automatically.
|
|
18
|
-
* Get a key at https://sovereign.dev
|
|
19
|
-
*/
|
|
20
|
-
apiKey?: string;
|
|
21
|
-
/** Hosted API base URL. Default: 'https://api.sovereign.dev' */
|
|
22
|
-
apiUrl?: string;
|
|
23
|
-
/** Options forwarded to the hosted verify endpoint (minJitterScore, requireBio, etc.) */
|
|
24
|
-
verifyOptions?: Partial<ValidateOptions>;
|
|
25
|
-
/** Number of WASM matrix-multiply iterations. Default: 200 */
|
|
26
|
-
iterations?: number;
|
|
27
|
-
/** How long to listen for mouse/keyboard bio signals (ms). Default: 3000 */
|
|
28
|
-
bioWindowMs?: number;
|
|
29
|
-
/** Run cold/load/hot phases for entropy-jitter ratio. Default: true */
|
|
30
|
-
phased?: boolean;
|
|
31
|
-
/** Use adaptive early exit (faster for obvious VMs). Default: true */
|
|
32
|
-
adaptive?: boolean;
|
|
33
|
-
/** Stop early if VM/HW signal reaches this confidence. Default: 0.85 */
|
|
34
|
-
adaptiveThreshold?: number;
|
|
35
|
-
/** Custom WASM binary URL/path (optional). */
|
|
36
|
-
wasmPath?: string;
|
|
37
|
-
/** Progress callback — called at each pipeline stage. */
|
|
38
|
-
onProgress?: (stage: PulseStage, meta?: ProgressMeta) => void;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
export type PulseStage =
|
|
42
|
-
| 'start'
|
|
43
|
-
| 'entropy_batch'
|
|
44
|
-
| 'entropy_done'
|
|
45
|
-
| 'canvas_done'
|
|
46
|
-
| 'audio_done'
|
|
47
|
-
| 'bio_done'
|
|
48
|
-
| 'analysis_done'
|
|
49
|
-
| 'complete';
|
|
50
|
-
|
|
51
|
-
export interface ProgressMeta {
|
|
52
|
-
/** Current iteration count (during adaptive probe). */
|
|
53
|
-
iterations?: number;
|
|
54
|
-
/** Max iterations configured. */
|
|
55
|
-
maxIterations?: number;
|
|
56
|
-
/** Percentage complete (0–100). */
|
|
57
|
-
pct?: number;
|
|
58
|
-
/** Preliminary verdict from adaptive probe. */
|
|
59
|
-
earlyVerdict?: 'vm' | 'physical' | 'borderline' | 'uncertain';
|
|
60
|
-
/** Estimated milliseconds remaining. */
|
|
61
|
-
etaMs?: number;
|
|
62
|
-
/** Current VM confidence (0–1). */
|
|
63
|
-
vmConf?: number;
|
|
64
|
-
/** Current physical hardware confidence (0–1). */
|
|
65
|
-
hwConf?: number;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
export interface PulseCommitment {
|
|
69
|
-
/** Statistical summary payload (~1.6KB). Send this to your server. */
|
|
70
|
-
payload: ProofPayload;
|
|
71
|
-
/** BLAKE3 hex hash of the canonical payload. */
|
|
72
|
-
hash: string;
|
|
73
|
-
/**
|
|
74
|
-
* Server validation result — only present when using apiKey (hosted mode).
|
|
75
|
-
* Undefined in self-hosted mode; validate server-side with validateProof().
|
|
76
|
-
*/
|
|
77
|
-
result?: ValidationResult;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
export function pulse(opts: PulseOptions): Promise<PulseCommitment>;
|
|
81
|
-
|
|
82
|
-
// =============================================================================
|
|
83
|
-
// React Hook (import from '@svrnsec/pulse/react')
|
|
84
|
-
// =============================================================================
|
|
85
|
-
|
|
86
|
-
export interface UsePulseOptions {
|
|
87
|
-
/** Sovereign hosted API key. Handles nonce + verify automatically. */
|
|
88
|
-
apiKey?: string;
|
|
89
|
-
/** Hosted API base URL. Default: 'https://api.sovereign.dev' */
|
|
90
|
-
apiUrl?: string;
|
|
91
|
-
/** Self-hosted challenge endpoint URL. */
|
|
92
|
-
challengeUrl?: string;
|
|
93
|
-
/** Self-hosted verify endpoint URL. */
|
|
94
|
-
verifyUrl?: string;
|
|
95
|
-
/** Number of WASM matrix-multiply iterations. Default: 200 */
|
|
96
|
-
iterations?: number;
|
|
97
|
-
/** Bio collection window in milliseconds. Default: 3000 */
|
|
98
|
-
bioWindowMs?: number;
|
|
99
|
-
/** Enable adaptive early exit. Default: true */
|
|
100
|
-
adaptive?: boolean;
|
|
101
|
-
/** Run immediately on mount. Default: false */
|
|
102
|
-
autoRun?: boolean;
|
|
103
|
-
/** Called when proof + result are ready. */
|
|
104
|
-
onResult?: (result: ValidationResult | null, commitment: PulseCommitment) => void;
|
|
105
|
-
/** Called on error. */
|
|
106
|
-
onError?: (error: Error) => void;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
export interface UsePulseReturn {
|
|
110
|
-
/** Trigger the probe manually. */
|
|
111
|
-
run: () => Promise<void>;
|
|
112
|
-
/** Reset all state back to idle. */
|
|
113
|
-
reset: () => void;
|
|
114
|
-
/** Current pipeline stage. */
|
|
115
|
-
stage: PulseStage | null;
|
|
116
|
-
/** Probe progress 0–100. */
|
|
117
|
-
pct: number;
|
|
118
|
-
/** Live VM confidence 0–1 (updates during entropy_batch stages). */
|
|
119
|
-
vmConf: number;
|
|
120
|
-
/** Live HW confidence 0–1. */
|
|
121
|
-
hwConf: number;
|
|
122
|
-
/** Preliminary verdict from adaptive probe, or null if still uncertain. */
|
|
123
|
-
earlyVerdict: 'vm' | 'physical' | 'borderline' | 'uncertain' | null;
|
|
124
|
-
/** The BLAKE3 commitment. Available after probe completes. */
|
|
125
|
-
proof: PulseCommitment | null;
|
|
126
|
-
/** Server validation result. Available after verify completes (hosted/verifyUrl mode). */
|
|
127
|
-
result: ValidationResult | null;
|
|
128
|
-
/** True while probe is in progress. */
|
|
129
|
-
isRunning: boolean;
|
|
130
|
-
/** True when probe has completed (pass or fail). */
|
|
131
|
-
isReady: boolean;
|
|
132
|
-
/** Any error thrown during the probe. */
|
|
133
|
-
error: Error | null;
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
/** React hook — import from '@svrnsec/pulse/react' */
|
|
137
|
-
export declare function usePulse(opts?: UsePulseOptions): UsePulseReturn;
|
|
138
|
-
|
|
139
|
-
// =============================================================================
|
|
140
|
-
// Fingerprint class (high-level API)
|
|
141
|
-
// =============================================================================
|
|
142
|
-
|
|
143
|
-
export class Fingerprint {
|
|
144
|
-
/** Collect all hardware signals and return a Fingerprint instance. */
|
|
145
|
-
static collect(opts: PulseOptions): Promise<Fingerprint>;
|
|
146
|
-
|
|
147
|
-
/** True if the device is likely a VM, AI endpoint, or sanitised cloud env. */
|
|
148
|
-
readonly isSynthetic: boolean;
|
|
149
|
-
|
|
150
|
-
/** Confidence in the isSynthetic verdict (0–100). */
|
|
151
|
-
readonly confidence: number;
|
|
152
|
-
|
|
153
|
-
/**
|
|
154
|
-
* Final normalised score [0.0, 1.0] after all three analysis stages.
|
|
155
|
-
* Higher = more physical.
|
|
156
|
-
*/
|
|
157
|
-
readonly score: number;
|
|
158
|
-
|
|
159
|
-
/**
|
|
160
|
-
* Dynamic passing threshold for this specific proof [0.55, 0.67].
|
|
161
|
-
* Lower when more evidence was collected; higher for minimal-evidence proofs.
|
|
162
|
-
*/
|
|
163
|
-
readonly threshold: number;
|
|
164
|
-
|
|
165
|
-
/**
|
|
166
|
-
* Evidence weight [0, 1] — reflects how much data was collected.
|
|
167
|
-
* 1.0 = 200 iterations + phased + bio + audio + canvas
|
|
168
|
-
*/
|
|
169
|
-
readonly evidenceWeight: number;
|
|
170
|
-
|
|
171
|
-
/** Confidence tier. */
|
|
172
|
-
readonly tier: 'high' | 'medium' | 'low' | 'uncertain';
|
|
173
|
-
|
|
174
|
-
/**
|
|
175
|
-
* Timing profile of the device.
|
|
176
|
-
* - `'analog-fog'` — real hardware, natural Brownian noise
|
|
177
|
-
* - `'picket-fence'` — VM steal-time bursts at regular intervals
|
|
178
|
-
* - `'burst-scheduler'` — irregular VM scheduling (VMware-style)
|
|
179
|
-
* - `'hypervisor-flat'` — completely flat (heavy datacenter VM)
|
|
180
|
-
* - `'near-physical'` — ambiguous (Nitro, GPU passthrough)
|
|
181
|
-
*/
|
|
182
|
-
readonly profile: 'analog-fog' | 'picket-fence' | 'burst-scheduler' | 'hypervisor-flat' | 'near-physical' | 'unknown';
|
|
183
|
-
|
|
184
|
-
/** Detected cloud provider / hypervisor identifier. */
|
|
185
|
-
readonly providerId: string;
|
|
186
|
-
|
|
187
|
-
/** Human-readable provider label (e.g. "DigitalOcean Droplet (KVM)"). */
|
|
188
|
-
readonly providerLabel: string;
|
|
189
|
-
|
|
190
|
-
/**
|
|
191
|
-
* Estimated hypervisor scheduler quantum in milliseconds.
|
|
192
|
-
* `null` if the device appears to be physical hardware.
|
|
193
|
-
*/
|
|
194
|
-
readonly schedulerQuantumMs: number | null;
|
|
195
|
-
|
|
196
|
-
/**
|
|
197
|
-
* Entropy-Jitter Ratio — key signal for real silicon vs VM.
|
|
198
|
-
* - ≥ 1.08 → thermal feedback confirmed (real hardware)
|
|
199
|
-
* - ~1.00 → hypervisor clock (VM)
|
|
200
|
-
* - `null` → phased collection not run
|
|
201
|
-
*/
|
|
202
|
-
readonly entropyJitterRatio: number | null;
|
|
203
|
-
|
|
204
|
-
/** Top diagnostic flag from the heuristic engine. */
|
|
205
|
-
readonly topFlag: string;
|
|
206
|
-
|
|
207
|
-
/** All diagnostic flags. */
|
|
208
|
-
readonly flags: string[];
|
|
209
|
-
|
|
210
|
-
/** Heuristic engine findings with severity labels. */
|
|
211
|
-
readonly findings: HeuristicFinding[];
|
|
212
|
-
|
|
213
|
-
/** Confirmed physical properties (positive evidence). */
|
|
214
|
-
readonly physicalEvidence: PhysicalEvidence[];
|
|
215
|
-
|
|
216
|
-
/**
|
|
217
|
-
* Stable, privacy-safe
|
|
218
|
-
* Stable per device, changes if GPU/driver changes, not reversible.
|
|
219
|
-
*/
|
|
220
|
-
hardwareId(): string;
|
|
221
|
-
|
|
222
|
-
/** Key metrics summary for logging / debugging. */
|
|
223
|
-
metrics(): FingerprintMetrics;
|
|
224
|
-
|
|
225
|
-
/** Full diagnostic report. */
|
|
226
|
-
report(): FingerprintReport;
|
|
227
|
-
|
|
228
|
-
/** Returns the BLAKE3 commitment to send to your server. */
|
|
229
|
-
toCommitment(): PulseCommitment;
|
|
230
|
-
|
|
231
|
-
toString(): string;
|
|
232
|
-
toJSON(): FingerprintReport;
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
export interface HeuristicFinding {
|
|
236
|
-
id: string;
|
|
237
|
-
label: string;
|
|
238
|
-
severity: 'critical' | 'high' | 'medium' | 'info';
|
|
239
|
-
detail: string;
|
|
240
|
-
penalty: number;
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
export interface PhysicalEvidence {
|
|
244
|
-
id: string;
|
|
245
|
-
label: string;
|
|
246
|
-
detail: string;
|
|
247
|
-
value: number;
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
export interface FingerprintMetrics {
|
|
251
|
-
// Final verdict
|
|
252
|
-
score: number; // stage-3 final score
|
|
253
|
-
threshold: number; // dynamic passing threshold [0.55, 0.67]
|
|
254
|
-
evidenceWeight: number; // how much evidence was collected [0, 1]
|
|
255
|
-
isSynthetic: boolean;
|
|
256
|
-
// Score pipeline
|
|
257
|
-
rawScore: number;
|
|
258
|
-
adjustedScore: number;
|
|
259
|
-
finalScore: number;
|
|
260
|
-
heuristicAdjustment: number;
|
|
261
|
-
coherenceAdjustment: number;
|
|
262
|
-
// Timing signals
|
|
263
|
-
cv: number | null;
|
|
264
|
-
hurstExponent: number | null;
|
|
265
|
-
quantizationEntropy: number | null;
|
|
266
|
-
autocorrLag1: number | null;
|
|
267
|
-
autocorrLag50: number | null;
|
|
268
|
-
outlierRate: number | null;
|
|
269
|
-
thermalPattern: string | null;
|
|
270
|
-
entropyJitterRatio: number | null;
|
|
271
|
-
picketFence: boolean;
|
|
272
|
-
// Coherence signals
|
|
273
|
-
coherenceFlags: string[];
|
|
274
|
-
physicalFlags: string[];
|
|
275
|
-
hardOverride: 'vm' | null;
|
|
276
|
-
// Provider
|
|
277
|
-
provider: string;
|
|
278
|
-
providerConfidence: number;
|
|
279
|
-
schedulerQuantumMs: number | null;
|
|
280
|
-
// Hardware
|
|
281
|
-
webglRenderer: string | null;
|
|
282
|
-
isSoftwareRenderer: boolean;
|
|
283
|
-
hardwareId: string;
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
export interface FingerprintReport {
|
|
287
|
-
verdict: {
|
|
288
|
-
isSynthetic: boolean;
|
|
289
|
-
score: number;
|
|
290
|
-
threshold: number;
|
|
291
|
-
confidence: number;
|
|
292
|
-
tier: string;
|
|
293
|
-
profile: string;
|
|
294
|
-
provider: string;
|
|
295
|
-
topFlag: string;
|
|
296
|
-
hardOverride: 'vm' | null;
|
|
297
|
-
evidenceWeight: number;
|
|
298
|
-
};
|
|
299
|
-
pipeline: {
|
|
300
|
-
rawScore: number;
|
|
301
|
-
adjustedScore: number;
|
|
302
|
-
finalScore: number;
|
|
303
|
-
heuristicAdjustment: number;
|
|
304
|
-
coherenceAdjustment: number;
|
|
305
|
-
dynamicThreshold: number;
|
|
306
|
-
};
|
|
307
|
-
metrics: FingerprintMetrics;
|
|
308
|
-
findings: HeuristicFinding[];
|
|
309
|
-
physicalEvidence: PhysicalEvidence[];
|
|
310
|
-
coherenceChecks: CoherenceCheck[];
|
|
311
|
-
coherenceBonuses: CoherenceBonus[];
|
|
312
|
-
phases: PhaseReport | null;
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
export interface PhaseReport {
|
|
316
|
-
cold: { qe: number; mean: number };
|
|
317
|
-
hot: { qe: number; mean: number };
|
|
318
|
-
entropyJitterRatio: number;
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
// =============================================================================
|
|
322
|
-
// Server-side validation
|
|
323
|
-
// =============================================================================
|
|
324
|
-
|
|
325
|
-
export interface ValidateOptions {
|
|
326
|
-
/** Minimum jitter score [0–1]. Default: 0.55 */
|
|
327
|
-
minJitterScore?: number;
|
|
328
|
-
/** Max proof age in milliseconds. Default: 300000 (5 min) */
|
|
329
|
-
maxAgeMs?: number;
|
|
330
|
-
/** Tolerated future clock skew. Default: 30000 */
|
|
331
|
-
clockSkewMs?: number;
|
|
332
|
-
/** Reject proofs with no bio activity. Default: false */
|
|
333
|
-
requireBio?: boolean;
|
|
334
|
-
/** Reject software WebGL renderers. Default: true */
|
|
335
|
-
blockSoftwareRenderer?: boolean;
|
|
336
|
-
/**
|
|
337
|
-
* Async nonce validator — must mark nonce as consumed atomically.
|
|
338
|
-
* Returns true if nonce is valid and unused.
|
|
339
|
-
*/
|
|
340
|
-
checkNonce?: (nonce: string) => Promise<boolean>;
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
export interface ValidationResult {
|
|
344
|
-
valid: boolean;
|
|
345
|
-
score: number;
|
|
346
|
-
confidence: 'high' | 'medium' | 'low' | 'rejected';
|
|
347
|
-
reasons: string[];
|
|
348
|
-
riskFlags: string[];
|
|
349
|
-
meta: {
|
|
350
|
-
receivedAt: number;
|
|
351
|
-
proofAge: number;
|
|
352
|
-
jitterScore: number;
|
|
353
|
-
canvasRenderer: string | null;
|
|
354
|
-
bioActivity: boolean;
|
|
355
|
-
};
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
export function validateProof(
|
|
359
|
-
payload: ProofPayload,
|
|
360
|
-
hash: string,
|
|
361
|
-
opts?: ValidateOptions
|
|
362
|
-
): Promise<ValidationResult>;
|
|
363
|
-
|
|
364
|
-
export function generateNonce(): string;
|
|
365
|
-
|
|
366
|
-
// =============================================================================
|
|
367
|
-
// Heuristic engine (advanced)
|
|
368
|
-
// =============================================================================
|
|
369
|
-
|
|
370
|
-
export interface HeuristicReport {
|
|
371
|
-
penalty: number;
|
|
372
|
-
bonus: number;
|
|
373
|
-
netAdjustment: number;
|
|
374
|
-
findings: HeuristicFinding[];
|
|
375
|
-
bonuses: PhysicalEvidence[];
|
|
376
|
-
entropyJitterRatio: number | null;
|
|
377
|
-
entropyJitterScore: number;
|
|
378
|
-
/**
|
|
379
|
-
* Set to 'vm' when a mathematical impossibility is detected in the phase data,
|
|
380
|
-
* specifically when the stored EJR value contradicts the stored QE values.
|
|
381
|
-
* This is a hard kill — isSynthetic returns true regardless of all other scores.
|
|
382
|
-
*/
|
|
383
|
-
hardOverride: 'vm' | null;
|
|
384
|
-
picketFence: {
|
|
385
|
-
detected: boolean;
|
|
386
|
-
dominantLag: number | null;
|
|
387
|
-
peakAC: number;
|
|
388
|
-
baseline: number;
|
|
389
|
-
detail: string;
|
|
390
|
-
};
|
|
391
|
-
coherenceFlags: string[];
|
|
392
|
-
}
|
|
393
|
-
|
|
394
|
-
export function runHeuristicEngine(opts: {
|
|
395
|
-
jitter: JitterAnalysis;
|
|
396
|
-
phases: PhasedData | null;
|
|
397
|
-
autocorrelations: Record<string, number>;
|
|
398
|
-
}): HeuristicReport;
|
|
399
|
-
|
|
400
|
-
// =============================================================================
|
|
401
|
-
// Provider detection (advanced)
|
|
402
|
-
// =============================================================================
|
|
403
|
-
|
|
404
|
-
export interface ProviderResult {
|
|
405
|
-
providerId: string;
|
|
406
|
-
providerLabel: string;
|
|
407
|
-
profile: string;
|
|
408
|
-
confidence: number;
|
|
409
|
-
isVirtualized: boolean;
|
|
410
|
-
signals: Record<string, number | boolean | string[]>;
|
|
411
|
-
alternatives: Array<{ id: string; label: string }>;
|
|
412
|
-
rendererHints: string[];
|
|
413
|
-
schedulerQuantumMs: number | null;
|
|
414
|
-
}
|
|
415
|
-
|
|
416
|
-
export function detectProvider(opts: {
|
|
417
|
-
jitter: JitterAnalysis;
|
|
418
|
-
autocorrelations: Record<string, number>;
|
|
419
|
-
canvas: CanvasFingerprint | null;
|
|
420
|
-
phases: PhasedData | null;
|
|
421
|
-
}): ProviderResult;
|
|
422
|
-
|
|
423
|
-
// =============================================================================
|
|
424
|
-
// Proof payload structure
|
|
425
|
-
// =============================================================================
|
|
426
|
-
|
|
427
|
-
export interface ProofPayload {
|
|
428
|
-
version: number;
|
|
429
|
-
timestamp: number;
|
|
430
|
-
nonce: string;
|
|
431
|
-
signals: {
|
|
432
|
-
entropy: Record<string, number | string | null>;
|
|
433
|
-
bio: Record<string, number | boolean | null>;
|
|
434
|
-
canvas: {
|
|
435
|
-
webglRenderer: string | null;
|
|
436
|
-
webglVendor: string | null;
|
|
437
|
-
webglVersion: 1 | 2 | null;
|
|
438
|
-
webglPixelHash: string | null;
|
|
439
|
-
canvas2dHash: string | null;
|
|
440
|
-
extensionCount: number;
|
|
441
|
-
isSoftwareRenderer: boolean;
|
|
442
|
-
available: boolean;
|
|
443
|
-
};
|
|
444
|
-
audio: Record<string, number | boolean | null>;
|
|
445
|
-
};
|
|
446
|
-
classification: {
|
|
447
|
-
jitterScore: number;
|
|
448
|
-
adjustedScore?: number;
|
|
449
|
-
finalScore?: number;
|
|
450
|
-
dynamicThreshold?: number;
|
|
451
|
-
flags: string[];
|
|
452
|
-
};
|
|
453
|
-
heuristic?: Record<string, unknown>;
|
|
454
|
-
provider?: {
|
|
455
|
-
id: string;
|
|
456
|
-
label: string;
|
|
457
|
-
profile: string;
|
|
458
|
-
confidence: number;
|
|
459
|
-
schedulerQuantum: number | null;
|
|
460
|
-
};
|
|
461
|
-
coherence?: {
|
|
462
|
-
netAdjustment: number;
|
|
463
|
-
dynamicThreshold: number;
|
|
464
|
-
evidenceWeight: number;
|
|
465
|
-
coherenceFlags: string[];
|
|
466
|
-
physicalFlags: string[];
|
|
467
|
-
hardOverride: 'vm' | null;
|
|
468
|
-
};
|
|
469
|
-
}
|
|
470
|
-
|
|
471
|
-
// =============================================================================
|
|
472
|
-
// Coherence analysis (stage 3)
|
|
473
|
-
// =============================================================================
|
|
474
|
-
|
|
475
|
-
export interface CoherenceCheck {
|
|
476
|
-
id: string;
|
|
477
|
-
label: string;
|
|
478
|
-
severity: 'critical' | 'high' | 'medium' | 'info';
|
|
479
|
-
detail: string;
|
|
480
|
-
penalty: number;
|
|
481
|
-
}
|
|
482
|
-
|
|
483
|
-
export interface CoherenceBonus {
|
|
484
|
-
id: string;
|
|
485
|
-
label: string;
|
|
486
|
-
detail: string;
|
|
487
|
-
value: number;
|
|
488
|
-
}
|
|
489
|
-
|
|
490
|
-
export interface CoherenceReport {
|
|
491
|
-
penalty: number;
|
|
492
|
-
bonus: number;
|
|
493
|
-
netAdjustment: number;
|
|
494
|
-
checks: CoherenceCheck[];
|
|
495
|
-
bonuses: CoherenceBonus[];
|
|
496
|
-
hardOverride: 'vm' | null;
|
|
497
|
-
/** Dynamic threshold [0.55, 0.67] — lower when more evidence collected. */
|
|
498
|
-
dynamicThreshold: number;
|
|
499
|
-
/** Evidence weight [0, 1] */
|
|
500
|
-
evidenceWeight: number;
|
|
501
|
-
coherenceFlags: string[];
|
|
502
|
-
physicalFlags: string[];
|
|
503
|
-
}
|
|
504
|
-
|
|
505
|
-
export function runCoherenceAnalysis(opts: {
|
|
506
|
-
timings: number[];
|
|
507
|
-
jitter: JitterAnalysis;
|
|
508
|
-
phases?: PhasedData | null;
|
|
509
|
-
batches?: object[] | null;
|
|
510
|
-
bio?: object;
|
|
511
|
-
canvas?: CanvasFingerprint | null;
|
|
512
|
-
audio?: object;
|
|
513
|
-
}): CoherenceReport;
|
|
514
|
-
|
|
515
|
-
export function computeServerDynamicThreshold(payload: ProofPayload): number;
|
|
516
|
-
|
|
517
|
-
// =============================================================================
|
|
518
|
-
// Internal types (exported for advanced consumers)
|
|
519
|
-
// =============================================================================
|
|
520
|
-
|
|
521
|
-
export interface JitterAnalysis {
|
|
522
|
-
score: number;
|
|
523
|
-
flags: string[];
|
|
524
|
-
stats: TimingStats | null;
|
|
525
|
-
autocorrelations: Record<string, number>;
|
|
526
|
-
hurstExponent: number;
|
|
527
|
-
quantizationEntropy: number;
|
|
528
|
-
thermalSignature: { slope: number; pattern: string; r2: number };
|
|
529
|
-
outlierRate: number;
|
|
530
|
-
}
|
|
531
|
-
|
|
532
|
-
export interface TimingStats {
|
|
533
|
-
n: number; mean: number; std: number; cv: number;
|
|
534
|
-
min: number; max: number;
|
|
535
|
-
p5: number; p25: number; p50: number; p75: number; p95: number; p99: number;
|
|
536
|
-
skewness: number; kurtosis: number;
|
|
537
|
-
}
|
|
538
|
-
|
|
539
|
-
export interface CanvasFingerprint {
|
|
540
|
-
webglRenderer: string | null;
|
|
541
|
-
webglVendor: string | null;
|
|
542
|
-
webglVersion: 1 | 2 | null;
|
|
543
|
-
webglPixelHash: string | null;
|
|
544
|
-
canvas2dHash: string | null;
|
|
545
|
-
extensionCount: number;
|
|
546
|
-
extensions: string[];
|
|
547
|
-
isSoftwareRenderer: boolean;
|
|
548
|
-
available: boolean;
|
|
549
|
-
}
|
|
550
|
-
|
|
551
|
-
export interface PhasedData {
|
|
552
|
-
cold: { qe: number; mean: number };
|
|
553
|
-
load: { qe: number; mean: number };
|
|
554
|
-
hot: { qe: number; mean: number };
|
|
555
|
-
entropyJitterRatio: number;
|
|
556
|
-
}
|
|
557
|
-
|
|
558
|
-
// =============================================================================
|
|
559
|
-
// SVRN Registry
|
|
560
|
-
// =============================================================================
|
|
561
|
-
|
|
562
|
-
export interface SvrnSignature {
|
|
563
|
-
version: number;
|
|
564
|
-
id: string;
|
|
565
|
-
profile: string;
|
|
566
|
-
provider: string;
|
|
567
|
-
class: string;
|
|
568
|
-
metrics: Record<string, { lo: number; hi: number; mid: number; label: string } | null>;
|
|
569
|
-
rendererClass: string;
|
|
570
|
-
isSynthetic: boolean;
|
|
571
|
-
hwLabel: string | null;
|
|
572
|
-
osHint: string | null;
|
|
573
|
-
date: string;
|
|
574
|
-
}
|
|
575
|
-
|
|
576
|
-
export interface RegistryMatch {
|
|
577
|
-
matched: boolean;
|
|
578
|
-
profile: object | null;
|
|
579
|
-
similarity: number;
|
|
580
|
-
alternatives: Array<{ name: string; similarity: number }>;
|
|
581
|
-
}
|
|
582
|
-
|
|
583
|
-
export interface SignatureComparison {
|
|
584
|
-
sameClass: boolean;
|
|
585
|
-
similarity: number;
|
|
586
|
-
profileMatch: boolean;
|
|
587
|
-
providerMatch: boolean;
|
|
588
|
-
}
|
|
589
|
-
|
|
590
|
-
// =============================================================================
|
|
591
|
-
// Extended Signal Layer Types
|
|
592
|
-
// =============================================================================
|
|
593
|
-
|
|
594
|
-
// ── ENF (Electrical Network Frequency) ───────────────────────────────────────
|
|
595
|
-
|
|
596
|
-
export interface EnfResult {
|
|
597
|
-
enfAvailable: boolean;
|
|
598
|
-
ripplePresent: boolean;
|
|
599
|
-
gridFrequency: 50 | 60 | null;
|
|
600
|
-
gridRegion: 'americas' | 'emea_apac' | 'unknown';
|
|
601
|
-
ripplePower: number;
|
|
602
|
-
snr50hz: number;
|
|
603
|
-
snr60hz: number;
|
|
604
|
-
enfDeviation: number | null;
|
|
605
|
-
sampleRateHz: number;
|
|
606
|
-
resolutionUs: number;
|
|
607
|
-
verdict: 'grid_60hz' | 'grid_50hz' | 'no_grid_signal' | 'grid_detected_region_unknown' | 'unavailable';
|
|
608
|
-
isVmIndicator: boolean;
|
|
609
|
-
temporalAnchor: {
|
|
610
|
-
nominalHz: number;
|
|
611
|
-
measuredRippleHz: number;
|
|
612
|
-
capturedAt: number;
|
|
613
|
-
gridHz: number;
|
|
614
|
-
} | null;
|
|
615
|
-
reason?: string;
|
|
616
|
-
}
|
|
617
|
-
|
|
618
|
-
export declare function collectEnfTimings(opts?: { iterations?: number }): Promise<EnfResult>;
|
|
619
|
-
|
|
620
|
-
// ── WebGPU Thermal Variance ───────────────────────────────────────────────────
|
|
621
|
-
|
|
622
|
-
export interface GpuEntropyResult {
|
|
623
|
-
gpuPresent: boolean;
|
|
624
|
-
isSoftware: boolean;
|
|
625
|
-
vendorString: string | null;
|
|
626
|
-
dispatchCV: number;
|
|
627
|
-
thermalGrowth: number;
|
|
628
|
-
verdict: 'real_gpu' | 'software_renderer' | 'no_webgpu' | 'ambiguous';
|
|
629
|
-
}
|
|
630
|
-
|
|
631
|
-
export declare function collectGpuEntropy(opts?: object): Promise<GpuEntropyResult>;
|
|
632
|
-
|
|
633
|
-
// ── DRAM Refresh Cycle ────────────────────────────────────────────────────────
|
|
634
|
-
|
|
635
|
-
export interface DramResult {
|
|
636
|
-
timings: number[];
|
|
637
|
-
refreshPeriodMs: number | null;
|
|
638
|
-
refreshPresent: boolean;
|
|
639
|
-
peakLag: number;
|
|
640
|
-
peakPower: number;
|
|
641
|
-
verdict: 'dram' | 'virtual' | 'ambiguous';
|
|
642
|
-
}
|
|
643
|
-
|
|
644
|
-
export declare function collectDramTimings(opts?: { iterations?: number; bufferMb?: number }): DramResult;
|
|
645
|
-
|
|
646
|
-
// ── LLM / AI Agent Behavioral Fingerprint ─────────────────────────────────────
|
|
647
|
-
|
|
648
|
-
export interface LlmResult {
|
|
649
|
-
aiConf: number;
|
|
650
|
-
thinkTimePattern: 'llm_latency_peak' | 'human_pareto' | 'unknown';
|
|
651
|
-
correctionRate: number;
|
|
652
|
-
rhythmicity: number;
|
|
653
|
-
pauseDistribution: 'uniform' | 'pareto' | 'unknown';
|
|
654
|
-
verdict: 'ai_agent' | 'human' | 'insufficient_data';
|
|
655
|
-
matchedModel: string | null;
|
|
656
|
-
}
|
|
657
|
-
|
|
658
|
-
export declare function detectLlmAgent(bioSnapshot: object): LlmResult;
|
|
659
|
-
|
|
660
|
-
// ── SAB Microsecond Timer ─────────────────────────────────────────────────────
|
|
661
|
-
|
|
662
|
-
export interface SabTimerResult {
|
|
663
|
-
isClamped: boolean;
|
|
664
|
-
clampAmountUs: number;
|
|
665
|
-
resolutionUs: number;
|
|
666
|
-
}
|
|
667
|
-
|
|
668
|
-
export declare function isSabAvailable(): boolean;
|
|
669
|
-
export declare function collectHighResTimings(opts?: { iterations?: number; matrixSize?: number }): {
|
|
670
|
-
timings: number[];
|
|
671
|
-
resolutionUs: number;
|
|
672
|
-
};
|
|
673
|
-
|
|
674
|
-
// =============================================================================
|
|
675
|
-
// Terminal / DX Utilities
|
|
676
|
-
// =============================================================================
|
|
677
|
-
|
|
678
|
-
export declare function renderProbeResult(opts: {
|
|
679
|
-
payload: ProofPayload;
|
|
680
|
-
hash: string;
|
|
681
|
-
result?: ValidationResult;
|
|
682
|
-
enf?: EnfResult | null;
|
|
683
|
-
gpu?: GpuEntropyResult | null;
|
|
684
|
-
dram?: DramResult | null;
|
|
685
|
-
llm?: LlmResult | null;
|
|
686
|
-
elapsedMs?: number;
|
|
687
|
-
}): void;
|
|
688
|
-
|
|
689
|
-
export declare function renderError(err: Error | string): void;
|
|
690
|
-
export declare function renderInlineUpdateHint(latest: string): void;
|
|
691
|
-
|
|
692
|
-
// =============================================================================
|
|
693
|
-
// Version / Update Notifier
|
|
694
|
-
// =============================================================================
|
|
695
|
-
|
|
696
|
-
export declare const CURRENT_VERSION: string;
|
|
697
|
-
|
|
698
|
-
export declare function checkForUpdate(opts?: {
|
|
699
|
-
silent?: boolean;
|
|
700
|
-
pkg?: string;
|
|
701
|
-
}): Promise<{ current: string; latest: string | null; updateAvailable: boolean }>;
|
|
702
|
-
|
|
703
|
-
export declare function notifyOnExit(opts?: { pkg?: string }): void;
|
|
704
|
-
|
|
705
|
-
// =============================================================================
|
|
706
|
-
// Extended PulseCommitment (includes extended signal layer results)
|
|
707
|
-
// =============================================================================
|
|
708
|
-
|
|
709
|
-
export interface ExtendedPulseCommitment extends PulseCommitment {
|
|
710
|
-
extended: {
|
|
711
|
-
enf: EnfResult | null;
|
|
712
|
-
gpu: GpuEntropyResult | null;
|
|
713
|
-
dram: DramResult | null;
|
|
714
|
-
llm: LlmResult | null;
|
|
715
|
-
};
|
|
716
|
-
}
|
|
717
|
-
|
|
718
|
-
// =============================================================================
|
|
719
|
-
// TrustScore
|
|
720
|
-
// =============================================================================
|
|
721
|
-
|
|
722
|
-
export interface TrustScoreBreakdown {
|
|
723
|
-
pts: number;
|
|
724
|
-
max: number;
|
|
725
|
-
[key: string]: unknown;
|
|
726
|
-
}
|
|
727
|
-
|
|
728
|
-
export interface TrustScorePenalty {
|
|
729
|
-
signal: string;
|
|
730
|
-
reason: string;
|
|
731
|
-
cap: number;
|
|
732
|
-
}
|
|
733
|
-
|
|
734
|
-
export interface TrustScoreBonus {
|
|
735
|
-
signal: string;
|
|
736
|
-
reason: string;
|
|
737
|
-
pts: number;
|
|
738
|
-
}
|
|
739
|
-
|
|
740
|
-
export interface TrustScore {
|
|
741
|
-
score: number;
|
|
742
|
-
grade: 'A' | 'B' | 'C' | 'D' | 'F';
|
|
743
|
-
label: 'Trusted' | 'Verified' | 'Marginal' | 'Suspicious' | 'Blocked';
|
|
744
|
-
color: string;
|
|
745
|
-
hardCap: number | null;
|
|
746
|
-
breakdown: {
|
|
747
|
-
physics: TrustScoreBreakdown;
|
|
748
|
-
enf: TrustScoreBreakdown;
|
|
749
|
-
gpu: TrustScoreBreakdown;
|
|
750
|
-
dram: TrustScoreBreakdown;
|
|
751
|
-
bio: TrustScoreBreakdown;
|
|
752
|
-
};
|
|
753
|
-
penalties: TrustScorePenalty[];
|
|
754
|
-
bonuses: TrustScoreBonus[];
|
|
755
|
-
signals: {
|
|
756
|
-
physics: number;
|
|
757
|
-
enf: number;
|
|
758
|
-
gpu: number;
|
|
759
|
-
dram: number;
|
|
760
|
-
bio: number;
|
|
761
|
-
};
|
|
762
|
-
}
|
|
763
|
-
|
|
764
|
-
export declare function computeTrustScore(
|
|
765
|
-
payload: ProofPayload,
|
|
766
|
-
extended?: { enf?: EnfResult; gpu?: GpuEntropyResult; dram?: DramResult; llm?: LlmResult }
|
|
767
|
-
): TrustScore;
|
|
768
|
-
|
|
769
|
-
export declare function formatTrustScore(ts: TrustScore): string;
|
|
770
|
-
|
|
771
|
-
// =============================================================================
|
|
772
|
-
// HMAC-Signed Challenge
|
|
773
|
-
// =============================================================================
|
|
774
|
-
|
|
775
|
-
export interface SignedChallenge {
|
|
776
|
-
nonce: string;
|
|
777
|
-
issuedAt: number;
|
|
778
|
-
expiresAt: number;
|
|
779
|
-
sig: string;
|
|
780
|
-
}
|
|
781
|
-
|
|
782
|
-
export interface ChallengeVerifyResult {
|
|
783
|
-
valid: boolean;
|
|
784
|
-
reason?: string;
|
|
785
|
-
}
|
|
786
|
-
|
|
787
|
-
export declare function createChallenge(
|
|
788
|
-
secret: string,
|
|
789
|
-
opts?: { ttlMs?: number; nonce?: string }
|
|
790
|
-
): SignedChallenge;
|
|
791
|
-
|
|
792
|
-
export declare function verifyChallenge(
|
|
793
|
-
challenge: SignedChallenge,
|
|
794
|
-
secret: string,
|
|
795
|
-
opts?: { checkNonce?: (nonce: string) => Promise<boolean> }
|
|
796
|
-
): Promise<ChallengeVerifyResult>;
|
|
797
|
-
|
|
798
|
-
export declare function embedChallenge(challenge: SignedChallenge, payload: ProofPayload): ProofPayload;
|
|
799
|
-
export declare function extractChallenge(payload: ProofPayload): SignedChallenge;
|
|
800
|
-
export declare function generateSecret(): string;
|
|
801
|
-
|
|
802
|
-
// =============================================================================
|
|
803
|
-
// React Native Hook
|
|
804
|
-
// =============================================================================
|
|
805
|
-
|
|
806
|
-
export interface TremorResult {
|
|
807
|
-
tremorPresent: boolean;
|
|
808
|
-
tremorPower: number;
|
|
809
|
-
rmsNoise: number;
|
|
810
|
-
sampleRate: number;
|
|
811
|
-
gyroNoise: number;
|
|
812
|
-
isStatic: boolean;
|
|
813
|
-
}
|
|
814
|
-
|
|
815
|
-
export interface TouchAnalysis {
|
|
816
|
-
humanConf: number;
|
|
817
|
-
dwellMean: number;
|
|
818
|
-
dwellCV: number;
|
|
819
|
-
sampleCount: number;
|
|
820
|
-
}
|
|
821
|
-
|
|
822
|
-
export interface UsePulseNativeOptions {
|
|
823
|
-
challengeUrl?: string;
|
|
824
|
-
verifyUrl?: string;
|
|
825
|
-
apiKey?: string;
|
|
826
|
-
sensorMs?: number;
|
|
827
|
-
autoRun?: boolean;
|
|
828
|
-
onResult?: (trustScore: TrustScore, proof: object) => void;
|
|
829
|
-
onError?: (error: Error) => void;
|
|
830
|
-
}
|
|
831
|
-
|
|
832
|
-
export interface UsePulseNativeReturn {
|
|
833
|
-
run: () => Promise<void>;
|
|
834
|
-
reset: () => void;
|
|
835
|
-
isRunning: boolean;
|
|
836
|
-
stage: string | null;
|
|
837
|
-
pct: number;
|
|
838
|
-
trustScore: TrustScore | null;
|
|
839
|
-
tremor: TremorResult | null;
|
|
840
|
-
touches: TouchAnalysis | null;
|
|
841
|
-
proof: object | null;
|
|
842
|
-
error: Error | null;
|
|
843
|
-
panHandlers: object | null;
|
|
844
|
-
}
|
|
845
|
-
|
|
846
|
-
export declare function usePulseNative(opts?: UsePulseNativeOptions): UsePulseNativeReturn;
|
|
1
|
+
/**
|
|
2
|
+
* @svrnsec/pulse — TypeScript Declarations
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
// =============================================================================
|
|
6
|
+
// Core pulse() API
|
|
7
|
+
// =============================================================================
|
|
8
|
+
|
|
9
|
+
export interface PulseOptions {
|
|
10
|
+
/**
|
|
11
|
+
* Server-issued challenge nonce — required in self-hosted mode.
|
|
12
|
+
* Omit when using apiKey (hosted API fetches its own nonce).
|
|
13
|
+
*/
|
|
14
|
+
nonce?: string;
|
|
15
|
+
/**
|
|
16
|
+
* Sovereign hosted API key — enables zero-config mode.
|
|
17
|
+
* When set, pulse() handles challenge + verify automatically.
|
|
18
|
+
* Get a key at https://sovereign.dev
|
|
19
|
+
*/
|
|
20
|
+
apiKey?: string;
|
|
21
|
+
/** Hosted API base URL. Default: 'https://api.sovereign.dev' */
|
|
22
|
+
apiUrl?: string;
|
|
23
|
+
/** Options forwarded to the hosted verify endpoint (minJitterScore, requireBio, etc.) */
|
|
24
|
+
verifyOptions?: Partial<ValidateOptions>;
|
|
25
|
+
/** Number of WASM matrix-multiply iterations. Default: 200 */
|
|
26
|
+
iterations?: number;
|
|
27
|
+
/** How long to listen for mouse/keyboard bio signals (ms). Default: 3000 */
|
|
28
|
+
bioWindowMs?: number;
|
|
29
|
+
/** Run cold/load/hot phases for entropy-jitter ratio. Default: true */
|
|
30
|
+
phased?: boolean;
|
|
31
|
+
/** Use adaptive early exit (faster for obvious VMs). Default: true */
|
|
32
|
+
adaptive?: boolean;
|
|
33
|
+
/** Stop early if VM/HW signal reaches this confidence. Default: 0.85 */
|
|
34
|
+
adaptiveThreshold?: number;
|
|
35
|
+
/** Custom WASM binary URL/path (optional). */
|
|
36
|
+
wasmPath?: string;
|
|
37
|
+
/** Progress callback — called at each pipeline stage. */
|
|
38
|
+
onProgress?: (stage: PulseStage, meta?: ProgressMeta) => void;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export type PulseStage =
|
|
42
|
+
| 'start'
|
|
43
|
+
| 'entropy_batch'
|
|
44
|
+
| 'entropy_done'
|
|
45
|
+
| 'canvas_done'
|
|
46
|
+
| 'audio_done'
|
|
47
|
+
| 'bio_done'
|
|
48
|
+
| 'analysis_done'
|
|
49
|
+
| 'complete';
|
|
50
|
+
|
|
51
|
+
export interface ProgressMeta {
|
|
52
|
+
/** Current iteration count (during adaptive probe). */
|
|
53
|
+
iterations?: number;
|
|
54
|
+
/** Max iterations configured. */
|
|
55
|
+
maxIterations?: number;
|
|
56
|
+
/** Percentage complete (0–100). */
|
|
57
|
+
pct?: number;
|
|
58
|
+
/** Preliminary verdict from adaptive probe. */
|
|
59
|
+
earlyVerdict?: 'vm' | 'physical' | 'borderline' | 'uncertain';
|
|
60
|
+
/** Estimated milliseconds remaining. */
|
|
61
|
+
etaMs?: number;
|
|
62
|
+
/** Current VM confidence (0–1). */
|
|
63
|
+
vmConf?: number;
|
|
64
|
+
/** Current physical hardware confidence (0–1). */
|
|
65
|
+
hwConf?: number;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export interface PulseCommitment {
|
|
69
|
+
/** Statistical summary payload (~1.6KB). Send this to your server. */
|
|
70
|
+
payload: ProofPayload;
|
|
71
|
+
/** BLAKE3 hex hash of the canonical payload. */
|
|
72
|
+
hash: string;
|
|
73
|
+
/**
|
|
74
|
+
* Server validation result — only present when using apiKey (hosted mode).
|
|
75
|
+
* Undefined in self-hosted mode; validate server-side with validateProof().
|
|
76
|
+
*/
|
|
77
|
+
result?: ValidationResult;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export function pulse(opts: PulseOptions): Promise<PulseCommitment>;
|
|
81
|
+
|
|
82
|
+
// =============================================================================
|
|
83
|
+
// React Hook (import from '@svrnsec/pulse/react')
|
|
84
|
+
// =============================================================================
|
|
85
|
+
|
|
86
|
+
export interface UsePulseOptions {
|
|
87
|
+
/** Sovereign hosted API key. Handles nonce + verify automatically. */
|
|
88
|
+
apiKey?: string;
|
|
89
|
+
/** Hosted API base URL. Default: 'https://api.sovereign.dev' */
|
|
90
|
+
apiUrl?: string;
|
|
91
|
+
/** Self-hosted challenge endpoint URL. */
|
|
92
|
+
challengeUrl?: string;
|
|
93
|
+
/** Self-hosted verify endpoint URL. */
|
|
94
|
+
verifyUrl?: string;
|
|
95
|
+
/** Number of WASM matrix-multiply iterations. Default: 200 */
|
|
96
|
+
iterations?: number;
|
|
97
|
+
/** Bio collection window in milliseconds. Default: 3000 */
|
|
98
|
+
bioWindowMs?: number;
|
|
99
|
+
/** Enable adaptive early exit. Default: true */
|
|
100
|
+
adaptive?: boolean;
|
|
101
|
+
/** Run immediately on mount. Default: false */
|
|
102
|
+
autoRun?: boolean;
|
|
103
|
+
/** Called when proof + result are ready. */
|
|
104
|
+
onResult?: (result: ValidationResult | null, commitment: PulseCommitment) => void;
|
|
105
|
+
/** Called on error. */
|
|
106
|
+
onError?: (error: Error) => void;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export interface UsePulseReturn {
|
|
110
|
+
/** Trigger the probe manually. */
|
|
111
|
+
run: () => Promise<void>;
|
|
112
|
+
/** Reset all state back to idle. */
|
|
113
|
+
reset: () => void;
|
|
114
|
+
/** Current pipeline stage. */
|
|
115
|
+
stage: PulseStage | null;
|
|
116
|
+
/** Probe progress 0–100. */
|
|
117
|
+
pct: number;
|
|
118
|
+
/** Live VM confidence 0–1 (updates during entropy_batch stages). */
|
|
119
|
+
vmConf: number;
|
|
120
|
+
/** Live HW confidence 0–1. */
|
|
121
|
+
hwConf: number;
|
|
122
|
+
/** Preliminary verdict from adaptive probe, or null if still uncertain. */
|
|
123
|
+
earlyVerdict: 'vm' | 'physical' | 'borderline' | 'uncertain' | null;
|
|
124
|
+
/** The BLAKE3 commitment. Available after probe completes. */
|
|
125
|
+
proof: PulseCommitment | null;
|
|
126
|
+
/** Server validation result. Available after verify completes (hosted/verifyUrl mode). */
|
|
127
|
+
result: ValidationResult | null;
|
|
128
|
+
/** True while probe is in progress. */
|
|
129
|
+
isRunning: boolean;
|
|
130
|
+
/** True when probe has completed (pass or fail). */
|
|
131
|
+
isReady: boolean;
|
|
132
|
+
/** Any error thrown during the probe. */
|
|
133
|
+
error: Error | null;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/** React hook — import from '@svrnsec/pulse/react' */
|
|
137
|
+
export declare function usePulse(opts?: UsePulseOptions): UsePulseReturn;
|
|
138
|
+
|
|
139
|
+
// =============================================================================
|
|
140
|
+
// Fingerprint class (high-level API)
|
|
141
|
+
// =============================================================================
|
|
142
|
+
|
|
143
|
+
export class Fingerprint {
|
|
144
|
+
/** Collect all hardware signals and return a Fingerprint instance. */
|
|
145
|
+
static collect(opts: PulseOptions): Promise<Fingerprint>;
|
|
146
|
+
|
|
147
|
+
/** True if the device is likely a VM, AI endpoint, or sanitised cloud env. */
|
|
148
|
+
readonly isSynthetic: boolean;
|
|
149
|
+
|
|
150
|
+
/** Confidence in the isSynthetic verdict (0–100). */
|
|
151
|
+
readonly confidence: number;
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Final normalised score [0.0, 1.0] after all three analysis stages.
|
|
155
|
+
* Higher = more physical.
|
|
156
|
+
*/
|
|
157
|
+
readonly score: number;
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Dynamic passing threshold for this specific proof [0.55, 0.67].
|
|
161
|
+
* Lower when more evidence was collected; higher for minimal-evidence proofs.
|
|
162
|
+
*/
|
|
163
|
+
readonly threshold: number;
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Evidence weight [0, 1] — reflects how much data was collected.
|
|
167
|
+
* 1.0 = 200 iterations + phased + bio + audio + canvas
|
|
168
|
+
*/
|
|
169
|
+
readonly evidenceWeight: number;
|
|
170
|
+
|
|
171
|
+
/** Confidence tier. */
|
|
172
|
+
readonly tier: 'high' | 'medium' | 'low' | 'uncertain';
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Timing profile of the device.
|
|
176
|
+
* - `'analog-fog'` — real hardware, natural Brownian noise
|
|
177
|
+
* - `'picket-fence'` — VM steal-time bursts at regular intervals
|
|
178
|
+
* - `'burst-scheduler'` — irregular VM scheduling (VMware-style)
|
|
179
|
+
* - `'hypervisor-flat'` — completely flat (heavy datacenter VM)
|
|
180
|
+
* - `'near-physical'` — ambiguous (Nitro, GPU passthrough)
|
|
181
|
+
*/
|
|
182
|
+
readonly profile: 'analog-fog' | 'picket-fence' | 'burst-scheduler' | 'hypervisor-flat' | 'near-physical' | 'unknown';
|
|
183
|
+
|
|
184
|
+
/** Detected cloud provider / hypervisor identifier. */
|
|
185
|
+
readonly providerId: string;
|
|
186
|
+
|
|
187
|
+
/** Human-readable provider label (e.g. "DigitalOcean Droplet (KVM)"). */
|
|
188
|
+
readonly providerLabel: string;
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Estimated hypervisor scheduler quantum in milliseconds.
|
|
192
|
+
* `null` if the device appears to be physical hardware.
|
|
193
|
+
*/
|
|
194
|
+
readonly schedulerQuantumMs: number | null;
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Entropy-Jitter Ratio — key signal for real silicon vs VM.
|
|
198
|
+
* - ≥ 1.08 → thermal feedback confirmed (real hardware)
|
|
199
|
+
* - ~1.00 → hypervisor clock (VM)
|
|
200
|
+
* - `null` → phased collection not run
|
|
201
|
+
*/
|
|
202
|
+
readonly entropyJitterRatio: number | null;
|
|
203
|
+
|
|
204
|
+
/** Top diagnostic flag from the heuristic engine. */
|
|
205
|
+
readonly topFlag: string;
|
|
206
|
+
|
|
207
|
+
/** All diagnostic flags. */
|
|
208
|
+
readonly flags: string[];
|
|
209
|
+
|
|
210
|
+
/** Heuristic engine findings with severity labels. */
|
|
211
|
+
readonly findings: HeuristicFinding[];
|
|
212
|
+
|
|
213
|
+
/** Confirmed physical properties (positive evidence). */
|
|
214
|
+
readonly physicalEvidence: PhysicalEvidence[];
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Stable, privacy-safe 32-char hex hardware identifier (128-bit collision resistance).
|
|
218
|
+
* Stable per device, changes if GPU/driver changes, not reversible.
|
|
219
|
+
*/
|
|
220
|
+
hardwareId(): string;
|
|
221
|
+
|
|
222
|
+
/** Key metrics summary for logging / debugging. */
|
|
223
|
+
metrics(): FingerprintMetrics;
|
|
224
|
+
|
|
225
|
+
/** Full diagnostic report. */
|
|
226
|
+
report(): FingerprintReport;
|
|
227
|
+
|
|
228
|
+
/** Returns the BLAKE3 commitment to send to your server. */
|
|
229
|
+
toCommitment(): PulseCommitment;
|
|
230
|
+
|
|
231
|
+
toString(): string;
|
|
232
|
+
toJSON(): FingerprintReport;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
export interface HeuristicFinding {
|
|
236
|
+
id: string;
|
|
237
|
+
label: string;
|
|
238
|
+
severity: 'critical' | 'high' | 'medium' | 'info';
|
|
239
|
+
detail: string;
|
|
240
|
+
penalty: number;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
export interface PhysicalEvidence {
|
|
244
|
+
id: string;
|
|
245
|
+
label: string;
|
|
246
|
+
detail: string;
|
|
247
|
+
value: number;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
export interface FingerprintMetrics {
|
|
251
|
+
// Final verdict
|
|
252
|
+
score: number; // stage-3 final score
|
|
253
|
+
threshold: number; // dynamic passing threshold [0.55, 0.67]
|
|
254
|
+
evidenceWeight: number; // how much evidence was collected [0, 1]
|
|
255
|
+
isSynthetic: boolean;
|
|
256
|
+
// Score pipeline
|
|
257
|
+
rawScore: number;
|
|
258
|
+
adjustedScore: number;
|
|
259
|
+
finalScore: number;
|
|
260
|
+
heuristicAdjustment: number;
|
|
261
|
+
coherenceAdjustment: number;
|
|
262
|
+
// Timing signals
|
|
263
|
+
cv: number | null;
|
|
264
|
+
hurstExponent: number | null;
|
|
265
|
+
quantizationEntropy: number | null;
|
|
266
|
+
autocorrLag1: number | null;
|
|
267
|
+
autocorrLag50: number | null;
|
|
268
|
+
outlierRate: number | null;
|
|
269
|
+
thermalPattern: string | null;
|
|
270
|
+
entropyJitterRatio: number | null;
|
|
271
|
+
picketFence: boolean;
|
|
272
|
+
// Coherence signals
|
|
273
|
+
coherenceFlags: string[];
|
|
274
|
+
physicalFlags: string[];
|
|
275
|
+
hardOverride: 'vm' | null;
|
|
276
|
+
// Provider
|
|
277
|
+
provider: string;
|
|
278
|
+
providerConfidence: number;
|
|
279
|
+
schedulerQuantumMs: number | null;
|
|
280
|
+
// Hardware
|
|
281
|
+
webglRenderer: string | null;
|
|
282
|
+
isSoftwareRenderer: boolean;
|
|
283
|
+
hardwareId: string;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
export interface FingerprintReport {
|
|
287
|
+
verdict: {
|
|
288
|
+
isSynthetic: boolean;
|
|
289
|
+
score: number;
|
|
290
|
+
threshold: number;
|
|
291
|
+
confidence: number;
|
|
292
|
+
tier: string;
|
|
293
|
+
profile: string;
|
|
294
|
+
provider: string;
|
|
295
|
+
topFlag: string;
|
|
296
|
+
hardOverride: 'vm' | null;
|
|
297
|
+
evidenceWeight: number;
|
|
298
|
+
};
|
|
299
|
+
pipeline: {
|
|
300
|
+
rawScore: number;
|
|
301
|
+
adjustedScore: number;
|
|
302
|
+
finalScore: number;
|
|
303
|
+
heuristicAdjustment: number;
|
|
304
|
+
coherenceAdjustment: number;
|
|
305
|
+
dynamicThreshold: number;
|
|
306
|
+
};
|
|
307
|
+
metrics: FingerprintMetrics;
|
|
308
|
+
findings: HeuristicFinding[];
|
|
309
|
+
physicalEvidence: PhysicalEvidence[];
|
|
310
|
+
coherenceChecks: CoherenceCheck[];
|
|
311
|
+
coherenceBonuses: CoherenceBonus[];
|
|
312
|
+
phases: PhaseReport | null;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
export interface PhaseReport {
|
|
316
|
+
cold: { qe: number; mean: number };
|
|
317
|
+
hot: { qe: number; mean: number };
|
|
318
|
+
entropyJitterRatio: number;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
// =============================================================================
|
|
322
|
+
// Server-side validation
|
|
323
|
+
// =============================================================================
|
|
324
|
+
|
|
325
|
+
export interface ValidateOptions {
|
|
326
|
+
/** Minimum jitter score [0–1]. Default: 0.55 */
|
|
327
|
+
minJitterScore?: number;
|
|
328
|
+
/** Max proof age in milliseconds. Default: 300000 (5 min) */
|
|
329
|
+
maxAgeMs?: number;
|
|
330
|
+
/** Tolerated future clock skew. Default: 30000 */
|
|
331
|
+
clockSkewMs?: number;
|
|
332
|
+
/** Reject proofs with no bio activity. Default: false */
|
|
333
|
+
requireBio?: boolean;
|
|
334
|
+
/** Reject software WebGL renderers. Default: true */
|
|
335
|
+
blockSoftwareRenderer?: boolean;
|
|
336
|
+
/**
|
|
337
|
+
* Async nonce validator — must mark nonce as consumed atomically.
|
|
338
|
+
* Returns true if nonce is valid and unused.
|
|
339
|
+
*/
|
|
340
|
+
checkNonce?: (nonce: string) => Promise<boolean>;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
export interface ValidationResult {
|
|
344
|
+
valid: boolean;
|
|
345
|
+
score: number;
|
|
346
|
+
confidence: 'high' | 'medium' | 'low' | 'rejected';
|
|
347
|
+
reasons: string[];
|
|
348
|
+
riskFlags: string[];
|
|
349
|
+
meta: {
|
|
350
|
+
receivedAt: number;
|
|
351
|
+
proofAge: number;
|
|
352
|
+
jitterScore: number;
|
|
353
|
+
canvasRenderer: string | null;
|
|
354
|
+
bioActivity: boolean;
|
|
355
|
+
};
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
export function validateProof(
|
|
359
|
+
payload: ProofPayload,
|
|
360
|
+
hash: string,
|
|
361
|
+
opts?: ValidateOptions
|
|
362
|
+
): Promise<ValidationResult>;
|
|
363
|
+
|
|
364
|
+
export function generateNonce(): string;
|
|
365
|
+
|
|
366
|
+
// =============================================================================
|
|
367
|
+
// Heuristic engine (advanced)
|
|
368
|
+
// =============================================================================
|
|
369
|
+
|
|
370
|
+
export interface HeuristicReport {
|
|
371
|
+
penalty: number;
|
|
372
|
+
bonus: number;
|
|
373
|
+
netAdjustment: number;
|
|
374
|
+
findings: HeuristicFinding[];
|
|
375
|
+
bonuses: PhysicalEvidence[];
|
|
376
|
+
entropyJitterRatio: number | null;
|
|
377
|
+
entropyJitterScore: number;
|
|
378
|
+
/**
|
|
379
|
+
* Set to 'vm' when a mathematical impossibility is detected in the phase data,
|
|
380
|
+
* specifically when the stored EJR value contradicts the stored QE values.
|
|
381
|
+
* This is a hard kill — isSynthetic returns true regardless of all other scores.
|
|
382
|
+
*/
|
|
383
|
+
hardOverride: 'vm' | null;
|
|
384
|
+
picketFence: {
|
|
385
|
+
detected: boolean;
|
|
386
|
+
dominantLag: number | null;
|
|
387
|
+
peakAC: number;
|
|
388
|
+
baseline: number;
|
|
389
|
+
detail: string;
|
|
390
|
+
};
|
|
391
|
+
coherenceFlags: string[];
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
export function runHeuristicEngine(opts: {
|
|
395
|
+
jitter: JitterAnalysis;
|
|
396
|
+
phases: PhasedData | null;
|
|
397
|
+
autocorrelations: Record<string, number>;
|
|
398
|
+
}): HeuristicReport;
|
|
399
|
+
|
|
400
|
+
// =============================================================================
|
|
401
|
+
// Provider detection (advanced)
|
|
402
|
+
// =============================================================================
|
|
403
|
+
|
|
404
|
+
export interface ProviderResult {
|
|
405
|
+
providerId: string;
|
|
406
|
+
providerLabel: string;
|
|
407
|
+
profile: string;
|
|
408
|
+
confidence: number;
|
|
409
|
+
isVirtualized: boolean;
|
|
410
|
+
signals: Record<string, number | boolean | string[]>;
|
|
411
|
+
alternatives: Array<{ id: string; label: string }>;
|
|
412
|
+
rendererHints: string[];
|
|
413
|
+
schedulerQuantumMs: number | null;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
export function detectProvider(opts: {
|
|
417
|
+
jitter: JitterAnalysis;
|
|
418
|
+
autocorrelations: Record<string, number>;
|
|
419
|
+
canvas: CanvasFingerprint | null;
|
|
420
|
+
phases: PhasedData | null;
|
|
421
|
+
}): ProviderResult;
|
|
422
|
+
|
|
423
|
+
// =============================================================================
|
|
424
|
+
// Proof payload structure
|
|
425
|
+
// =============================================================================
|
|
426
|
+
|
|
427
|
+
export interface ProofPayload {
|
|
428
|
+
version: number;
|
|
429
|
+
timestamp: number;
|
|
430
|
+
nonce: string;
|
|
431
|
+
signals: {
|
|
432
|
+
entropy: Record<string, number | string | null>;
|
|
433
|
+
bio: Record<string, number | boolean | null>;
|
|
434
|
+
canvas: {
|
|
435
|
+
webglRenderer: string | null;
|
|
436
|
+
webglVendor: string | null;
|
|
437
|
+
webglVersion: 1 | 2 | null;
|
|
438
|
+
webglPixelHash: string | null;
|
|
439
|
+
canvas2dHash: string | null;
|
|
440
|
+
extensionCount: number;
|
|
441
|
+
isSoftwareRenderer: boolean;
|
|
442
|
+
available: boolean;
|
|
443
|
+
};
|
|
444
|
+
audio: Record<string, number | boolean | null>;
|
|
445
|
+
};
|
|
446
|
+
classification: {
|
|
447
|
+
jitterScore: number;
|
|
448
|
+
adjustedScore?: number;
|
|
449
|
+
finalScore?: number;
|
|
450
|
+
dynamicThreshold?: number;
|
|
451
|
+
flags: string[];
|
|
452
|
+
};
|
|
453
|
+
heuristic?: Record<string, unknown>;
|
|
454
|
+
provider?: {
|
|
455
|
+
id: string;
|
|
456
|
+
label: string;
|
|
457
|
+
profile: string;
|
|
458
|
+
confidence: number;
|
|
459
|
+
schedulerQuantum: number | null;
|
|
460
|
+
};
|
|
461
|
+
coherence?: {
|
|
462
|
+
netAdjustment: number;
|
|
463
|
+
dynamicThreshold: number;
|
|
464
|
+
evidenceWeight: number;
|
|
465
|
+
coherenceFlags: string[];
|
|
466
|
+
physicalFlags: string[];
|
|
467
|
+
hardOverride: 'vm' | null;
|
|
468
|
+
};
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
// =============================================================================
|
|
472
|
+
// Coherence analysis (stage 3)
|
|
473
|
+
// =============================================================================
|
|
474
|
+
|
|
475
|
+
export interface CoherenceCheck {
|
|
476
|
+
id: string;
|
|
477
|
+
label: string;
|
|
478
|
+
severity: 'critical' | 'high' | 'medium' | 'info';
|
|
479
|
+
detail: string;
|
|
480
|
+
penalty: number;
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
export interface CoherenceBonus {
|
|
484
|
+
id: string;
|
|
485
|
+
label: string;
|
|
486
|
+
detail: string;
|
|
487
|
+
value: number;
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
export interface CoherenceReport {
|
|
491
|
+
penalty: number;
|
|
492
|
+
bonus: number;
|
|
493
|
+
netAdjustment: number;
|
|
494
|
+
checks: CoherenceCheck[];
|
|
495
|
+
bonuses: CoherenceBonus[];
|
|
496
|
+
hardOverride: 'vm' | null;
|
|
497
|
+
/** Dynamic threshold [0.55, 0.67] — lower when more evidence collected. */
|
|
498
|
+
dynamicThreshold: number;
|
|
499
|
+
/** Evidence weight [0, 1] */
|
|
500
|
+
evidenceWeight: number;
|
|
501
|
+
coherenceFlags: string[];
|
|
502
|
+
physicalFlags: string[];
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
export function runCoherenceAnalysis(opts: {
|
|
506
|
+
timings: number[];
|
|
507
|
+
jitter: JitterAnalysis;
|
|
508
|
+
phases?: PhasedData | null;
|
|
509
|
+
batches?: object[] | null;
|
|
510
|
+
bio?: object;
|
|
511
|
+
canvas?: CanvasFingerprint | null;
|
|
512
|
+
audio?: object;
|
|
513
|
+
}): CoherenceReport;
|
|
514
|
+
|
|
515
|
+
export function computeServerDynamicThreshold(payload: ProofPayload): number;
|
|
516
|
+
|
|
517
|
+
// =============================================================================
|
|
518
|
+
// Internal types (exported for advanced consumers)
|
|
519
|
+
// =============================================================================
|
|
520
|
+
|
|
521
|
+
export interface JitterAnalysis {
|
|
522
|
+
score: number;
|
|
523
|
+
flags: string[];
|
|
524
|
+
stats: TimingStats | null;
|
|
525
|
+
autocorrelations: Record<string, number>;
|
|
526
|
+
hurstExponent: number;
|
|
527
|
+
quantizationEntropy: number;
|
|
528
|
+
thermalSignature: { slope: number; pattern: string; r2: number };
|
|
529
|
+
outlierRate: number;
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
export interface TimingStats {
|
|
533
|
+
n: number; mean: number; std: number; cv: number;
|
|
534
|
+
min: number; max: number;
|
|
535
|
+
p5: number; p25: number; p50: number; p75: number; p95: number; p99: number;
|
|
536
|
+
skewness: number; kurtosis: number;
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
export interface CanvasFingerprint {
|
|
540
|
+
webglRenderer: string | null;
|
|
541
|
+
webglVendor: string | null;
|
|
542
|
+
webglVersion: 1 | 2 | null;
|
|
543
|
+
webglPixelHash: string | null;
|
|
544
|
+
canvas2dHash: string | null;
|
|
545
|
+
extensionCount: number;
|
|
546
|
+
extensions: string[];
|
|
547
|
+
isSoftwareRenderer: boolean;
|
|
548
|
+
available: boolean;
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
export interface PhasedData {
|
|
552
|
+
cold: { qe: number; mean: number };
|
|
553
|
+
load: { qe: number; mean: number };
|
|
554
|
+
hot: { qe: number; mean: number };
|
|
555
|
+
entropyJitterRatio: number;
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
// =============================================================================
|
|
559
|
+
// SVRN Registry
|
|
560
|
+
// =============================================================================
|
|
561
|
+
|
|
562
|
+
export interface SvrnSignature {
|
|
563
|
+
version: number;
|
|
564
|
+
id: string;
|
|
565
|
+
profile: string;
|
|
566
|
+
provider: string;
|
|
567
|
+
class: string;
|
|
568
|
+
metrics: Record<string, { lo: number; hi: number; mid: number; label: string } | null>;
|
|
569
|
+
rendererClass: string;
|
|
570
|
+
isSynthetic: boolean;
|
|
571
|
+
hwLabel: string | null;
|
|
572
|
+
osHint: string | null;
|
|
573
|
+
date: string;
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
export interface RegistryMatch {
|
|
577
|
+
matched: boolean;
|
|
578
|
+
profile: object | null;
|
|
579
|
+
similarity: number;
|
|
580
|
+
alternatives: Array<{ name: string; similarity: number }>;
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
export interface SignatureComparison {
|
|
584
|
+
sameClass: boolean;
|
|
585
|
+
similarity: number;
|
|
586
|
+
profileMatch: boolean;
|
|
587
|
+
providerMatch: boolean;
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
// =============================================================================
|
|
591
|
+
// Extended Signal Layer Types
|
|
592
|
+
// =============================================================================
|
|
593
|
+
|
|
594
|
+
// ── ENF (Electrical Network Frequency) ───────────────────────────────────────
|
|
595
|
+
|
|
596
|
+
export interface EnfResult {
|
|
597
|
+
enfAvailable: boolean;
|
|
598
|
+
ripplePresent: boolean;
|
|
599
|
+
gridFrequency: 50 | 60 | null;
|
|
600
|
+
gridRegion: 'americas' | 'emea_apac' | 'unknown';
|
|
601
|
+
ripplePower: number;
|
|
602
|
+
snr50hz: number;
|
|
603
|
+
snr60hz: number;
|
|
604
|
+
enfDeviation: number | null;
|
|
605
|
+
sampleRateHz: number;
|
|
606
|
+
resolutionUs: number;
|
|
607
|
+
verdict: 'grid_60hz' | 'grid_50hz' | 'no_grid_signal' | 'grid_detected_region_unknown' | 'unavailable';
|
|
608
|
+
isVmIndicator: boolean;
|
|
609
|
+
temporalAnchor: {
|
|
610
|
+
nominalHz: number;
|
|
611
|
+
measuredRippleHz: number;
|
|
612
|
+
capturedAt: number;
|
|
613
|
+
gridHz: number;
|
|
614
|
+
} | null;
|
|
615
|
+
reason?: string;
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
export declare function collectEnfTimings(opts?: { iterations?: number }): Promise<EnfResult>;
|
|
619
|
+
|
|
620
|
+
// ── WebGPU Thermal Variance ───────────────────────────────────────────────────
|
|
621
|
+
|
|
622
|
+
export interface GpuEntropyResult {
|
|
623
|
+
gpuPresent: boolean;
|
|
624
|
+
isSoftware: boolean;
|
|
625
|
+
vendorString: string | null;
|
|
626
|
+
dispatchCV: number;
|
|
627
|
+
thermalGrowth: number;
|
|
628
|
+
verdict: 'real_gpu' | 'virtual_gpu' | 'software_renderer' | 'no_gpu' | 'no_webgpu' | 'ambiguous';
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
export declare function collectGpuEntropy(opts?: object): Promise<GpuEntropyResult>;
|
|
632
|
+
|
|
633
|
+
// ── DRAM Refresh Cycle ────────────────────────────────────────────────────────
|
|
634
|
+
|
|
635
|
+
export interface DramResult {
|
|
636
|
+
timings: number[];
|
|
637
|
+
refreshPeriodMs: number | null;
|
|
638
|
+
refreshPresent: boolean;
|
|
639
|
+
peakLag: number;
|
|
640
|
+
peakPower: number;
|
|
641
|
+
verdict: 'dram' | 'virtual' | 'ambiguous';
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
export declare function collectDramTimings(opts?: { iterations?: number; bufferMb?: number }): DramResult;
|
|
645
|
+
|
|
646
|
+
// ── LLM / AI Agent Behavioral Fingerprint ─────────────────────────────────────
|
|
647
|
+
|
|
648
|
+
export interface LlmResult {
|
|
649
|
+
aiConf: number;
|
|
650
|
+
thinkTimePattern: 'llm_latency_peak' | 'human_pareto' | 'unknown';
|
|
651
|
+
correctionRate: number;
|
|
652
|
+
rhythmicity: number;
|
|
653
|
+
pauseDistribution: 'uniform' | 'pareto' | 'unknown';
|
|
654
|
+
verdict: 'ai_agent' | 'human' | 'insufficient_data';
|
|
655
|
+
matchedModel: string | null;
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
export declare function detectLlmAgent(bioSnapshot: object): LlmResult;
|
|
659
|
+
|
|
660
|
+
// ── SAB Microsecond Timer ─────────────────────────────────────────────────────
|
|
661
|
+
|
|
662
|
+
export interface SabTimerResult {
|
|
663
|
+
isClamped: boolean;
|
|
664
|
+
clampAmountUs: number;
|
|
665
|
+
resolutionUs: number;
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
export declare function isSabAvailable(): boolean;
|
|
669
|
+
export declare function collectHighResTimings(opts?: { iterations?: number; matrixSize?: number }): {
|
|
670
|
+
timings: number[];
|
|
671
|
+
resolutionUs: number;
|
|
672
|
+
};
|
|
673
|
+
|
|
674
|
+
// =============================================================================
|
|
675
|
+
// Terminal / DX Utilities
|
|
676
|
+
// =============================================================================
|
|
677
|
+
|
|
678
|
+
export declare function renderProbeResult(opts: {
|
|
679
|
+
payload: ProofPayload;
|
|
680
|
+
hash: string;
|
|
681
|
+
result?: ValidationResult;
|
|
682
|
+
enf?: EnfResult | null;
|
|
683
|
+
gpu?: GpuEntropyResult | null;
|
|
684
|
+
dram?: DramResult | null;
|
|
685
|
+
llm?: LlmResult | null;
|
|
686
|
+
elapsedMs?: number;
|
|
687
|
+
}): void;
|
|
688
|
+
|
|
689
|
+
export declare function renderError(err: Error | string): void;
|
|
690
|
+
export declare function renderInlineUpdateHint(latest: string): void;
|
|
691
|
+
|
|
692
|
+
// =============================================================================
|
|
693
|
+
// Version / Update Notifier
|
|
694
|
+
// =============================================================================
|
|
695
|
+
|
|
696
|
+
export declare const CURRENT_VERSION: string;
|
|
697
|
+
|
|
698
|
+
export declare function checkForUpdate(opts?: {
|
|
699
|
+
silent?: boolean;
|
|
700
|
+
pkg?: string;
|
|
701
|
+
}): Promise<{ current: string; latest: string | null; updateAvailable: boolean }>;
|
|
702
|
+
|
|
703
|
+
export declare function notifyOnExit(opts?: { pkg?: string }): void;
|
|
704
|
+
|
|
705
|
+
// =============================================================================
|
|
706
|
+
// Extended PulseCommitment (includes extended signal layer results)
|
|
707
|
+
// =============================================================================
|
|
708
|
+
|
|
709
|
+
export interface ExtendedPulseCommitment extends PulseCommitment {
|
|
710
|
+
extended: {
|
|
711
|
+
enf: EnfResult | null;
|
|
712
|
+
gpu: GpuEntropyResult | null;
|
|
713
|
+
dram: DramResult | null;
|
|
714
|
+
llm: LlmResult | null;
|
|
715
|
+
};
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
// =============================================================================
|
|
719
|
+
// TrustScore
|
|
720
|
+
// =============================================================================
|
|
721
|
+
|
|
722
|
+
export interface TrustScoreBreakdown {
|
|
723
|
+
pts: number;
|
|
724
|
+
max: number;
|
|
725
|
+
[key: string]: unknown;
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
export interface TrustScorePenalty {
|
|
729
|
+
signal: string;
|
|
730
|
+
reason: string;
|
|
731
|
+
cap: number;
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
export interface TrustScoreBonus {
|
|
735
|
+
signal: string;
|
|
736
|
+
reason: string;
|
|
737
|
+
pts: number;
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
export interface TrustScore {
|
|
741
|
+
score: number;
|
|
742
|
+
grade: 'A' | 'B' | 'C' | 'D' | 'F';
|
|
743
|
+
label: 'Trusted' | 'Verified' | 'Marginal' | 'Suspicious' | 'Blocked';
|
|
744
|
+
color: string;
|
|
745
|
+
hardCap: number | null;
|
|
746
|
+
breakdown: {
|
|
747
|
+
physics: TrustScoreBreakdown;
|
|
748
|
+
enf: TrustScoreBreakdown;
|
|
749
|
+
gpu: TrustScoreBreakdown;
|
|
750
|
+
dram: TrustScoreBreakdown;
|
|
751
|
+
bio: TrustScoreBreakdown;
|
|
752
|
+
};
|
|
753
|
+
penalties: TrustScorePenalty[];
|
|
754
|
+
bonuses: TrustScoreBonus[];
|
|
755
|
+
signals: {
|
|
756
|
+
physics: number;
|
|
757
|
+
enf: number;
|
|
758
|
+
gpu: number;
|
|
759
|
+
dram: number;
|
|
760
|
+
bio: number;
|
|
761
|
+
};
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
export declare function computeTrustScore(
|
|
765
|
+
payload: ProofPayload,
|
|
766
|
+
extended?: { enf?: EnfResult; gpu?: GpuEntropyResult; dram?: DramResult; llm?: LlmResult }
|
|
767
|
+
): TrustScore;
|
|
768
|
+
|
|
769
|
+
export declare function formatTrustScore(ts: TrustScore): string;
|
|
770
|
+
|
|
771
|
+
// =============================================================================
|
|
772
|
+
// HMAC-Signed Challenge
|
|
773
|
+
// =============================================================================
|
|
774
|
+
|
|
775
|
+
export interface SignedChallenge {
|
|
776
|
+
nonce: string;
|
|
777
|
+
issuedAt: number;
|
|
778
|
+
expiresAt: number;
|
|
779
|
+
sig: string;
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
export interface ChallengeVerifyResult {
|
|
783
|
+
valid: boolean;
|
|
784
|
+
reason?: string;
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
export declare function createChallenge(
|
|
788
|
+
secret: string,
|
|
789
|
+
opts?: { ttlMs?: number; nonce?: string }
|
|
790
|
+
): SignedChallenge;
|
|
791
|
+
|
|
792
|
+
export declare function verifyChallenge(
|
|
793
|
+
challenge: SignedChallenge,
|
|
794
|
+
secret: string,
|
|
795
|
+
opts?: { checkNonce?: (nonce: string) => Promise<boolean> }
|
|
796
|
+
): Promise<ChallengeVerifyResult>;
|
|
797
|
+
|
|
798
|
+
export declare function embedChallenge(challenge: SignedChallenge, payload: ProofPayload): ProofPayload;
|
|
799
|
+
export declare function extractChallenge(payload: ProofPayload): SignedChallenge;
|
|
800
|
+
export declare function generateSecret(): string;
|
|
801
|
+
|
|
802
|
+
// =============================================================================
|
|
803
|
+
// React Native Hook
|
|
804
|
+
// =============================================================================
|
|
805
|
+
|
|
806
|
+
export interface TremorResult {
|
|
807
|
+
tremorPresent: boolean;
|
|
808
|
+
tremorPower: number;
|
|
809
|
+
rmsNoise: number;
|
|
810
|
+
sampleRate: number;
|
|
811
|
+
gyroNoise: number;
|
|
812
|
+
isStatic: boolean;
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
export interface TouchAnalysis {
|
|
816
|
+
humanConf: number;
|
|
817
|
+
dwellMean: number;
|
|
818
|
+
dwellCV: number;
|
|
819
|
+
sampleCount: number;
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
export interface UsePulseNativeOptions {
|
|
823
|
+
challengeUrl?: string;
|
|
824
|
+
verifyUrl?: string;
|
|
825
|
+
apiKey?: string;
|
|
826
|
+
sensorMs?: number;
|
|
827
|
+
autoRun?: boolean;
|
|
828
|
+
onResult?: (trustScore: TrustScore, proof: object) => void;
|
|
829
|
+
onError?: (error: Error) => void;
|
|
830
|
+
}
|
|
831
|
+
|
|
832
|
+
export interface UsePulseNativeReturn {
|
|
833
|
+
run: () => Promise<void>;
|
|
834
|
+
reset: () => void;
|
|
835
|
+
isRunning: boolean;
|
|
836
|
+
stage: string | null;
|
|
837
|
+
pct: number;
|
|
838
|
+
trustScore: TrustScore | null;
|
|
839
|
+
tremor: TremorResult | null;
|
|
840
|
+
touches: TouchAnalysis | null;
|
|
841
|
+
proof: object | null;
|
|
842
|
+
error: Error | null;
|
|
843
|
+
panHandlers: object | null;
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
export declare function usePulseNative(opts?: UsePulseNativeOptions): UsePulseNativeReturn;
|
|
847
|
+
|
|
848
|
+
// =============================================================================
|
|
849
|
+
// Engagement Token
|
|
850
|
+
// =============================================================================
|
|
851
|
+
|
|
852
|
+
export interface EngagementTokenResult {
|
|
853
|
+
token: object;
|
|
854
|
+
compact: string;
|
|
855
|
+
expiresAt: number;
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
export interface EngagementVerifyResult {
|
|
859
|
+
valid: boolean;
|
|
860
|
+
reason?: string;
|
|
861
|
+
expiredByMs?: number;
|
|
862
|
+
token?: object;
|
|
863
|
+
idleWarnings?: string[];
|
|
864
|
+
riskSignals?: Array<{ code: string; severity: 'high' | 'medium' | 'low' }>;
|
|
865
|
+
issuedAt?: number;
|
|
866
|
+
expiresAt?: number;
|
|
867
|
+
}
|
|
868
|
+
|
|
869
|
+
export declare function createEngagementToken(opts: {
|
|
870
|
+
pulseResult: object;
|
|
871
|
+
idleProof?: object | null;
|
|
872
|
+
interaction?: { type?: string; ts?: number; motorConsistency?: number };
|
|
873
|
+
secret: string;
|
|
874
|
+
_overrides?: object;
|
|
875
|
+
}): EngagementTokenResult;
|
|
876
|
+
|
|
877
|
+
export declare function verifyEngagementToken(
|
|
878
|
+
tokenOrCompact: string | object,
|
|
879
|
+
secret: string,
|
|
880
|
+
opts?: {
|
|
881
|
+
checkNonce?: (nonce: string) => Promise<boolean>;
|
|
882
|
+
now?: () => number;
|
|
883
|
+
}
|
|
884
|
+
): Promise<EngagementVerifyResult>;
|
|
885
|
+
|
|
886
|
+
export declare function encodeToken(token: object): string;
|
|
887
|
+
|
|
888
|
+
/** @deprecated Use decodeTokenUnsafe instead */
|
|
889
|
+
export declare function decodeToken(compact: string): object;
|
|
890
|
+
|
|
891
|
+
/**
|
|
892
|
+
* Decode a compact token WITHOUT verifying the signature.
|
|
893
|
+
* For logging/debugging only — use verifyEngagementToken for security checks.
|
|
894
|
+
*/
|
|
895
|
+
export declare function decodeTokenUnsafe(compact: string): object & { _verified: false };
|
|
896
|
+
|
|
897
|
+
// =============================================================================
|
|
898
|
+
// Structured Error Codes
|
|
899
|
+
// =============================================================================
|
|
900
|
+
|
|
901
|
+
export declare const PulseErrorCode: Readonly<{
|
|
902
|
+
// Structural
|
|
903
|
+
INVALID_PAYLOAD_STRUCTURE: 'INVALID_PAYLOAD_STRUCTURE';
|
|
904
|
+
PROTOTYPE_POLLUTION_ATTEMPT: 'PROTOTYPE_POLLUTION_ATTEMPT';
|
|
905
|
+
MISSING_REQUIRED_FIELD: 'MISSING_REQUIRED_FIELD';
|
|
906
|
+
INVALID_TYPE: 'INVALID_TYPE';
|
|
907
|
+
TIMESTAMP_OUT_OF_RANGE: 'TIMESTAMP_OUT_OF_RANGE';
|
|
908
|
+
UNSUPPORTED_PROOF_VERSION: 'UNSUPPORTED_PROOF_VERSION';
|
|
909
|
+
|
|
910
|
+
// Hash integrity
|
|
911
|
+
INVALID_HASH_FORMAT: 'INVALID_HASH_FORMAT';
|
|
912
|
+
HASH_MISMATCH_PAYLOAD_TAMPERED: 'HASH_MISMATCH_PAYLOAD_TAMPERED';
|
|
913
|
+
|
|
914
|
+
// Timestamp / freshness
|
|
915
|
+
PROOF_EXPIRED: 'PROOF_EXPIRED';
|
|
916
|
+
PROOF_FROM_FUTURE: 'PROOF_FROM_FUTURE';
|
|
917
|
+
NONCE_INVALID_OR_REPLAYED: 'NONCE_INVALID_OR_REPLAYED';
|
|
918
|
+
|
|
919
|
+
// Jitter / scoring
|
|
920
|
+
JITTER_SCORE_TOO_LOW: 'JITTER_SCORE_TOO_LOW';
|
|
921
|
+
DYNAMIC_THRESHOLD_NOT_MET: 'DYNAMIC_THRESHOLD_NOT_MET';
|
|
922
|
+
|
|
923
|
+
// Heuristic / coherence overrides
|
|
924
|
+
HEURISTIC_HARD_OVERRIDE: 'HEURISTIC_HARD_OVERRIDE';
|
|
925
|
+
COHERENCE_HARD_OVERRIDE: 'COHERENCE_HARD_OVERRIDE';
|
|
926
|
+
|
|
927
|
+
// Renderer
|
|
928
|
+
SOFTWARE_RENDERER_DETECTED: 'SOFTWARE_RENDERER_DETECTED';
|
|
929
|
+
BLOCKLISTED_RENDERER: 'BLOCKLISTED_RENDERER';
|
|
930
|
+
|
|
931
|
+
// Bio activity
|
|
932
|
+
NO_BIO_ACTIVITY_DETECTED: 'NO_BIO_ACTIVITY_DETECTED';
|
|
933
|
+
|
|
934
|
+
// Cross-signal forgery detection
|
|
935
|
+
FORGED_SIGNAL_CV_SCORE_IMPOSSIBLE: 'FORGED_SIGNAL:CV_SCORE_IMPOSSIBLE';
|
|
936
|
+
FORGED_SIGNAL_AUTOCORR_SCORE_IMPOSSIBLE: 'FORGED_SIGNAL:AUTOCORR_SCORE_IMPOSSIBLE';
|
|
937
|
+
FORGED_SIGNAL_QE_SCORE_IMPOSSIBLE: 'FORGED_SIGNAL:QE_SCORE_IMPOSSIBLE';
|
|
938
|
+
|
|
939
|
+
// Risk flags (informational)
|
|
940
|
+
NONCE_FRESHNESS_NOT_CHECKED: 'NONCE_FRESHNESS_NOT_CHECKED';
|
|
941
|
+
CANVAS_UNAVAILABLE: 'CANVAS_UNAVAILABLE';
|
|
942
|
+
ZERO_BIO_SAMPLES: 'ZERO_BIO_SAMPLES';
|
|
943
|
+
NEGATIVE_INTERFERENCE_COEFFICIENT: 'NEGATIVE_INTERFERENCE_COEFFICIENT';
|
|
944
|
+
INCONSISTENCY_LOW_CV_BUT_HIGH_SCORE: 'INCONSISTENCY:LOW_CV_BUT_HIGH_SCORE';
|
|
945
|
+
SUSPICIOUS_ZERO_TIMER_GRANULARITY: 'SUSPICIOUS_ZERO_TIMER_GRANULARITY';
|
|
946
|
+
INCONSISTENCY_FLAT_THERMAL_BUT_HIGH_SCORE: 'INCONSISTENCY:FLAT_THERMAL_BUT_HIGH_SCORE';
|
|
947
|
+
EXTREME_HURST: 'EXTREME_HURST';
|
|
948
|
+
AUDIO_JITTER_TOO_FLAT: 'AUDIO_JITTER_TOO_FLAT';
|
|
949
|
+
}>;
|