@svrnsec/pulse 0.3.0 → 0.3.1
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/dist/pulse.cjs.js +2137 -205
- package/dist/pulse.cjs.js.map +1 -1
- package/dist/pulse.esm.js +2129 -206
- package/dist/pulse.esm.js.map +1 -1
- package/index.d.ts +128 -0
- package/package.json +1 -1
- package/src/proof/fingerprint.js +61 -5
package/index.d.ts
CHANGED
|
@@ -586,3 +586,131 @@ export interface SignatureComparison {
|
|
|
586
586
|
profileMatch: boolean;
|
|
587
587
|
providerMatch: boolean;
|
|
588
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
|
+
}
|
package/package.json
CHANGED
package/src/proof/fingerprint.js
CHANGED
|
@@ -54,9 +54,9 @@ export function blake3HexStr(str) {
|
|
|
54
54
|
* @param {string} p.nonce – server-issued challenge nonce (hex)
|
|
55
55
|
* @returns {ProofPayload}
|
|
56
56
|
*/
|
|
57
|
-
export function buildProof({ entropy, jitter, bio, canvas, audio, nonce }) {
|
|
57
|
+
export function buildProof({ entropy, jitter, bio, canvas, audio, enf, gpu, dram, llm, nonce }) {
|
|
58
58
|
if (!nonce || typeof nonce !== 'string') {
|
|
59
|
-
throw new Error('@
|
|
59
|
+
throw new Error('@svrnsec/pulse: nonce is required for anti-replay protection');
|
|
60
60
|
}
|
|
61
61
|
|
|
62
62
|
// Hash the raw timing arrays IN-BROWSER so we can prove their integrity
|
|
@@ -138,12 +138,68 @@ export function buildProof({ entropy, jitter, bio, canvas, audio, nonce }) {
|
|
|
138
138
|
jitterMeanMs: _round(audio.jitterMeanMs, 4),
|
|
139
139
|
jitterP95Ms: _round(audio.jitterP95Ms, 4),
|
|
140
140
|
},
|
|
141
|
+
|
|
142
|
+
// ── Electrical Network Frequency ─────────────────────────────────────
|
|
143
|
+
enf: enf ? {
|
|
144
|
+
available: enf.enfAvailable,
|
|
145
|
+
ripplePresent: enf.ripplePresent,
|
|
146
|
+
gridFrequency: enf.gridFrequency,
|
|
147
|
+
gridRegion: enf.gridRegion,
|
|
148
|
+
ripplePower: _round(enf.ripplePower, 4),
|
|
149
|
+
enfDeviation: _round(enf.enfDeviation, 3),
|
|
150
|
+
snr50hz: _round(enf.snr50hz, 2),
|
|
151
|
+
snr60hz: _round(enf.snr60hz, 2),
|
|
152
|
+
sampleRateHz: _round(enf.sampleRateHz, 1),
|
|
153
|
+
verdict: enf.verdict,
|
|
154
|
+
isVmIndicator: enf.isVmIndicator,
|
|
155
|
+
capturedAt: enf.temporalAnchor?.capturedAt ?? null,
|
|
156
|
+
} : null,
|
|
157
|
+
|
|
158
|
+
// ── WebGPU thermal variance ───────────────────────────────────────────
|
|
159
|
+
gpu: gpu ? {
|
|
160
|
+
available: gpu.gpuPresent,
|
|
161
|
+
isSoftware: gpu.isSoftware,
|
|
162
|
+
vendorString: gpu.vendorString,
|
|
163
|
+
dispatchCV: _round(gpu.dispatchCV, 4),
|
|
164
|
+
thermalGrowth: _round(gpu.thermalGrowth, 4),
|
|
165
|
+
verdict: gpu.verdict,
|
|
166
|
+
} : null,
|
|
167
|
+
|
|
168
|
+
// ── DRAM refresh cycle ────────────────────────────────────────────────
|
|
169
|
+
dram: dram ? {
|
|
170
|
+
refreshPresent: dram.refreshPresent,
|
|
171
|
+
refreshPeriodMs: _round(dram.refreshPeriodMs, 2),
|
|
172
|
+
peakPower: _round(dram.peakPower, 4),
|
|
173
|
+
verdict: dram.verdict,
|
|
174
|
+
} : null,
|
|
175
|
+
|
|
176
|
+
// ── LLM / AI agent behavioral fingerprint ────────────────────────────
|
|
177
|
+
llm: llm ? {
|
|
178
|
+
aiConf: _round(llm.aiConf, 3),
|
|
179
|
+
thinkTimePattern: llm.thinkTimePattern,
|
|
180
|
+
correctionRate: _round(llm.correctionRate, 3),
|
|
181
|
+
rhythmicity: _round(llm.rhythmicity, 3),
|
|
182
|
+
pauseDistribution: llm.pauseDistribution,
|
|
183
|
+
verdict: llm.verdict,
|
|
184
|
+
matchedModel: llm.matchedModel ?? null,
|
|
185
|
+
} : null,
|
|
141
186
|
},
|
|
142
187
|
|
|
143
|
-
// Top-level classification summary
|
|
188
|
+
// Top-level classification summary — all signal layers combined
|
|
144
189
|
classification: {
|
|
145
|
-
jitterScore:
|
|
146
|
-
flags:
|
|
190
|
+
jitterScore: _round(jitter.score, 4),
|
|
191
|
+
flags: jitter.flags ?? [],
|
|
192
|
+
enfVerdict: enf?.verdict ?? 'unavailable',
|
|
193
|
+
gpuVerdict: gpu?.verdict ?? 'unavailable',
|
|
194
|
+
dramVerdict: dram?.verdict ?? 'unavailable',
|
|
195
|
+
llmVerdict: llm?.verdict ?? 'unavailable',
|
|
196
|
+
// Combined VM confidence: any hard signal raises this
|
|
197
|
+
vmIndicators: [
|
|
198
|
+
enf?.isVmIndicator ? 'enf_no_grid' : null,
|
|
199
|
+
gpu?.isSoftware ? 'gpu_software' : null,
|
|
200
|
+
dram?.verdict === 'virtual' ? 'dram_no_refresh' : null,
|
|
201
|
+
llm?.aiConf > 0.7 ? 'llm_agent' : null,
|
|
202
|
+
].filter(Boolean),
|
|
147
203
|
},
|
|
148
204
|
};
|
|
149
205
|
|