@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.
Files changed (49) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +883 -782
  3. package/SECURITY.md +27 -22
  4. package/bin/svrnsec-pulse.js +7 -7
  5. package/dist/{pulse.cjs.js → pulse.cjs} +6428 -6413
  6. package/dist/pulse.cjs.map +1 -0
  7. package/dist/pulse.esm.js +6429 -6415
  8. package/dist/pulse.esm.js.map +1 -1
  9. package/index.d.ts +949 -846
  10. package/package.json +189 -184
  11. package/pkg/pulse_core.js +174 -173
  12. package/src/analysis/audio.js +213 -213
  13. package/src/analysis/authenticityAudit.js +408 -393
  14. package/src/analysis/coherence.js +502 -502
  15. package/src/analysis/coordinatedBehavior.js +825 -804
  16. package/src/analysis/heuristic.js +428 -428
  17. package/src/analysis/jitter.js +446 -446
  18. package/src/analysis/llm.js +473 -472
  19. package/src/analysis/populationEntropy.js +404 -403
  20. package/src/analysis/provider.js +248 -248
  21. package/src/analysis/refraction.js +392 -391
  22. package/src/analysis/trustScore.js +356 -356
  23. package/src/cli/args.js +36 -36
  24. package/src/cli/commands/scan.js +192 -192
  25. package/src/cli/runner.js +157 -157
  26. package/src/collector/adaptive.js +200 -200
  27. package/src/collector/bio.js +297 -287
  28. package/src/collector/canvas.js +247 -239
  29. package/src/collector/dram.js +203 -203
  30. package/src/collector/enf.js +311 -311
  31. package/src/collector/entropy.js +195 -195
  32. package/src/collector/gpu.js +248 -245
  33. package/src/collector/idleAttestation.js +480 -480
  34. package/src/collector/sabTimer.js +189 -191
  35. package/src/errors.js +54 -0
  36. package/src/fingerprint.js +475 -475
  37. package/src/index.js +345 -342
  38. package/src/integrations/react-native.js +462 -459
  39. package/src/integrations/react.js +184 -185
  40. package/src/middleware/express.js +155 -155
  41. package/src/middleware/next.js +174 -175
  42. package/src/proof/challenge.js +249 -249
  43. package/src/proof/engagementToken.js +426 -394
  44. package/src/proof/fingerprint.js +268 -268
  45. package/src/proof/validator.js +82 -142
  46. package/src/registry/serializer.js +349 -349
  47. package/src/terminal.js +263 -263
  48. package/src/update-notifier.js +259 -264
  49. 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 16-char hex hardware identifier.
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
+ }>;