@svrnsec/pulse 0.5.0 → 0.7.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/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # @sovereign/pulse
1
+ # @svrnsec/pulse
2
2
 
3
3
  [![CI](https://github.com/ayronny14-alt/Svrn-Pulse-Security/actions/workflows/ci.yml/badge.svg)](https://github.com/ayronny14-alt/Svrn-Pulse-Security/actions/workflows/ci.yml)
4
4
  [![npm version](https://img.shields.io/npm/v/@svrnsec/pulse.svg?style=flat)](https://www.npmjs.com/package/@svrnsec/pulse)
@@ -43,8 +43,10 @@ function TrustGate() {
43
43
  // Node.js — raw proof commitment
44
44
  import { pulse } from '@svrnsec/pulse';
45
45
 
46
- const proof = await pulse({ nonce: crypto.randomUUID() });
47
- console.log(proof.score, proof.confidence); // 0.798, 'high'
46
+ const { payload, hash } = await pulse({ nonce: crypto.randomUUID() });
47
+ // payload.classification.jitterScore → 0.798 (real hw) | 0.45 (VM)
48
+ // payload.classification.flags → [] (clean) | ['CV_TOO_HIGH_...'] (VM)
49
+ // hash → SHA-256 commitment you send to your server for validation
48
50
  ```
49
51
 
50
52
  No API key. No account. No data leaves the client. Runs entirely in your infrastructure.
@@ -84,7 +86,7 @@ hotQE / coldQE ≥ 1.08 → thermal feedback confirmed (real silicon)
84
86
  hotQE / coldQE ≈ 1.00 → clock is insensitive to guest thermal state (VM)
85
87
  ```
86
88
 
87
- A KVM hypervisor maintains a synthetic clock that ticks at a constant rate regardless of what the guest OS is doing. Its entropy ratio across cold/load/hot phases is flat. On 192.222.57.254 it measured 1.01. On the local GTX 1650 Super machine it measured 1.24.
89
+ A KVM hypervisor maintains a synthetic clock that ticks at a constant rate regardless of what the guest OS is doing. Its entropy ratio across cold/load/hot phases is flat. On 192.222.57.254 — a 12 vCPU / 480GB RAM / GH200 Grace Hopper machine — it measured 1.01. On the local GTX 1650 Super machine it measured 1.24.
88
90
 
89
91
  A software implementation cannot fake this without generating actual heat.
90
92
 
@@ -98,7 +100,7 @@ If you measure H=0.5 but find high autocorrelation — or low H but low autocorr
98
100
 
99
101
  High coefficient of variation (timing spread) must come from a genuinely spread-out distribution, which means high quantization entropy. A VM that inflates CV by adding synthetic outliers at fixed offsets — say, every 50th iteration triggers a steal-time burst — produces high CV but low entropy because 93% of samples still fall in two bins.
100
102
 
101
- From 192.222.57.254: CV=0.0829 (seems variable) but QE=1.27 bits (extreme clustering). Incoherent. On real hardware, CV=0.1494 → QE=3.59 bits. Coherent.
103
+ From 192.222.57.254 (GH200): CV=0.0829 (seems variable) but QE=1.27 bits (extreme clustering). Incoherent. On real hardware, CV=0.1494 → QE=3.59 bits. Coherent.
102
104
 
103
105
  ### 4. The Picket Fence Detector
104
106
 
@@ -158,7 +160,7 @@ Normal bell curve, right-tailed from OS preemptions. Exactly what Brownian timin
158
160
 
159
161
  ---
160
162
 
161
- ### Remote VM — 192.222.57.254 — KVM · 2 vCPU · 2GB · Ubuntu 22.04
163
+ ### Remote VM — 192.222.57.254 — KVM · 12 vCPU · 480GB RAM · NVIDIA GH200 Grace Hopper · Ubuntu 22.04
162
164
 
163
165
  ```
164
166
  Pulse Score [██████████████████░░░░░░░░░░░░░░░░░░░░░░] 45.0%
@@ -213,7 +215,7 @@ Physical desktop ~120 ~2.1s 40%
213
215
  Ambiguous 200 ~3.5s —
214
216
  ```
215
217
 
216
- The 192.222.57.254 VM hit the exit condition at iteration 50. The signal was conclusive within the first batch.
218
+ The 192.222.57.254 GH200 VM hit the exit condition at iteration 50. 480GB of RAM and a Grace Hopper Superchip cannot change the fact that the hypervisor clock is mathematically perfect. The signal was conclusive within the first batch.
217
219
 
218
220
  ---
219
221
 
@@ -243,7 +245,7 @@ npm run build
243
245
  ### Client side
244
246
 
245
247
  ```js
246
- import { pulse } from '@sovereign/pulse';
248
+ import { pulse } from '@svrnsec/pulse';
247
249
 
248
250
  // Get a nonce from your server (prevents replay attacks)
249
251
  const { nonce } = await fetch('/api/pulse/challenge').then(r => r.json());
@@ -271,7 +273,7 @@ const result = await fetch('/api/pulse/verify', {
271
273
  ### High-level `Fingerprint` class
272
274
 
273
275
  ```js
274
- import { Fingerprint } from '@sovereign/pulse';
276
+ import { Fingerprint } from '@svrnsec/pulse';
275
277
 
276
278
  const fp = await Fingerprint.collect({ nonce });
277
279
 
@@ -296,7 +298,7 @@ fp.toCommitment() // { payload, hash } — send to server
296
298
  ### Server side
297
299
 
298
300
  ```js
299
- import { validateProof, generateNonce } from '@sovereign/pulse/validator';
301
+ import { validateProof, generateNonce } from '@svrnsec/pulse/validator';
300
302
 
301
303
  // Challenge endpoint — runs on your server, not ours
302
304
  app.get('/api/pulse/challenge', async (req, res) => {
@@ -319,7 +321,7 @@ app.post('/api/pulse/verify', async (req, res) => {
319
321
  ### Express middleware
320
322
 
321
323
  ```js
322
- import { createPulseMiddleware } from '@sovereign/pulse/middleware/express';
324
+ import { createPulseMiddleware } from '@svrnsec/pulse/middleware/express';
323
325
 
324
326
  const pulse = createPulseMiddleware({
325
327
  threshold: 0.6,
@@ -337,11 +339,11 @@ app.post('/checkout', pulse.verify, handler); // req.pulse injected
337
339
 
338
340
  ```js
339
341
  // app/api/pulse/challenge/route.js
340
- import { pulseChallenge } from '@sovereign/pulse/middleware/next';
342
+ import { pulseChallenge } from '@svrnsec/pulse/middleware/next';
341
343
  export const GET = pulseChallenge();
342
344
 
343
345
  // app/api/checkout/route.js
344
- import { withPulse } from '@sovereign/pulse/middleware/next';
346
+ import { withPulse } from '@svrnsec/pulse/middleware/next';
345
347
  export const POST = withPulse({ threshold: 0.6 })(async (req) => {
346
348
  const { score, provider } = req.pulse;
347
349
  return Response.json({ ok: true, score });
@@ -351,7 +353,7 @@ export const POST = withPulse({ threshold: 0.6 })(async (req) => {
351
353
  ### React hook
352
354
 
353
355
  ```jsx
354
- import { usePulse } from '@sovereign/pulse/react';
356
+ import { usePulse } from '@svrnsec/pulse/react';
355
357
 
356
358
  function Checkout() {
357
359
  const { run, stage, pct, vmConf, hwConf, result, isReady } = usePulse({
@@ -374,12 +376,12 @@ function Checkout() {
374
376
  Full declarations shipped in `index.d.ts`. Every interface, every callback, every return type:
375
377
 
376
378
  ```ts
377
- import { pulse, Fingerprint } from '@sovereign/pulse';
379
+ import { pulse, Fingerprint } from '@svrnsec/pulse';
378
380
  import type {
379
381
  PulseOptions, PulseCommitment,
380
382
  ProgressMeta, PulseStage,
381
383
  ValidationResult, FingerprintReport,
382
- } from '@sovereign/pulse';
384
+ } from '@svrnsec/pulse';
383
385
 
384
386
  const fp = await Fingerprint.collect({ nonce });
385
387
  // fp is fully typed — all properties, methods, and nested objects
@@ -443,7 +445,7 @@ If the heuristic engine says "this is a VM," the registry says "specifically, th
443
445
  You can extend the registry with a signature collected from any new environment:
444
446
 
445
447
  ```js
446
- import { serializeSignature, KNOWN_PROFILES } from '@sovereign/pulse/registry';
448
+ import { serializeSignature, KNOWN_PROFILES } from '@svrnsec/pulse/registry';
447
449
 
448
450
  // After collecting a Fingerprint on the target machine:
449
451
  const sig = serializeSignature(fp, { name: 'AWS r7g.xlarge (Graviton3)', date: '2025-01' });
@@ -455,6 +457,182 @@ The detection engine doesn't need updates when new hardware ships. The registry
455
457
 
456
458
  ---
457
459
 
460
+ ---
461
+
462
+ ## TrustScore — Unified 0–100 Human Score
463
+
464
+ The TrustScore engine converts all physical signals into a single integer that security teams can threshold, dashboard, and alert on.
465
+
466
+ ```js
467
+ import { computeTrustScore, formatTrustScore } from '@svrnsec/pulse/trust';
468
+
469
+ const ts = computeTrustScore(payload, { enf, gpu, dram, llm, idle });
470
+ // → { score: 87, grade: 'B', label: 'Verified', hardCap: null, breakdown: {...} }
471
+
472
+ console.log(formatTrustScore(ts));
473
+ // → "TrustScore 87/100 B · Verified [physics:91% enf:80% gpu:100% dram:87% bio:70%]"
474
+ ```
475
+
476
+ **Signal weights:** Physics layer 40pts · ENF 20pts · GPU 15pts · DRAM 15pts · Bio/LLM 10pts
477
+
478
+ **Hard floors** that bonus points cannot override:
479
+
480
+ | Condition | Cap | Why |
481
+ |---|---|---|
482
+ | EJR forgery detected | 20 | Physics law violated |
483
+ | Software GPU renderer | 45 | Likely VM/container |
484
+ | LLM agent conf > 0.85 | 30 | AI-driven session |
485
+ | No bio + no ENF | 55 | Cannot confirm human on real device |
486
+
487
+ ---
488
+
489
+ ## Proof-of-Idle — Defeating Click Farms at the Physics Layer
490
+
491
+ Click farms run 1,000 real phones at sustained maximum throughput. Browser fingerprinting cannot catch them — they ARE real devices.
492
+
493
+ The physics: a real device between interactions cools via Newton's Law of Cooling — a smooth exponential variance decay. A farm script pausing to fake idle drops CPU load from 100% to 0% instantly, producing a step function in the timing variance. You cannot fake a cooling curve faster than real time.
494
+
495
+ ```js
496
+ import { createIdleMonitor } from '@svrnsec/pulse/idle';
497
+
498
+ // Browser — hooks visibilitychange and blur/focus automatically
499
+ const monitor = createIdleMonitor();
500
+ monitor.start();
501
+
502
+ // When user triggers an engagement action:
503
+ const idleProof = monitor.getProof(); // null if device never genuinely rested
504
+
505
+ // Node.js / React Native — manual control
506
+ monitor.declareIdle();
507
+ monitor.declareActive();
508
+ ```
509
+
510
+ **Thermal transition taxonomy:**
511
+
512
+ | Label | Meaning | Farm? |
513
+ |---|---|---|
514
+ | `hot_to_cold` | Smooth exponential variance decay | No — genuine cooling |
515
+ | `cold` | Device already at rest temperature | No — genuine idle |
516
+ | `cooling` | Mild ongoing decay | No |
517
+ | `step_function` | >75% variance drop in first interval | Yes — script paused |
518
+ | `sustained_hot` | No cooling at all during idle period | Yes — constant load |
519
+
520
+ **TrustScore impact:** `hot_to_cold` → +8pts bonus. `step_function` → hard cap 65. `sustained_hot` → hard cap 60.
521
+
522
+ The hash chain (`SHA-256(prevHash ‖ ts ‖ meanMs ‖ variance)`) proves samples were taken in sequence at real intervals. N nodes at 30-second spacing = (N−1)×30s minimum elapsed time — cannot be back-filled faster than real time.
523
+
524
+ ---
525
+
526
+ ## Population Entropy — Sybil Detection at Cohort Level
527
+
528
+ One fake account is hard to detect. A warehouse of 1,000 phones running the same script is statistically impossible to hide.
529
+
530
+ ```js
531
+ import { analysePopulation } from '@svrnsec/pulse/population';
532
+
533
+ const verdict = analysePopulation(tokenCohort);
534
+ // → { authentic: false, sybilScore: 84, flags: ['TIMESTAMP_RHYTHM', 'THERMAL_HOMOGENEOUS'], ... }
535
+ ```
536
+
537
+ Five independent statistical tests on a cohort of engagement tokens:
538
+
539
+ | Test | What it catches | Farm signal |
540
+ |---|---|---|
541
+ | Timestamp rhythm | Lag-1/lag-2 autocorrelation of arrival times | Farms dispatch in clock-timed batches |
542
+ | Entropy dispersion | CV of physics scores across cohort | Cloned VMs are too similar (CV < 0.04) |
543
+ | Thermal diversity | Shannon entropy of transition labels | 1,000 phones → same thermal state |
544
+ | Idle plausibility | Clustering of idle durations | Scripts always pause for the same duration |
545
+ | ENF phase coherence | Variance of grid frequency deviations | Co-located devices share the same circuit |
546
+
547
+ `sybilScore < 40 = authentic cohort`. Coordinated farms score 80+.
548
+
549
+ ---
550
+
551
+ ## Engagement Tokens — 30-Second Physics-Backed Proof
552
+
553
+ A short-lived cryptographic token that proves a specific engagement event originated from a real human on real hardware that had genuinely rested between interactions.
554
+
555
+ ```js
556
+ import { createEngagementToken, verifyEngagementToken } from '@svrnsec/pulse/engage';
557
+
558
+ // Client — after the interaction
559
+ const { compact } = createEngagementToken({
560
+ pulseResult,
561
+ idleProof: monitor.getProof(),
562
+ interaction: { type: 'click', ts: Date.now(), motorConsistency: 0.82 },
563
+ secret: process.env.PULSE_SECRET,
564
+ });
565
+ // Attach to API call: X-Pulse-Token: <compact>
566
+
567
+ // Server — before crediting any engagement metric
568
+ const result = await verifyEngagementToken(compact, process.env.PULSE_SECRET, {
569
+ checkNonce: (n) => redis.del(`pulse:nonce:${n}`).then(d => d === 1),
570
+ });
571
+ // result.valid, result.riskSignals, result.idleWarnings
572
+ ```
573
+
574
+ **What the token proves:**
575
+
576
+ 1. Real hardware — DRAM refresh present, ENF grid signal detected
577
+ 2. Genuine idle — Hash-chained thermal measurements spanning ≥ 45s
578
+ 3. Physical cooling — Variance decay was smooth, not a step function
579
+ 4. Fresh interaction — 30-second TTL eliminates token brokers
580
+ 5. Tamper-evident — HMAC-SHA256 over all fraud-relevant fields
581
+
582
+ HMAC signs: `v|n|iat|exp|idle.chain|idle.dMs|hw.ent|evt.t|evt.ts`
583
+
584
+ Advisory fields (thermal label, cooling monotonicity) are in the token body for risk scoring but deliberately excluded from the HMAC — changing them can't gain access credit without breaking the signature.
585
+
586
+ ---
587
+
588
+ ## Authenticity Audit — The $44 Billion Question
589
+
590
+ Elon paid $44 billion arguing about what percentage of Twitter's users were real humans. Nobody had a physics-layer tool to measure it. This is that tool.
591
+
592
+ ```js
593
+ import { authenticityAudit } from '@svrnsec/pulse/audit';
594
+
595
+ const report = authenticityAudit(tokenCohort, { confidenceLevel: 0.95 });
596
+ ```
597
+
598
+ ```js
599
+ {
600
+ cohortSize: 10000,
601
+ estimatedHumanPct: 73.4,
602
+ confidenceInterval: [69.1, 77.8], // 95% bootstrap CI
603
+ grade: 'HIGH_FRAUD',
604
+ botClusterCount: 5,
605
+ botClusters: [
606
+ {
607
+ id: 'farm_a3f20c81',
608
+ size: 847,
609
+ sybilScore: 94,
610
+ signature: {
611
+ enfRegion: 'americas',
612
+ dramVerdict: 'dram',
613
+ thermalLabel: 'sustained_hot',
614
+ meanEnfDev: 0.0231, // Hz — localizes to substation/building
615
+ meanIdleMs: 57200, // script sleeps for exactly 57s
616
+ },
617
+ topSignals: ['timestamp_rhythm', 'thermal_diversity'],
618
+ },
619
+ ],
620
+ recommendation: 'CRITICAL: 5 bot farm clusters account for a majority of traffic...',
621
+ }
622
+ ```
623
+
624
+ **Method:** Tokens are clustered by hardware signature (ENF deviation bucket × DRAM verdict × thermal label × 10-minute time bucket). Organic users scatter across all dimensions. A farm in one building, running the same script, on the same hardware generation collapses into one tight cluster. Each cluster is scored with Population Entropy. A non-parametric bootstrap produces the confidence interval.
625
+
626
+ **Typical values:**
627
+
628
+ | Scenario | estimatedHumanPct |
629
+ |---|---|
630
+ | Organic product feed | 92–97% |
631
+ | Incentivised engagement campaign | 55–75% |
632
+ | Coordinated click farm attack | 8–35% |
633
+
634
+ ---
635
+
458
636
  ## Tests
459
637
 
460
638
  ```bash
@@ -462,53 +640,19 @@ npm test
462
640
  ```
463
641
 
464
642
  ```
465
- computeStats ✓ basic statistics are correct
466
- constant array has zero CV
467
- computeHurst ✓ returns value in [0,1]
468
- constant series returns ~0.5 (fallback)
469
- detectQuantizationEntropy real hardware samples have high entropy
470
- quantized (VM) samples have low entropy
471
- detectThermalSignature ✓ detects rising pattern
472
- detects flat pattern
473
- classifyJitter ✓ real hardware scores higher than VM
474
- ✓ score is in [0,1]
475
- VM samples are flagged
476
- insufficient data returns zero score with flag
477
- runHeuristicEngine ✓ EJR < 1.02 triggers penalty
478
- ✓ EJR ≥ 1.08 triggers bonus
479
- ✓ Hurst-autocorr incoherence penalised
480
- ✓ picket fence detector triggers on periodic AC
481
- ✓ skewness-kurtosis bonus on right-skewed leptokurtic
482
- ✓ clean metrics produce no flags
483
- detectProvider ✓ KVM profile matched from autocorr signature
484
- ✓ physical profile matched from analog-fog metrics
485
- ✓ scheduler quantum estimated from lag-25 AC
486
- ✓ Nitro identified from near-flat AC profile
487
- ✓ alternatives list populated
488
- buildCommitment ✓ produces deterministic hash
489
- ✓ any field change breaks the hash
490
- canonicalJson ✓ sorts keys deterministically
491
- validateProof ✓ valid proof passes
492
- ✓ tampered payload is rejected
493
- ✓ low jitter score is rejected
494
- ✓ software renderer is blocked
495
- ✓ expired proof is rejected
496
- ✓ nonce check is called
497
- ✓ rejected nonce fails proof
498
- generateNonce ✓ produces 64-char hex strings
499
- ✓ each call is unique
500
- serializeSignature ✓ produces deterministic sig_ ID
501
- ✓ buckets continuous metrics for privacy
502
- ✓ isSynthetic flag preserved
503
- matchRegistry ✓ exact match returns similarity 1.0
504
- ✓ different class returns low similarity
505
- ✓ alternatives sorted by similarity
506
- compareSignatures ✓ same class returns sameClass=true
507
- ✓ physical vs VM returns sameClass=false
508
-
509
- Test Suites: 1 passed
510
- Tests: 43 passed, 0 failed
511
- Time: 0.327s
643
+ integration.test.js 43 tests — core engine, provider classifier, commitment, registry
644
+ stress.test.js 92 tests — adversarial: KVM, VMware, Docker, LLM agents,
645
+ Gaussian noise injection, synthetic thermal drift,
646
+ score separation (real min vs VM max)
647
+ engagement.test.js 45 tests IdleAttestation state machine, thermal classification,
648
+ Population Entropy (all 5 tests), Engagement Token
649
+ creation/verification/replay/tamper, risk signals
650
+ audit.test.js 18 tests — Authenticity Audit: organic vs farm cohorts, CI
651
+ properties, multi-farm fingerprinting, grade thresholds
652
+
653
+ Test Suites: 4 passed
654
+ Tests: 158 passed, 0 failed
655
+ Time: ~1.0s
512
656
  ```
513
657
 
514
658
  ---
@@ -536,30 +680,46 @@ sovereign-pulse/
536
680
  │ │ ├── entropy.js WASM bridge + phased/adaptive routing
537
681
  │ │ ├── adaptive.js Adaptive early-exit engine
538
682
  │ │ ├── bio.js Mouse/keyboard interference coefficient
539
- │ │ └── canvas.js WebGL/2D canvas fingerprint
683
+ │ │ ├── canvas.js WebGL/2D canvas fingerprint
684
+ │ │ ├── gpu.js WebGPU thermal growth probe
685
+ │ │ ├── dram.js DRAM refresh cycle detector
686
+ │ │ ├── enf.js Electrical Network Frequency probe
687
+ │ │ ├── sabTimer.js Sub-millisecond SAB timer
688
+ │ │ └── idleAttestation.js Proof-of-Idle — thermal hash chain (v0.5.0)
540
689
  │ ├── analysis/
541
- │ │ ├── jitter.js Statistical classifier (6 components)
542
- │ │ ├── heuristic.js Cross-metric physics coherence engine
543
- │ │ ├── provider.js Hypervisor/cloud provider classifier
544
- │ │ └── audio.js AudioContext callback jitter
690
+ │ │ ├── jitter.js Statistical classifier (6 components)
691
+ │ │ ├── heuristic.js Cross-metric physics coherence engine
692
+ │ │ ├── provider.js Hypervisor/cloud provider classifier
693
+ │ │ ├── audio.js AudioContext callback jitter
694
+ │ │ ├── llm.js LLM agent behavioural detector
695
+ │ │ ├── trustScore.js Unified 0–100 TrustScore engine (v0.4.0)
696
+ │ │ ├── populationEntropy.js Sybil detection — 5 cohort-level tests (v0.5.0)
697
+ │ │ └── authenticityAudit.js $44B question — humanPct + CI (v0.6.0)
545
698
  │ ├── middleware/
546
- │ │ ├── express.js Express/Fastify/Hono drop-in
547
- │ │ └── next.js Next.js App Router HOC
699
+ │ │ ├── express.js Express/Fastify/Hono drop-in
700
+ │ │ └── next.js Next.js App Router HOC
548
701
  │ ├── integrations/
549
- │ │ └── react.js usePulse() hook
702
+ │ │ ├── react.js usePulse() hook
703
+ │ │ └── react-native.js Expo accelerometer + thermal bridge
550
704
  │ ├── proof/
551
- │ │ ├── fingerprint.js BLAKE3 commitment builder
552
- │ │ └── validator.js Server-side proof verifier
705
+ │ │ ├── fingerprint.js BLAKE3 commitment builder
706
+ │ │ ├── validator.js Server-side proof verifier
707
+ │ │ ├── challenge.js HMAC challenge/response
708
+ │ │ └── engagementToken.js 30s physics-backed engagement token (v0.5.0)
553
709
  │ └── registry/
554
- │ └── serializer.js Provider signature serializer + matcher
555
- ├── crates/pulse-core/ Rust/WASM entropy probe
556
- ├── index.d.ts Full TypeScript declarations
710
+ │ └── serializer.js Provider signature serializer + matcher
711
+ ├── crates/pulse-core/ Rust/WASM entropy probe
712
+ ├── index.d.ts Full TypeScript declarations
557
713
  ├── demo/
558
- │ ├── web/index.html Standalone browser demo
559
- │ ├── node-demo.js CLI demo (no WASM required)
560
- │ ├── benchmark.js Generates numbers in this README
561
- │ └── perf.js Pipeline overhead benchmarks
562
- └── test/integration.test.js 43 tests
714
+ │ ├── web/index.html Standalone browser demo
715
+ │ ├── node-demo.js CLI demo (no WASM required)
716
+ │ ├── benchmark.js Generates numbers in this README
717
+ │ └── perf.js Pipeline overhead benchmarks
718
+ └── test/
719
+ ├── integration.test.js 43 tests — core engine
720
+ ├── stress.test.js 92 tests — adversarial attack suite
721
+ ├── engagement.test.js 45 tests — idle / population / tokens
722
+ └── audit.test.js 18 tests — authenticity audit
563
723
  ```
564
724
 
565
725
  ---
package/SECURITY.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  ## Overview
4
4
 
5
- `@sovereign/pulse` is a hardware-physics fingerprinting library used as a security layer.
5
+ `@svrnsec/pulse` is a hardware-physics fingerprinting library used as a security layer.
6
6
  We take vulnerabilities seriously and will respond promptly.
7
7
 
8
8
  ## Supported Versions
package/dist/pulse.cjs.js CHANGED
@@ -5,7 +5,7 @@ var node_crypto = require('node:crypto');
5
5
 
6
6
  var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
7
7
  /**
8
- * @sovereign/pulse — Statistical Jitter Analysis
8
+ * @svrnsec/pulse — Statistical Jitter Analysis
9
9
  *
10
10
  * Analyses the timing distribution from the entropy probe to classify
11
11
  * the host as a real consumer device or a sanitised datacenter VM.
@@ -461,7 +461,7 @@ var jitter = /*#__PURE__*/Object.freeze({
461
461
  });
462
462
 
463
463
  /**
464
- * @sovereign/pulse — Adaptive Entropy Probe
464
+ * @svrnsec/pulse — Adaptive Entropy Probe
465
465
  *
466
466
  * Runs the WASM probe in batches and stops early once the signal is decisive.
467
467
  *
@@ -661,7 +661,7 @@ async function collectEntropyAdaptive(wasmModule, opts = {}) {
661
661
  */
662
662
 
663
663
  /**
664
- * @sovereign/pulse — Entropy Collector
664
+ * @svrnsec/pulse — Entropy Collector
665
665
  *
666
666
  * Bridges the Rust/WASM matrix-multiply probe into JavaScript.
667
667
  * The WASM module is lazily initialised once and cached for subsequent calls.
@@ -856,7 +856,7 @@ function _mean$4(arr) {
856
856
  */
857
857
 
858
858
  /**
859
- * @sovereign/pulse — Bio-Binding Layer
859
+ * @svrnsec/pulse — Bio-Binding Layer
860
860
  *
861
861
  * Captures mouse-movement micro-stutters and keystroke-cadence dynamics
862
862
  * WHILE the hardware entropy probe is running. Computes the
@@ -1694,7 +1694,7 @@ class BLAKE3 extends BLAKE2 {
1694
1694
  const blake3 = /* @__PURE__ */ createXOFer((opts) => new BLAKE3(opts));
1695
1695
 
1696
1696
  /**
1697
- * @sovereign/pulse — Hardware Fingerprint & Proof Builder
1697
+ * @svrnsec/pulse — Hardware Fingerprint & Proof Builder
1698
1698
  *
1699
1699
  * Assembles all collected signals into a canonical ProofPayload, then
1700
1700
  * produces a BLAKE3 commitment: BLAKE3(canonicalJSON(payload)).
@@ -1961,7 +1961,7 @@ function _round$1(v, decimals) {
1961
1961
  }
1962
1962
 
1963
1963
  /**
1964
- * @sovereign/pulse — GPU Canvas Fingerprint
1964
+ * @svrnsec/pulse — GPU Canvas Fingerprint
1965
1965
  *
1966
1966
  * Collects device-class signals from WebGL and 2D Canvas rendering.
1967
1967
  * The exact pixel values of GPU-rendered scenes are vendor/driver-specific
@@ -2200,7 +2200,7 @@ function _compileShader(gl, type, source) {
2200
2200
  }
2201
2201
 
2202
2202
  /**
2203
- * @sovereign/pulse — AudioContext Oscillator Jitter
2203
+ * @svrnsec/pulse — AudioContext Oscillator Jitter
2204
2204
  *
2205
2205
  * Measures the scheduling jitter of the browser's audio pipeline.
2206
2206
  * Real audio hardware callbacks are driven by a hardware interrupt (IRQ)
@@ -2414,7 +2414,7 @@ function _percentile(arr, p) {
2414
2414
  }
2415
2415
 
2416
2416
  /**
2417
- * @sovereign/pulse — WebGPU Thermal Variance Probe
2417
+ * @svrnsec/pulse — WebGPU Thermal Variance Probe
2418
2418
  *
2419
2419
  * Runs a compute shader on the GPU and measures dispatch timing variance.
2420
2420
  *
@@ -2660,7 +2660,7 @@ function _timeout(ms, msg) {
2660
2660
  */
2661
2661
 
2662
2662
  /**
2663
- * @sovereign/pulse — DRAM Refresh Cycle Detector
2663
+ * @svrnsec/pulse — DRAM Refresh Cycle Detector
2664
2664
  *
2665
2665
  * DDR4 DRAM refreshes every 7.8 ms (tREFI per JEDEC JESD79-4). During a
2666
2666
  * refresh, the memory controller stalls all access requests for ~350 ns.
@@ -2864,7 +2864,7 @@ function _autocorr(data, maxLag) {
2864
2864
  }
2865
2865
 
2866
2866
  /**
2867
- * @sovereign/pulse — SharedArrayBuffer Microsecond Timer
2867
+ * @svrnsec/pulse — SharedArrayBuffer Microsecond Timer
2868
2868
  *
2869
2869
  * Bypasses browser timer clamping (Brave 100µs cap, Firefox 20µs cap, Safari
2870
2870
  * 1ms cap) using Atomics.wait() which is exempt from clamping because it maps
@@ -2903,7 +2903,7 @@ function isSabAvailable() {
2903
2903
  typeof SharedArrayBuffer !== 'undefined' &&
2904
2904
  typeof Atomics !== 'undefined' &&
2905
2905
  typeof Atomics.wait === 'function' &&
2906
- crossOriginIsolated === true // window flag set by COOP+COEP headers
2906
+ typeof crossOriginIsolated !== 'undefined' && crossOriginIsolated === true // COOP+COEP headers
2907
2907
  );
2908
2908
  }
2909
2909
 
@@ -3056,7 +3056,7 @@ function _getAtomicsTs() {
3056
3056
  }
3057
3057
 
3058
3058
  /**
3059
- * @sovereign/pulse — Electrical Network Frequency (ENF) Detection
3059
+ * @svrnsec/pulse — Electrical Network Frequency (ENF) Detection
3060
3060
  *
3061
3061
  * ┌─────────────────────────────────────────────────────────────────────────┐
3062
3062
  * │ WHAT THIS IS │
@@ -3367,7 +3367,7 @@ function _noEnf(reason) {
3367
3367
  */
3368
3368
 
3369
3369
  /**
3370
- * @sovereign/pulse — LLM / AI Agent Behavioral Fingerprint
3370
+ * @svrnsec/pulse — LLM / AI Agent Behavioral Fingerprint
3371
3371
  *
3372
3372
  * Detects automation driven by large language models, headless browsers
3373
3373
  * controlled by AI agents (AutoGPT, CrewAI, browser-use, Playwright+LLM,
@@ -3995,7 +3995,7 @@ function _stripAnsi(s) {
3995
3995
  }
3996
3996
 
3997
3997
  /**
3998
- * @sovereign/pulse — Cross-Metric Heuristic Engine
3998
+ * @svrnsec/pulse — Cross-Metric Heuristic Engine
3999
3999
  *
4000
4000
  * Instead of checking individual thresholds in isolation, this module looks
4001
4001
  * at the *relationships* between metrics. A sophisticated adversary can spoof
@@ -4423,7 +4423,7 @@ function _empty$1() {
4423
4423
  }
4424
4424
 
4425
4425
  /**
4426
- * @sovereign/pulse — Zero-Latency Second-Stage Coherence Analysis
4426
+ * @svrnsec/pulse — Zero-Latency Second-Stage Coherence Analysis
4427
4427
  *
4428
4428
  * Runs entirely on data already collected by the entropy probe, bio
4429
4429
  * collector, canvas fingerprinter, and audio analyser.
@@ -4926,7 +4926,7 @@ function _empty(threshold) {
4926
4926
  */
4927
4927
 
4928
4928
  /**
4929
- * @sovereign/pulse — Hypervisor & Cloud Provider Fingerprinter
4929
+ * @svrnsec/pulse — Hypervisor & Cloud Provider Fingerprinter
4930
4930
  *
4931
4931
  * Each hypervisor has a distinct "steal-time rhythm" — a characteristic
4932
4932
  * pattern in how it schedules guest vCPUs on host physical cores.
@@ -5175,7 +5175,7 @@ function _estimateQuantum({ lag1, lag25, lag50, qe }) {
5175
5175
  }
5176
5176
 
5177
5177
  /**
5178
- * @sovereign/pulse — High-Level Fingerprint Class
5178
+ * @svrnsec/pulse — High-Level Fingerprint Class
5179
5179
  *
5180
5180
  * The developer-facing API. Instead of forcing devs to understand Hurst
5181
5181
  * Exponents and Quantization Entropy, they get a Fingerprint object with
@@ -5183,7 +5183,7 @@ function _estimateQuantum({ lag1, lag25, lag50, qe }) {
5183
5183
  *
5184
5184
  * Usage:
5185
5185
  *
5186
- * import { Fingerprint } from '@sovereign/pulse';
5186
+ * import { Fingerprint } from '@svrnsec/pulse';
5187
5187
  *
5188
5188
  * const fp = await Fingerprint.collect({ nonce });
5189
5189
  *
@@ -5642,7 +5642,7 @@ function _round(v, d) {
5642
5642
  }
5643
5643
 
5644
5644
  /**
5645
- * @sovereign/pulse — Server-Side Validator
5645
+ * @svrnsec/pulse — Server-Side Validator
5646
5646
  *
5647
5647
  * Verifies a ProofPayload + BLAKE3 commitment received from the client.
5648
5648
  * This module is for NODE.JS / SERVER use only. It should NOT be bundled
@@ -6356,14 +6356,14 @@ function renderInlineUpdateHint(latest) {
6356
6356
  }
6357
6357
 
6358
6358
  /**
6359
- * @sovereign/pulse
6359
+ * @svrnsec/pulse
6360
6360
  *
6361
6361
  * Physical Turing Test — distinguishes a real consumer device with a human
6362
6362
  * operator from a sanitised Datacenter VM / AI Instance.
6363
6363
  *
6364
6364
  * Usage (client-side):
6365
6365
  *
6366
- * import { pulse } from '@sovereign/pulse';
6366
+ * import { pulse } from '@svrnsec/pulse';
6367
6367
  *
6368
6368
  * // 1. Get a server-issued nonce (prevents replay attacks)
6369
6369
  * const { nonce } = await fetch('/api/pulse-challenge').then(r => r.json());
@@ -6379,7 +6379,7 @@ function renderInlineUpdateHint(latest) {
6379
6379
  *
6380
6380
  * Usage (server-side):
6381
6381
  *
6382
- * import { validateProof, generateNonce } from '@sovereign/pulse/validator';
6382
+ * import { validateProof, generateNonce } from '@svrnsec/pulse/validator';
6383
6383
  *
6384
6384
  * // Challenge endpoint
6385
6385
  * app.get('/api/pulse-challenge', (req, res) => {
@@ -6476,7 +6476,7 @@ async function _pulseHosted(opts) {
6476
6476
  // ---------------------------------------------------------------------------
6477
6477
 
6478
6478
  /**
6479
- * Run the full @sovereign/pulse probe and return a signed commitment.
6479
+ * Run the full @svrnsec/pulse probe and return a signed commitment.
6480
6480
  *
6481
6481
  * Two modes:
6482
6482
  * - pulse({ nonce }) — self-hosted (you manage the nonce server)
@@ -6495,7 +6495,7 @@ async function pulse(opts = {}) {
6495
6495
  const { nonce } = opts;
6496
6496
  if (!nonce || typeof nonce !== 'string') {
6497
6497
  throw new Error(
6498
- '@sovereign/pulse: opts.nonce is required (self-hosted), or pass opts.apiKey for zero-config hosted mode.'
6498
+ '@svrnsec/pulse: opts.nonce is required (self-hosted), or pass opts.apiKey for zero-config hosted mode.'
6499
6499
  );
6500
6500
  }
6501
6501
 
@@ -6574,7 +6574,7 @@ async function _runProbe(opts) {
6574
6574
  const [enfResult, gpuResult, dramResult, llmResult] = await Promise.all([
6575
6575
  collectEnfTimings().catch(() => null),
6576
6576
  collectGpuEntropy().catch(() => null),
6577
- collectDramTimings().catch(() => null),
6577
+ Promise.resolve(collectDramTimings()).catch(() => null),
6578
6578
  Promise.resolve(detectLlmAgent(bioSnapshot)).catch(() => null),
6579
6579
  ]);
6580
6580