@entros/pulse-sdk 1.2.0 → 1.4.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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/config.ts","../src/log.ts","../src/sensor/audio.ts","../src/sensor/encode.ts","../src/sensor/motion.ts","../src/sensor/touch.ts","../src/extraction/statistics.ts","../src/extraction/lpc.ts","../src/extraction/speaker.ts","../src/extraction/kinematic.ts","../src/hashing/simhash.ts","../src/hashing/poseidon.ts","../src/proof/serializer.ts","../src/proof/prover.ts","../src/submit/wallet.ts","../src/submit/relayer.ts","../src/identity/crypto.ts","../src/identity/anchor.ts","../src/pulse.ts","../src/attestation/sas.ts","../src/agent/anchor.ts","../src/challenge/phrase.ts","../src/challenge/lissajous.ts","../src/challenge/fetch.ts"],"sourcesContent":["// BN254 base field prime (for G1 point negation in proof_a)\nexport const BN254_BASE_FIELD = BigInt(\n \"21888242871839275222246405745257275088696311157297823662689037894645226208583\"\n);\n\n// BN254 scalar field prime (for salt generation, field element bounds)\nexport const BN254_SCALAR_FIELD = BigInt(\n \"21888242871839275222246405745257275088548364400416034343698204186575808495617\"\n);\n\nexport const FINGERPRINT_BITS = 256;\nexport const DEFAULT_THRESHOLD = 96;\nexport const DEFAULT_MIN_DISTANCE = 3;\nexport const NUM_PUBLIC_INPUTS = 4;\n\nexport const PROOF_A_SIZE = 64;\nexport const PROOF_B_SIZE = 128;\nexport const PROOF_C_SIZE = 64;\nexport const TOTAL_PROOF_SIZE = 256;\n\n// Frozen at the original v1 string for backward compatibility — every existing\n// user's baseline projects features into bit positions derived from this seed,\n// so changing it would invalidate every prior fingerprint and force a global\n// baseline reset. Kerckhoffs-compliant either way (the seed is public).\nexport const SIMHASH_SEED = \"IAM-PROTOCOL-SIMHASH-V1\";\n\n// Capture duration bounds (ms)\nexport const MIN_CAPTURE_MS = 2000;\nexport const MAX_CAPTURE_MS = 60000;\nexport const DEFAULT_CAPTURE_MS = 7000;\n\nexport const PROGRAM_IDS = {\n entrosAnchor: \"GZYwTp2ozeuRA5Gof9vs4ya961aANcJBdUzB7LN6q4b2\",\n entrosVerifier: \"4F97jNoxQzT2qRbkWpW3ztC3Nz2TtKj3rnKG8ExgnrfV\",\n entrosRegistry: \"6VBs3zr9KrfFPGd6j7aGBPQWwZa5tajVfA7HN6MMV9VW\",\n} as const;\n\nexport const AGENT_REGISTRY_CONFIG = {\n programIdDevnet: \"8oo4J9tBB3Hna1jRQ3rWvJjojqM5DYTDJo5cejUuJy3C\",\n programIdMainnet: \"8oo4dC4JvBLwy5tGgiH3WwK4B9PWxL9Z4XjA2jzkQMbQ\",\n metadataKey: \"entros:human-operator\",\n} as const;\n\nexport const SAS_CONFIG = {\n programId: \"22zoJMtdu4tQc2PzL74ZUT7FrwgB1Udec8DdW4yw4BdG\",\n entrosCredentialPda: \"GaPTkZC6JEGds1G5h645qyUrogx7NWghR2JgjvKQwTDo\",\n entrosSchemaPda: \"EPkajiGQjycPwcc3pupqExVdAmSfxWd31tRYZezd8c5g\",\n} as const;\n\nexport interface PulseConfig {\n cluster: \"devnet\" | \"mainnet-beta\" | \"localnet\";\n rpcEndpoint?: string;\n relayerUrl?: string;\n relayerApiKey?: string;\n zkeyUrl?: string;\n wasmUrl?: string;\n threshold?: number;\n /** Enable console logging for diagnostics. Default: false. */\n debug?: boolean;\n}\n","/** Module-level debug flag, set by PulseSDK constructor. */\nlet debugEnabled = false;\n\nexport function setDebug(enabled: boolean): void {\n debugEnabled = enabled;\n}\n\nexport function sdkLog(...args: unknown[]): void {\n if (debugEnabled) console.log(...args);\n}\n\nexport function sdkWarn(...args: unknown[]): void {\n if (debugEnabled) console.warn(...args);\n}\n","import type { AudioCapture, CaptureOptions } from \"./types\";\nimport { MIN_CAPTURE_MS, MAX_CAPTURE_MS } from \"../config\";\n\nconst TARGET_SAMPLE_RATE = 16000;\n\n/**\n * Capture audio at 16kHz until signaled to stop.\n * Uses ScriptProcessorNode for raw PCM sample access.\n *\n * NOTE: ScriptProcessorNode is deprecated in favor of AudioWorklet.\n * Migration planned for v1.0. ScriptProcessorNode is used because it\n * provides synchronous access to raw PCM samples without requiring a\n * separate worker file, which simplifies SDK distribution. All current\n * browsers still support it.\n *\n * Stop behavior:\n * - If signal fires before minDurationMs, capture continues until minimum is reached.\n * - If signal never fires, capture auto-stops at maxDurationMs.\n * - If no signal provided, captures for maxDurationMs.\n */\nexport async function captureAudio(\n options: CaptureOptions = {}\n): Promise<AudioCapture> {\n const {\n signal,\n minDurationMs = MIN_CAPTURE_MS,\n maxDurationMs = MAX_CAPTURE_MS,\n onAudioLevel,\n stream: preAcquiredStream,\n } = options;\n\n const stream = preAcquiredStream ?? await navigator.mediaDevices.getUserMedia({\n audio: {\n sampleRate: TARGET_SAMPLE_RATE,\n channelCount: 1,\n echoCancellation: false,\n noiseSuppression: false,\n autoGainControl: false,\n },\n });\n\n const ctx = new AudioContext({ sampleRate: TARGET_SAMPLE_RATE });\n await ctx.resume(); // Required on iOS — AudioContext may be suspended outside user gesture\n const capturedSampleRate = ctx.sampleRate;\n const source = ctx.createMediaStreamSource(stream);\n const chunks: Float32Array[] = [];\n const startTime = performance.now();\n\n return new Promise((resolve) => {\n let stopped = false;\n const bufferSize = 4096;\n const processor = ctx.createScriptProcessor(bufferSize, 1, 1);\n\n processor.onaudioprocess = (e: AudioProcessingEvent) => {\n const data = e.inputBuffer.getChannelData(0);\n chunks.push(new Float32Array(data));\n\n if (onAudioLevel) {\n let sum = 0;\n for (let i = 0; i < data.length; i++) sum += data[i]! * data[i]!;\n onAudioLevel(Math.sqrt(sum / data.length));\n }\n };\n\n source.connect(processor);\n processor.connect(ctx.destination);\n\n function stopCapture() {\n if (stopped) return;\n stopped = true;\n clearTimeout(maxTimer);\n\n processor.disconnect();\n source.disconnect();\n stream.getTracks().forEach((t: MediaStreamTrack) => t.stop());\n ctx.close().catch(() => {});\n\n const totalLength = chunks.reduce((sum, c) => sum + c.length, 0);\n const samples = new Float32Array(totalLength);\n let offset = 0;\n for (const chunk of chunks) {\n samples.set(chunk, offset);\n offset += chunk.length;\n }\n\n resolve({\n samples,\n sampleRate: capturedSampleRate,\n duration: totalLength / capturedSampleRate,\n });\n }\n\n const maxTimer = setTimeout(stopCapture, maxDurationMs);\n\n if (signal) {\n if (signal.aborted) {\n setTimeout(stopCapture, minDurationMs);\n } else {\n signal.addEventListener(\n \"abort\",\n () => {\n const elapsed = performance.now() - startTime;\n const remaining = Math.max(0, minDurationMs - elapsed);\n setTimeout(stopCapture, remaining);\n },\n { once: true }\n );\n }\n }\n });\n}\n","/**\n * Encode captured Float32 audio samples as base64 int16 PCM for transmission\n * to the validation service (master-list #89 phrase content binding).\n *\n * Audio is captured as `Float32Array` with values in `[-1.0, 1.0]` by the\n * Pulse SDK (`sensor/audio.ts`). The validation service's phrase-binding\n * module decodes base64 → Vec<i16> → Vec<f32> before feeding Whisper-tiny.\n * int16 is the standard compact representation: 2 bytes per sample vs 4 for\n * f32, halving wire size without perceptible quality loss for 16kHz speech.\n *\n * Byte layout: little-endian int16 samples, contiguous, no header.\n */\n\n/**\n * Convert Float32 PCM samples to base64-encoded 16-bit little-endian PCM.\n * Samples are clamped to [-1, 1] and scaled. Uses `btoa`, a DOM global\n * available in browser runtimes and in Node 16+.\n */\nexport function encodeAudioAsBase64(samples: Float32Array): string {\n const buf = new ArrayBuffer(samples.length * 2);\n const view = new DataView(buf);\n for (let i = 0; i < samples.length; i++) {\n const s = Math.max(-1, Math.min(1, samples[i]!));\n const int16 = s < 0 ? Math.round(s * 0x8000) : Math.round(s * 0x7fff);\n view.setInt16(i * 2, int16, true);\n }\n return bytesToBase64(new Uint8Array(buf));\n}\n\nfunction bytesToBase64(bytes: Uint8Array): string {\n // `btoa` is a DOM global and is also available as a Node global since\n // Node 16 (2021), which covers every runtime the SDK ships into. Chunk\n // the input to avoid \"maximum call stack size\" on large arrays — btoa\n // needs a string, and `String.fromCharCode(...bytes)` blows the stack\n // for Uint8Array length > ~128KB.\n const chunkSize = 0x8000;\n let binary = \"\";\n for (let i = 0; i < bytes.length; i += chunkSize) {\n const chunk = bytes.subarray(i, i + chunkSize);\n binary += String.fromCharCode(...chunk);\n }\n return btoa(binary);\n}\n","import type { MotionSample, CaptureOptions } from \"./types\";\nimport { MIN_CAPTURE_MS, MAX_CAPTURE_MS } from \"../config\";\n\n/**\n * Request motion sensor permission (required on iOS 13+).\n * No-op on Android/Chrome where permission is implicit.\n */\nexport async function requestMotionPermission(): Promise<boolean> {\n const DME = (globalThis as any).DeviceMotionEvent;\n if (!DME) return false;\n\n if (typeof DME.requestPermission === \"function\") {\n const permission = await DME.requestPermission();\n return permission === \"granted\";\n }\n\n // Android/Chrome: permission is implicit\n return true;\n}\n\n/**\n * Capture accelerometer + gyroscope data until signaled to stop.\n * Samples at the device's native rate (typically ~60-100Hz).\n */\nexport async function captureMotion(\n options: CaptureOptions = {}\n): Promise<MotionSample[]> {\n const {\n signal,\n minDurationMs = MIN_CAPTURE_MS,\n maxDurationMs = MAX_CAPTURE_MS,\n } = options;\n\n const hasPermission = options.permissionGranted ?? await requestMotionPermission();\n if (!hasPermission) return [];\n\n const samples: MotionSample[] = [];\n const startTime = performance.now();\n\n return new Promise((resolve) => {\n let stopped = false;\n\n const handler = (e: DeviceMotionEvent) => {\n samples.push({\n timestamp: performance.now(),\n ax: e.acceleration?.x ?? 0,\n ay: e.acceleration?.y ?? 0,\n az: e.acceleration?.z ?? 0,\n gx: e.rotationRate?.alpha ?? 0,\n gy: e.rotationRate?.beta ?? 0,\n gz: e.rotationRate?.gamma ?? 0,\n });\n };\n\n function stopCapture() {\n if (stopped) return;\n stopped = true;\n clearTimeout(maxTimer);\n window.removeEventListener(\"devicemotion\", handler);\n resolve(samples);\n }\n\n window.addEventListener(\"devicemotion\", handler);\n\n const maxTimer = setTimeout(stopCapture, maxDurationMs);\n\n if (signal) {\n if (signal.aborted) {\n setTimeout(stopCapture, minDurationMs);\n } else {\n signal.addEventListener(\n \"abort\",\n () => {\n const elapsed = performance.now() - startTime;\n const remaining = Math.max(0, minDurationMs - elapsed);\n setTimeout(stopCapture, remaining);\n },\n { once: true }\n );\n }\n }\n });\n}\n","import type { TouchSample, CaptureOptions } from \"./types\";\nimport { MIN_CAPTURE_MS, MAX_CAPTURE_MS } from \"../config\";\nimport { sdkLog } from \"../log\";\n\n/**\n * Capture touch/pointer data (position, pressure, contact area) until signaled to stop.\n * Uses PointerEvent for cross-platform support (touch, pen, mouse).\n */\nexport function captureTouch(\n element: HTMLElement,\n options: CaptureOptions = {}\n): Promise<TouchSample[]> {\n const {\n signal,\n minDurationMs = MIN_CAPTURE_MS,\n maxDurationMs = MAX_CAPTURE_MS,\n } = options;\n\n const samples: TouchSample[] = [];\n const startTime = performance.now();\n\n return new Promise((resolve) => {\n let stopped = false;\n\n const handler = (e: PointerEvent) => {\n samples.push({\n timestamp: performance.now(),\n x: e.clientX,\n y: e.clientY,\n pressure: e.pressure,\n width: e.width,\n height: e.height,\n });\n };\n\n function stopCapture() {\n if (stopped) return;\n stopped = true;\n clearTimeout(maxTimer);\n element.removeEventListener(\"pointermove\", handler);\n element.removeEventListener(\"pointerdown\", handler);\n sdkLog(`[Entros SDK] Touch capture stopped: ${samples.length} samples collected`);\n resolve(samples);\n }\n\n element.addEventListener(\"pointermove\", handler);\n element.addEventListener(\"pointerdown\", handler);\n sdkLog(`[Entros SDK] Touch capture started on <${element.tagName}>, listening for pointer events`);\n\n const maxTimer = setTimeout(stopCapture, maxDurationMs);\n\n if (signal) {\n if (signal.aborted) {\n setTimeout(stopCapture, minDurationMs);\n } else {\n signal.addEventListener(\n \"abort\",\n () => {\n const elapsed = performance.now() - startTime;\n const remaining = Math.max(0, minDurationMs - elapsed);\n setTimeout(stopCapture, remaining);\n },\n { once: true }\n );\n }\n }\n });\n}\n","import type { StatsSummary } from \"./types\";\n\nexport function mean(values: number[]): number {\n if (values.length === 0) return 0;\n let sum = 0;\n for (const v of values) sum += v;\n return sum / values.length;\n}\n\nexport function variance(values: number[], mu?: number): number {\n if (values.length < 2) return 0;\n const m = mu ?? mean(values);\n let sum = 0;\n for (const v of values) sum += (v - m) ** 2;\n return sum / (values.length - 1);\n}\n\nexport function skewness(values: number[]): number {\n if (values.length < 3) return 0;\n const n = values.length;\n const m = mean(values);\n const s = Math.sqrt(variance(values, m));\n if (s === 0) return 0;\n let sum = 0;\n for (const v of values) sum += ((v - m) / s) ** 3;\n return (n / ((n - 1) * (n - 2))) * sum;\n}\n\nexport function kurtosis(values: number[]): number {\n if (values.length < 4) return 0;\n const n = values.length;\n const m = mean(values);\n const s2 = variance(values, m);\n if (s2 === 0) return 0;\n let sum = 0;\n for (const v of values) sum += ((v - m) ** 4) / s2 ** 2;\n const k =\n ((n * (n + 1)) / ((n - 1) * (n - 2) * (n - 3))) * sum -\n (3 * (n - 1) ** 2) / ((n - 2) * (n - 3));\n return k;\n}\n\nexport function condense(values: number[]): StatsSummary {\n const m = mean(values);\n return {\n mean: m,\n variance: variance(values, m),\n skewness: skewness(values),\n kurtosis: kurtosis(values),\n };\n}\n\n/**\n * Shannon entropy over histogram bins. Measures information density.\n * Real human data has moderate entropy (varied but structured).\n * Synthetic data is either too uniform (high entropy) or too structured (low entropy).\n */\nexport function entropy(values: number[], bins: number = 16): number {\n if (values.length < 2) return 0;\n let min = values[0]!;\n let max = values[0]!;\n for (let i = 1; i < values.length; i++) {\n if (values[i]! < min) min = values[i]!;\n if (values[i]! > max) max = values[i]!;\n }\n if (min === max) return 0;\n\n const counts = new Array(bins).fill(0);\n const range = max - min;\n for (const v of values) {\n const idx = Math.min(Math.floor(((v - min) / range) * bins), bins - 1);\n counts[idx]++;\n }\n\n let h = 0;\n for (const c of counts) {\n if (c > 0) {\n const p = c / values.length;\n h -= p * Math.log2(p);\n }\n }\n return h;\n}\n\n/**\n * Autocorrelation at a given lag. Detects periodic synthetic patterns.\n * Real human data has low autocorrelation at most lags (chaotic/noisy).\n * Synthetic data often has high autocorrelation (periodic/smooth).\n */\nexport function autocorrelation(values: number[], lag: number = 1): number {\n if (values.length <= lag) return 0;\n const m = mean(values);\n const v = variance(values, m);\n if (v === 0) return 0;\n\n let sum = 0;\n for (let i = 0; i < values.length - lag; i++) {\n sum += (values[i]! - m) * (values[i + lag]! - m);\n }\n return sum / ((values.length - lag) * v);\n}\n\n/**\n * Normalize a feature group to zero mean and unit variance.\n * Ensures each modality (audio, motion, touch) contributes equally\n * to SimHash hyperplane projections regardless of raw magnitude scale.\n */\n/**\n * Z-score normalize a feature group to zero mean and unit variance.\n * Ensures each modality contributes equally to SimHash hyperplane\n * projections regardless of raw magnitude scale.\n */\nexport function normalizeGroup(features: number[]): number[] {\n if (features.length === 0) return features;\n\n // Sanitize NaN/Infinity to 0 before computing stats.\n // Meyda spectral features can produce NaN on near-silent frames (0/0),\n // and a single NaN would poison the entire modality group.\n const clean = features.map((v) => (Number.isFinite(v) ? v : 0));\n\n let sum = 0;\n for (const v of clean) sum += v;\n const mean = sum / clean.length;\n\n let sqSum = 0;\n for (const v of clean) sqSum += (v - mean) * (v - mean);\n const std = Math.sqrt(sqSum / clean.length);\n\n if (std < 1e-8) return clean.map(() => 0);\n return clean.map((v) => (v - mean) / std);\n}\n\n/**\n * Concatenate raw features without normalization.\n * Used for server-side validation where physical units matter.\n */\nexport function fuseRawFeatures(\n audio: number[],\n motion: number[],\n touch: number[]\n): number[] {\n const sanitize = (v: number) => (Number.isFinite(v) ? v : 0);\n return [...audio.map(sanitize), ...motion.map(sanitize), ...touch.map(sanitize)];\n}\n\n/**\n * Normalize and concatenate features for SimHash computation.\n */\nexport function fuseFeatures(\n audio: number[],\n motion: number[],\n touch: number[]\n): number[] {\n return [...normalizeGroup(audio), ...normalizeGroup(motion), ...normalizeGroup(touch)];\n}\n","/**\n * Linear Predictive Coding (LPC) for formant detection.\n *\n * Implements Levinson-Durbin recursion for LPC coefficient computation\n * and polynomial root-finding for formant frequency estimation.\n */\n\n/**\n * Compute autocorrelation of a signal for lags 0..order.\n */\nfunction autocorrelate(signal: Float32Array, order: number): number[] {\n const r: number[] = [];\n for (let lag = 0; lag <= order; lag++) {\n let sum = 0;\n for (let i = 0; i < signal.length - lag; i++) {\n sum += signal[i]! * signal[i + lag]!;\n }\n r.push(sum);\n }\n return r;\n}\n\n/**\n * Levinson-Durbin recursion to compute LPC coefficients from autocorrelation.\n * Returns the LPC coefficients a[1..order] (a[0] is implicitly 1).\n */\nfunction levinsonDurbin(r: number[], order: number): number[] {\n const a: number[] = new Array(order + 1).fill(0);\n const aTemp: number[] = new Array(order + 1).fill(0);\n a[0] = 1;\n\n let error = r[0]!;\n if (error === 0) return new Array(order).fill(0);\n\n for (let i = 1; i <= order; i++) {\n let lambda = 0;\n for (let j = 1; j < i; j++) {\n lambda += a[j]! * r[i - j]!;\n }\n lambda = -(r[i]! + lambda) / error;\n\n for (let j = 1; j < i; j++) {\n aTemp[j] = a[j]! + lambda * a[i - j]!;\n }\n aTemp[i] = lambda;\n\n for (let j = 1; j <= i; j++) {\n a[j] = aTemp[j]!;\n }\n\n error *= 1 - lambda * lambda;\n if (error <= 0) break;\n }\n\n return a.slice(1);\n}\n\n/**\n * Find roots of a polynomial using the Durand-Kerner method.\n * The polynomial is 1 + a[0]*z^-1 + a[1]*z^-2 + ... + a[n-1]*z^-n\n * which is equivalent to z^n + a[0]*z^(n-1) + ... + a[n-1] = 0.\n *\n * Returns complex roots as [real, imag] pairs.\n */\nfunction findRoots(coefficients: number[], maxIterations: number = 50): [number, number][] {\n const n = coefficients.length;\n if (n === 0) return [];\n\n // Initial guesses: points on a circle of radius 0.9\n const roots: [number, number][] = [];\n for (let i = 0; i < n; i++) {\n const angle = (2 * Math.PI * i) / n + 0.1;\n roots.push([0.9 * Math.cos(angle), 0.9 * Math.sin(angle)]);\n }\n\n for (let iter = 0; iter < maxIterations; iter++) {\n let maxShift = 0;\n\n for (let i = 0; i < n; i++) {\n // Evaluate polynomial at roots[i]: z^n + a[0]*z^(n-1) + ... + a[n-1]\n let pReal = 1;\n let pImag = 0;\n let zPowReal = 1;\n let zPowImag = 0;\n\n // Compute z^n by repeated multiplication\n const [rr, ri] = roots[i]!;\n let curReal = 1;\n let curImag = 0;\n\n // Evaluate as: z^n + sum(a[k] * z^(n-1-k))\n // Start with z^n\n let znReal = 1;\n let znImag = 0;\n for (let k = 0; k < n; k++) {\n const newReal = znReal * rr - znImag * ri;\n const newImag = znReal * ri + znImag * rr;\n znReal = newReal;\n znImag = newImag;\n }\n pReal = znReal;\n pImag = znImag;\n\n // Add coefficient terms: a[k] * z^(n-1-k)\n zPowReal = 1;\n zPowImag = 0;\n for (let k = n - 1; k >= 0; k--) {\n pReal += coefficients[k]! * zPowReal;\n pImag += coefficients[k]! * zPowImag;\n const newReal = zPowReal * rr - zPowImag * ri;\n const newImag = zPowReal * ri + zPowImag * rr;\n zPowReal = newReal;\n zPowImag = newImag;\n }\n\n // Compute product of (roots[i] - roots[j]) for j != i\n let denomReal = 1;\n let denomImag = 0;\n for (let j = 0; j < n; j++) {\n if (j === i) continue;\n const diffReal = rr - roots[j]![0];\n const diffImag = ri - roots[j]![1];\n const newReal = denomReal * diffReal - denomImag * diffImag;\n const newImag = denomReal * diffImag + denomImag * diffReal;\n denomReal = newReal;\n denomImag = newImag;\n }\n\n // Divide p / denom\n const denomMag2 = denomReal * denomReal + denomImag * denomImag;\n if (denomMag2 < 1e-30) continue;\n\n const shiftReal = (pReal * denomReal + pImag * denomImag) / denomMag2;\n const shiftImag = (pImag * denomReal - pReal * denomImag) / denomMag2;\n\n roots[i] = [rr - shiftReal, ri - shiftImag];\n maxShift = Math.max(maxShift, Math.sqrt(shiftReal * shiftReal + shiftImag * shiftImag));\n }\n\n if (maxShift < 1e-10) break;\n }\n\n return roots;\n}\n\n/**\n * Extract formant frequencies (F1, F2, F3) from a single audio frame.\n * Returns [F1, F2, F3] in Hz, or null if extraction fails.\n */\nfunction extractFormants(\n frame: Float32Array,\n sampleRate: number,\n lpcOrder: number = 12\n): [number, number, number] | null {\n const r = autocorrelate(frame, lpcOrder);\n const coeffs = levinsonDurbin(r, lpcOrder);\n\n const roots = findRoots(coeffs);\n\n // Convert roots to frequencies, keep only positive-frequency roots\n const formantCandidates: number[] = [];\n\n for (const [real, imag] of roots) {\n if (imag <= 0) continue; // Keep only positive-frequency roots\n\n const freq = (Math.atan2(imag, real) / (2 * Math.PI)) * sampleRate;\n const bandwidth = (-sampleRate / (2 * Math.PI)) * Math.log(Math.sqrt(real * real + imag * imag));\n\n // Filter: formants are in 200-5000Hz range with reasonable bandwidth\n if (freq > 200 && freq < 5000 && bandwidth < 500) {\n formantCandidates.push(freq);\n }\n }\n\n formantCandidates.sort((a, b) => a - b);\n\n if (formantCandidates.length < 3) return null;\n\n return [formantCandidates[0]!, formantCandidates[1]!, formantCandidates[2]!];\n}\n\n/**\n * Extract formant ratio time series (F1/F2 and F2/F3) from audio.\n * Returns { f1f2: number[], f2f3: number[] } — one ratio per frame where formants were detected.\n */\nexport function extractFormantRatios(\n samples: Float32Array,\n sampleRate: number,\n frameSize: number,\n hopSize: number\n): { f1f2: number[]; f2f3: number[] } {\n const f1f2: number[] = [];\n const f2f3: number[] = [];\n const numFrames = Math.floor((samples.length - frameSize) / hopSize) + 1;\n\n for (let i = 0; i < numFrames; i++) {\n const start = i * hopSize;\n // Read-only — windowed below is a fresh allocation that copies values\n // out, so a zero-copy view here is bit-equivalent and saves a Float32Array.\n const frame = samples.subarray(start, start + frameSize);\n\n // Apply Hamming window\n const windowed = new Float32Array(frameSize);\n for (let j = 0; j < frameSize; j++) {\n windowed[j] = (frame[j] ?? 0) * (0.54 - 0.46 * Math.cos((2 * Math.PI * j) / (frameSize - 1)));\n }\n\n const formants = extractFormants(windowed, sampleRate);\n if (formants) {\n const [f1, f2, f3] = formants;\n if (f2 > 0) f1f2.push(f1 / f2);\n if (f3 > 0) f2f3.push(f2 / f3);\n }\n }\n\n return { f1f2, f2f3 };\n}\n","/**\n * Speaker-dependent audio feature extraction.\n *\n * Extracts features that characterize HOW someone speaks (prosody, vocal physiology)\n * rather than WHAT they say (phonetic content). These features are stable across\n * different utterances from the same speaker.\n *\n * Output: 44 values\n * F0 statistics (5) + F0 delta (4) + jitter (4) + shimmer (4) +\n * HNR statistics (5) + formant ratios (8) + LTAS (8) + voicing ratio (1) +\n * amplitude statistics (5)\n */\nimport type { AudioCapture } from \"../sensor/types\";\nimport { condense, entropy } from \"./statistics\";\nimport { extractFormantRatios } from \"./lpc\";\nimport { sdkWarn } from \"../log\";\n\n/**\n * Compute frame size adaptive to actual sample rate.\n * YIN pitch detection requires: frameSize >= 4 * sampleRate / minF0\n * (because YIN halves the buffer twice internally).\n * Returns next power of 2 for FFT compatibility.\n */\nfunction getFrameSize(sampleRate: number): number {\n const MIN_F0 = 50; // lowest detectable pitch (Hz)\n const minSize = Math.ceil(4 * sampleRate / MIN_F0);\n let size = 512; // minimum\n while (size < minSize) size *= 2;\n return size;\n}\n\n/**\n * Compute hop size as ~10ms at the given sample rate.\n */\nfunction getHopSize(sampleRate: number): number {\n return Math.max(1, Math.round(sampleRate * 0.01));\n}\n\nconst SPEAKER_FEATURE_COUNT = 44;\n\n// Dynamic imports for browser compatibility\nlet pitchDetector: ((buf: Float32Array) => number | null) | null = null;\nlet pitchDetectorRate = 0;\nlet meydaModule: any = null;\n\nasync function getPitchDetector(sampleRate: number): Promise<(buf: Float32Array) => number | null> {\n if (!pitchDetector || pitchDetectorRate !== sampleRate) {\n const PitchFinder = await import(\"pitchfinder\");\n pitchDetector = PitchFinder.YIN({ sampleRate, threshold: 0.15 });\n pitchDetectorRate = sampleRate;\n }\n return pitchDetector;\n}\n\nasync function getMeyda(): Promise<any> {\n if (!meydaModule) {\n try {\n meydaModule = await import(\"meyda\");\n } catch {\n return null;\n }\n }\n return meydaModule.default ?? meydaModule;\n}\n\n/**\n * Detect F0 (fundamental frequency) contour and amplitude peaks per frame.\n */\nasync function detectF0Contour(\n samples: Float32Array,\n sampleRate: number\n): Promise<{ f0: number[]; amplitudes: number[]; periods: number[] }> {\n const detect = await getPitchDetector(sampleRate);\n const frameSize = getFrameSize(sampleRate);\n const hopSize = getHopSize(sampleRate);\n const f0: number[] = [];\n const amplitudes: number[] = [];\n const periods: number[] = [];\n const numFrames = Math.floor((samples.length - frameSize) / hopSize) + 1;\n\n if (sampleRate !== 16000) {\n sdkWarn(`[Entros SDK] Audio captured at ${sampleRate}Hz (requested 16kHz). Frame size adjusted to ${frameSize}.`);\n }\n\n for (let i = 0; i < numFrames; i++) {\n const start = i * hopSize;\n // `subarray` is a zero-copy view — `detect()` and the RMS loop below\n // are read-only, so we save ~1.2k Float32Array allocations per session\n // (and matching GC pressure on Hermes).\n const frame = samples.subarray(start, start + frameSize);\n\n // F0 detection\n const pitch = detect(frame);\n if (pitch && pitch > 50 && pitch < 600) {\n f0.push(pitch);\n periods.push(1 / pitch);\n } else {\n f0.push(0); // unvoiced frame\n }\n\n // RMS amplitude per frame\n let sum = 0;\n for (let j = 0; j < frame.length; j++) {\n sum += (frame[j] ?? 0) * (frame[j] ?? 0);\n }\n amplitudes.push(Math.sqrt(sum / frame.length));\n }\n\n return { f0, amplitudes, periods };\n}\n\n/**\n * Compute jitter measures from pitch period contour.\n * Jitter = cycle-to-cycle perturbation of the fundamental period.\n */\nfunction computeJitter(periods: number[]): number[] {\n const voiced = periods.filter((p) => p > 0);\n if (voiced.length < 3) return [0, 0, 0, 0];\n\n const meanPeriod = voiced.reduce((a, b) => a + b, 0) / voiced.length;\n if (meanPeriod === 0) return [0, 0, 0, 0];\n\n // Jitter (local): average absolute difference between consecutive periods\n let localSum = 0;\n for (let i = 1; i < voiced.length; i++) {\n localSum += Math.abs(voiced[i]! - voiced[i - 1]!);\n }\n const jitterLocal = localSum / (voiced.length - 1) / meanPeriod;\n\n // RAP: Relative Average Perturbation (3-point running average)\n let rapSum = 0;\n for (let i = 1; i < voiced.length - 1; i++) {\n const avg3 = (voiced[i - 1]! + voiced[i]! + voiced[i + 1]!) / 3;\n rapSum += Math.abs(voiced[i]! - avg3);\n }\n const jitterRAP = voiced.length > 2 ? rapSum / (voiced.length - 2) / meanPeriod : 0;\n\n // PPQ5: Five-Point Period Perturbation Quotient\n let ppq5Sum = 0;\n let ppq5Count = 0;\n for (let i = 2; i < voiced.length - 2; i++) {\n const avg5 = (voiced[i - 2]! + voiced[i - 1]! + voiced[i]! + voiced[i + 1]! + voiced[i + 2]!) / 5;\n ppq5Sum += Math.abs(voiced[i]! - avg5);\n ppq5Count++;\n }\n const jitterPPQ5 = ppq5Count > 0 ? ppq5Sum / ppq5Count / meanPeriod : 0;\n\n // DDP: Difference of Differences of Periods\n let ddpSum = 0;\n for (let i = 1; i < voiced.length - 1; i++) {\n const d1 = voiced[i]! - voiced[i - 1]!;\n const d2 = voiced[i + 1]! - voiced[i]!;\n ddpSum += Math.abs(d2 - d1);\n }\n const jitterDDP = voiced.length > 2 ? ddpSum / (voiced.length - 2) / meanPeriod : 0;\n\n return [jitterLocal, jitterRAP, jitterPPQ5, jitterDDP];\n}\n\n/**\n * Compute shimmer measures from amplitude peaks.\n * Shimmer = cycle-to-cycle amplitude perturbation.\n */\nfunction computeShimmer(amplitudes: number[], f0: number[]): number[] {\n // Use amplitudes only at voiced frames\n const voicedAmps = amplitudes.filter((_, i) => f0[i]! > 0);\n if (voicedAmps.length < 3) return [0, 0, 0, 0];\n\n const meanAmp = voicedAmps.reduce((a, b) => a + b, 0) / voicedAmps.length;\n if (meanAmp === 0) return [0, 0, 0, 0];\n\n // Shimmer (local)\n let localSum = 0;\n for (let i = 1; i < voicedAmps.length; i++) {\n localSum += Math.abs(voicedAmps[i]! - voicedAmps[i - 1]!);\n }\n const shimmerLocal = localSum / (voicedAmps.length - 1) / meanAmp;\n\n // APQ3: 3-point Amplitude Perturbation Quotient\n let apq3Sum = 0;\n for (let i = 1; i < voicedAmps.length - 1; i++) {\n const avg3 = (voicedAmps[i - 1]! + voicedAmps[i]! + voicedAmps[i + 1]!) / 3;\n apq3Sum += Math.abs(voicedAmps[i]! - avg3);\n }\n const shimmerAPQ3 = voicedAmps.length > 2 ? apq3Sum / (voicedAmps.length - 2) / meanAmp : 0;\n\n // APQ5\n let apq5Sum = 0;\n let apq5Count = 0;\n for (let i = 2; i < voicedAmps.length - 2; i++) {\n const avg5 = (voicedAmps[i - 2]! + voicedAmps[i - 1]! + voicedAmps[i]! + voicedAmps[i + 1]! + voicedAmps[i + 2]!) / 5;\n apq5Sum += Math.abs(voicedAmps[i]! - avg5);\n apq5Count++;\n }\n const shimmerAPQ5 = apq5Count > 0 ? apq5Sum / apq5Count / meanAmp : 0;\n\n // DDA: Difference of Differences of Amplitudes\n let ddaSum = 0;\n for (let i = 1; i < voicedAmps.length - 1; i++) {\n const d1 = voicedAmps[i]! - voicedAmps[i - 1]!;\n const d2 = voicedAmps[i + 1]! - voicedAmps[i]!;\n ddaSum += Math.abs(d2 - d1);\n }\n const shimmerDDA = voicedAmps.length > 2 ? ddaSum / (voicedAmps.length - 2) / meanAmp : 0;\n\n return [shimmerLocal, shimmerAPQ3, shimmerAPQ5, shimmerDDA];\n}\n\n/**\n * Compute Harmonic-to-Noise Ratio per frame using autocorrelation.\n */\nfunction computeHNR(\n samples: Float32Array,\n sampleRate: number,\n f0Contour: number[]\n): number[] {\n const frameSize = getFrameSize(sampleRate);\n const hopSize = getHopSize(sampleRate);\n const hnr: number[] = [];\n const numFrames = Math.floor((samples.length - frameSize) / hopSize) + 1;\n\n for (let i = 0; i < numFrames && i < f0Contour.length; i++) {\n const f0 = f0Contour[i]!;\n if (f0 <= 0) continue; // Skip unvoiced frames\n\n const start = i * hopSize;\n // Read-only autocorrelation — view is safe.\n const frame = samples.subarray(start, start + frameSize);\n const period = Math.round(sampleRate / f0);\n\n if (period <= 0 || period >= frame.length) continue;\n\n // Autocorrelation at the fundamental period\n let num = 0;\n let den = 0;\n for (let j = 0; j < frame.length - period; j++) {\n num += (frame[j] ?? 0) * (frame[j + period] ?? 0);\n den += (frame[j] ?? 0) * (frame[j] ?? 0);\n }\n\n if (den > 0) {\n const r = num / den;\n const clampedR = Math.max(0.001, Math.min(0.999, r));\n hnr.push(10 * Math.log10(clampedR / (1 - clampedR)));\n }\n }\n\n return hnr;\n}\n\n/**\n * Compute LTAS (Long-Term Average Spectrum) features using Meyda.\n * Returns 8 values: spectral centroid, rolloff, flatness, spread — each mean + variance.\n */\nasync function computeLTAS(\n samples: Float32Array,\n sampleRate: number\n): Promise<number[]> {\n const frameSize = getFrameSize(sampleRate);\n const hopSize = getHopSize(sampleRate);\n const Meyda = await getMeyda();\n if (!Meyda) return new Array(8).fill(0);\n\n const centroids: number[] = [];\n const rolloffs: number[] = [];\n const flatnesses: number[] = [];\n const spreads: number[] = [];\n const numFrames = Math.floor((samples.length - frameSize) / hopSize) + 1;\n // Pre-allocate the buffer Meyda receives — frames are exactly `frameSize`\n // (the loop bounds guarantee no overrun), so we can overwrite each\n // iteration via `.set()` instead of allocating ~1.2k Float32Arrays.\n const paddedFrame = new Float32Array(frameSize);\n\n for (let i = 0; i < numFrames; i++) {\n const start = i * hopSize;\n paddedFrame.set(samples.subarray(start, start + frameSize), 0);\n\n const features = Meyda.extract(\n [\"spectralCentroid\", \"spectralRolloff\", \"spectralFlatness\", \"spectralSpread\"],\n paddedFrame,\n { sampleRate, bufferSize: frameSize }\n );\n\n if (features) {\n if (Number.isFinite(features.spectralCentroid)) centroids.push(features.spectralCentroid);\n if (Number.isFinite(features.spectralRolloff)) rolloffs.push(features.spectralRolloff);\n if (Number.isFinite(features.spectralFlatness)) flatnesses.push(features.spectralFlatness);\n if (Number.isFinite(features.spectralSpread)) spreads.push(features.spectralSpread);\n }\n }\n\n const m = (arr: number[]) => arr.length > 0 ? arr.reduce((a, b) => a + b, 0) / arr.length : 0;\n const v = (arr: number[]) => {\n if (arr.length < 2) return 0;\n const mu = m(arr);\n return arr.reduce((sum, x) => sum + (x - mu) * (x - mu), 0) / (arr.length - 1);\n };\n\n return [\n m(centroids), v(centroids),\n m(rolloffs), v(rolloffs),\n m(flatnesses), v(flatnesses),\n m(spreads), v(spreads),\n ];\n}\n\n/**\n * Compute derivative (frame-to-frame differences) of a time series.\n */\nfunction derivative(values: number[]): number[] {\n const d: number[] = [];\n for (let i = 1; i < values.length; i++) {\n d.push(values[i]! - values[i - 1]!);\n }\n return d;\n}\n\n/**\n * Extract speaker-dependent audio features.\n *\n * Captures physiological vocal characteristics (F0, jitter, shimmer, HNR, formant\n * ratios) that are stable across different utterances from the same speaker.\n * Content-independent by design — different phrases produce similar feature values.\n *\n * Returns 44 values.\n */\n/**\n * Extracts 44 speaker features AND the raw F0 contour.\n * The F0 contour is surfaced so Tier 2 cross-modal temporal analysis can be\n * performed server-side against the motion time-series. Feature vector shape\n * and semantics are unchanged.\n */\nexport async function extractSpeakerFeaturesDetailed(\n audio: AudioCapture,\n): Promise<{ features: number[]; f0Contour: number[] }> {\n const { samples, sampleRate } = audio;\n\n if (!Number.isFinite(sampleRate) || sampleRate <= 0 || samples.length === 0) {\n sdkWarn(\"[Entros SDK] Invalid audio data. Speaker features will be zeros.\");\n return { features: new Array(SPEAKER_FEATURE_COUNT).fill(0), f0Contour: [] };\n }\n\n const frameSize = getFrameSize(sampleRate);\n const hopSize = getHopSize(sampleRate);\n\n const numFrames = Math.floor((samples.length - frameSize) / hopSize) + 1;\n if (numFrames < 5) {\n sdkWarn(`[Entros SDK] Too few audio frames (${numFrames}). Speaker features will be zeros.`);\n return { features: new Array(SPEAKER_FEATURE_COUNT).fill(0), f0Contour: [] };\n }\n\n // Peak-normalize audio for robust pitch detection.\n // Raw mic input (especially desktop without AGC) can be very quiet,\n // causing autocorrelation-based pitch detectors to fail.\n // All relative features (jitter, shimmer, HNR, F0) are unaffected\n // since they measure ratios, not absolute levels.\n // Absolute amplitude is computed from the original samples below.\n let peakAmp = 0;\n for (let i = 0; i < samples.length; i++) {\n const abs = Math.abs(samples[i] ?? 0);\n if (abs > peakAmp) peakAmp = abs;\n }\n\n // Single-allocation normalisation. Order of operations preserved exactly\n // (`(s / peakAmp) * 0.9`) so the output is bit-identical to the previous\n // `samples.map(...)` form.\n let normalizedSamples: Float32Array;\n if (peakAmp > 1e-6) {\n normalizedSamples = new Float32Array(samples.length);\n for (let i = 0; i < samples.length; i++) {\n normalizedSamples[i] = (samples[i]! / peakAmp) * 0.9;\n }\n } else {\n normalizedSamples = samples;\n }\n\n // 1. F0 detection + amplitude contour (on normalized audio)\n const { f0, amplitudes: normalizedAmplitudes, periods } = await detectF0Contour(normalizedSamples, sampleRate);\n\n // Compute amplitude from ORIGINAL samples (pre-normalization) for biometric consistency\n const amplitudes: number[] = [];\n for (let i = 0; i < numFrames; i++) {\n const start = i * hopSize;\n let sum = 0;\n const end = Math.min(start + frameSize, samples.length);\n for (let j = start; j < end; j++) {\n sum += (samples[j] ?? 0) * (samples[j] ?? 0);\n }\n amplitudes.push(Math.sqrt(sum / (end - start)));\n }\n\n const voicedF0 = f0.filter((v) => v > 0);\n const voicedRatio = voicedF0.length / f0.length;\n\n // 2. F0 statistics (5 values)\n const f0Stats = condense(voicedF0);\n const f0Entropy = entropy(voicedF0);\n const f0Features = [f0Stats.mean, f0Stats.variance, f0Stats.skewness, f0Stats.kurtosis, f0Entropy];\n\n // 3. F0 delta statistics (4 values)\n const f0Delta = derivative(voicedF0);\n const f0DeltaStats = condense(f0Delta);\n const f0DeltaFeatures = [f0DeltaStats.mean, f0DeltaStats.variance, f0DeltaStats.skewness, f0DeltaStats.kurtosis];\n\n // 4. Jitter (4 values)\n const jitterFeatures = computeJitter(periods);\n\n // 5. Shimmer (4 values)\n const shimmerFeatures = computeShimmer(amplitudes, f0);\n\n // 6. HNR statistics (5 values)\n const hnrValues = computeHNR(normalizedSamples, sampleRate, f0);\n const hnrStats = condense(hnrValues);\n const hnrEntropy = entropy(hnrValues);\n const hnrFeatures = [hnrStats.mean, hnrStats.variance, hnrStats.skewness, hnrStats.kurtosis, hnrEntropy];\n\n // 7. Formant ratios (8 values)\n const { f1f2, f2f3 } = extractFormantRatios(normalizedSamples, sampleRate, frameSize, hopSize);\n const f1f2Stats = condense(f1f2);\n const f2f3Stats = condense(f2f3);\n const formantFeatures = [\n f1f2Stats.mean, f1f2Stats.variance, f1f2Stats.skewness, f1f2Stats.kurtosis,\n f2f3Stats.mean, f2f3Stats.variance, f2f3Stats.skewness, f2f3Stats.kurtosis,\n ];\n\n // 8. LTAS (8 values)\n const ltasFeatures = await computeLTAS(samples, sampleRate);\n\n // 9. Voicing ratio (1 value)\n const voicingFeatures = [voicedRatio];\n\n // 10. Amplitude statistics (5 values)\n const ampStats = condense(amplitudes);\n const ampEntropy = entropy(amplitudes);\n const ampFeatures = [ampStats.mean, ampStats.variance, ampStats.skewness, ampStats.kurtosis, ampEntropy];\n\n const features = [\n ...f0Features, // 5\n ...f0DeltaFeatures, // 4\n ...jitterFeatures, // 4\n ...shimmerFeatures, // 4\n ...hnrFeatures, // 5\n ...formantFeatures, // 8\n ...ltasFeatures, // 8\n ...voicingFeatures, // 1\n ...ampFeatures, // 5\n ]; // = 44\n\n return { features, f0Contour: f0 };\n}\n\n/**\n * Extracts 44 speaker features. Backward-compatible wrapper that discards\n * the F0 contour; use `extractSpeakerFeaturesDetailed` when the contour is\n * needed (e.g. for Tier 2 server-side cross-modal analysis).\n */\nexport async function extractSpeakerFeatures(audio: AudioCapture): Promise<number[]> {\n const { features } = await extractSpeakerFeaturesDetailed(audio);\n return features;\n}\n\nexport { SPEAKER_FEATURE_COUNT };\n","import type { MotionSample, TouchSample } from \"../sensor/types\";\nimport { condense, variance, entropy } from \"./statistics\";\n\n/**\n * Compute per-sample acceleration magnitude |a| = √(ax² + ay² + az²) and\n * linearly resample to a target frame count. Used for Tier 2 cross-modal\n * temporal analysis against the F0 contour; the two time-series must share\n * the same frame count for direct correlation.\n *\n * Returns an empty array if motion data is absent or too short.\n */\nexport function extractAccelerationMagnitude(\n samples: MotionSample[],\n targetFrameCount: number,\n): number[] {\n if (samples.length < 2 || targetFrameCount < 2) return [];\n\n const magnitudes = samples.map((s) => Math.sqrt(s.ax * s.ax + s.ay * s.ay + s.az * s.az));\n\n if (magnitudes.length === targetFrameCount) return magnitudes;\n\n // Linear resample: map target index i to source position (i / (target-1)) * (source-1)\n const out = new Array<number>(targetFrameCount);\n const srcLen = magnitudes.length;\n const scale = (srcLen - 1) / (targetFrameCount - 1);\n for (let i = 0; i < targetFrameCount; i++) {\n const pos = i * scale;\n const lo = Math.floor(pos);\n const hi = Math.min(lo + 1, srcLen - 1);\n const t = pos - lo;\n out[i] = magnitudes[lo]! * (1 - t) + magnitudes[hi]! * t;\n }\n return out;\n}\n\n/**\n * Extract kinematic features from motion (IMU) data.\n * Computes jerk (3rd derivative) and jounce (4th derivative) of acceleration,\n * then condenses each axis into statistics.\n *\n * Returns: ~54 values (6 axes × 2 derivatives × 4 stats + 6 jitter variance values)\n */\nexport function extractMotionFeatures(samples: MotionSample[]): number[] {\n if (samples.length < 5) return new Array(54).fill(0);\n\n // Extract acceleration and rotation time series\n const axes = {\n ax: samples.map((s) => s.ax),\n ay: samples.map((s) => s.ay),\n az: samples.map((s) => s.az),\n gx: samples.map((s) => s.gx),\n gy: samples.map((s) => s.gy),\n gz: samples.map((s) => s.gz),\n };\n\n const features: number[] = [];\n\n for (const values of Object.values(axes)) {\n // Jerk = 3rd derivative of position = 1st derivative of acceleration\n const jerk = derivative(values);\n // Jounce = 4th derivative of position = 2nd derivative of acceleration\n const jounce = derivative(jerk);\n\n const jerkStats = condense(jerk);\n const jounceStats = condense(jounce);\n\n features.push(\n jerkStats.mean,\n jerkStats.variance,\n jerkStats.skewness,\n jerkStats.kurtosis,\n jounceStats.mean,\n jounceStats.variance,\n jounceStats.skewness,\n jounceStats.kurtosis\n );\n }\n\n // Jitter variance per axis: variance of windowed jerk variance.\n // Real human tremor fluctuates over time (high jitter variance).\n // Synthetic/replay data has constant jitter (low jitter variance).\n for (const values of Object.values(axes)) {\n const jerk = derivative(values);\n const windowSize = Math.max(5, Math.floor(jerk.length / 4));\n const windowVariances: number[] = [];\n for (let i = 0; i <= jerk.length - windowSize; i += windowSize) {\n windowVariances.push(variance(jerk.slice(i, i + windowSize)));\n }\n features.push(windowVariances.length >= 2 ? variance(windowVariances) : 0);\n }\n\n return features;\n}\n\n/**\n * Extract kinematic features from touch data.\n * Computes velocity and acceleration of touch coordinates,\n * plus pressure and area statistics.\n *\n * Returns: ~36 values (32 base + 4 jitter variance for x, y, pressure, area)\n */\nexport function extractTouchFeatures(samples: TouchSample[]): number[] {\n if (samples.length < 5) return new Array(36).fill(0);\n\n const x = samples.map((s) => s.x);\n const y = samples.map((s) => s.y);\n const pressure = samples.map((s) => s.pressure);\n const area = samples.map((s) => s.width * s.height);\n\n const features: number[] = [];\n\n // X velocity and acceleration\n const vx = derivative(x);\n const accX = derivative(vx);\n features.push(...Object.values(condense(vx)));\n features.push(...Object.values(condense(accX)));\n\n // Y velocity and acceleration\n const vy = derivative(y);\n const accY = derivative(vy);\n features.push(...Object.values(condense(vy)));\n features.push(...Object.values(condense(accY)));\n\n // Pressure statistics\n features.push(...Object.values(condense(pressure)));\n\n // Contact area statistics\n features.push(...Object.values(condense(area)));\n\n // Jerk of touch path\n const jerkX = derivative(accX);\n const jerkY = derivative(accY);\n features.push(...Object.values(condense(jerkX)));\n features.push(...Object.values(condense(jerkY)));\n\n // Jitter variance for touch signals: detects synthetic smoothness\n for (const values of [vx, vy, pressure, area]) {\n const windowSize = Math.max(5, Math.floor(values.length / 4));\n const windowVariances: number[] = [];\n for (let i = 0; i <= values.length - windowSize; i += windowSize) {\n windowVariances.push(variance(values.slice(i, i + windowSize)));\n }\n features.push(windowVariances.length >= 2 ? variance(windowVariances) : 0);\n }\n\n return features;\n}\n\n/** Compute discrete derivative (differences between consecutive values) */\nfunction derivative(values: number[]): number[] {\n const d: number[] = [];\n for (let i = 1; i < values.length; i++) {\n d.push((values[i] ?? 0) - (values[i - 1] ?? 0));\n }\n return d;\n}\n\n/**\n * Extract mouse dynamics features as a desktop replacement for motion sensor data.\n * Captures behavioral patterns from mouse/pointer movement that are user-specific:\n * path curvature, speed patterns, micro-corrections, pause behavior.\n *\n * Returns: 54 values (matches motion feature dimension for consistent SimHash input)\n */\nexport function extractMouseDynamics(samples: TouchSample[]): number[] {\n if (samples.length < 10) return new Array(54).fill(0);\n\n const x = samples.map((s) => s.x);\n const y = samples.map((s) => s.y);\n const pressure = samples.map((s) => s.pressure);\n const area = samples.map((s) => s.width * s.height);\n\n // Velocity\n const vx = derivative(x);\n const vy = derivative(y);\n const speed = vx.map((dx, i) => Math.sqrt(dx * dx + (vy[i] ?? 0) * (vy[i] ?? 0)));\n\n // Acceleration\n const accX = derivative(vx);\n const accY = derivative(vy);\n const acc = accX.map((ax, i) => Math.sqrt(ax * ax + (accY[i] ?? 0) * (accY[i] ?? 0)));\n\n // Jerk (derivative of acceleration)\n const jerkX = derivative(accX);\n const jerkY = derivative(accY);\n const jerk = jerkX.map((jx, i) => Math.sqrt(jx * jx + (jerkY[i] ?? 0) * (jerkY[i] ?? 0)));\n\n // Path curvature: angle change between consecutive movement vectors\n const curvatures: number[] = [];\n for (let i = 1; i < vx.length; i++) {\n const angle1 = Math.atan2(vy[i - 1] ?? 0, vx[i - 1] ?? 0);\n const angle2 = Math.atan2(vy[i] ?? 0, vx[i] ?? 0);\n let diff = angle2 - angle1;\n while (diff > Math.PI) diff -= 2 * Math.PI;\n while (diff < -Math.PI) diff += 2 * Math.PI;\n curvatures.push(Math.abs(diff));\n }\n\n // Movement directions for directional entropy\n const directions = vx.map((dx, i) => Math.atan2(vy[i] ?? 0, dx));\n\n // Micro-corrections: direction reversals\n let reversals = 0;\n for (let i = 2; i < directions.length; i++) {\n const d1 = directions[i - 1]! - directions[i - 2]!;\n const d2 = directions[i]! - directions[i - 1]!;\n if (d1 * d2 < 0) reversals++;\n }\n const reversalRate = directions.length > 2 ? reversals / (directions.length - 2) : 0;\n const reversalMagnitude = curvatures.length > 0\n ? curvatures.reduce((a, b) => a + b, 0) / curvatures.length\n : 0;\n\n // Pause detection: frames where speed is near zero\n const speedThreshold = 0.5;\n const pauseFrames = speed.filter((s) => s < speedThreshold).length;\n const pauseRatio = speed.length > 0 ? pauseFrames / speed.length : 0;\n\n // Path efficiency: straight-line distance / total path length\n const totalPathLength = speed.reduce((a, b) => a + b, 0);\n const straightLine = Math.sqrt(\n (x[x.length - 1]! - x[0]!) ** 2 + (y[y.length - 1]! - y[0]!) ** 2\n );\n const pathEfficiency = totalPathLength > 0 ? straightLine / totalPathLength : 0;\n\n // Movement durations between pauses\n const movementDurations: number[] = [];\n let currentDuration = 0;\n for (const s of speed) {\n if (s >= speedThreshold) {\n currentDuration++;\n } else if (currentDuration > 0) {\n movementDurations.push(currentDuration);\n currentDuration = 0;\n }\n }\n if (currentDuration > 0) movementDurations.push(currentDuration);\n\n // Segment lengths between direction changes\n const segmentLengths: number[] = [];\n let segLen = 0;\n for (let i = 1; i < directions.length; i++) {\n segLen += speed[i] ?? 0;\n const angleDiff = Math.abs(directions[i]! - directions[i - 1]!);\n if (angleDiff > Math.PI / 4) {\n segmentLengths.push(segLen);\n segLen = 0;\n }\n }\n if (segLen > 0) segmentLengths.push(segLen);\n\n // Windowed jitter variance of speed\n const windowSize = Math.max(5, Math.floor(speed.length / 4));\n const windowVariances: number[] = [];\n for (let i = 0; i + windowSize <= speed.length; i += windowSize) {\n const window = speed.slice(i, i + windowSize);\n windowVariances.push(variance(window));\n }\n const speedJitter = windowVariances.length > 1 ? variance(windowVariances) : 0;\n\n // Path length normalized by capture duration\n const duration = samples.length > 1\n ? (samples[samples.length - 1]!.timestamp - samples[0]!.timestamp) / 1000\n : 1;\n const normalizedPathLength = totalPathLength / Math.max(duration, 0.001);\n\n // Angle autocorrelation at lags 1, 2, 3\n const angleAutoCorr: number[] = [];\n for (let lag = 1; lag <= 3; lag++) {\n if (directions.length <= lag) {\n angleAutoCorr.push(0);\n continue;\n }\n const n = directions.length - lag;\n const meanDir = directions.reduce((a, b) => a + b, 0) / directions.length;\n let num = 0;\n let den = 0;\n for (let i = 0; i < n; i++) {\n num += (directions[i]! - meanDir) * (directions[i + lag]! - meanDir);\n den += (directions[i]! - meanDir) ** 2;\n }\n angleAutoCorr.push(den > 0 ? num / den : 0);\n }\n\n // Assemble 54 features\n const curvatureStats = condense(curvatures); // 4\n const dirEntropy = entropy(directions, 16); // 1\n const speedStats = condense(speed); // 4\n const accStats = condense(acc); // 4\n // micro-corrections: reversalRate + reversalMagnitude // 2\n // pauseRatio // 1\n // pathEfficiency // 1\n // speedJitter // 1\n const jerkStats = condense(jerk); // 4\n const vxStats = condense(vx); // 4\n const vyStats = condense(vy); // 4\n const accXStats = condense(accX); // 4\n const accYStats = condense(accY); // 4\n const pressureStats = condense(pressure); // 4\n const moveDurStats = condense(movementDurations); // 4\n const segLenStats = condense(segmentLengths); // 4\n // angleAutoCorr[0..2] // 3\n // normalizedPathLength // 1\n // Total: 4+1+4+4+2+1+1+1+4+4+4+4+4+4+4+4+3+1 = 54\n\n return [\n curvatureStats.mean, curvatureStats.variance, curvatureStats.skewness, curvatureStats.kurtosis,\n dirEntropy,\n speedStats.mean, speedStats.variance, speedStats.skewness, speedStats.kurtosis,\n accStats.mean, accStats.variance, accStats.skewness, accStats.kurtosis,\n reversalRate, reversalMagnitude,\n pauseRatio,\n pathEfficiency,\n speedJitter,\n jerkStats.mean, jerkStats.variance, jerkStats.skewness, jerkStats.kurtosis,\n vxStats.mean, vxStats.variance, vxStats.skewness, vxStats.kurtosis,\n vyStats.mean, vyStats.variance, vyStats.skewness, vyStats.kurtosis,\n accXStats.mean, accXStats.variance, accXStats.skewness, accXStats.kurtosis,\n accYStats.mean, accYStats.variance, accYStats.skewness, accYStats.kurtosis,\n pressureStats.mean, pressureStats.variance, pressureStats.skewness, pressureStats.kurtosis,\n moveDurStats.mean, moveDurStats.variance, moveDurStats.skewness, moveDurStats.kurtosis,\n segLenStats.mean, segLenStats.variance, segLenStats.skewness, segLenStats.kurtosis,\n angleAutoCorr[0] ?? 0, angleAutoCorr[1] ?? 0, angleAutoCorr[2] ?? 0,\n normalizedPathLength,\n ];\n}\n","import { FINGERPRINT_BITS, SIMHASH_SEED } from \"../config\";\nimport { sdkWarn } from \"../log\";\nimport type { TemporalFingerprint } from \"./types\";\n\n// Mulberry32 PRNG: deterministic, fast, good distribution\nfunction mulberry32(seed: number): () => number {\n let state = seed | 0;\n return () => {\n state = (state + 0x6d2b79f5) | 0;\n let t = Math.imul(state ^ (state >>> 15), 1 | state);\n t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;\n return ((t ^ (t >>> 14)) >>> 0) / 4294967296;\n };\n}\n\n// Derive a numeric seed from the protocol seed string\nfunction deriveSeed(seedStr: string): number {\n let hash = 0;\n for (let i = 0; i < seedStr.length; i++) {\n const ch = seedStr.charCodeAt(i);\n hash = ((hash << 5) - hash + ch) | 0;\n }\n return hash;\n}\n\nlet cachedHyperplanes: number[][] | null = null;\nlet cachedDimension = 0;\n\nfunction getHyperplanes(dimension: number): number[][] {\n if (cachedHyperplanes && cachedDimension === dimension) {\n return cachedHyperplanes;\n }\n\n const rng = mulberry32(deriveSeed(SIMHASH_SEED));\n const planes: number[][] = [];\n\n for (let i = 0; i < FINGERPRINT_BITS; i++) {\n const plane: number[] = [];\n for (let j = 0; j < dimension; j++) {\n // Random value in [-1, 1]\n plane.push(rng() * 2 - 1);\n }\n planes.push(plane);\n }\n\n cachedHyperplanes = planes;\n cachedDimension = dimension;\n return planes;\n}\n\n/**\n * Compute a 256-bit SimHash fingerprint from a feature vector.\n * Uses deterministic random hyperplanes seeded from the protocol constant.\n * Similar feature vectors produce fingerprints with low Hamming distance.\n */\nconst EXPECTED_FEATURE_DIMENSION = 134; // 44 speaker + 54 motion/mouse + 36 touch\n\nexport function simhash(features: number[]): TemporalFingerprint {\n if (features.length === 0) {\n return new Array(FINGERPRINT_BITS).fill(0);\n }\n\n if (features.length !== EXPECTED_FEATURE_DIMENSION) {\n sdkWarn(\n `[Entros SDK] Feature vector has ${features.length} dimensions, expected ${EXPECTED_FEATURE_DIMENSION}. ` +\n `Fingerprint quality may be degraded.`\n );\n }\n\n const planes = getHyperplanes(features.length);\n const fingerprint: TemporalFingerprint = [];\n\n for (let i = 0; i < FINGERPRINT_BITS; i++) {\n const plane = planes[i];\n let dot = 0;\n for (let j = 0; j < features.length; j++) {\n dot += (features[j] ?? 0) * (plane?.[j] ?? 0);\n }\n fingerprint.push(dot >= 0 ? 1 : 0);\n }\n\n return fingerprint;\n}\n\n/**\n * Compute Hamming distance between two fingerprints.\n */\nexport function hammingDistance(\n a: TemporalFingerprint,\n b: TemporalFingerprint\n): number {\n let distance = 0;\n for (let i = 0; i < a.length; i++) {\n if (a[i] !== b[i]) distance++;\n }\n return distance;\n}\n","import { BN254_SCALAR_FIELD, FINGERPRINT_BITS } from \"../config\";\nimport type { PackedFingerprint, TBH, TemporalFingerprint } from \"./types\";\n\n// Lazy-initialized Poseidon instance\nlet poseidonInstance: any = null;\n\nasync function getPoseidon(): Promise<any> {\n if (!poseidonInstance) {\n const circomlibjs = await import(\"circomlibjs\");\n poseidonInstance = await (circomlibjs as any).buildPoseidon();\n }\n return poseidonInstance;\n}\n\n/**\n * Pack 256-bit fingerprint into two 128-bit field elements.\n * Little-endian bit ordering within each chunk (matches circuit's Bits2Num).\n */\nexport function packBits(fingerprint: TemporalFingerprint): PackedFingerprint {\n let lo = BigInt(0);\n for (let i = 0; i < 128; i++) {\n if (fingerprint[i] === 1) {\n lo += BigInt(1) << BigInt(i);\n }\n }\n\n let hi = BigInt(0);\n for (let i = 0; i < 128; i++) {\n if (fingerprint[128 + i] === 1) {\n hi += BigInt(1) << BigInt(i);\n }\n }\n\n return { lo, hi };\n}\n\n/**\n * Compute Poseidon commitment: Poseidon(pack_lo, pack_hi, salt).\n * Matches the circuit's CommitmentCheck template exactly.\n */\nexport async function computeCommitment(\n fingerprint: TemporalFingerprint,\n salt: bigint\n): Promise<bigint> {\n const poseidon = await getPoseidon();\n const { lo, hi } = packBits(fingerprint);\n const hash = poseidon([lo, hi, salt]);\n return poseidon.F.toObject(hash) as bigint;\n}\n\n/**\n * Generate a random salt within the BN254 scalar field.\n */\nexport function generateSalt(): bigint {\n const bytes = new Uint8Array(31);\n crypto.getRandomValues(bytes);\n let val = BigInt(0);\n for (let i = 0; i < bytes.length; i++) {\n val = (val << BigInt(8)) + BigInt(bytes[i] ?? 0);\n }\n return val % BN254_SCALAR_FIELD;\n}\n\n/**\n * Convert a BigInt to a 32-byte big-endian Uint8Array.\n */\nexport function bigintToBytes32(n: bigint): Uint8Array {\n const bytes = new Uint8Array(32);\n let val = n;\n for (let i = 31; i >= 0; i--) {\n bytes[i] = Number(val & BigInt(0xff));\n val >>= BigInt(8);\n }\n return bytes;\n}\n\n/**\n * Generate a complete TBH from a fingerprint.\n */\nexport async function generateTBH(\n fingerprint: TemporalFingerprint,\n salt?: bigint\n): Promise<TBH> {\n const s = salt ?? generateSalt();\n const commitment = await computeCommitment(fingerprint, s);\n return {\n fingerprint,\n salt: s,\n commitment,\n commitmentBytes: bigintToBytes32(commitment),\n };\n}\n","import {\n BN254_BASE_FIELD,\n PROOF_A_SIZE,\n PROOF_B_SIZE,\n PROOF_C_SIZE,\n TOTAL_PROOF_SIZE,\n NUM_PUBLIC_INPUTS,\n} from \"../config\";\nimport type { RawProof, SolanaProof } from \"./types\";\n\n/**\n * Convert a decimal string to a 32-byte big-endian Uint8Array.\n */\nexport function toBigEndian32(decStr: string): Uint8Array {\n let n = BigInt(decStr);\n const bytes = new Uint8Array(32);\n for (let i = 31; i >= 0; i--) {\n bytes[i] = Number(n & BigInt(0xff));\n n >>= BigInt(8);\n }\n return bytes;\n}\n\n/**\n * Negate a G1 y-coordinate for groth16-solana proof_a format.\n */\nfunction negateG1Y(yDecStr: string): Uint8Array {\n const y = BigInt(yDecStr);\n const yNeg = (BN254_BASE_FIELD - y) % BN254_BASE_FIELD;\n return toBigEndian32(yNeg.toString());\n}\n\n/**\n * Serialize an snarkjs proof into the 256-byte format groth16-solana expects.\n *\n * proof_a: 64 bytes (x + negated y)\n * proof_b: 128 bytes (G2 with reversed coordinate ordering: c1 before c0)\n * proof_c: 64 bytes (x + y)\n */\nexport function serializeProof(\n proof: RawProof,\n publicSignals: string[]\n): SolanaProof {\n if (publicSignals.length !== NUM_PUBLIC_INPUTS) {\n throw new Error(\n `Expected ${NUM_PUBLIC_INPUTS} public signals, got ${publicSignals.length}`\n );\n }\n\n // proof_a: x (32 bytes) + negated y (32 bytes)\n const a0 = toBigEndian32(proof.pi_a[0]!);\n const a1 = negateG1Y(proof.pi_a[1]!);\n const proofA = new Uint8Array(PROOF_A_SIZE);\n proofA.set(a0, 0);\n proofA.set(a1, 32);\n\n // proof_b: G2 reversed coordinate ordering\n const b00 = toBigEndian32(proof.pi_b[0]![1]!); // c1 first\n const b01 = toBigEndian32(proof.pi_b[0]![0]!); // c0 second\n const b10 = toBigEndian32(proof.pi_b[1]![1]!);\n const b11 = toBigEndian32(proof.pi_b[1]![0]!);\n const proofB = new Uint8Array(PROOF_B_SIZE);\n proofB.set(b00, 0);\n proofB.set(b01, 32);\n proofB.set(b10, 64);\n proofB.set(b11, 96);\n\n // proof_c: x + y (no negation)\n const c0 = toBigEndian32(proof.pi_c[0]!);\n const c1 = toBigEndian32(proof.pi_c[1]!);\n const proofC = new Uint8Array(PROOF_C_SIZE);\n proofC.set(c0, 0);\n proofC.set(c1, 32);\n\n // Combine into single 256-byte blob\n const proofBytes = new Uint8Array(TOTAL_PROOF_SIZE);\n proofBytes.set(proofA, 0);\n proofBytes.set(proofB, PROOF_A_SIZE);\n proofBytes.set(proofC, PROOF_A_SIZE + PROOF_B_SIZE);\n\n // Public inputs as 32-byte big-endian arrays\n const publicInputs = publicSignals.map((s) => toBigEndian32(s));\n\n return { proofBytes, publicInputs };\n}\n","import type { TBH } from \"../hashing/types\";\nimport type { CircuitInput, ProofResult, SolanaProof } from \"./types\";\nimport { serializeProof } from \"./serializer\";\nimport { DEFAULT_THRESHOLD, DEFAULT_MIN_DISTANCE } from \"../config\";\n\n// Use dynamic import for snarkjs (it's a CJS module)\nlet snarkjsModule: any = null;\n\nasync function getSnarkjs(): Promise<any> {\n if (!snarkjsModule) {\n snarkjsModule = await import(\"snarkjs\");\n }\n return snarkjsModule;\n}\n\n/**\n * Prepare circuit input from current and previous TBH data.\n */\nexport function prepareCircuitInput(\n current: TBH,\n previous: TBH,\n threshold: number = DEFAULT_THRESHOLD,\n minDistance: number = DEFAULT_MIN_DISTANCE\n): CircuitInput {\n return {\n ft_new: current.fingerprint,\n ft_prev: previous.fingerprint,\n salt_new: current.salt.toString(),\n salt_prev: previous.salt.toString(),\n commitment_new: current.commitment.toString(),\n commitment_prev: previous.commitment.toString(),\n threshold: threshold.toString(),\n min_distance: minDistance.toString(),\n };\n}\n\n/**\n * Generate a Groth16 proof for the Hamming distance circuit.\n *\n * @param input - Circuit input (fingerprints, salts, commitments, threshold)\n * @param wasmPath - Path or URL to entros_hamming.wasm\n * @param zkeyPath - Path or URL to entros_hamming_final.zkey\n */\nexport async function generateProof(\n input: CircuitInput,\n wasmPath: string,\n zkeyPath: string\n): Promise<ProofResult> {\n const snarkjs = await getSnarkjs();\n const { proof, publicSignals } = await snarkjs.groth16.fullProve(\n input,\n wasmPath,\n zkeyPath\n );\n return { proof, publicSignals };\n}\n\n/**\n * Generate a proof and serialize it for Solana submission.\n */\nexport async function generateSolanaProof(\n current: TBH,\n previous: TBH,\n wasmPath: string,\n zkeyPath: string,\n threshold?: number\n): Promise<SolanaProof> {\n const input = prepareCircuitInput(current, previous, threshold);\n const { proof, publicSignals } = await generateProof(\n input,\n wasmPath,\n zkeyPath\n );\n return serializeProof(proof, publicSignals);\n}\n\n/**\n * Verify a proof locally using snarkjs (for debugging/testing).\n * Caller is responsible for loading the verification key.\n */\nexport async function verifyProofLocally(\n proof: any,\n publicSignals: string[],\n vkey: Record<string, unknown>\n): Promise<boolean> {\n const snarkjs = await getSnarkjs();\n return snarkjs.groth16.verify(vkey, publicSignals, proof);\n}\n","/* eslint-disable @typescript-eslint/no-explicit-any */\n// Anchor program interactions use runtime IDL fetching, requiring dynamic typing.\nimport type { SolanaProof } from \"../proof/types\";\nimport type { SubmissionResult } from \"./types\";\nimport { PROGRAM_IDS } from \"../config\";\nimport { sdkLog, sdkWarn } from \"../log\";\n\n/**\n * Best-effort SAS attestation request. POSTs to the executor's `/attest`\n * endpoint with the wallet's public key, an optional server-issued challenge\n * nonce, and an `Entros-ATTEST:{wallet}:{timestamp}` ownership signature.\n *\n * Returns the attestation tx signature on success, `undefined` on any\n * failure (attestation is non-fatal — the on-chain tx has already confirmed\n * by the time this is called).\n */\nasync function requestSasAttestation(\n wallet: any,\n walletAddress: string,\n relayerUrl: string,\n relayerApiKey: string | undefined,\n serverNonce: number[] | undefined,\n): Promise<string | undefined> {\n try {\n const attestHeaders: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n };\n if (relayerApiKey) {\n attestHeaders[\"X-API-Key\"] = relayerApiKey;\n }\n\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), 15_000);\n\n const baseUrl = new URL(relayerUrl);\n const attestUrl = `${baseUrl.origin}/attest`;\n\n const attestBody: Record<string, unknown> = { wallet_address: walletAddress };\n if (serverNonce) attestBody.nonce = serverNonce;\n\n if (wallet?.signMessage) {\n try {\n const timestamp = Math.floor(Date.now() / 1000);\n const attestMessage = `Entros-ATTEST:${walletAddress}:${timestamp}`;\n const messageBytes = new TextEncoder().encode(attestMessage);\n const sigBytes: Uint8Array = await wallet.signMessage(messageBytes);\n const sigHex = Array.from(sigBytes)\n .map((b) => b.toString(16).padStart(2, \"0\"))\n .join(\"\");\n attestBody.signature = sigHex;\n attestBody.message = attestMessage;\n } catch {\n sdkWarn(\"Wallet signMessage failed, skipping ownership proof\");\n }\n }\n\n const attestRes = await fetch(attestUrl, {\n method: \"POST\",\n headers: attestHeaders,\n body: JSON.stringify(attestBody),\n signal: controller.signal,\n });\n\n clearTimeout(timer);\n\n if (attestRes.ok) {\n const attestData = (await attestRes.json()) as {\n success?: boolean;\n attestation_tx?: string;\n };\n if (attestData.success && attestData.attestation_tx) {\n return attestData.attestation_tx;\n }\n }\n } catch {\n // Attestation is best-effort; on-chain tx already confirmed.\n }\n return undefined;\n}\n\n/**\n * Submit a proof on-chain via a connected wallet (wallet-connected mode).\n * Uses Anchor SDK to construct and send the transaction.\n *\n * Flow for re-verification: single batched transaction containing\n * ComputeBudget → create_challenge → verify_proof → update_anchor\n * Flow for first verification: mint_anchor (already 1 transaction)\n */\nexport async function submitViaWallet(\n proof: SolanaProof,\n commitment: Uint8Array,\n options: {\n wallet: any;\n connection: any;\n isFirstVerification: boolean;\n relayerUrl?: string;\n relayerApiKey?: string;\n }\n): Promise<SubmissionResult> {\n try {\n const anchor = await import(\"@coral-xyz/anchor\");\n const { PublicKey, SystemProgram, Transaction, ComputeBudgetProgram } =\n await import(\"@solana/web3.js\");\n\n const provider = new anchor.AnchorProvider(\n options.connection,\n options.wallet,\n { commitment: \"confirmed\" }\n );\n\n const anchorProgramId = new PublicKey(PROGRAM_IDS.entrosAnchor);\n\n let txSig: string | undefined;\n let serverNonce = false;\n let nonce: number[] = [];\n\n if (!options.isFirstVerification) {\n // Re-verification: batch create_challenge + verify_proof + update_anchor\n // into a single transaction (1 wallet prompt instead of 3)\n const verifierProgramId = new PublicKey(PROGRAM_IDS.entrosVerifier);\n\n // Fetch server-generated nonce (prevents pre-computation attacks).\n // Falls back to client-generated nonce if executor is unreachable.\n if (options.relayerUrl) {\n try {\n const baseUrl = new URL(options.relayerUrl);\n const challengeHeaders: Record<string, string> = {};\n if (options.relayerApiKey) {\n challengeHeaders[\"X-API-Key\"] = options.relayerApiKey;\n }\n const challengeController = new AbortController();\n const challengeTimer = setTimeout(() => challengeController.abort(), 5_000);\n const challengeRes = await fetch(\n `${baseUrl.origin}/challenge?wallet=${provider.wallet.publicKey.toBase58()}`,\n { headers: challengeHeaders, signal: challengeController.signal }\n );\n clearTimeout(challengeTimer);\n if (challengeRes.ok) {\n const challengeData = (await challengeRes.json()) as { nonce?: number[] };\n if (challengeData.nonce && challengeData.nonce.length === 32) {\n nonce = challengeData.nonce;\n serverNonce = true;\n sdkLog(\"Using server-generated challenge nonce\");\n } else {\n nonce = Array.from(crypto.getRandomValues(new Uint8Array(32)));\n sdkWarn(\"Server returned invalid nonce, using client-generated\");\n }\n } else {\n nonce = Array.from(crypto.getRandomValues(new Uint8Array(32)));\n sdkWarn(\"Challenge endpoint returned error, using client-generated nonce\");\n }\n } catch {\n nonce = Array.from(crypto.getRandomValues(new Uint8Array(32)));\n sdkWarn(\"Challenge fetch failed, using client-generated nonce\");\n }\n } else {\n nonce = Array.from(crypto.getRandomValues(new Uint8Array(32)));\n }\n\n const [challengePda] = PublicKey.findProgramAddressSync(\n [\n new TextEncoder().encode(\"challenge\"),\n provider.wallet.publicKey.toBuffer(),\n new Uint8Array(nonce),\n ],\n verifierProgramId\n );\n\n const [verificationPda] = PublicKey.findProgramAddressSync(\n [\n new TextEncoder().encode(\"verification\"),\n provider.wallet.publicKey.toBuffer(),\n new Uint8Array(nonce),\n ],\n verifierProgramId\n );\n\n const [identityPda] = PublicKey.findProgramAddressSync(\n [new TextEncoder().encode(\"identity\"), provider.wallet.publicKey.toBuffer()],\n anchorProgramId\n );\n\n const registryProgramId = new PublicKey(PROGRAM_IDS.entrosRegistry);\n const [protocolConfigPda] = PublicKey.findProgramAddressSync(\n [new TextEncoder().encode(\"protocol_config\")],\n registryProgramId\n );\n const [treasuryPda] = PublicKey.findProgramAddressSync(\n [new TextEncoder().encode(\"protocol_treasury\")],\n registryProgramId\n );\n\n // Fetch both IDLs\n const [verifierIdl, anchorIdl] = await Promise.all([\n anchor.Program.fetchIdl(verifierProgramId, provider),\n anchor.Program.fetchIdl(anchorProgramId, provider),\n ]);\n if (!verifierIdl) {\n return {\n success: false,\n error: `Failed to fetch entros-verifier IDL from Solana (program ${PROGRAM_IDS.entrosVerifier}). Check your RPC endpoint is reachable and on the correct cluster.`,\n };\n }\n if (!anchorIdl) {\n return {\n success: false,\n error: `Failed to fetch entros-anchor IDL from Solana (program ${PROGRAM_IDS.entrosAnchor}). Check your RPC endpoint is reachable and on the correct cluster.`,\n };\n }\n\n const verifierProgram: any = new anchor.Program(verifierIdl, provider);\n const anchorProgram: any = new anchor.Program(anchorIdl, provider);\n const { Buffer: SolBuffer } = await import(\"buffer\");\n\n // Build all three instructions without sending\n const createChallengeIx = await verifierProgram.methods\n .createChallenge(nonce)\n .accounts({\n challenger: provider.wallet.publicKey,\n challenge: challengePda,\n systemProgram: SystemProgram.programId,\n })\n .instruction();\n\n // Anchor 0.32.1 uses buffer-layout v1.2 which requires Node.js Buffer\n // (not Uint8Array) for Blob.encode on Vec<u8> fields.\n const verifyProofIx = await verifierProgram.methods\n .verifyProof(\n SolBuffer.from(proof.proofBytes),\n proof.publicInputs.map((pi) => SolBuffer.from(pi)),\n nonce\n )\n .accounts({\n verifier: provider.wallet.publicKey,\n challenge: challengePda,\n verificationResult: verificationPda,\n systemProgram: SystemProgram.programId,\n })\n .instruction();\n\n // updateAnchor post-2026-04-20 binding patch takes the verification\n // nonce as a second arg and requires the VerificationResult PDA as an\n // account. Without these, the instruction would accept any commitment\n // with no biometric proof — see protocol-core AUDIT.md for details.\n const updateAnchorIx = await anchorProgram.methods\n .updateAnchor(Array.from(commitment), nonce)\n .accounts({\n authority: provider.wallet.publicKey,\n identityState: identityPda,\n verificationResult: verificationPda,\n protocolConfig: protocolConfigPda,\n treasury: treasuryPda,\n systemProgram: SystemProgram.programId,\n })\n .instruction();\n\n // Batch: compute budget + 3 program instructions → 1 wallet prompt\n // Total CU ~205K; request 250K to exceed the 200K default limit.\n const tx = new Transaction();\n tx.add(ComputeBudgetProgram.setComputeUnitLimit({ units: 250_000 }));\n tx.add(createChallengeIx);\n tx.add(verifyProofIx);\n tx.add(updateAnchorIx);\n\n tx.feePayer = provider.wallet.publicKey;\n tx.recentBlockhash = (\n await options.connection.getLatestBlockhash(\"confirmed\")\n ).blockhash;\n\n txSig = await options.wallet.sendTransaction(tx, options.connection, {\n skipPreflight: true,\n });\n await options.connection.confirmTransaction(txSig, \"confirmed\");\n } else {\n // First verification: mint anchor (already 1 transaction, no batching needed)\n const anchorIdl = await anchor.Program.fetchIdl(anchorProgramId, provider);\n if (!anchorIdl) {\n return {\n success: false,\n error: `Failed to fetch entros-anchor IDL from Solana (program ${PROGRAM_IDS.entrosAnchor}). Check your RPC endpoint is reachable and on the correct cluster.`,\n };\n }\n\n const anchorProgram: any = new anchor.Program(anchorIdl, provider);\n\n const [identityPda] = PublicKey.findProgramAddressSync(\n [new TextEncoder().encode(\"identity\"), provider.wallet.publicKey.toBuffer()],\n anchorProgramId\n );\n const [mintPda] = PublicKey.findProgramAddressSync(\n [new TextEncoder().encode(\"mint\"), provider.wallet.publicKey.toBuffer()],\n anchorProgramId\n );\n const [mintAuthority] = PublicKey.findProgramAddressSync(\n [new TextEncoder().encode(\"mint_authority\")],\n anchorProgramId\n );\n\n const registryProgramId = new PublicKey(PROGRAM_IDS.entrosRegistry);\n const [protocolConfigPda] = PublicKey.findProgramAddressSync(\n [new TextEncoder().encode(\"protocol_config\")],\n registryProgramId\n );\n const [treasuryPda] = PublicKey.findProgramAddressSync(\n [new TextEncoder().encode(\"protocol_treasury\")],\n registryProgramId\n );\n\n const TOKEN_2022_PROGRAM_ID = new PublicKey(\n \"TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb\"\n );\n\n const { getAssociatedTokenAddressSync } = await import(\"@solana/spl-token\");\n const ata = getAssociatedTokenAddressSync(\n mintPda,\n provider.wallet.publicKey,\n false,\n TOKEN_2022_PROGRAM_ID\n );\n\n await anchorProgram.methods\n .mintAnchor(Array.from(commitment))\n .accounts({\n user: provider.wallet.publicKey,\n identityState: identityPda,\n mint: mintPda,\n mintAuthority,\n tokenAccount: ata,\n associatedTokenProgram: new PublicKey(\n \"ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL\"\n ),\n tokenProgram: TOKEN_2022_PROGRAM_ID,\n systemProgram: SystemProgram.programId,\n protocolConfig: protocolConfigPda,\n treasury: treasuryPda,\n })\n .rpc();\n }\n\n const attestationTx = options.relayerUrl\n ? await requestSasAttestation(\n options.wallet,\n provider.wallet.publicKey.toBase58(),\n options.relayerUrl,\n options.relayerApiKey,\n serverNonce ? nonce : undefined,\n )\n : undefined;\n\n return { success: true, txSignature: txSig, attestationTx };\n } catch (err: any) {\n return { success: false, error: err.message ?? String(err) };\n }\n}\n\n/**\n * Submit a baseline reset on-chain via a connected wallet.\n *\n * Fires when the on-chain IdentityState exists for the wallet but the\n * device's local encrypted fingerprint envelope is unrecoverable. The\n * ZK Hamming proof used by `update_anchor` needs the previous\n * fingerprint's bits as a private witness; without them, re-verification\n * is blocked. `reset_identity_state` rotates `current_commitment`\n * in place, zeroes verification_count / trust_score / recent_timestamps,\n * and sets a 7-day cooldown before the next reset.\n *\n * Transaction shape: single instruction (no challenge / verify_proof /\n * ZK proof required). Humanness evidence comes from the Tier 1\n * validation pipeline invoked at the /attest step (same as mint and\n * update).\n */\nexport async function submitResetViaWallet(\n commitment: Uint8Array,\n options: {\n wallet: any;\n connection: any;\n relayerUrl?: string;\n relayerApiKey?: string;\n }\n): Promise<SubmissionResult> {\n try {\n const anchor = await import(\"@coral-xyz/anchor\");\n const { PublicKey, SystemProgram, Transaction, ComputeBudgetProgram } =\n await import(\"@solana/web3.js\");\n\n const provider = new anchor.AnchorProvider(\n options.connection,\n options.wallet,\n { commitment: \"confirmed\" }\n );\n\n const anchorProgramId = new PublicKey(PROGRAM_IDS.entrosAnchor);\n const registryProgramId = new PublicKey(PROGRAM_IDS.entrosRegistry);\n\n const [identityPda] = PublicKey.findProgramAddressSync(\n [new TextEncoder().encode(\"identity\"), provider.wallet.publicKey.toBuffer()],\n anchorProgramId\n );\n const [protocolConfigPda] = PublicKey.findProgramAddressSync(\n [new TextEncoder().encode(\"protocol_config\")],\n registryProgramId\n );\n const [treasuryPda] = PublicKey.findProgramAddressSync(\n [new TextEncoder().encode(\"protocol_treasury\")],\n registryProgramId\n );\n\n const anchorIdl = await anchor.Program.fetchIdl(anchorProgramId, provider);\n if (!anchorIdl) {\n return {\n success: false,\n error: `Failed to fetch entros-anchor IDL from Solana (program ${PROGRAM_IDS.entrosAnchor}). Check your RPC endpoint is reachable and on the correct cluster.`,\n };\n }\n const anchorProgram: any = new anchor.Program(anchorIdl, provider);\n\n const resetIx = await anchorProgram.methods\n .resetIdentityState(Array.from(commitment))\n .accounts({\n authority: provider.wallet.publicKey,\n identityState: identityPda,\n protocolConfig: protocolConfigPda,\n treasury: treasuryPda,\n systemProgram: SystemProgram.programId,\n })\n .instruction();\n\n // Reset does no ZK verification; budget is well under the 200K default.\n // Keep an explicit limit for determinism and to match batched-tx ergonomics.\n const tx = new Transaction();\n tx.add(ComputeBudgetProgram.setComputeUnitLimit({ units: 150_000 }));\n tx.add(resetIx);\n\n tx.feePayer = provider.wallet.publicKey;\n tx.recentBlockhash = (\n await options.connection.getLatestBlockhash(\"confirmed\")\n ).blockhash;\n\n const txSig: string = await options.wallet.sendTransaction(\n tx,\n options.connection,\n { skipPreflight: true }\n );\n await options.connection.confirmTransaction(txSig, \"confirmed\");\n\n // Request a fresh SAS attestation. The executor's /attest handler\n // closes any prior attestation for this wallet and creates a new one\n // bound to the current commitment.\n const attestationTx = options.relayerUrl\n ? await requestSasAttestation(\n options.wallet,\n provider.wallet.publicKey.toBase58(),\n options.relayerUrl,\n options.relayerApiKey,\n undefined,\n )\n : undefined;\n\n return { success: true, txSignature: txSig, attestationTx };\n } catch (err: any) {\n return { success: false, error: err.message ?? String(err) };\n }\n}\n","import type { SolanaProof } from \"../proof/types\";\nimport type { SubmissionResult } from \"./types\";\n\nconst RELAYER_TIMEOUT_MS = 30_000;\n\n/**\n * Submit a proof via the Entros relayer API (walletless mode).\n * The relayer submits the on-chain transaction using the integrator's funded account.\n * The user needs no wallet, no SOL, no crypto knowledge.\n */\nexport async function submitViaRelayer(\n proof: SolanaProof,\n commitment: Uint8Array,\n options: {\n relayerUrl: string;\n apiKey?: string;\n isFirstVerification: boolean;\n }\n): Promise<SubmissionResult> {\n try {\n const body = {\n proof_bytes: Array.from(proof.proofBytes),\n public_inputs: proof.publicInputs.map((pi) => Array.from(pi)),\n commitment: Array.from(commitment),\n is_first_verification: options.isFirstVerification,\n };\n\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n };\n\n if (options.apiKey) {\n headers[\"X-API-Key\"] = options.apiKey;\n }\n\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), RELAYER_TIMEOUT_MS);\n\n const response = await fetch(options.relayerUrl, {\n method: \"POST\",\n headers,\n body: JSON.stringify(body),\n signal: controller.signal,\n });\n\n clearTimeout(timer);\n\n if (!response.ok) {\n const errorText = await response.text();\n return {\n success: false,\n error: `Relayer returned HTTP ${response.status} from ${options.relayerUrl}: ${errorText}. Check relayerUrl and apiKey in PulseConfig.`,\n };\n }\n\n const result = (await response.json()) as {\n success?: boolean;\n tx_signature?: string;\n verified?: boolean;\n registered?: boolean;\n };\n\n if (result.success !== true) {\n return {\n success: false,\n error: \"Relayer accepted the request but reported failure. Typically means proof verification failed on-chain — check the relayer logs.\",\n };\n }\n\n return {\n success: true,\n txSignature: result.tx_signature,\n };\n } catch (err: any) {\n if (err.name === \"AbortError\") {\n return {\n success: false,\n error: `Relayer request timed out after ${RELAYER_TIMEOUT_MS / 1000}s. Check network connectivity and relayerUrl reachability.`,\n };\n }\n return { success: false, error: err.message ?? String(err) };\n }\n}\n","/**\n * Client-side encryption for stored verification data.\n *\n * Uses AES-256-GCM via Web Crypto API with a non-extractable CryptoKey\n * stored in IndexedDB. The key cannot be exported or exfiltrated — only\n * the browser's internal crypto engine can use it for encrypt/decrypt\n * on the same origin.\n */\n\nconst DB_NAME = \"entros-protocol-keystore\";\n// Bumped to 2 on 2026-04-20 to force `onupgradeneeded` on pre-existing DBs\n// whose `keys` object store went missing (observed in the wild — browser\n// interrupted an earlier upgrade or a concurrent-tab race left the DB\n// partially initialized). Existing users with a healthy v1 DB upgrade\n// cleanly — the handler below is idempotent.\nconst DB_VERSION = 2;\nconst STORE_NAME = \"keys\";\nconst KEY_ID = \"encryption-key\";\n\n// --- Capability detection ---\n\nexport function hasCryptoSupport(): boolean {\n return (\n typeof globalThis.crypto?.subtle !== \"undefined\" &&\n typeof globalThis.indexedDB !== \"undefined\"\n );\n}\n\n// --- IndexedDB key management ---\n\nfunction openAtVersion(version: number): Promise<IDBDatabase> {\n return new Promise((resolve, reject) => {\n const request = indexedDB.open(DB_NAME, version);\n request.onupgradeneeded = () => {\n const db = request.result;\n // Idempotent: only create if missing. Preserves existing key+data on\n // version bumps that don't require a schema change.\n if (!db.objectStoreNames.contains(STORE_NAME)) {\n db.createObjectStore(STORE_NAME);\n }\n };\n request.onsuccess = () => resolve(request.result);\n request.onerror = () => reject(request.error);\n });\n}\n\nasync function openKeyStore(): Promise<IDBDatabase> {\n const db = await openAtVersion(DB_VERSION);\n // Defensive post-open check: if the DB somehow arrives at the current\n // version without the required store (observed in the wild — browser\n // interrupted an earlier upgrade, concurrent-tab race, manual DevTools\n // deletion), close and reopen at version+1 to force `onupgradeneeded`\n // to fire and recreate the store. Without this, every subsequent\n // `transaction(STORE_NAME, ...)` would throw `NotFoundError` forever.\n if (!db.objectStoreNames.contains(STORE_NAME)) {\n const nextVersion = db.version + 1;\n db.close();\n return openAtVersion(nextVersion);\n }\n return db;\n}\n\nfunction getKey(db: IDBDatabase): Promise<CryptoKey | null> {\n return new Promise((resolve, reject) => {\n const tx = db.transaction(STORE_NAME, \"readonly\");\n const store = tx.objectStore(STORE_NAME);\n const request = store.get(KEY_ID);\n request.onsuccess = () => resolve(request.result ?? null);\n request.onerror = () => reject(request.error);\n });\n}\n\nfunction putKey(db: IDBDatabase, key: CryptoKey): Promise<void> {\n return new Promise((resolve, reject) => {\n const tx = db.transaction(STORE_NAME, \"readwrite\");\n const store = tx.objectStore(STORE_NAME);\n const request = store.put(key, KEY_ID);\n request.onsuccess = () => resolve();\n request.onerror = () => reject(request.error);\n });\n}\n\nexport async function getOrCreateEncryptionKey(): Promise<CryptoKey | null> {\n try {\n const db = await openKeyStore();\n try {\n const existing = await getKey(db);\n if (existing) return existing;\n\n const key = await crypto.subtle.generateKey(\n { name: \"AES-GCM\", length: 256 },\n false, // non-extractable\n [\"encrypt\", \"decrypt\"]\n );\n\n await putKey(db, key);\n return key;\n } finally {\n db.close();\n }\n } catch {\n return null;\n }\n}\n\n// --- AES-256-GCM encrypt / decrypt ---\n\nexport async function encrypt(\n plaintext: string,\n key: CryptoKey\n): Promise<{ iv: string; ct: string }> {\n const iv = crypto.getRandomValues(new Uint8Array(12));\n const encoded = new TextEncoder().encode(plaintext);\n const ciphertext = await crypto.subtle.encrypt(\n { name: \"AES-GCM\", iv },\n key,\n encoded\n );\n return {\n iv: toBase64(iv),\n ct: toBase64(new Uint8Array(ciphertext)),\n };\n}\n\nexport async function decrypt(\n iv: string,\n ct: string,\n key: CryptoKey\n): Promise<string> {\n const ivBytes = fromBase64(iv);\n const ctBytes = fromBase64(ct);\n const plaintext = await crypto.subtle.decrypt(\n { name: \"AES-GCM\", iv: ivBytes.buffer as ArrayBuffer },\n key,\n ctBytes.buffer as ArrayBuffer\n );\n return new TextDecoder().decode(plaintext);\n}\n\n// --- Base64 helpers (browser-only, no deps) ---\n\nfunction toBase64(bytes: Uint8Array): string {\n let binary = \"\";\n for (let i = 0; i < bytes.length; i++) {\n binary += String.fromCharCode(bytes[i]!);\n }\n return btoa(binary);\n}\n\nfunction fromBase64(b64: string): Uint8Array {\n const binary = atob(b64);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) {\n bytes[i] = binary.charCodeAt(i);\n }\n return bytes;\n}\n","import { PROGRAM_IDS } from \"../config\";\nimport { sdkWarn } from \"../log\";\nimport type { IdentityState, StoredVerificationData } from \"./types\";\nimport {\n hasCryptoSupport,\n getOrCreateEncryptionKey,\n encrypt,\n decrypt,\n} from \"./crypto\";\n\nconst STORAGE_KEY = \"entros-protocol-verification-data\";\nconst ENCRYPTED_VERSION = 2;\n\n// In-memory fallback for environments without localStorage (Node.js, SSR,\n// private browsing on some browsers). Data is lost on page reload — users\n// in private browsing mode must re-enroll on each session.\nlet inMemoryStore: StoredVerificationData | null = null;\n\n// --- Envelope detection ---\n\ninterface EncryptedEnvelope {\n v: 2;\n iv: string;\n ct: string;\n}\n\nfunction isEncryptedEnvelope(obj: unknown): obj is EncryptedEnvelope {\n return (\n typeof obj === \"object\" &&\n obj !== null &&\n (obj as Record<string, unknown>).v === ENCRYPTED_VERSION &&\n typeof (obj as Record<string, unknown>).iv === \"string\" &&\n typeof (obj as Record<string, unknown>).ct === \"string\"\n );\n}\n\nfunction isPlaintextData(obj: unknown): obj is StoredVerificationData {\n return (\n typeof obj === \"object\" &&\n obj !== null &&\n Array.isArray((obj as Record<string, unknown>).fingerprint)\n );\n}\n\n// --- Public API ---\n\n/**\n * Fetch identity state from the on-chain IdentityState PDA.\n */\nexport async function fetchIdentityState(\n walletPubkey: string,\n connection: any\n): Promise<IdentityState | null> {\n try {\n const { PublicKey } = await import(\"@solana/web3.js\");\n const anchor = await import(\"@coral-xyz/anchor\");\n\n const programId = new PublicKey(PROGRAM_IDS.entrosAnchor);\n const [identityPda] = PublicKey.findProgramAddressSync(\n [new TextEncoder().encode(\"identity\"), new PublicKey(walletPubkey).toBuffer()],\n programId\n );\n\n const accountInfo = await connection.getAccountInfo(identityPda);\n if (!accountInfo) return null;\n\n const idl = await anchor.Program.fetchIdl(programId, {\n connection,\n } as any);\n if (!idl) return null;\n\n const coder = new anchor.BorshAccountsCoder(idl);\n const decoded = coder.decode(\"identityState\", accountInfo.data);\n\n return {\n owner: decoded.owner.toBase58(),\n creationTimestamp: decoded.creationTimestamp.toNumber(),\n lastVerificationTimestamp: decoded.lastVerificationTimestamp.toNumber(),\n verificationCount: decoded.verificationCount,\n trustScore: decoded.trustScore,\n currentCommitment: new Uint8Array(decoded.currentCommitment),\n mint: decoded.mint.toBase58(),\n // Anchor's Borsh coder returns the raw BN for i64 fields; .toNumber()\n // is safe here because Unix timestamps fit in Number.MAX_SAFE_INTEGER\n // until year 275760.\n lastResetTimestamp: decoded.lastResetTimestamp?.toNumber?.() ?? 0,\n };\n } catch {\n return null;\n }\n}\n\n/**\n * Store verification data locally for re-verification.\n * Encrypts with AES-256-GCM when Web Crypto is available.\n * Falls back to plaintext with a warning otherwise.\n */\nexport async function storeVerificationData(data: StoredVerificationData): Promise<void> {\n try {\n if (!hasCryptoSupport()) {\n sdkWarn(\"[Entros SDK] Crypto unavailable — verification data stored unencrypted\");\n localStorage.setItem(STORAGE_KEY, JSON.stringify(data));\n return;\n }\n\n const key = await getOrCreateEncryptionKey();\n if (!key) {\n sdkWarn(\"[Entros SDK] Encryption key unavailable — storing unencrypted\");\n localStorage.setItem(STORAGE_KEY, JSON.stringify(data));\n return;\n }\n\n const { iv, ct } = await encrypt(JSON.stringify(data), key);\n const envelope: EncryptedEnvelope = { v: ENCRYPTED_VERSION, iv, ct };\n localStorage.setItem(STORAGE_KEY, JSON.stringify(envelope));\n } catch {\n inMemoryStore = data;\n }\n}\n\n/**\n * Load previously stored verification data.\n * Decrypts if encrypted, migrates plaintext to encrypted on first load.\n */\nexport async function loadVerificationData(): Promise<StoredVerificationData | null> {\n try {\n const raw = localStorage.getItem(STORAGE_KEY);\n if (!raw) return inMemoryStore;\n\n const parsed: unknown = JSON.parse(raw);\n\n // Encrypted envelope\n if (isEncryptedEnvelope(parsed)) {\n if (!hasCryptoSupport()) {\n sdkWarn(\"[Entros SDK] Encrypted data found but crypto unavailable\");\n return inMemoryStore;\n }\n const key = await getOrCreateEncryptionKey();\n if (!key) {\n // Preserve the envelope. If the IndexedDB key is temporarily\n // unavailable (transient storage issue, permission prompt denied\n // once, etc.), a future load with a recovered key can still decrypt.\n // Silently deleting was the previous behavior and caused permanent\n // baseline loss for wallet-connected users whose IndexedDB got\n // corrupted into a post-patch recoverable state (DB_VERSION bump\n // in crypto.ts now self-heals the store, but the envelope must\n // survive the broken window to benefit).\n sdkWarn(\n \"[Entros SDK] Encryption key unavailable — keeping envelope for recovery. \" +\n \"If this persists across reloads, check IndexedDB state via DevTools.\"\n );\n return inMemoryStore;\n }\n try {\n const plaintext = await decrypt(parsed.iv, parsed.ct, key);\n return JSON.parse(plaintext) as StoredVerificationData;\n } catch {\n // Same rationale as above: decrypt failure is often transient\n // (IndexedDB hiccup, key re-derivation edge case). Preserve the\n // envelope so the next successful decrypt can recover the data.\n // If the data truly cannot be decrypted by this device, a user-\n // triggered baseline reset (or manual \"Clear site data\") is the\n // right path — not a silent delete on the SDK's initiative.\n sdkWarn(\n \"[Entros SDK] Decryption failed — keeping envelope for recovery. \" +\n \"Trigger a baseline reset or Clear site data if this is persistent.\"\n );\n return inMemoryStore;\n }\n }\n\n // Plaintext legacy data — migrate to encrypted\n if (isPlaintextData(parsed)) {\n await storeVerificationData(parsed);\n return parsed;\n }\n\n // Unrecognized format\n sdkWarn(\"[Entros SDK] Unrecognized verification data format — clearing\");\n localStorage.removeItem(STORAGE_KEY);\n return inMemoryStore;\n } catch {\n return inMemoryStore;\n }\n}\n","import type { PulseConfig } from \"./config\";\nimport { DEFAULT_THRESHOLD, DEFAULT_CAPTURE_MS, PROGRAM_IDS } from \"./config\";\nimport { setDebug, sdkLog, sdkWarn } from \"./log\";\nimport type { SensorData, AudioCapture, MotionSample, TouchSample, StageState } from \"./sensor/types\";\nimport type { TBH } from \"./hashing/types\";\nimport type { SolanaProof } from \"./proof/types\";\nimport type { VerificationResult } from \"./submit/types\";\nimport type { StoredVerificationData } from \"./identity/types\";\n\nimport { captureAudio } from \"./sensor/audio\";\nimport { encodeAudioAsBase64 } from \"./sensor/encode\";\nimport { captureMotion, requestMotionPermission } from \"./sensor/motion\";\nimport { captureTouch } from \"./sensor/touch\";\nimport { extractSpeakerFeaturesDetailed, SPEAKER_FEATURE_COUNT } from \"./extraction/speaker\";\nimport {\n extractMotionFeatures,\n extractTouchFeatures,\n extractMouseDynamics,\n extractAccelerationMagnitude,\n} from \"./extraction/kinematic\";\nimport { fuseFeatures, fuseRawFeatures } from \"./extraction/statistics\";\nimport { simhash, hammingDistance } from \"./hashing/simhash\";\nimport { generateTBH, bigintToBytes32 } from \"./hashing/poseidon\";\nimport { prepareCircuitInput, generateProof } from \"./proof/prover\";\nimport { serializeProof } from \"./proof/serializer\";\nimport { submitViaWallet, submitResetViaWallet } from \"./submit/wallet\";\nimport { submitViaRelayer } from \"./submit/relayer\";\nimport {\n storeVerificationData,\n loadVerificationData,\n} from \"./identity/anchor\";\n\n// Build-time constant. Replaced by tsup `define` (true when IAM_INTERNAL_TEST=1)\n// and by vitest `define`. In default builds (npm publish path) this is `false`\n// and any test hook short-circuits to throw — guaranteeing the harness-only\n// injection path is unreachable in published artifacts.\ndeclare const __IAM_INTERNAL_TEST__: boolean;\n\ntype ResolvedConfig = Required<Pick<PulseConfig, \"cluster\" | \"threshold\">> &\n PulseConfig;\n\ninterface ExtractedFeatures {\n /** Raw features in physical units (Hz, ratios, dB, px/frame). For server-side validation. */\n raw: number[];\n /** Z-score normalized features. For SimHash fingerprint computation. */\n normalized: number[];\n /**\n * F0 (fundamental frequency) contour per audio frame (~10ms hop).\n * Sent to the validation service for cross-modal temporal analysis.\n * Empty array when audio is invalid or too short.\n */\n f0Contour: number[];\n /**\n * Acceleration magnitude (√(ax²+ay²+az²)) resampled to match the F0 frame count.\n * Paired with `f0Contour` for server-side lagged cross-correlation.\n * Empty array when motion data is absent.\n */\n accelMagnitude: number[];\n}\n\n/**\n * Extract features from sensor data. Returns both raw (physical units)\n * and normalized (z-scored) feature vectors.\n */\nasync function extractFeatures(data: SensorData): Promise<ExtractedFeatures> {\n if (!data.audio) {\n throw new Error(\n \"Audio data missing. Capture audio via session.startAudio() before extracting features.\",\n );\n }\n const { features: audioFeatures, f0Contour } = await extractSpeakerFeaturesDetailed(\n data.audio,\n );\n\n const hasMotion = data.motion.length >= MIN_MOTION_SAMPLES;\n const hasTouch = data.touch.length >= MIN_TOUCH_SAMPLES;\n\n const motionFeatures =\n hasMotion && hasTouch\n ? extractMouseDynamics(data.touch)\n : hasMotion\n ? extractMotionFeatures(data.motion)\n : extractMouseDynamics(data.touch);\n\n const touchFeatures = extractTouchFeatures(data.touch);\n\n // Align acceleration magnitude to the F0 frame count for direct cross-correlation.\n // Empty if motion absent or F0 extraction produced no frames (e.g. silent capture).\n const accelMagnitude =\n hasMotion && f0Contour.length > 0\n ? extractAccelerationMagnitude(data.motion, f0Contour.length)\n : [];\n\n return {\n raw: fuseRawFeatures(audioFeatures, motionFeatures, touchFeatures),\n normalized: fuseFeatures(audioFeatures, motionFeatures, touchFeatures),\n f0Contour,\n accelMagnitude,\n };\n}\n\n/**\n * Shared pipeline: features → simhash → TBH → proof → submit.\n * Used by both PulseSDK.verify() and PulseSession.complete().\n */\n// Minimum sample counts for meaningful feature extraction.\n// Exported so consumers (including the internal-build-only red team harness)\n// can enforce the same thresholds upstream and surface clearer errors than\n// the SDK's data-quality gate would.\nexport const MIN_AUDIO_SAMPLES = 16000; // ~1 second at 16 kHz\nexport const MIN_MOTION_SAMPLES = 10;\nexport const MIN_TOUCH_SAMPLES = 10;\n\ntype ExtractionResult =\n | {\n ok: true;\n features: number[];\n f0Contour: number[];\n accelMagnitude: number[];\n fingerprint: number[];\n tbh: TBH;\n }\n | { ok: false; error: string; reason?: string };\n\n/**\n * Shared front half of the verification pipeline, covering feature\n * extraction, server-side feature validation (if configured), and\n * TBH (Poseidon commitment) generation. Used by both the normal\n * verify path and the reset path — the back half diverges after this\n * point (proof generation + update_anchor for verify, direct\n * reset_identity_state for reset).\n *\n * `walletAddress` is the base58-encoded public key sent to the\n * validator's `/validate-features` endpoint as `wallet_id`. Pass\n * `undefined` for walletless mode to skip server validation.\n */\nasync function extractFingerprintAndValidate(\n sensorData: SensorData,\n config: ResolvedConfig,\n walletAddress: string | undefined,\n onProgress?: (stage: string) => void,\n): Promise<ExtractionResult> {\n onProgress?.(\"Extracting features...\");\n const {\n raw: features,\n normalized: normalizedFeatures,\n f0Contour,\n accelMagnitude,\n } = await extractFeatures(sensorData);\n\n // Diagnostic: log feature vector composition\n const nonZero = features.filter((v) => v !== 0).length;\n sdkLog(\n `[Entros SDK] Feature vector: ${features.length} dimensions, ${nonZero} non-zero. ` +\n `Audio[0..43]: ${features.slice(0, 44).filter((v) => v !== 0).length} non-zero. ` +\n `Motion/Mouse[44..97]: ${features.slice(44, 98).filter((v) => v !== 0).length} non-zero. ` +\n `Touch[98..133]: ${features.slice(98, 134).filter((v) => v !== 0).length} non-zero.`\n );\n\n onProgress?.(\"Validating...\");\n if (config.relayerUrl && walletAddress) {\n try {\n const baseUrl = new URL(config.relayerUrl);\n const validateUrl = `${baseUrl.origin}/validate-features`;\n const validateHeaders: Record<string, string> = { \"Content-Type\": \"application/json\" };\n if (config.relayerApiKey) {\n validateHeaders[\"X-API-Key\"] = config.relayerApiKey;\n }\n\n // Encode captured audio for server-side phrase content binding\n // (master-list #89). Validation runs Whisper-tiny on the samples and\n // phoneme-matches against the server-issued challenge phrase (which\n // the executor looks up server-side via the wallet-keyed nonce\n // registry). If audio is absent, the validation service skips the\n // phrase check — preserving backward compatibility for older SDKs.\n //\n // We also transmit the actual `sampleRate` from the capture — browsers\n // occasionally ignore the 16kHz AudioContext request (Safari with\n // Bluetooth codec negotiation, some Android devices) and deliver 44.1k\n // or 48k. The validator resamples to 16kHz internally before feeding\n // Whisper, so transmitting the true rate avoids silent transcription\n // quality loss.\n const audioSamplesB64 = sensorData.audio?.samples\n ? encodeAudioAsBase64(sensorData.audio.samples)\n : undefined;\n const audioSampleRateHz = sensorData.audio?.sampleRate;\n\n // Whisper-tiny inference adds ~1s to the validation round trip.\n // Extend timeout from 10s to 15s to tolerate cold-start model load\n // without aborting on legitimate requests.\n const validateController = new AbortController();\n const validateTimer = setTimeout(() => validateController.abort(), 15_000);\n\n const validateResponse = await fetch(validateUrl, {\n method: \"POST\",\n headers: validateHeaders,\n body: JSON.stringify({\n features,\n f0_contour: f0Contour,\n accel_magnitude: accelMagnitude,\n wallet_id: walletAddress,\n audio_samples_b64: audioSamplesB64,\n audio_sample_rate_hz: audioSampleRateHz,\n }),\n signal: validateController.signal,\n });\n\n clearTimeout(validateTimer);\n\n if (!validateResponse.ok) {\n const errorBody = await validateResponse.json().catch(() => ({}));\n const body = errorBody as Record<string, string>;\n // Reason is the validator's safe-to-reveal label (master-list #94).\n // Absent for attack-signal rejections + capture bugs by design — the\n // executor strips those before forwarding. Caller must treat the\n // field as optional even on rejection.\n const reason = typeof body.reason === \"string\" ? body.reason : undefined;\n sdkWarn(\n `[Entros SDK] Feature validation rejected by server${reason ? ` (reason: ${reason})` : \"\"}`\n );\n return {\n ok: false,\n error: body.error || \"Feature validation failed\",\n reason,\n };\n }\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n sdkWarn(`[Entros SDK] Feature validation unavailable: ${msg}, proceeding without server validation`);\n }\n }\n\n const fingerprint = simhash(normalizedFeatures);\n const tbh = await generateTBH(fingerprint);\n\n return { ok: true, features, f0Contour, accelMagnitude, fingerprint, tbh };\n}\n\nasync function processSensorData(\n sensorData: SensorData,\n config: ResolvedConfig,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Solana types are optional peer deps\n wallet?: any,\n connection?: any,\n onProgress?: (stage: string) => void,\n): Promise<VerificationResult> {\n // Data quality gate: reject if insufficient behavioral data captured\n const audioSamples = sensorData.audio?.samples.length ?? 0;\n const motionSamples = sensorData.motion.length;\n const touchSamples = sensorData.touch.length;\n\n // Need at least audio OR (motion + touch) to produce a meaningful fingerprint\n const hasAudio = audioSamples >= MIN_AUDIO_SAMPLES;\n const hasMotion = motionSamples >= MIN_MOTION_SAMPLES;\n const hasTouch = touchSamples >= MIN_TOUCH_SAMPLES;\n\n if (!hasAudio && !hasMotion && !hasTouch) {\n return {\n success: false,\n commitment: new Uint8Array(32),\n isFirstVerification: true,\n error: \"Insufficient behavioral data. Please speak the phrase and trace the curve during capture.\",\n };\n }\n\n if (!hasAudio) {\n return {\n success: false,\n commitment: new Uint8Array(32),\n isFirstVerification: true,\n error: \"No voice data detected. Please speak the phrase clearly during capture.\",\n };\n }\n\n // Re-verification requires audio + at least one other modality.\n // Audio-only fingerprints lack inter-session variance from motion/touch,\n // producing identical SimHash results that fail the min_distance constraint.\n let hasPreviousData: boolean;\n if (wallet && connection) {\n const walletPubkey = wallet.adapter?.publicKey ?? wallet.publicKey;\n if (walletPubkey) {\n try {\n const { PublicKey } = await import(\"@solana/web3.js\");\n const programId = new PublicKey(PROGRAM_IDS.entrosAnchor);\n const [identityPda] = PublicKey.findProgramAddressSync(\n [new TextEncoder().encode(\"identity\"), walletPubkey.toBuffer()],\n programId\n );\n const accountInfo = await connection.getAccountInfo(identityPda);\n hasPreviousData = !!accountInfo;\n } catch {\n hasPreviousData = (await loadVerificationData()) !== null;\n }\n } else {\n hasPreviousData = (await loadVerificationData()) !== null;\n }\n } else {\n hasPreviousData = (await loadVerificationData()) !== null;\n }\n if (hasPreviousData && !hasMotion && !hasTouch) {\n return {\n success: false,\n commitment: new Uint8Array(32),\n isFirstVerification: false,\n error: \"Insufficient sensor data for re-verification. Please trace the curve and allow motion access.\",\n };\n }\n\n const walletAddress = wallet?.adapter?.publicKey?.toBase58?.()\n ?? wallet?.publicKey?.toBase58?.();\n const extraction = await extractFingerprintAndValidate(\n sensorData,\n config,\n walletAddress,\n onProgress,\n );\n if (!extraction.ok) {\n return {\n success: false,\n commitment: new Uint8Array(32),\n isFirstVerification: false,\n error: extraction.error,\n reason: extraction.reason,\n };\n }\n const { fingerprint, tbh, features } = extraction;\n\n // Determine if this is a first verification.\n // Wallet-connected: check on-chain IdentityState PDA (source of truth).\n // Walletless: check localStorage for stored fingerprint.\n let isFirstVerification: boolean;\n const previousData = await loadVerificationData();\n\n if (wallet && connection) {\n const walletPubkey = wallet.adapter?.publicKey ?? wallet.publicKey;\n if (walletPubkey) {\n // Check if IdentityState PDA exists on-chain (simple existence check, no IDL needed)\n try {\n const { PublicKey } = await import(\"@solana/web3.js\");\n const programId = new PublicKey(PROGRAM_IDS.entrosAnchor);\n const [identityPda] = PublicKey.findProgramAddressSync(\n [new TextEncoder().encode(\"identity\"), walletPubkey.toBuffer()],\n programId\n );\n const accountInfo = await connection.getAccountInfo(identityPda);\n isFirstVerification = !accountInfo;\n } catch {\n isFirstVerification = !previousData;\n }\n } else {\n isFirstVerification = !previousData;\n }\n } else {\n isFirstVerification = !previousData;\n }\n\n // Edge case: on-chain identity exists but local fingerprint is missing\n // (cleared browser data, new device, different browser). Can't generate\n // Hamming distance proof without the previous fingerprint.\n if (!isFirstVerification && !previousData) {\n return {\n success: false,\n commitment: tbh.commitmentBytes,\n isFirstVerification: false,\n error: \"Previous behavioral fingerprint not found on this device. Your Entros Anchor exists on-chain but the local baseline is missing. Reset your baseline to re-enroll from this device, or verify from the device that has the original baseline.\",\n };\n }\n\n let solanaProof: SolanaProof | null = null;\n\n if (!isFirstVerification && previousData) {\n onProgress?.(\"Computing proof...\");\n const previousTBH: TBH = {\n fingerprint: previousData.fingerprint,\n salt: BigInt(previousData.salt),\n commitment: BigInt(previousData.commitment),\n commitmentBytes: bigintToBytes32(BigInt(previousData.commitment)),\n };\n\n const distance = hammingDistance(fingerprint, previousData.fingerprint);\n sdkLog(\n `[Entros SDK] Re-verification: Hamming distance = ${distance} / 256 bits (threshold = ${config.threshold})`\n );\n\n const circuitInput = prepareCircuitInput(\n tbh,\n previousTBH,\n config.threshold\n );\n\n const wasmPath = config.wasmUrl;\n const zkeyPath = config.zkeyUrl;\n\n if (!wasmPath || !zkeyPath) {\n return {\n success: false,\n commitment: tbh.commitmentBytes,\n isFirstVerification: false,\n error: \"Re-verification requires wasmUrl and zkeyUrl in PulseConfig. Host the entros_hamming.wasm and entros_hamming_final.zkey circuit artifacts at public URLs.\",\n };\n }\n\n try {\n const { proof, publicSignals } = await generateProof(\n circuitInput,\n wasmPath,\n zkeyPath\n );\n solanaProof = serializeProof(proof, publicSignals);\n } catch (proofErr: any) {\n // Include diagnostics in error for mobile debugging (no devtools)\n const audioNZ = features.slice(0, 44).filter((v) => v !== 0).length;\n const motionNZ = features.slice(44, 98).filter((v) => v !== 0).length;\n const touchNZ = features.slice(98, 134).filter((v) => v !== 0).length;\n const rawAudio = sensorData.audio?.samples.length ?? 0;\n const rawMotion = sensorData.motion.length;\n const rawTouch = sensorData.touch.length;\n // First 3 feature values as a fingerprint to detect identical data\n const sig = features.slice(0, 3).map((v) => v.toFixed(4)).join(\",\");\n return {\n success: false,\n commitment: tbh.commitmentBytes,\n isFirstVerification: false,\n error: `Proof generation failed: ${proofErr?.message ?? proofErr}. Check wasmUrl/zkeyUrl reachability. Diagnostics: dist=${distance}, nz=${audioNZ}/${motionNZ}/${touchNZ}, raw=${rawAudio}/${rawMotion}/${rawTouch}, sig=${sig}`,\n };\n }\n }\n\n // Submit\n onProgress?.(\"Submitting to Solana...\");\n let submission;\n\n if (wallet && connection) {\n if (isFirstVerification) {\n submission = await submitViaWallet(\n solanaProof ?? { proofBytes: new Uint8Array(0), publicInputs: [] },\n tbh.commitmentBytes,\n { wallet, connection, isFirstVerification: true, relayerUrl: config.relayerUrl, relayerApiKey: config.relayerApiKey }\n );\n } else {\n submission = await submitViaWallet(solanaProof!, tbh.commitmentBytes, {\n wallet,\n connection,\n isFirstVerification: false,\n relayerUrl: config.relayerUrl,\n relayerApiKey: config.relayerApiKey,\n });\n }\n } else if (config.relayerUrl) {\n submission = await submitViaRelayer(\n solanaProof ?? { proofBytes: new Uint8Array(0), publicInputs: [] },\n tbh.commitmentBytes,\n { relayerUrl: config.relayerUrl, apiKey: config.relayerApiKey, isFirstVerification }\n );\n } else {\n return {\n success: false,\n commitment: tbh.commitmentBytes,\n isFirstVerification,\n error: \"No submission path available. Pass wallet+connection to verify() for wallet-connected mode, or set relayerUrl in PulseConfig for walletless mode.\",\n };\n }\n\n // Store verification data locally for next re-verification\n if (submission.success) {\n await storeVerificationData({\n fingerprint: tbh.fingerprint,\n salt: tbh.salt.toString(),\n commitment: tbh.commitment.toString(),\n timestamp: Date.now(),\n });\n }\n\n return {\n success: submission.success,\n commitment: tbh.commitmentBytes,\n txSignature: submission.txSignature,\n attestationTx: submission.attestationTx,\n isFirstVerification,\n error: submission.error,\n };\n}\n\n/**\n * Reset pipeline: features → simhash → TBH → reset_identity_state → store.\n * Mirrors `processSensorData()` but skips the Hamming ZK proof (there is no\n * prior fingerprint to bind against) and substitutes `submitResetViaWallet`\n * for the wallet submission path.\n *\n * Humanness is enforced server-side: the /validate-features and /attest\n * endpoints on the executor reject synthetic captures identically to the\n * normal verify flow.\n */\nasync function processResetSensorData(\n sensorData: SensorData,\n config: ResolvedConfig,\n wallet: any,\n connection: any,\n onProgress?: (stage: string) => void,\n): Promise<VerificationResult> {\n const audioSamples = sensorData.audio?.samples.length ?? 0;\n const motionSamples = sensorData.motion.length;\n const touchSamples = sensorData.touch.length;\n\n const hasAudio = audioSamples >= MIN_AUDIO_SAMPLES;\n const hasMotion = motionSamples >= MIN_MOTION_SAMPLES;\n const hasTouch = touchSamples >= MIN_TOUCH_SAMPLES;\n\n if (!hasAudio && !hasMotion && !hasTouch) {\n return {\n success: false,\n commitment: new Uint8Array(32),\n isFirstVerification: true,\n error: \"Insufficient behavioral data. Please speak the phrase and trace the curve during capture.\",\n };\n }\n\n if (!hasAudio) {\n return {\n success: false,\n commitment: new Uint8Array(32),\n isFirstVerification: true,\n error: \"No voice data detected. Please speak the phrase clearly during capture.\",\n };\n }\n\n // Reset requires the full multi-modal capture just like a fresh mint, so\n // the on-chain baseline is established from a meaningful fingerprint.\n if (!hasMotion && !hasTouch) {\n return {\n success: false,\n commitment: new Uint8Array(32),\n isFirstVerification: true,\n error: \"Insufficient sensor data for baseline reset. Please trace the curve and allow motion access.\",\n };\n }\n\n const walletAddress = wallet.adapter?.publicKey?.toBase58?.()\n ?? wallet.publicKey?.toBase58?.();\n const extraction = await extractFingerprintAndValidate(\n sensorData,\n config,\n walletAddress,\n onProgress,\n );\n if (!extraction.ok) {\n return {\n success: false,\n commitment: new Uint8Array(32),\n isFirstVerification: true,\n error: extraction.error,\n reason: extraction.reason,\n };\n }\n const { tbh } = extraction;\n\n onProgress?.(\"Submitting reset to Solana...\");\n const submission = await submitResetViaWallet(tbh.commitmentBytes, {\n wallet,\n connection,\n relayerUrl: config.relayerUrl,\n relayerApiKey: config.relayerApiKey,\n });\n\n // Persist the new local baseline on on-chain success. A throw here would\n // leave the user with an on-chain commitment they can't prove locally;\n // surface the failure explicitly instead of swallowing it so the UI can\n // prompt the user to reset again (after the 7-day cooldown) or transfer\n // the baseline from another device.\n if (submission.success) {\n try {\n await storeVerificationData({\n fingerprint: tbh.fingerprint,\n salt: tbh.salt.toString(),\n commitment: tbh.commitment.toString(),\n timestamp: Date.now(),\n });\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n sdkWarn(`[Entros SDK] Reset succeeded on chain but local baseline persistence failed: ${msg}`);\n return {\n success: false,\n commitment: tbh.commitmentBytes,\n txSignature: submission.txSignature,\n attestationTx: submission.attestationTx,\n isFirstVerification: true,\n error:\n \"Reset confirmed on chain, but saving the new baseline to this device failed. \" +\n \"Re-verification from this device will not work. Try clearing site data and \" +\n \"resetting again after the 7-day cooldown, or transfer a baseline from another \" +\n \"device.\",\n };\n }\n }\n\n return {\n success: submission.success,\n commitment: tbh.commitmentBytes,\n txSignature: submission.txSignature,\n attestationTx: submission.attestationTx,\n // Semantically this is a fresh baseline enrollment from the UX\n // perspective. `isFirstVerification: true` lets the caller render\n // success copy that matches first-time flows.\n isFirstVerification: true,\n error: submission.error,\n };\n}\n\n/**\n * PulseSession — event-driven staged capture session.\n *\n * Gives the caller control over when each sensor stage starts and stops.\n * After all stages complete, call complete() to run the processing pipeline.\n *\n * Usage:\n * const session = pulse.createSession(touchElement);\n * await session.startAudio();\n * // ... user speaks ...\n * await session.stopAudio();\n * await session.startMotion();\n * // ... user holds device ...\n * await session.stopMotion();\n * await session.startTouch();\n * // ... user traces curve ...\n * await session.stopTouch();\n * const result = await session.complete(wallet, connection);\n */\nexport class PulseSession {\n private config: ResolvedConfig;\n private touchElement: HTMLElement | undefined;\n\n private audioStageState: StageState = \"idle\";\n private motionStageState: StageState = \"idle\";\n private touchStageState: StageState = \"idle\";\n\n private audioController: AbortController | null = null;\n private motionController: AbortController | null = null;\n private touchController: AbortController | null = null;\n\n private audioPromise: Promise<AudioCapture | null> | null = null;\n private motionPromise: Promise<MotionSample[]> | null = null;\n private touchPromise: Promise<TouchSample[]> | null = null;\n\n private audioData: AudioCapture | null = null;\n private motionData: MotionSample[] = [];\n private touchData: TouchSample[] = [];\n\n constructor(config: ResolvedConfig, touchElement?: HTMLElement) {\n this.config = config;\n this.touchElement = touchElement;\n }\n\n // --- Audio ---\n\n async startAudio(onAudioLevel?: (rms: number) => void): Promise<void> {\n if (this.audioStageState !== \"idle\")\n throw new Error(\n \"Audio capture already in progress. Call stopAudio() before starting a new capture.\",\n );\n\n // Acquire microphone permission within the user gesture context.\n // Awaited so the caller knows audio is ready before proceeding.\n // State transitions happen AFTER permission succeeds to avoid zombie state.\n const stream = await navigator.mediaDevices.getUserMedia({\n audio: {\n sampleRate: 16000,\n channelCount: 1,\n echoCancellation: false,\n noiseSuppression: false,\n autoGainControl: false,\n },\n });\n\n this.audioStageState = \"capturing\";\n this.audioController = new AbortController();\n this.audioPromise = captureAudio({\n signal: this.audioController.signal,\n onAudioLevel,\n stream,\n }).catch(() => {\n stream.getTracks().forEach((t) => t.stop());\n return null;\n });\n }\n\n async stopAudio(): Promise<AudioCapture | null> {\n if (this.audioStageState !== \"capturing\")\n throw new Error(\n \"No active audio capture to stop. Call startAudio() first.\",\n );\n this.audioController!.abort();\n this.audioData = await this.audioPromise!;\n this.audioStageState = \"captured\";\n return this.audioData;\n }\n\n // Audio is mandatory — no skipAudio() method.\n // If startAudio() fails, the verification cannot proceed.\n\n // --- Motion ---\n\n async startMotion(): Promise<void> {\n if (this.motionStageState !== \"idle\")\n throw new Error(\n \"Motion capture already in progress. Call stopMotion() before starting a new capture.\",\n );\n\n // Request motion permission within the user gesture context (iOS 13+).\n // Awaited so the capture timer doesn't start before the user approves.\n const hasPermission = await requestMotionPermission();\n if (!hasPermission) {\n this.motionStageState = \"skipped\";\n return;\n }\n\n this.motionStageState = \"capturing\";\n this.motionController = new AbortController();\n this.motionPromise = captureMotion({\n signal: this.motionController.signal,\n permissionGranted: true,\n }).catch(() => []);\n }\n\n async stopMotion(): Promise<MotionSample[]> {\n if (this.motionStageState !== \"capturing\")\n throw new Error(\n \"No active motion capture to stop. Call startMotion() first.\",\n );\n this.motionController!.abort();\n this.motionData = await this.motionPromise!;\n this.motionStageState = \"captured\";\n return this.motionData;\n }\n\n skipMotion(): void {\n if (this.motionStageState !== \"idle\")\n throw new Error(\n \"Cannot skip motion: capture already started. skipMotion() must be called before startMotion().\",\n );\n this.motionStageState = \"skipped\";\n }\n\n isMotionCapturing(): boolean {\n return this.motionStageState === \"capturing\";\n }\n\n // --- Touch ---\n\n async startTouch(): Promise<void> {\n if (this.touchStageState !== \"idle\")\n throw new Error(\n \"Touch capture already in progress. Call stopTouch() before starting a new capture.\",\n );\n if (!this.touchElement)\n throw new Error(\n \"No touch element provided to session. Pass an HTMLElement to createSession() to enable touch capture.\",\n );\n this.touchStageState = \"capturing\";\n this.touchController = new AbortController();\n this.touchPromise = captureTouch(this.touchElement, {\n signal: this.touchController.signal,\n }).catch(() => []);\n }\n\n async stopTouch(): Promise<TouchSample[]> {\n if (this.touchStageState !== \"capturing\")\n throw new Error(\n \"No active touch capture to stop. Call startTouch() first.\",\n );\n this.touchController!.abort();\n this.touchData = await this.touchPromise!;\n this.touchStageState = \"captured\";\n return this.touchData;\n }\n\n skipTouch(): void {\n if (this.touchStageState !== \"idle\")\n throw new Error(\n \"Cannot skip touch: capture already started. skipTouch() must be called before startTouch().\",\n );\n this.touchStageState = \"skipped\";\n }\n\n // --- Test hooks (internal builds only) ---\n\n /**\n * @internal Test-only. Primes the session with pre-captured sensor data,\n * bypassing browser capture APIs. Throws unless built with IAM_INTERNAL_TEST=1.\n * Stripped from the published .d.ts so npm consumers never see it. Used by the\n * red team harness to drive the real verification pipeline (extraction →\n * SimHash → TBH → proof → submit) against synthetic sensor data — never\n * available to npm consumers.\n */\n __injectSensorData(data: {\n audio: AudioCapture;\n motion: MotionSample[];\n touch: TouchSample[];\n }): void {\n // typeof guard tolerates the constant being undeclared at runtime (e.g.\n // direct ts-node/tsx execution that bypasses tsup/vitest `define`).\n // Without this, a missing build-time replacement throws ReferenceError\n // before the user-facing message can fire.\n if (typeof __IAM_INTERNAL_TEST__ !== \"boolean\" || !__IAM_INTERNAL_TEST__) {\n throw new Error(\n \"PulseSession.__injectSensorData is only available in internal test builds. \" +\n \"Set IAM_INTERNAL_TEST=1 when building pulse-sdk from source.\",\n );\n }\n const conflicts: string[] = [];\n if (this.audioStageState === \"capturing\") conflicts.push(\"audio\");\n if (this.motionStageState === \"capturing\") conflicts.push(\"motion\");\n if (this.touchStageState === \"capturing\") conflicts.push(\"touch\");\n if (conflicts.length > 0) {\n throw new Error(\n `__injectSensorData: cannot inject while stages are capturing: ${conflicts.join(\", \")}. ` +\n `Create a fresh session via sdk.createSession() and inject before any startAudio/startMotion/startTouch call.`,\n );\n }\n if (!data.audio || data.audio.samples.length < MIN_AUDIO_SAMPLES) {\n throw new Error(\n `__injectSensorData: audio required, minimum ${MIN_AUDIO_SAMPLES} samples (got ${data.audio?.samples.length ?? 0}).`,\n );\n }\n if (data.motion.length < MIN_MOTION_SAMPLES) {\n throw new Error(\n `__injectSensorData: motion required, minimum ${MIN_MOTION_SAMPLES} samples (got ${data.motion.length}).`,\n );\n }\n if (data.touch.length < MIN_TOUCH_SAMPLES) {\n throw new Error(\n `__injectSensorData: touch required, minimum ${MIN_TOUCH_SAMPLES} samples (got ${data.touch.length}).`,\n );\n }\n this.audioData = data.audio;\n this.motionData = data.motion;\n this.touchData = data.touch;\n this.audioStageState = \"captured\";\n this.motionStageState = \"captured\";\n this.touchStageState = \"captured\";\n }\n\n /**\n * @internal\n *\n * Run the validation step of the verify pipeline only: feature extraction\n * + `/validate-features` POST. Returns the validation outcome without ever\n * touching the on-chain submission path. Mirrors the production user\n * flow's pre-payment gate — the validation server runs without requiring\n * the wallet to have SOL, just like a real user gets a validation result\n * before being prompted to sign the on-chain mint.\n *\n * Note: this is a strict subset of `complete()`. It skips the data-quality\n * gates and re-verification check that `processSensorData` performs. The\n * validation server still runs its full pipeline (Tier 1 + Tier 2 +\n * phrase binding); only the client-side pre-flight checks differ.\n *\n * Use case: red team campaigns measuring server-side validation at scale\n * without per-attempt SOL funding. Build-time gated identically to\n * `__injectSensorData`; throws in production builds.\n */\n async __validateOnly(walletAddress: string): Promise<{\n validated: boolean;\n error?: string;\n reason?: string;\n }> {\n if (typeof __IAM_INTERNAL_TEST__ !== \"boolean\" || !__IAM_INTERNAL_TEST__) {\n throw new Error(\n \"PulseSession.__validateOnly is only available in internal test builds. \" +\n \"Set IAM_INTERNAL_TEST=1 when building pulse-sdk from source.\",\n );\n }\n if (typeof walletAddress !== \"string\" || walletAddress.length === 0) {\n throw new Error(\n \"__validateOnly requires a non-empty walletAddress string (used as wallet_id in the /validate-features payload).\",\n );\n }\n const active: string[] = [];\n if (this.audioStageState === \"capturing\") active.push(\"audio\");\n if (this.motionStageState === \"capturing\") active.push(\"motion\");\n if (this.touchStageState === \"capturing\") active.push(\"touch\");\n if (active.length > 0) {\n throw new Error(\n `Cannot validate: stages still capturing: ${active.join(\", \")}`,\n );\n }\n if (\n !this.audioData ||\n this.motionData.length === 0 ||\n this.touchData.length === 0\n ) {\n throw new Error(\n \"__validateOnly requires sensor data first — call __injectSensorData() before this.\",\n );\n }\n\n const sensorData: SensorData = {\n audio: this.audioData,\n motion: this.motionData,\n touch: this.touchData,\n modalities: {\n audio: true,\n motion: true,\n touch: true,\n },\n };\n\n const extraction = await extractFingerprintAndValidate(\n sensorData,\n this.config,\n walletAddress,\n );\n\n if (!extraction.ok) {\n return { validated: false, error: extraction.error, reason: extraction.reason };\n }\n return { validated: true };\n }\n\n // --- Complete ---\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Solana types are optional peer deps\n async complete(wallet?: any, connection?: any, onProgress?: (stage: string) => void): Promise<VerificationResult> {\n const active: string[] = [];\n if (this.audioStageState === \"capturing\") active.push(\"audio\");\n if (this.motionStageState === \"capturing\") active.push(\"motion\");\n if (this.touchStageState === \"capturing\") active.push(\"touch\");\n if (active.length > 0) {\n throw new Error(\n `Cannot complete: stages still capturing: ${active.join(\", \")}`\n );\n }\n\n const sensorData: SensorData = {\n audio: this.audioData,\n motion: this.motionData,\n touch: this.touchData,\n modalities: {\n audio: this.audioData !== null,\n motion: this.motionData.length > 0,\n touch: this.touchData.length > 0,\n },\n };\n\n return processSensorData(sensorData, this.config, wallet, connection, onProgress);\n }\n\n /**\n * Complete the session as a baseline RESET instead of a normal verify.\n *\n * Use when the wallet has an on-chain IdentityState but the device has\n * no recoverable local baseline (cleared site data, new device, etc).\n * Skips the Hamming ZK proof; submits `reset_identity_state` on chain,\n * which rotates the commitment and zeros verification history.\n *\n * Requires a connected wallet + Solana connection. Rejects if either\n * is missing — reset is a wallet-mode-only operation since it writes\n * to the user's on-chain account.\n */\n async completeReset(\n wallet: any,\n connection: any,\n onProgress?: (stage: string) => void\n ): Promise<VerificationResult> {\n const active: string[] = [];\n if (this.audioStageState === \"capturing\") active.push(\"audio\");\n if (this.motionStageState === \"capturing\") active.push(\"motion\");\n if (this.touchStageState === \"capturing\") active.push(\"touch\");\n if (active.length > 0) {\n throw new Error(\n `Cannot complete reset: stages still capturing: ${active.join(\", \")}`\n );\n }\n\n if (!wallet || !connection) {\n return {\n success: false,\n commitment: new Uint8Array(32),\n isFirstVerification: true,\n error:\n \"Baseline reset requires a connected wallet and Solana connection. \" +\n \"Reset cannot be performed in walletless mode.\",\n };\n }\n\n const sensorData: SensorData = {\n audio: this.audioData,\n motion: this.motionData,\n touch: this.touchData,\n modalities: {\n audio: this.audioData !== null,\n motion: this.motionData.length > 0,\n touch: this.touchData.length > 0,\n },\n };\n\n return processResetSensorData(sensorData, this.config, wallet, connection, onProgress);\n }\n}\n\n/**\n * PulseSDK — main entry point for Entros Protocol verification.\n *\n * Two usage modes:\n * 1. Simple (backward-compatible): pulse.verify(touchElement) — captures all sensors\n * for DEFAULT_CAPTURE_MS in parallel, then processes.\n * 2. Staged (event-driven): pulse.createSession(touchElement) — caller controls\n * when each sensor stage starts and stops.\n */\nexport class PulseSDK {\n private config: ResolvedConfig;\n\n constructor(config: PulseConfig) {\n this.config = {\n threshold: DEFAULT_THRESHOLD,\n ...config,\n };\n setDebug(config.debug ?? false);\n }\n\n /**\n * Create a staged capture session for event-driven control.\n */\n createSession(touchElement?: HTMLElement): PulseSession {\n return new PulseSession(this.config, touchElement);\n }\n\n /**\n * Run a full verification with automatic timed capture (backward-compatible).\n * Captures all sensors in parallel for DEFAULT_CAPTURE_MS, then processes.\n */\n async verify(\n touchElement?: HTMLElement,\n wallet?: any,\n connection?: any\n ): Promise<VerificationResult> {\n try {\n const session = this.createSession(touchElement);\n const stopPromises: Promise<void>[] = [];\n\n // Motion first — requires user gesture on iOS (gesture expires after getUserMedia)\n try {\n await session.startMotion();\n } catch {\n /* unexpected error — motion already skipped or idle */\n }\n if (session.isMotionCapturing()) {\n stopPromises.push(\n new Promise<void>((r) => setTimeout(r, DEFAULT_CAPTURE_MS))\n .then(() => session.stopMotion())\n .then(() => {})\n );\n }\n\n // Audio second — getUserMedia works without a gesture on secure origins\n try {\n await session.startAudio();\n stopPromises.push(\n new Promise<void>((r) => setTimeout(r, DEFAULT_CAPTURE_MS))\n .then(() => session.stopAudio())\n .then(() => {})\n );\n } catch (err: any) {\n throw new Error(\n `Audio capture failed: ${err?.message ?? \"microphone unavailable\"}. Ensure microphone permission is granted and no other app is using it.`,\n );\n }\n\n // Touch\n if (touchElement) {\n try {\n await session.startTouch();\n stopPromises.push(\n new Promise<void>((r) => setTimeout(r, DEFAULT_CAPTURE_MS))\n .then(() => session.stopTouch())\n .then(() => {})\n );\n } catch {\n session.skipTouch();\n }\n } else {\n session.skipTouch();\n }\n\n await Promise.all(stopPromises);\n return session.complete(wallet, connection);\n } catch (err: any) {\n return {\n success: false,\n commitment: new Uint8Array(32),\n isFirstVerification: true,\n error: err.message ?? String(err),\n };\n }\n }\n\n /**\n * Reset the wallet's on-chain baseline using a fresh capture.\n *\n * Convenience wrapper that mirrors `verify()` but routes the captured\n * sensor data through `reset_identity_state` instead of `update_anchor`.\n * Use when the wallet has an on-chain IdentityState but the local\n * encrypted baseline is unrecoverable.\n *\n * For fine-grained control, call `createSession()` and `completeReset()`\n * directly — the session API exposes per-stage start/stop hooks that\n * this convenience wrapper trades away for simplicity.\n */\n async resetBaseline(\n touchElement: HTMLElement | undefined,\n wallet: any,\n connection: any,\n onProgress?: (stage: string) => void\n ): Promise<VerificationResult> {\n try {\n const session = this.createSession(touchElement);\n const stopPromises: Promise<void>[] = [];\n\n try {\n await session.startMotion();\n } catch {\n /* unexpected error — motion already skipped or idle */\n }\n if (session.isMotionCapturing()) {\n stopPromises.push(\n new Promise<void>((r) => setTimeout(r, DEFAULT_CAPTURE_MS))\n .then(() => session.stopMotion())\n .then(() => {})\n );\n }\n\n try {\n await session.startAudio();\n stopPromises.push(\n new Promise<void>((r) => setTimeout(r, DEFAULT_CAPTURE_MS))\n .then(() => session.stopAudio())\n .then(() => {})\n );\n } catch (err: any) {\n throw new Error(\n `Audio capture failed: ${err?.message ?? \"microphone unavailable\"}. Ensure microphone permission is granted and no other app is using it.`,\n );\n }\n\n if (touchElement) {\n try {\n await session.startTouch();\n stopPromises.push(\n new Promise<void>((r) => setTimeout(r, DEFAULT_CAPTURE_MS))\n .then(() => session.stopTouch())\n .then(() => {})\n );\n } catch {\n session.skipTouch();\n }\n } else {\n session.skipTouch();\n }\n\n await Promise.all(stopPromises);\n return session.completeReset(wallet, connection, onProgress);\n } catch (err: any) {\n return {\n success: false,\n commitment: new Uint8Array(32),\n isFirstVerification: true,\n error: err.message ?? String(err),\n };\n }\n }\n}\n","/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { SAS_CONFIG } from \"../config\";\n\n/** Decoded Entros attestation from the Solana Attestation Service */\nexport interface EntrosAttestation {\n isHuman: boolean;\n trustScore: number;\n verifiedAt: number;\n mode: string;\n expired: boolean;\n}\n\n/**\n * Check if a wallet has a valid Entros attestation via SAS.\n *\n * Derives the attestation PDA, fetches the account, deserializes\n * the attestation data, and checks expiry.\n *\n * @param walletAddress - Base58 Solana wallet address\n * @param connection - Solana web3.js Connection instance\n * @returns Decoded attestation or null if none exists\n */\nexport async function verifyEntrosAttestation(\n walletAddress: string,\n connection: any\n): Promise<EntrosAttestation | null> {\n try {\n const { PublicKey } = await import(\"@solana/web3.js\");\n\n const sasProgramId = new PublicKey(SAS_CONFIG.programId);\n const credentialPda = new PublicKey(SAS_CONFIG.entrosCredentialPda);\n const schemaPda = new PublicKey(SAS_CONFIG.entrosSchemaPda);\n const userWallet = new PublicKey(walletAddress);\n\n // Derive attestation PDA: [\"attestation\", credential, schema, nonce(wallet)]\n const [attestationPda] = PublicKey.findProgramAddressSync(\n [\n new TextEncoder().encode(\"attestation\"),\n credentialPda.toBuffer(),\n schemaPda.toBuffer(),\n userWallet.toBuffer(),\n ],\n sasProgramId\n );\n\n const accountInfo = await connection.getAccountInfo(attestationPda);\n if (!accountInfo) return null;\n\n return deserializeSasAttestation(new Uint8Array(accountInfo.data));\n } catch {\n return null;\n }\n}\n\n/** Read a u16 from a Uint8Array at the given offset (little-endian) */\nfunction readU16LE(data: Uint8Array, offset: number): number {\n return data[offset]! | (data[offset + 1]! << 8);\n}\n\n/** Read a u32 from a Uint8Array at the given offset (little-endian) */\nfunction readU32LE(data: Uint8Array, offset: number): number {\n return (\n data[offset]! |\n (data[offset + 1]! << 8) |\n (data[offset + 2]! << 16) |\n ((data[offset + 3]! << 24) >>> 0)\n );\n}\n\n/** Read an i64 from a Uint8Array at the given offset (little-endian, safe for JS number range) */\nfunction readI64LE(data: Uint8Array, offset: number): number {\n const low = readU32LE(data, offset);\n const high = readU32LE(data, offset + 4);\n // Convert high word to signed for proper negative handling\n const signedHigh = high > 0x7FFFFFFF ? high - 0x100000000 : high;\n return signedHigh * 0x100000000 + low;\n}\n\n/**\n * Deserialize a SAS Attestation account into EntrosAttestation fields.\n *\n * SAS Attestation account layout (borsh):\n * 1 byte: discriminator (u8)\n * 32 bytes: nonce (Pubkey)\n * 32 bytes: credential (Pubkey)\n * 32 bytes: schema (Pubkey)\n * 4 bytes: data length (u32 LE) + N bytes: data (Vec<u8>)\n * 32 bytes: signer (Pubkey)\n * 8 bytes: expiry (i64 LE)\n * 32 bytes: token_account (Pubkey)\n *\n * Entros attestation data layout (inside the data Vec):\n * 1 byte: isHuman (bool)\n * 2 bytes: trustScore (u16 LE)\n * 8 bytes: verifiedAt (i64 LE)\n * 4 bytes: mode length (u32 LE) + N bytes: mode (UTF-8 string)\n */\nfunction deserializeSasAttestation(raw: Uint8Array): EntrosAttestation | null {\n // Minimum account size: 1 + 32 + 32 + 32 + 4 + 0 + 32 + 8 + 32 = 173 bytes\n if (raw.length < 173) return null;\n\n let offset = 0;\n\n // Skip discriminator (1 byte)\n offset += 1;\n\n // Skip nonce, credential, schema (32 + 32 + 32 = 96 bytes)\n offset += 96;\n\n // Read data Vec<u8>: 4-byte LE length prefix\n const dataLen = readU32LE(raw, offset);\n offset += 4;\n\n if (raw.length < offset + dataLen + 32 + 8 + 32) return null;\n\n const attestationData = raw.slice(offset, offset + dataLen);\n offset += dataLen;\n\n // Skip signer (32 bytes)\n offset += 32;\n\n // Read expiry (i64 LE)\n const expiry = readI64LE(raw, offset);\n\n // Parse Entros attestation data: [bool, u16, i64, string]\n if (attestationData.length < 11) return null;\n\n let dataOffset = 0;\n\n // isHuman: bool (1 byte)\n const isHuman = attestationData[dataOffset] === 1;\n dataOffset += 1;\n\n // trustScore: u16 LE (2 bytes)\n const trustScore = readU16LE(attestationData, dataOffset);\n dataOffset += 2;\n\n // verifiedAt: i64 LE (8 bytes)\n const verifiedAt = readI64LE(attestationData, dataOffset);\n dataOffset += 8;\n\n // mode: string (4-byte LE length + UTF-8)\n let mode = \"unknown\";\n if (dataOffset + 4 <= attestationData.length) {\n const modeLen = readU32LE(attestationData, dataOffset);\n dataOffset += 4;\n if (dataOffset + modeLen <= attestationData.length) {\n mode = new TextDecoder().decode(\n attestationData.slice(dataOffset, dataOffset + modeLen)\n );\n }\n }\n\n const now = Math.floor(Date.now() / 1000);\n const expired = expiry > 0 && now >= expiry;\n\n return { isHuman, trustScore, verifiedAt, mode, expired };\n}\n","/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { PROGRAM_IDS, AGENT_REGISTRY_CONFIG } from \"../config\";\nimport type { PulseConfig } from \"../config\";\n\nfunction getRegistryProgramId(cluster?: PulseConfig[\"cluster\"]): string {\n return cluster === \"mainnet-beta\"\n ? AGENT_REGISTRY_CONFIG.programIdMainnet\n : AGENT_REGISTRY_CONFIG.programIdDevnet;\n}\n\n/** Metadata written to an AI agent linking it to a verified human operator */\nexport interface AgentHumanOperator {\n anchorPda: string;\n trustScore: number;\n verifiedAt: number;\n wallet: string;\n}\n\n/**\n * Compute SHA256 hash, browser-compatible via SubtleCrypto.\n */\nasync function sha256(data: Uint8Array): Promise<Uint8Array> {\n const ab = new ArrayBuffer(data.length);\n new Uint8Array(ab).set(data);\n return new Uint8Array(await crypto.subtle.digest(\"SHA-256\", ab));\n}\n\n/**\n * Attest that a verified Entros human operates an AI agent on the Solana Agent Registry.\n *\n * Reads the user's on-chain IdentityState PDA, builds metadata JSON, and writes\n * it to the agent's metadata via a manually constructed set_metadata_pda instruction.\n * The metadata is immutable once set, permanently linking the agent to its human operator.\n *\n * The wallet must own both the Entros Anchor and the agent's Metaplex Core NFT.\n *\n * @param agentAsset - Base58 pubkey of the agent's Metaplex Core NFT\n * @param options - Wallet adapter and Solana connection\n * @returns Transaction signature on success\n */\nexport async function attestAgentOperator(\n agentAsset: string,\n options: {\n wallet: any;\n connection: any;\n cluster?: PulseConfig[\"cluster\"];\n }\n): Promise<{ success: boolean; signature?: string; error?: string }> {\n try {\n const { PublicKey, Transaction, TransactionInstruction, SystemProgram } =\n await import(\"@solana/web3.js\");\n\n const walletPubkey =\n options.wallet.adapter?.publicKey ?? options.wallet.publicKey;\n if (!walletPubkey) {\n return {\n success: false,\n error: \"Wallet not connected. Call wallet.connect() before attestAgentOperator().\",\n };\n }\n\n // 1. Read Entros IdentityState PDA\n const programId = new PublicKey(PROGRAM_IDS.entrosAnchor);\n const [identityPda] = PublicKey.findProgramAddressSync(\n [new TextEncoder().encode(\"identity\"), walletPubkey.toBuffer()],\n programId\n );\n\n const accountInfo = await options.connection.getAccountInfo(identityPda);\n if (!accountInfo || accountInfo.data.length < 62) {\n return {\n success: false,\n error: \"No Entros Anchor found. Complete a verification first.\",\n };\n }\n\n // 2. Deserialize trust_score and last_verification_timestamp\n const data = accountInfo.data;\n const view = new DataView(data.buffer, data.byteOffset, data.byteLength);\n const lastVerificationTimestamp = Number(view.getBigInt64(48, true));\n const trustScore = view.getUint16(60, true);\n\n // 3. Build metadata JSON value\n const metadata: AgentHumanOperator = {\n anchorPda: identityPda.toBase58(),\n trustScore,\n verifiedAt: lastVerificationTimestamp,\n wallet: walletPubkey.toBase58(),\n };\n const metadataValue = JSON.stringify(metadata);\n const metadataKey = AGENT_REGISTRY_CONFIG.metadataKey;\n\n // 4. Derive PDAs for the 8004 Agent Registry\n const registryProgramId = new PublicKey(\n getRegistryProgramId(options.cluster)\n );\n const assetPubkey = new PublicKey(agentAsset);\n\n // Agent PDA: [\"agent\", asset]\n const [agentPda] = PublicKey.findProgramAddressSync(\n [new TextEncoder().encode(\"agent\"), assetPubkey.toBuffer()],\n registryProgramId\n );\n\n // Key hash: SHA256(key)[0..16]\n const keyBytes = new TextEncoder().encode(metadataKey);\n const keyHashFull = await sha256(keyBytes);\n const keyHash = keyHashFull.slice(0, 16);\n\n // Metadata entry PDA: [\"agent_meta\", asset, keyHash[0..16]]\n const [metadataEntryPda] = PublicKey.findProgramAddressSync(\n [\n new TextEncoder().encode(\"agent_meta\"),\n assetPubkey.toBuffer(),\n keyHash,\n ],\n registryProgramId\n );\n\n // 5. Build set_metadata_pda instruction data\n // Discriminator: [236, 60, 23, 48, 138, 69, 196, 153]\n // Args: key_hash ([u8; 16]), key (String), value (Vec<u8>), immutable (bool)\n const valueBytes = new TextEncoder().encode(metadataValue);\n const discriminator = new Uint8Array([236, 60, 23, 48, 138, 69, 196, 153]);\n\n const ixDataSize =\n 8 + // discriminator\n 16 + // key_hash [u8; 16]\n 4 + keyBytes.length + // key (Borsh string: 4-byte len + utf8)\n 4 + valueBytes.length + // value (Borsh Vec<u8>: 4-byte len + bytes)\n 1; // immutable (bool)\n\n const ixData = new Uint8Array(ixDataSize);\n const ixView = new DataView(ixData.buffer);\n let offset = 0;\n\n // Discriminator\n ixData.set(discriminator, offset);\n offset += 8;\n\n // key_hash: [u8; 16]\n ixData.set(keyHash, offset);\n offset += 16;\n\n // key: Borsh String (4-byte LE len + UTF-8)\n ixView.setUint32(offset, keyBytes.length, true);\n offset += 4;\n ixData.set(keyBytes, offset);\n offset += keyBytes.length;\n\n // value: Borsh Vec<u8> (4-byte LE len + bytes)\n ixView.setUint32(offset, valueBytes.length, true);\n offset += 4;\n ixData.set(valueBytes, offset);\n offset += valueBytes.length;\n\n // immutable: bool\n ixData[offset] = 1; // true\n offset += 1;\n\n // 6. Build instruction with 5 accounts\n const { Buffer: SolBuffer } = await import(\"buffer\");\n const instruction = new TransactionInstruction({\n programId: registryProgramId,\n keys: [\n { pubkey: metadataEntryPda, isSigner: false, isWritable: true },\n { pubkey: agentPda, isSigner: false, isWritable: false },\n { pubkey: assetPubkey, isSigner: false, isWritable: false },\n { pubkey: walletPubkey, isSigner: true, isWritable: true },\n {\n pubkey: SystemProgram.programId,\n isSigner: false,\n isWritable: false,\n },\n ],\n data: SolBuffer.from(ixData),\n });\n\n // 7. Build transaction, sign, send\n const tx = new Transaction().add(instruction);\n tx.feePayer = walletPubkey;\n const { blockhash } = await options.connection.getLatestBlockhash(\n \"confirmed\"\n );\n tx.recentBlockhash = blockhash;\n\n const signFn =\n options.wallet.adapter?.signTransaction ??\n options.wallet.signTransaction;\n if (!signFn) {\n return {\n success: false,\n error: \"Wallet adapter does not expose signTransaction. Use a wallet that implements the standard Solana Wallet Adapter interface (Phantom, Solflare, Backpack).\",\n };\n }\n const signed = await signFn.call(\n options.wallet.adapter ?? options.wallet,\n tx\n );\n\n const sig = await options.connection.sendRawTransaction(\n signed.serialize(),\n { skipPreflight: false, preflightCommitment: \"confirmed\" }\n );\n\n await options.connection.confirmTransaction(sig, \"confirmed\");\n\n return { success: true, signature: sig };\n } catch (err: any) {\n return { success: false, error: err.message ?? String(err) };\n }\n}\n\n/**\n * Query whether an AI agent has a verified human operator via Entros.\n *\n * Reads the \"entros:human-operator\" metadata from the agent's on-chain record\n * and returns the operator's Entros Anchor details.\n *\n * @param agentAsset - Base58 pubkey of the agent's Metaplex Core NFT\n * @param connection - Solana connection (optional, defaults to devnet)\n * @returns Operator metadata or null if no Entros attestation exists\n */\nexport async function getAgentHumanOperator(\n agentAsset: string,\n connection?: any,\n cluster?: PulseConfig[\"cluster\"],\n): Promise<AgentHumanOperator | null> {\n try {\n const { PublicKey } = await import(\"@solana/web3.js\");\n\n const registryProgramId = new PublicKey(\n getRegistryProgramId(cluster)\n );\n const assetPubkey = new PublicKey(agentAsset);\n const metadataKey = AGENT_REGISTRY_CONFIG.metadataKey;\n\n // Derive metadata entry PDA\n const keyBytes = new TextEncoder().encode(metadataKey);\n const keyHashFull = await sha256(keyBytes);\n const keyHash = keyHashFull.slice(0, 16);\n\n const [metadataEntryPda] = PublicKey.findProgramAddressSync(\n [\n new TextEncoder().encode(\"agent_meta\"),\n assetPubkey.toBuffer(),\n keyHash,\n ],\n registryProgramId\n );\n\n // Read account directly (no SDK dependency)\n const conn =\n connection ??\n new (await import(\"@solana/web3.js\")).Connection(\n \"https://api.devnet.solana.com\",\n \"confirmed\"\n );\n\n const accountInfo = await conn.getAccountInfo(metadataEntryPda);\n if (!accountInfo) return null;\n\n // Deserialize MetadataEntryPda\n // Layout: 8 (disc) + 32 (asset) + 1 (immutable) + 1 (bump) + 4+N (metadata_key) + 4+M (metadata_value)\n const raw = accountInfo.data;\n if (raw.length < 46) return null; // minimum size\n\n let offset = 8 + 32 + 1 + 1; // skip disc, asset, immutable, bump = 42\n\n // Read metadata_key (Borsh String: 4-byte LE len + UTF-8)\n const keyLen = new DataView(\n raw.buffer,\n raw.byteOffset + offset,\n 4\n ).getUint32(0, true);\n offset += 4 + keyLen;\n\n // Read metadata_value (Borsh Vec<u8>: 4-byte LE len + bytes)\n if (offset + 4 > raw.length) return null;\n const valueLen = new DataView(\n raw.buffer,\n raw.byteOffset + offset,\n 4\n ).getUint32(0, true);\n offset += 4;\n\n if (offset + valueLen > raw.length) return null;\n const valueBytes = raw.slice(offset, offset + valueLen);\n const valueStr = new TextDecoder().decode(valueBytes);\n\n return JSON.parse(valueStr) as AgentHumanOperator;\n } catch {\n return null;\n }\n}\n","// Phonetically-balanced nonsense syllables for the voice challenge — FALLBACK ONLY.\n//\n// The authoritative challenge phrase is server-issued by the executor's\n// `/challenge` endpoint (a 5-word phrase drawn from a curated English-word\n// dictionary — see `entros-validation/src/word_dict.rs` for the source of truth).\n// This client-side generator only fires when the executor is unreachable; in\n// that path the server has no record of the phrase and validation skips\n// phrase content binding entirely (Tier 1 acoustic + Tier 2 cross-modal still\n// run). The fallback intentionally stays nonsense to avoid shipping the\n// curated dictionary client-side — the JS bundle stays lean, and a degraded\n// session is visually distinct from a normal one for users / contributors\n// debugging.\nconst SYLLABLES = [\n \"ba\", \"da\", \"fa\", \"ga\", \"ha\", \"ja\", \"ka\", \"la\", \"ma\", \"na\",\n \"pa\", \"ra\", \"sa\", \"ta\", \"wa\", \"za\", \"be\", \"de\", \"fe\", \"ge\",\n \"ke\", \"le\", \"me\", \"ne\", \"pe\", \"re\", \"se\", \"te\", \"we\", \"ze\",\n \"bi\", \"di\", \"fi\", \"gi\", \"ki\", \"li\", \"mi\", \"ni\", \"pi\", \"ri\",\n \"si\", \"ti\", \"wi\", \"zi\", \"bo\", \"do\", \"fo\", \"go\", \"ko\", \"lo\",\n \"mo\", \"no\", \"po\", \"ro\", \"so\", \"to\", \"wo\", \"zo\", \"bu\", \"du\",\n \"fu\", \"gu\", \"ku\", \"lu\", \"mu\", \"nu\", \"pu\", \"ru\", \"su\", \"tu\",\n];\n\n/** Cryptographically random integer in [0, max) */\nfunction secureRandom(max: number): number {\n const arr = new Uint32Array(1);\n crypto.getRandomValues(arr);\n return arr[0]! % max;\n}\n\n/**\n * FALLBACK challenge-phrase generator. Used only when the executor's\n * `/challenge` endpoint is unreachable; the authoritative phrase comes from\n * the server (5 real words drawn from a curated English-word dictionary). On\n * this fallback path, validation skips server-side phrase content binding —\n * Tier 1 acoustic + Tier 2 cross-modal still run.\n *\n * Output is 5-6 syllable pairs, forming nonsensical but speakable words.\n * Uses crypto.getRandomValues for unpredictable challenge generation.\n */\nexport function generatePhrase(wordCount: number = 5): string {\n const words: string[] = [];\n for (let w = 0; w < wordCount; w++) {\n const syllableCount = 2 + secureRandom(2);\n let word = \"\";\n for (let s = 0; s < syllableCount; s++) {\n word += SYLLABLES[secureRandom(SYLLABLES.length)];\n }\n words.push(word);\n }\n return words.join(\" \");\n}\n\n/**\n * Generate a sequence of phrases for dynamic mid-session switching.\n * Each phrase uses a different syllable subset to prevent pre-computation.\n */\nexport function generatePhraseSequence(\n count: number = 3,\n wordCount: number = 4\n): string[] {\n const subsetSize = Math.floor(SYLLABLES.length / count);\n const phrases: string[] = [];\n\n for (let p = 0; p < count; p++) {\n const start = (p * subsetSize) % SYLLABLES.length;\n const subset = [\n ...SYLLABLES.slice(start, start + subsetSize),\n ...SYLLABLES.slice(0, Math.max(0, (start + subsetSize) - SYLLABLES.length)),\n ];\n\n const words: string[] = [];\n for (let w = 0; w < wordCount; w++) {\n const syllableCount = 2 + secureRandom(2);\n let word = \"\";\n for (let s = 0; s < syllableCount; s++) {\n word += subset[secureRandom(subset.length)];\n }\n words.push(word);\n }\n phrases.push(words.join(\" \"));\n }\n\n return phrases;\n}\n","/**\n * Generate Lissajous curve points for the touch tracing challenge.\n * The user traces this shape on screen while speaking the phrase.\n *\n * x(t) = A * sin(a*t + delta)\n * y(t) = B * sin(b*t)\n */\nexport interface LissajousParams {\n a: number;\n b: number;\n delta: number;\n points: number;\n}\n\nexport interface Point2D {\n x: number;\n y: number;\n}\n\n/**\n * Generate random Lissajous parameters for a challenge.\n */\nexport function randomLissajousParams(): LissajousParams {\n const ratios = [\n [1, 2],\n [2, 3],\n [3, 4],\n [3, 5],\n [4, 5],\n ];\n const arr = new Uint32Array(2);\n crypto.getRandomValues(arr);\n const pair = ratios[arr[0]! % ratios.length]!;\n return {\n a: pair[0]!,\n b: pair[1]!,\n delta: Math.PI * (0.25 + (arr[1]! / 0xFFFFFFFF) * 0.5),\n points: 200,\n };\n}\n\n/**\n * Generate Lissajous curve points normalized to [0, 1] range.\n */\nexport function generateLissajousPoints(params: LissajousParams): Point2D[] {\n const { a, b, delta, points } = params;\n const result: Point2D[] = [];\n\n for (let i = 0; i < points; i++) {\n const t = (i / points) * 2 * Math.PI;\n result.push({\n x: (Math.sin(a * t + delta) + 1) / 2,\n y: (Math.sin(b * t) + 1) / 2,\n });\n }\n\n return result;\n}\n\n/**\n * Generate a sequence of Lissajous curves for dynamic mid-session switching.\n * Each curve uses different parameters, preventing pre-computation.\n */\nexport function generateLissajousSequence(\n count: number = 2\n): { params: LissajousParams; points: Point2D[] }[] {\n const allRatios: [number, number][] = [\n [1, 2], [2, 3], [3, 4], [3, 5], [4, 5],\n [1, 3], [2, 5], [5, 6], [3, 7], [4, 7],\n ];\n\n // Fisher-Yates shuffle with crypto randomness\n const shuffled = [...allRatios];\n for (let i = shuffled.length - 1; i > 0; i--) {\n const arr = new Uint32Array(1);\n crypto.getRandomValues(arr);\n const j = arr[0]! % (i + 1);\n [shuffled[i], shuffled[j]] = [shuffled[j]!, shuffled[i]!];\n }\n\n const sequence: { params: LissajousParams; points: Point2D[] }[] = [];\n\n for (let i = 0; i < count; i++) {\n const pair = shuffled[i % shuffled.length]!;\n const deltaArr = new Uint32Array(1);\n crypto.getRandomValues(deltaArr);\n const params: LissajousParams = {\n a: pair[0],\n b: pair[1],\n delta: Math.PI * (0.1 + (deltaArr[0]! / 0xFFFFFFFF) * 0.8),\n points: 200,\n };\n sequence.push({ params, points: generateLissajousPoints(params) });\n }\n\n return sequence;\n}\n","/**\n * Fetch the server-issued challenge from the executor.\n *\n * The executor's `/challenge` endpoint returns a fresh nonce + 5-word phrase\n * bound to the wallet for a short TTL (default 60s). The phrase is drawn from\n * a curated English-word dictionary (source of truth at\n * `entros-validation/src/word_dict.rs`); shown to the user as the voice challenge\n * and looked up server-side at `/validate-features` to verify the audio\n * matches the issued phrase (master-list #89, phrase content binding).\n *\n * Server-issued phrases are the only safe design for content binding: if the\n * client generated the phrase and sent it to the server alongside the audio,\n * an attacker would submit their own phrase matching whatever content they\n * captured. With server issuance, the phrase is bound to the nonce and the\n * client cannot substitute it.\n */\n\nimport { sdkWarn } from \"../log\";\n\n/**\n * Server-issued challenge artifacts. Returned by `fetchChallenge`.\n */\nexport interface ChallengeResponse {\n /** 32-byte nonce used for on-chain `create_challenge` and the `/attest` handshake. */\n nonce: Uint8Array;\n /** Server-issued 5-word challenge phrase (drawn from a curated English-word dictionary) the user must speak aloud. */\n phrase: string;\n /** Nonce TTL in seconds (default 60). */\n expiresIn: number;\n}\n\n/**\n * Fetch a fresh nonce + phrase from the executor. Throws on network error or\n * non-2xx response so the caller can surface a retry UX.\n *\n * @param executorUrl - Base URL of the executor (e.g. `https://executor.entros.io`).\n * @param walletAddress - Base58-encoded wallet public key.\n * @param apiKey - Optional executor API key (`X-API-Key` header).\n */\nexport async function fetchChallenge(\n executorUrl: string,\n walletAddress: string,\n apiKey?: string,\n): Promise<ChallengeResponse> {\n const base = new URL(executorUrl);\n const url = new URL(\"/challenge\", base.origin);\n url.searchParams.set(\"wallet\", walletAddress);\n\n const headers: Record<string, string> = { Accept: \"application/json\" };\n if (apiKey) headers[\"X-API-Key\"] = apiKey;\n\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), 5_000);\n let response: Response;\n try {\n response = await fetch(url.toString(), {\n method: \"GET\",\n headers,\n signal: controller.signal,\n });\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n sdkWarn(`[Entros SDK] /challenge fetch failed: ${msg}`);\n throw new Error(`Unable to fetch challenge from executor: ${msg}`);\n } finally {\n clearTimeout(timer);\n }\n\n if (!response.ok) {\n throw new Error(\n `Executor returned ${response.status} for /challenge. Check the wallet address and try again.`,\n );\n }\n\n const body = (await response.json()) as {\n nonce: number[];\n expires_in: number;\n phrase: string;\n };\n\n if (!Array.isArray(body.nonce) || body.nonce.length !== 32) {\n throw new Error(\"Executor returned malformed nonce; expected 32-byte array\");\n }\n if (typeof body.phrase !== \"string\" || body.phrase.trim().length === 0) {\n throw new Error(\"Executor returned empty challenge phrase\");\n }\n\n return {\n nonce: Uint8Array.from(body.nonce),\n phrase: body.phrase,\n expiresIn: body.expires_in ?? 60,\n };\n}\n"],"mappings":"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","names":["mean","derivative","window"]}
1
+ {"version":3,"sources":["../src/config.ts","../src/log.ts","../src/sensor/audio.ts","../src/sensor/encode.ts","../src/sensor/motion.ts","../src/sensor/touch.ts","../src/extraction/statistics.ts","../src/extraction/lpc.ts","../src/extraction/speaker.ts","../src/extraction/kinematic.ts","../src/hashing/simhash.ts","../src/hashing/poseidon.ts","../src/proof/serializer.ts","../src/proof/prover.ts","../src/submit/receipt.ts","../src/submit/wallet.ts","../src/submit/relayer.ts","../src/identity/crypto.ts","../src/identity/anchor.ts","../src/pulse.ts","../src/attestation/sas.ts","../src/agent/anchor.ts","../src/challenge/phrase.ts","../src/challenge/lissajous.ts","../src/challenge/fetch.ts"],"sourcesContent":["// BN254 base field prime (for G1 point negation in proof_a)\nexport const BN254_BASE_FIELD = BigInt(\n \"21888242871839275222246405745257275088696311157297823662689037894645226208583\"\n);\n\n// BN254 scalar field prime (for salt generation, field element bounds)\nexport const BN254_SCALAR_FIELD = BigInt(\n \"21888242871839275222246405745257275088548364400416034343698204186575808495617\"\n);\n\nexport const FINGERPRINT_BITS = 256;\nexport const DEFAULT_THRESHOLD = 96;\nexport const DEFAULT_MIN_DISTANCE = 3;\nexport const NUM_PUBLIC_INPUTS = 4;\n\nexport const PROOF_A_SIZE = 64;\nexport const PROOF_B_SIZE = 128;\nexport const PROOF_C_SIZE = 64;\nexport const TOTAL_PROOF_SIZE = 256;\n\n// Frozen at the original v1 string for backward compatibility — every existing\n// user's baseline projects features into bit positions derived from this seed,\n// so changing it would invalidate every prior fingerprint and force a global\n// baseline reset. Kerckhoffs-compliant either way (the seed is public).\nexport const SIMHASH_SEED = \"IAM-PROTOCOL-SIMHASH-V1\";\n\n// Capture duration bounds (ms)\nexport const MIN_CAPTURE_MS = 2000;\nexport const MAX_CAPTURE_MS = 60000;\nexport const DEFAULT_CAPTURE_MS = 7000;\n\nexport const PROGRAM_IDS = {\n entrosAnchor: \"GZYwTp2ozeuRA5Gof9vs4ya961aANcJBdUzB7LN6q4b2\",\n entrosVerifier: \"4F97jNoxQzT2qRbkWpW3ztC3Nz2TtKj3rnKG8ExgnrfV\",\n entrosRegistry: \"6VBs3zr9KrfFPGd6j7aGBPQWwZa5tajVfA7HN6MMV9VW\",\n} as const;\n\nexport const AGENT_REGISTRY_CONFIG = {\n programIdDevnet: \"8oo4J9tBB3Hna1jRQ3rWvJjojqM5DYTDJo5cejUuJy3C\",\n programIdMainnet: \"8oo4dC4JvBLwy5tGgiH3WwK4B9PWxL9Z4XjA2jzkQMbQ\",\n metadataKey: \"entros:human-operator\",\n} as const;\n\nexport const SAS_CONFIG = {\n programId: \"22zoJMtdu4tQc2PzL74ZUT7FrwgB1Udec8DdW4yw4BdG\",\n entrosCredentialPda: \"GaPTkZC6JEGds1G5h645qyUrogx7NWghR2JgjvKQwTDo\",\n entrosSchemaPda: \"EPkajiGQjycPwcc3pupqExVdAmSfxWd31tRYZezd8c5g\",\n} as const;\n\nexport interface PulseConfig {\n cluster: \"devnet\" | \"mainnet-beta\" | \"localnet\";\n rpcEndpoint?: string;\n relayerUrl?: string;\n relayerApiKey?: string;\n zkeyUrl?: string;\n wasmUrl?: string;\n threshold?: number;\n /** Enable console logging for diagnostics. Default: false. */\n debug?: boolean;\n /**\n * Optional callback invoked when the SDK detects that encrypted local\n * storage is unavailable (e.g. iOS Safari private browsing, Brave\n * shields, Firefox Total Cookie Protection). The host app can prompt\n * the user and resolve to:\n * - `true` → SDK stores verification data in plaintext localStorage.\n * Convenient (baseline survives reload) but the\n * 256-bit fingerprint + salt + commitment sit unencrypted.\n * - `false` → SDK stores in-memory only. Data is lost on reload;\n * user must re-enroll each session.\n * If this callback is NOT provided, the SDK defaults to in-memory only —\n * never silently writes plaintext to localStorage. This default is the\n * safer choice; opt-in to plaintext via the callback when the host app\n * has surfaced the privacy tradeoff to the user.\n */\n onPrivacyFallback?: () => Promise<boolean>;\n}\n","/** Module-level debug flag, set by PulseSDK constructor. */\nlet debugEnabled = false;\n\nexport function setDebug(enabled: boolean): void {\n debugEnabled = enabled;\n}\n\nexport function sdkLog(...args: unknown[]): void {\n if (debugEnabled) console.log(...args);\n}\n\nexport function sdkWarn(...args: unknown[]): void {\n if (debugEnabled) console.warn(...args);\n}\n","import type { AudioCapture, CaptureOptions } from \"./types\";\nimport { MIN_CAPTURE_MS, MAX_CAPTURE_MS } from \"../config\";\n\nconst TARGET_SAMPLE_RATE = 16000;\n\n/**\n * Capture audio at 16kHz until signaled to stop.\n * Uses ScriptProcessorNode for raw PCM sample access.\n *\n * @privacyGuarantee Raw audio samples returned from this function are processed\n * locally by the SDK's feature extraction pipeline. The 134-feature derived\n * statistical summary is the only audio-related signal that crosses the\n * device boundary. The single sanctioned exception is the encoded base64\n * audio bytes sent to the validator's `/validate-features` endpoint for\n * server-side phrase content binding (master-list #89), which the validator\n * processes ephemerally — see entros.io paper §6.8 for the threat model.\n *\n * NOTE: ScriptProcessorNode is deprecated in favor of AudioWorklet.\n * Migration planned for v1.0. ScriptProcessorNode is used because it\n * provides synchronous access to raw PCM samples without requiring a\n * separate worker file, which simplifies SDK distribution. All current\n * browsers still support it.\n *\n * Stop behavior:\n * - If signal fires before minDurationMs, capture continues until minimum is reached.\n * - If signal never fires, capture auto-stops at maxDurationMs.\n * - If no signal provided, captures for maxDurationMs.\n */\nexport async function captureAudio(\n options: CaptureOptions = {}\n): Promise<AudioCapture> {\n const {\n signal,\n minDurationMs = MIN_CAPTURE_MS,\n maxDurationMs = MAX_CAPTURE_MS,\n onAudioLevel,\n stream: preAcquiredStream,\n } = options;\n\n const stream = preAcquiredStream ?? await navigator.mediaDevices.getUserMedia({\n audio: {\n sampleRate: TARGET_SAMPLE_RATE,\n channelCount: 1,\n echoCancellation: false,\n noiseSuppression: false,\n autoGainControl: false,\n },\n });\n\n // If anything between `getUserMedia` and the Promise constructor throws\n // (AudioContext construction, ctx.resume(), createMediaStreamSource) the\n // stream we just acquired would leak indefinitely. Wrap the setup in a\n // try-on-error path that stops the stream tracks before re-throwing.\n let ctx: AudioContext;\n let source: MediaStreamAudioSourceNode;\n let capturedSampleRate: number;\n try {\n ctx = new AudioContext({ sampleRate: TARGET_SAMPLE_RATE });\n await ctx.resume(); // Required on iOS — AudioContext may be suspended outside user gesture\n capturedSampleRate = ctx.sampleRate;\n source = ctx.createMediaStreamSource(stream);\n } catch (err) {\n // Stop tracks we already acquired; we can't acquire them again so leaks\n // would persist for the page lifetime if we don't release here.\n if (!preAcquiredStream) {\n stream.getTracks().forEach((t: MediaStreamTrack) => t.stop());\n }\n throw err;\n }\n const chunks: Float32Array[] = [];\n const startTime = performance.now();\n\n return new Promise((resolve) => {\n let stopped = false;\n // See motion.ts for the abortTimer rationale.\n let abortTimer: ReturnType<typeof setTimeout> | null = null;\n const bufferSize = 4096;\n const processor = ctx.createScriptProcessor(bufferSize, 1, 1);\n\n processor.onaudioprocess = (e: AudioProcessingEvent) => {\n const data = e.inputBuffer.getChannelData(0);\n chunks.push(new Float32Array(data));\n\n if (onAudioLevel) {\n let sum = 0;\n for (let i = 0; i < data.length; i++) sum += data[i]! * data[i]!;\n onAudioLevel(Math.sqrt(sum / data.length));\n }\n };\n\n source.connect(processor);\n processor.connect(ctx.destination);\n\n function stopCapture() {\n if (stopped) return;\n stopped = true;\n clearTimeout(maxTimer);\n if (abortTimer !== null) clearTimeout(abortTimer);\n\n processor.disconnect();\n source.disconnect();\n stream.getTracks().forEach((t: MediaStreamTrack) => t.stop());\n ctx.close().catch(() => {});\n\n const totalLength = chunks.reduce((sum, c) => sum + c.length, 0);\n const samples = new Float32Array(totalLength);\n let offset = 0;\n for (const chunk of chunks) {\n samples.set(chunk, offset);\n offset += chunk.length;\n }\n\n resolve({\n samples,\n sampleRate: capturedSampleRate,\n duration: totalLength / capturedSampleRate,\n });\n }\n\n const maxTimer = setTimeout(stopCapture, maxDurationMs);\n\n if (signal) {\n if (signal.aborted) {\n abortTimer = setTimeout(stopCapture, minDurationMs);\n } else {\n signal.addEventListener(\n \"abort\",\n () => {\n const elapsed = performance.now() - startTime;\n const remaining = Math.max(0, minDurationMs - elapsed);\n abortTimer = setTimeout(stopCapture, remaining);\n },\n { once: true }\n );\n }\n }\n });\n}\n","/**\n * Encode captured Float32 audio samples as base64 int16 PCM for transmission\n * to the validation service (master-list #89 phrase content binding).\n *\n * Audio is captured as `Float32Array` with values in `[-1.0, 1.0]` by the\n * Pulse SDK (`sensor/audio.ts`). The validation service's phrase-binding\n * module decodes base64 → Vec<i16> → Vec<f32> before feeding Whisper-tiny.\n * int16 is the standard compact representation: 2 bytes per sample vs 4 for\n * f32, halving wire size without perceptible quality loss for 16kHz speech.\n *\n * Byte layout: little-endian int16 samples, contiguous, no header.\n */\n\n/**\n * Convert Float32 PCM samples to base64-encoded 16-bit little-endian PCM.\n * Samples are clamped to [-1, 1] and scaled. Uses `btoa`, a DOM global\n * available in browser runtimes and in Node 16+.\n */\nexport function encodeAudioAsBase64(samples: Float32Array): string {\n const buf = new ArrayBuffer(samples.length * 2);\n const view = new DataView(buf);\n for (let i = 0; i < samples.length; i++) {\n const s = Math.max(-1, Math.min(1, samples[i]!));\n const int16 = s < 0 ? Math.round(s * 0x8000) : Math.round(s * 0x7fff);\n view.setInt16(i * 2, int16, true);\n }\n return bytesToBase64(new Uint8Array(buf));\n}\n\nfunction bytesToBase64(bytes: Uint8Array): string {\n // `btoa` is a DOM global and is also available as a Node global since\n // Node 16 (2021), which covers every runtime the SDK ships into. Chunk\n // the input to avoid \"maximum call stack size\" on large arrays — btoa\n // needs a string, and `String.fromCharCode(...bytes)` blows the stack\n // for Uint8Array length > ~128KB.\n const chunkSize = 0x8000;\n let binary = \"\";\n for (let i = 0; i < bytes.length; i += chunkSize) {\n const chunk = bytes.subarray(i, i + chunkSize);\n binary += String.fromCharCode(...chunk);\n }\n return btoa(binary);\n}\n","import type { MotionSample, CaptureOptions } from \"./types\";\nimport { MIN_CAPTURE_MS, MAX_CAPTURE_MS } from \"../config\";\n\n/**\n * Request motion sensor permission (required on iOS 13+).\n * No-op on Android/Chrome where permission is implicit.\n */\nexport async function requestMotionPermission(): Promise<boolean> {\n const DME = (globalThis as any).DeviceMotionEvent;\n if (!DME) return false;\n\n if (typeof DME.requestPermission === \"function\") {\n const permission = await DME.requestPermission();\n return permission === \"granted\";\n }\n\n // Android/Chrome: permission is implicit\n return true;\n}\n\n/**\n * Capture accelerometer + gyroscope data until signaled to stop.\n * Samples at the device's native rate (typically ~60-100Hz).\n */\nexport async function captureMotion(\n options: CaptureOptions = {}\n): Promise<MotionSample[]> {\n const {\n signal,\n minDurationMs = MIN_CAPTURE_MS,\n maxDurationMs = MAX_CAPTURE_MS,\n } = options;\n\n const hasPermission = options.permissionGranted ?? await requestMotionPermission();\n if (!hasPermission) return [];\n\n const samples: MotionSample[] = [];\n const startTime = performance.now();\n\n return new Promise((resolve) => {\n let stopped = false;\n // Tracks the abort-path setTimeout (when `signal` fires before\n // `maxDurationMs`) so it can be cleared if `maxTimer` runs first.\n // Without tracking, the abort-path timer fires later as a no-op via\n // the `stopped` flag — not a memory leak per se, but explicit cleanup\n // matches the rest of the SDK's resource-hygiene posture.\n let abortTimer: ReturnType<typeof setTimeout> | null = null;\n\n const handler = (e: DeviceMotionEvent) => {\n samples.push({\n timestamp: performance.now(),\n ax: e.acceleration?.x ?? 0,\n ay: e.acceleration?.y ?? 0,\n az: e.acceleration?.z ?? 0,\n gx: e.rotationRate?.alpha ?? 0,\n gy: e.rotationRate?.beta ?? 0,\n gz: e.rotationRate?.gamma ?? 0,\n });\n };\n\n function stopCapture() {\n if (stopped) return;\n stopped = true;\n clearTimeout(maxTimer);\n if (abortTimer !== null) clearTimeout(abortTimer);\n window.removeEventListener(\"devicemotion\", handler);\n resolve(samples);\n }\n\n window.addEventListener(\"devicemotion\", handler);\n\n const maxTimer = setTimeout(stopCapture, maxDurationMs);\n\n if (signal) {\n if (signal.aborted) {\n abortTimer = setTimeout(stopCapture, minDurationMs);\n } else {\n signal.addEventListener(\n \"abort\",\n () => {\n const elapsed = performance.now() - startTime;\n const remaining = Math.max(0, minDurationMs - elapsed);\n abortTimer = setTimeout(stopCapture, remaining);\n },\n { once: true }\n );\n }\n }\n });\n}\n","import type { TouchSample, CaptureOptions } from \"./types\";\nimport { MIN_CAPTURE_MS, MAX_CAPTURE_MS } from \"../config\";\nimport { sdkLog } from \"../log\";\n\n/**\n * Capture touch/pointer data (position, pressure, contact area) until signaled to stop.\n * Uses PointerEvent for cross-platform support (touch, pen, mouse).\n */\nexport function captureTouch(\n element: HTMLElement,\n options: CaptureOptions = {}\n): Promise<TouchSample[]> {\n const {\n signal,\n minDurationMs = MIN_CAPTURE_MS,\n maxDurationMs = MAX_CAPTURE_MS,\n } = options;\n\n const samples: TouchSample[] = [];\n const startTime = performance.now();\n\n return new Promise((resolve) => {\n let stopped = false;\n // See motion.ts for the abortTimer rationale — same pattern across\n // all three sensor modules.\n let abortTimer: ReturnType<typeof setTimeout> | null = null;\n\n const handler = (e: PointerEvent) => {\n samples.push({\n timestamp: performance.now(),\n x: e.clientX,\n y: e.clientY,\n pressure: e.pressure,\n width: e.width,\n height: e.height,\n });\n };\n\n function stopCapture() {\n if (stopped) return;\n stopped = true;\n clearTimeout(maxTimer);\n if (abortTimer !== null) clearTimeout(abortTimer);\n element.removeEventListener(\"pointermove\", handler);\n element.removeEventListener(\"pointerdown\", handler);\n sdkLog(`[Entros SDK] Touch capture stopped: ${samples.length} samples collected`);\n resolve(samples);\n }\n\n element.addEventListener(\"pointermove\", handler);\n element.addEventListener(\"pointerdown\", handler);\n sdkLog(`[Entros SDK] Touch capture started on <${element.tagName}>, listening for pointer events`);\n\n const maxTimer = setTimeout(stopCapture, maxDurationMs);\n\n if (signal) {\n if (signal.aborted) {\n abortTimer = setTimeout(stopCapture, minDurationMs);\n } else {\n signal.addEventListener(\n \"abort\",\n () => {\n const elapsed = performance.now() - startTime;\n const remaining = Math.max(0, minDurationMs - elapsed);\n abortTimer = setTimeout(stopCapture, remaining);\n },\n { once: true }\n );\n }\n }\n });\n}\n","import type { StatsSummary } from \"./types\";\n\nexport function mean(values: number[]): number {\n if (values.length === 0) return 0;\n let sum = 0;\n for (const v of values) sum += v;\n return sum / values.length;\n}\n\nexport function variance(values: number[], mu?: number): number {\n if (values.length < 2) return 0;\n const m = mu ?? mean(values);\n let sum = 0;\n for (const v of values) sum += (v - m) ** 2;\n return sum / (values.length - 1);\n}\n\nexport function skewness(values: number[]): number {\n if (values.length < 3) return 0;\n const n = values.length;\n const m = mean(values);\n const s = Math.sqrt(variance(values, m));\n if (s === 0) return 0;\n let sum = 0;\n for (const v of values) sum += ((v - m) / s) ** 3;\n return (n / ((n - 1) * (n - 2))) * sum;\n}\n\nexport function kurtosis(values: number[]): number {\n if (values.length < 4) return 0;\n const n = values.length;\n const m = mean(values);\n const s2 = variance(values, m);\n if (s2 === 0) return 0;\n let sum = 0;\n for (const v of values) sum += ((v - m) ** 4) / s2 ** 2;\n const k =\n ((n * (n + 1)) / ((n - 1) * (n - 2) * (n - 3))) * sum -\n (3 * (n - 1) ** 2) / ((n - 2) * (n - 3));\n return k;\n}\n\nexport function condense(values: number[]): StatsSummary {\n const m = mean(values);\n return {\n mean: m,\n variance: variance(values, m),\n skewness: skewness(values),\n kurtosis: kurtosis(values),\n };\n}\n\n/**\n * Shannon entropy over histogram bins. Measures information density.\n * Real human data has moderate entropy (varied but structured).\n * Synthetic data is either too uniform (high entropy) or too structured (low entropy).\n */\nexport function entropy(values: number[], bins: number = 16): number {\n if (values.length < 2) return 0;\n let min = values[0]!;\n let max = values[0]!;\n for (let i = 1; i < values.length; i++) {\n if (values[i]! < min) min = values[i]!;\n if (values[i]! > max) max = values[i]!;\n }\n if (min === max) return 0;\n\n const counts = new Array(bins).fill(0);\n const range = max - min;\n for (const v of values) {\n const idx = Math.min(Math.floor(((v - min) / range) * bins), bins - 1);\n counts[idx]++;\n }\n\n let h = 0;\n for (const c of counts) {\n if (c > 0) {\n const p = c / values.length;\n h -= p * Math.log2(p);\n }\n }\n return h;\n}\n\n/**\n * Autocorrelation at a given lag. Detects periodic synthetic patterns.\n * Real human data has low autocorrelation at most lags (chaotic/noisy).\n * Synthetic data often has high autocorrelation (periodic/smooth).\n */\nexport function autocorrelation(values: number[], lag: number = 1): number {\n if (values.length <= lag) return 0;\n const m = mean(values);\n const v = variance(values, m);\n if (v === 0) return 0;\n\n let sum = 0;\n for (let i = 0; i < values.length - lag; i++) {\n sum += (values[i]! - m) * (values[i + lag]! - m);\n }\n return sum / ((values.length - lag) * v);\n}\n\n/**\n * Normalize a feature group to zero mean and unit variance.\n * Ensures each modality (audio, motion, touch) contributes equally\n * to SimHash hyperplane projections regardless of raw magnitude scale.\n */\n/**\n * Z-score normalize a feature group to zero mean and unit variance.\n * Ensures each modality contributes equally to SimHash hyperplane\n * projections regardless of raw magnitude scale.\n */\nexport function normalizeGroup(features: number[]): number[] {\n if (features.length === 0) return features;\n\n // Sanitize NaN/Infinity to 0 before computing stats.\n // Meyda spectral features can produce NaN on near-silent frames (0/0),\n // and a single NaN would poison the entire modality group.\n const clean = features.map((v) => (Number.isFinite(v) ? v : 0));\n\n let sum = 0;\n for (const v of clean) sum += v;\n const mean = sum / clean.length;\n\n let sqSum = 0;\n for (const v of clean) sqSum += (v - mean) * (v - mean);\n const std = Math.sqrt(sqSum / clean.length);\n\n if (std < 1e-8) return clean.map(() => 0);\n return clean.map((v) => (v - mean) / std);\n}\n\n/**\n * Concatenate raw features without normalization.\n * Used for server-side validation where physical units matter.\n */\nexport function fuseRawFeatures(\n audio: number[],\n motion: number[],\n touch: number[]\n): number[] {\n const sanitize = (v: number) => (Number.isFinite(v) ? v : 0);\n return [...audio.map(sanitize), ...motion.map(sanitize), ...touch.map(sanitize)];\n}\n\n/**\n * Normalize and concatenate features for SimHash computation.\n */\nexport function fuseFeatures(\n audio: number[],\n motion: number[],\n touch: number[]\n): number[] {\n return [...normalizeGroup(audio), ...normalizeGroup(motion), ...normalizeGroup(touch)];\n}\n","/**\n * Linear Predictive Coding (LPC) for formant detection.\n *\n * Implements Levinson-Durbin recursion for LPC coefficient computation\n * and polynomial root-finding for formant frequency estimation.\n */\n\n/**\n * Compute autocorrelation of a signal for lags 0..order.\n */\nfunction autocorrelate(signal: Float32Array, order: number): number[] {\n const r: number[] = [];\n for (let lag = 0; lag <= order; lag++) {\n let sum = 0;\n for (let i = 0; i < signal.length - lag; i++) {\n sum += signal[i]! * signal[i + lag]!;\n }\n r.push(sum);\n }\n return r;\n}\n\n/**\n * Levinson-Durbin recursion to compute LPC coefficients from autocorrelation.\n * Returns the LPC coefficients a[1..order] (a[0] is implicitly 1).\n */\nfunction levinsonDurbin(r: number[], order: number): number[] {\n const a: number[] = new Array(order + 1).fill(0);\n const aTemp: number[] = new Array(order + 1).fill(0);\n a[0] = 1;\n\n let error = r[0]!;\n if (error === 0) return new Array(order).fill(0);\n\n for (let i = 1; i <= order; i++) {\n let lambda = 0;\n for (let j = 1; j < i; j++) {\n lambda += a[j]! * r[i - j]!;\n }\n lambda = -(r[i]! + lambda) / error;\n\n for (let j = 1; j < i; j++) {\n aTemp[j] = a[j]! + lambda * a[i - j]!;\n }\n aTemp[i] = lambda;\n\n for (let j = 1; j <= i; j++) {\n a[j] = aTemp[j]!;\n }\n\n error *= 1 - lambda * lambda;\n if (error <= 0) break;\n }\n\n return a.slice(1);\n}\n\n/**\n * Find roots of a polynomial using the Durand-Kerner method.\n * The polynomial is 1 + a[0]*z^-1 + a[1]*z^-2 + ... + a[n-1]*z^-n\n * which is equivalent to z^n + a[0]*z^(n-1) + ... + a[n-1] = 0.\n *\n * Returns complex roots as [real, imag] pairs.\n */\nfunction findRoots(coefficients: number[], maxIterations: number = 50): [number, number][] {\n const n = coefficients.length;\n if (n === 0) return [];\n\n // Initial guesses: points on a circle of radius 0.9\n const roots: [number, number][] = [];\n for (let i = 0; i < n; i++) {\n const angle = (2 * Math.PI * i) / n + 0.1;\n roots.push([0.9 * Math.cos(angle), 0.9 * Math.sin(angle)]);\n }\n\n for (let iter = 0; iter < maxIterations; iter++) {\n let maxShift = 0;\n\n for (let i = 0; i < n; i++) {\n // Evaluate polynomial at roots[i]: z^n + a[0]*z^(n-1) + ... + a[n-1]\n let pReal = 1;\n let pImag = 0;\n let zPowReal = 1;\n let zPowImag = 0;\n\n // Compute z^n by repeated multiplication\n const [rr, ri] = roots[i]!;\n let curReal = 1;\n let curImag = 0;\n\n // Evaluate as: z^n + sum(a[k] * z^(n-1-k))\n // Start with z^n\n let znReal = 1;\n let znImag = 0;\n for (let k = 0; k < n; k++) {\n const newReal = znReal * rr - znImag * ri;\n const newImag = znReal * ri + znImag * rr;\n znReal = newReal;\n znImag = newImag;\n }\n pReal = znReal;\n pImag = znImag;\n\n // Add coefficient terms: a[k] * z^(n-1-k)\n zPowReal = 1;\n zPowImag = 0;\n for (let k = n - 1; k >= 0; k--) {\n pReal += coefficients[k]! * zPowReal;\n pImag += coefficients[k]! * zPowImag;\n const newReal = zPowReal * rr - zPowImag * ri;\n const newImag = zPowReal * ri + zPowImag * rr;\n zPowReal = newReal;\n zPowImag = newImag;\n }\n\n // Compute product of (roots[i] - roots[j]) for j != i\n let denomReal = 1;\n let denomImag = 0;\n for (let j = 0; j < n; j++) {\n if (j === i) continue;\n const diffReal = rr - roots[j]![0];\n const diffImag = ri - roots[j]![1];\n const newReal = denomReal * diffReal - denomImag * diffImag;\n const newImag = denomReal * diffImag + denomImag * diffReal;\n denomReal = newReal;\n denomImag = newImag;\n }\n\n // Divide p / denom\n const denomMag2 = denomReal * denomReal + denomImag * denomImag;\n if (denomMag2 < 1e-30) continue;\n\n const shiftReal = (pReal * denomReal + pImag * denomImag) / denomMag2;\n const shiftImag = (pImag * denomReal - pReal * denomImag) / denomMag2;\n\n roots[i] = [rr - shiftReal, ri - shiftImag];\n maxShift = Math.max(maxShift, Math.sqrt(shiftReal * shiftReal + shiftImag * shiftImag));\n }\n\n if (maxShift < 1e-10) break;\n }\n\n return roots;\n}\n\n/**\n * Extract formant frequencies (F1, F2, F3) from a single audio frame.\n * Returns [F1, F2, F3] in Hz, or null if extraction fails.\n */\nfunction extractFormants(\n frame: Float32Array,\n sampleRate: number,\n lpcOrder: number = 12\n): [number, number, number] | null {\n const r = autocorrelate(frame, lpcOrder);\n const coeffs = levinsonDurbin(r, lpcOrder);\n\n const roots = findRoots(coeffs);\n\n // Convert roots to frequencies, keep only positive-frequency roots\n const formantCandidates: number[] = [];\n\n for (const [real, imag] of roots) {\n if (imag <= 0) continue; // Keep only positive-frequency roots\n\n const freq = (Math.atan2(imag, real) / (2 * Math.PI)) * sampleRate;\n const bandwidth = (-sampleRate / (2 * Math.PI)) * Math.log(Math.sqrt(real * real + imag * imag));\n\n // Filter: formants are in 200-5000Hz range with reasonable bandwidth\n if (freq > 200 && freq < 5000 && bandwidth < 500) {\n formantCandidates.push(freq);\n }\n }\n\n formantCandidates.sort((a, b) => a - b);\n\n if (formantCandidates.length < 3) return null;\n\n return [formantCandidates[0]!, formantCandidates[1]!, formantCandidates[2]!];\n}\n\n/**\n * Extract formant ratio time series (F1/F2 and F2/F3) from audio.\n * Returns { f1f2: number[], f2f3: number[] } — one ratio per frame where formants were detected.\n */\nexport function extractFormantRatios(\n samples: Float32Array,\n sampleRate: number,\n frameSize: number,\n hopSize: number\n): { f1f2: number[]; f2f3: number[] } {\n const f1f2: number[] = [];\n const f2f3: number[] = [];\n const numFrames = Math.floor((samples.length - frameSize) / hopSize) + 1;\n\n for (let i = 0; i < numFrames; i++) {\n const start = i * hopSize;\n // Read-only — windowed below is a fresh allocation that copies values\n // out, so a zero-copy view here is bit-equivalent and saves a Float32Array.\n const frame = samples.subarray(start, start + frameSize);\n\n // Apply Hamming window\n const windowed = new Float32Array(frameSize);\n for (let j = 0; j < frameSize; j++) {\n windowed[j] = (frame[j] ?? 0) * (0.54 - 0.46 * Math.cos((2 * Math.PI * j) / (frameSize - 1)));\n }\n\n const formants = extractFormants(windowed, sampleRate);\n if (formants) {\n const [f1, f2, f3] = formants;\n if (f2 > 0) f1f2.push(f1 / f2);\n if (f3 > 0) f2f3.push(f2 / f3);\n }\n }\n\n return { f1f2, f2f3 };\n}\n","/**\n * Speaker-dependent audio feature extraction.\n *\n * Extracts features that characterize HOW someone speaks (prosody, vocal physiology)\n * rather than WHAT they say (phonetic content). These features are stable across\n * different utterances from the same speaker.\n *\n * Output: 44 values\n * F0 statistics (5) + F0 delta (4) + jitter (4) + shimmer (4) +\n * HNR statistics (5) + formant ratios (8) + LTAS (8) + voicing ratio (1) +\n * amplitude statistics (5)\n */\nimport type { AudioCapture } from \"../sensor/types\";\nimport { condense, entropy } from \"./statistics\";\nimport { extractFormantRatios } from \"./lpc\";\nimport { sdkWarn } from \"../log\";\n\n/**\n * Compute frame size adaptive to actual sample rate.\n * YIN pitch detection requires: frameSize >= 4 * sampleRate / minF0\n * (because YIN halves the buffer twice internally).\n * Returns next power of 2 for FFT compatibility.\n */\nfunction getFrameSize(sampleRate: number): number {\n const MIN_F0 = 50; // lowest detectable pitch (Hz)\n const minSize = Math.ceil(4 * sampleRate / MIN_F0);\n let size = 512; // minimum\n while (size < minSize) size *= 2;\n return size;\n}\n\n/**\n * Compute hop size as ~10ms at the given sample rate.\n */\nfunction getHopSize(sampleRate: number): number {\n return Math.max(1, Math.round(sampleRate * 0.01));\n}\n\nconst SPEAKER_FEATURE_COUNT = 44;\n\n// Dynamic imports for browser compatibility\nlet pitchDetector: ((buf: Float32Array) => number | null) | null = null;\nlet pitchDetectorRate = 0;\nlet meydaModule: any = null;\n\nasync function getPitchDetector(sampleRate: number): Promise<(buf: Float32Array) => number | null> {\n if (!pitchDetector || pitchDetectorRate !== sampleRate) {\n const PitchFinder = await import(\"pitchfinder\");\n pitchDetector = PitchFinder.YIN({ sampleRate, threshold: 0.15 });\n pitchDetectorRate = sampleRate;\n }\n return pitchDetector;\n}\n\nasync function getMeyda(): Promise<any> {\n if (!meydaModule) {\n try {\n meydaModule = await import(\"meyda\");\n } catch {\n return null;\n }\n }\n return meydaModule.default ?? meydaModule;\n}\n\n/**\n * Detect F0 (fundamental frequency) contour and amplitude peaks per frame.\n */\nasync function detectF0Contour(\n samples: Float32Array,\n sampleRate: number\n): Promise<{ f0: number[]; amplitudes: number[]; periods: number[] }> {\n const detect = await getPitchDetector(sampleRate);\n const frameSize = getFrameSize(sampleRate);\n const hopSize = getHopSize(sampleRate);\n const f0: number[] = [];\n const amplitudes: number[] = [];\n const periods: number[] = [];\n const numFrames = Math.floor((samples.length - frameSize) / hopSize) + 1;\n\n if (sampleRate !== 16000) {\n sdkWarn(`[Entros SDK] Audio captured at ${sampleRate}Hz (requested 16kHz). Frame size adjusted to ${frameSize}.`);\n }\n\n for (let i = 0; i < numFrames; i++) {\n const start = i * hopSize;\n // `subarray` is a zero-copy view — `detect()` and the RMS loop below\n // are read-only, so we save ~1.2k Float32Array allocations per session\n // (and matching GC pressure on Hermes).\n const frame = samples.subarray(start, start + frameSize);\n\n // F0 detection\n const pitch = detect(frame);\n if (pitch && pitch > 50 && pitch < 600) {\n f0.push(pitch);\n periods.push(1 / pitch);\n } else {\n f0.push(0); // unvoiced frame\n }\n\n // RMS amplitude per frame\n let sum = 0;\n for (let j = 0; j < frame.length; j++) {\n sum += (frame[j] ?? 0) * (frame[j] ?? 0);\n }\n amplitudes.push(Math.sqrt(sum / frame.length));\n }\n\n return { f0, amplitudes, periods };\n}\n\n/**\n * Compute jitter measures from pitch period contour.\n * Jitter = cycle-to-cycle perturbation of the fundamental period.\n */\nfunction computeJitter(periods: number[]): number[] {\n const voiced = periods.filter((p) => p > 0);\n if (voiced.length < 3) return [0, 0, 0, 0];\n\n const meanPeriod = voiced.reduce((a, b) => a + b, 0) / voiced.length;\n if (meanPeriod === 0) return [0, 0, 0, 0];\n\n // Jitter (local): average absolute difference between consecutive periods\n let localSum = 0;\n for (let i = 1; i < voiced.length; i++) {\n localSum += Math.abs(voiced[i]! - voiced[i - 1]!);\n }\n const jitterLocal = localSum / (voiced.length - 1) / meanPeriod;\n\n // RAP: Relative Average Perturbation (3-point running average)\n let rapSum = 0;\n for (let i = 1; i < voiced.length - 1; i++) {\n const avg3 = (voiced[i - 1]! + voiced[i]! + voiced[i + 1]!) / 3;\n rapSum += Math.abs(voiced[i]! - avg3);\n }\n const jitterRAP = voiced.length > 2 ? rapSum / (voiced.length - 2) / meanPeriod : 0;\n\n // PPQ5: Five-Point Period Perturbation Quotient\n let ppq5Sum = 0;\n let ppq5Count = 0;\n for (let i = 2; i < voiced.length - 2; i++) {\n const avg5 = (voiced[i - 2]! + voiced[i - 1]! + voiced[i]! + voiced[i + 1]! + voiced[i + 2]!) / 5;\n ppq5Sum += Math.abs(voiced[i]! - avg5);\n ppq5Count++;\n }\n const jitterPPQ5 = ppq5Count > 0 ? ppq5Sum / ppq5Count / meanPeriod : 0;\n\n // DDP: Difference of Differences of Periods\n let ddpSum = 0;\n for (let i = 1; i < voiced.length - 1; i++) {\n const d1 = voiced[i]! - voiced[i - 1]!;\n const d2 = voiced[i + 1]! - voiced[i]!;\n ddpSum += Math.abs(d2 - d1);\n }\n const jitterDDP = voiced.length > 2 ? ddpSum / (voiced.length - 2) / meanPeriod : 0;\n\n return [jitterLocal, jitterRAP, jitterPPQ5, jitterDDP];\n}\n\n/**\n * Compute shimmer measures from amplitude peaks.\n * Shimmer = cycle-to-cycle amplitude perturbation.\n */\nfunction computeShimmer(amplitudes: number[], f0: number[]): number[] {\n // Use amplitudes only at voiced frames\n const voicedAmps = amplitudes.filter((_, i) => f0[i]! > 0);\n if (voicedAmps.length < 3) return [0, 0, 0, 0];\n\n const meanAmp = voicedAmps.reduce((a, b) => a + b, 0) / voicedAmps.length;\n if (meanAmp === 0) return [0, 0, 0, 0];\n\n // Shimmer (local)\n let localSum = 0;\n for (let i = 1; i < voicedAmps.length; i++) {\n localSum += Math.abs(voicedAmps[i]! - voicedAmps[i - 1]!);\n }\n const shimmerLocal = localSum / (voicedAmps.length - 1) / meanAmp;\n\n // APQ3: 3-point Amplitude Perturbation Quotient\n let apq3Sum = 0;\n for (let i = 1; i < voicedAmps.length - 1; i++) {\n const avg3 = (voicedAmps[i - 1]! + voicedAmps[i]! + voicedAmps[i + 1]!) / 3;\n apq3Sum += Math.abs(voicedAmps[i]! - avg3);\n }\n const shimmerAPQ3 = voicedAmps.length > 2 ? apq3Sum / (voicedAmps.length - 2) / meanAmp : 0;\n\n // APQ5\n let apq5Sum = 0;\n let apq5Count = 0;\n for (let i = 2; i < voicedAmps.length - 2; i++) {\n const avg5 = (voicedAmps[i - 2]! + voicedAmps[i - 1]! + voicedAmps[i]! + voicedAmps[i + 1]! + voicedAmps[i + 2]!) / 5;\n apq5Sum += Math.abs(voicedAmps[i]! - avg5);\n apq5Count++;\n }\n const shimmerAPQ5 = apq5Count > 0 ? apq5Sum / apq5Count / meanAmp : 0;\n\n // DDA: Difference of Differences of Amplitudes\n let ddaSum = 0;\n for (let i = 1; i < voicedAmps.length - 1; i++) {\n const d1 = voicedAmps[i]! - voicedAmps[i - 1]!;\n const d2 = voicedAmps[i + 1]! - voicedAmps[i]!;\n ddaSum += Math.abs(d2 - d1);\n }\n const shimmerDDA = voicedAmps.length > 2 ? ddaSum / (voicedAmps.length - 2) / meanAmp : 0;\n\n return [shimmerLocal, shimmerAPQ3, shimmerAPQ5, shimmerDDA];\n}\n\n/**\n * Compute Harmonic-to-Noise Ratio per frame using autocorrelation.\n */\nfunction computeHNR(\n samples: Float32Array,\n sampleRate: number,\n f0Contour: number[]\n): number[] {\n const frameSize = getFrameSize(sampleRate);\n const hopSize = getHopSize(sampleRate);\n const hnr: number[] = [];\n const numFrames = Math.floor((samples.length - frameSize) / hopSize) + 1;\n\n for (let i = 0; i < numFrames && i < f0Contour.length; i++) {\n const f0 = f0Contour[i]!;\n if (f0 <= 0) continue; // Skip unvoiced frames\n\n const start = i * hopSize;\n // Read-only autocorrelation — view is safe.\n const frame = samples.subarray(start, start + frameSize);\n const period = Math.round(sampleRate / f0);\n\n if (period <= 0 || period >= frame.length) continue;\n\n // Autocorrelation at the fundamental period\n let num = 0;\n let den = 0;\n for (let j = 0; j < frame.length - period; j++) {\n num += (frame[j] ?? 0) * (frame[j + period] ?? 0);\n den += (frame[j] ?? 0) * (frame[j] ?? 0);\n }\n\n if (den > 0) {\n const r = num / den;\n const clampedR = Math.max(0.001, Math.min(0.999, r));\n hnr.push(10 * Math.log10(clampedR / (1 - clampedR)));\n }\n }\n\n return hnr;\n}\n\n/**\n * Compute LTAS (Long-Term Average Spectrum) features using Meyda.\n * Returns 8 values: spectral centroid, rolloff, flatness, spread — each mean + variance.\n */\nasync function computeLTAS(\n samples: Float32Array,\n sampleRate: number\n): Promise<number[]> {\n const frameSize = getFrameSize(sampleRate);\n const hopSize = getHopSize(sampleRate);\n const Meyda = await getMeyda();\n if (!Meyda) return new Array(8).fill(0);\n\n const centroids: number[] = [];\n const rolloffs: number[] = [];\n const flatnesses: number[] = [];\n const spreads: number[] = [];\n const numFrames = Math.floor((samples.length - frameSize) / hopSize) + 1;\n // Pre-allocate the buffer Meyda receives — frames are exactly `frameSize`\n // (the loop bounds guarantee no overrun), so we can overwrite each\n // iteration via `.set()` instead of allocating ~1.2k Float32Arrays.\n const paddedFrame = new Float32Array(frameSize);\n\n for (let i = 0; i < numFrames; i++) {\n const start = i * hopSize;\n paddedFrame.set(samples.subarray(start, start + frameSize), 0);\n\n const features = Meyda.extract(\n [\"spectralCentroid\", \"spectralRolloff\", \"spectralFlatness\", \"spectralSpread\"],\n paddedFrame,\n { sampleRate, bufferSize: frameSize }\n );\n\n if (features) {\n if (Number.isFinite(features.spectralCentroid)) centroids.push(features.spectralCentroid);\n if (Number.isFinite(features.spectralRolloff)) rolloffs.push(features.spectralRolloff);\n if (Number.isFinite(features.spectralFlatness)) flatnesses.push(features.spectralFlatness);\n if (Number.isFinite(features.spectralSpread)) spreads.push(features.spectralSpread);\n }\n }\n\n const m = (arr: number[]) => arr.length > 0 ? arr.reduce((a, b) => a + b, 0) / arr.length : 0;\n const v = (arr: number[]) => {\n if (arr.length < 2) return 0;\n const mu = m(arr);\n return arr.reduce((sum, x) => sum + (x - mu) * (x - mu), 0) / (arr.length - 1);\n };\n\n return [\n m(centroids), v(centroids),\n m(rolloffs), v(rolloffs),\n m(flatnesses), v(flatnesses),\n m(spreads), v(spreads),\n ];\n}\n\n/**\n * Compute derivative (frame-to-frame differences) of a time series.\n */\nfunction derivative(values: number[]): number[] {\n const d: number[] = [];\n for (let i = 1; i < values.length; i++) {\n d.push(values[i]! - values[i - 1]!);\n }\n return d;\n}\n\n/**\n * Extract speaker-dependent audio features.\n *\n * Captures physiological vocal characteristics (F0, jitter, shimmer, HNR, formant\n * ratios) that are stable across different utterances from the same speaker.\n * Content-independent by design — different phrases produce similar feature values.\n *\n * Returns 44 values.\n */\n/**\n * Extracts 44 speaker features AND the raw F0 contour.\n * The F0 contour is surfaced so Tier 2 cross-modal temporal analysis can be\n * performed server-side against the motion time-series. Feature vector shape\n * and semantics are unchanged.\n */\nexport async function extractSpeakerFeaturesDetailed(\n audio: AudioCapture,\n): Promise<{ features: number[]; f0Contour: number[] }> {\n const { samples, sampleRate } = audio;\n\n if (!Number.isFinite(sampleRate) || sampleRate <= 0 || samples.length === 0) {\n sdkWarn(\"[Entros SDK] Invalid audio data. Speaker features will be zeros.\");\n return { features: new Array(SPEAKER_FEATURE_COUNT).fill(0), f0Contour: [] };\n }\n\n const frameSize = getFrameSize(sampleRate);\n const hopSize = getHopSize(sampleRate);\n\n const numFrames = Math.floor((samples.length - frameSize) / hopSize) + 1;\n if (numFrames < 5) {\n sdkWarn(`[Entros SDK] Too few audio frames (${numFrames}). Speaker features will be zeros.`);\n return { features: new Array(SPEAKER_FEATURE_COUNT).fill(0), f0Contour: [] };\n }\n\n // Peak-normalize audio for robust pitch detection.\n // Raw mic input (especially desktop without AGC) can be very quiet,\n // causing autocorrelation-based pitch detectors to fail.\n // All relative features (jitter, shimmer, HNR, F0) are unaffected\n // since they measure ratios, not absolute levels.\n // Absolute amplitude is computed from the original samples below.\n let peakAmp = 0;\n for (let i = 0; i < samples.length; i++) {\n const abs = Math.abs(samples[i] ?? 0);\n if (abs > peakAmp) peakAmp = abs;\n }\n\n // Single-allocation normalisation. Order of operations preserved exactly\n // (`(s / peakAmp) * 0.9`) so the output is bit-identical to the previous\n // `samples.map(...)` form.\n let normalizedSamples: Float32Array;\n if (peakAmp > 1e-6) {\n normalizedSamples = new Float32Array(samples.length);\n for (let i = 0; i < samples.length; i++) {\n normalizedSamples[i] = (samples[i]! / peakAmp) * 0.9;\n }\n } else {\n normalizedSamples = samples;\n }\n\n // 1. F0 detection + amplitude contour (on normalized audio)\n const { f0, amplitudes: normalizedAmplitudes, periods } = await detectF0Contour(normalizedSamples, sampleRate);\n\n // Compute amplitude from ORIGINAL samples (pre-normalization) for biometric consistency\n const amplitudes: number[] = [];\n for (let i = 0; i < numFrames; i++) {\n const start = i * hopSize;\n let sum = 0;\n const end = Math.min(start + frameSize, samples.length);\n for (let j = start; j < end; j++) {\n sum += (samples[j] ?? 0) * (samples[j] ?? 0);\n }\n amplitudes.push(Math.sqrt(sum / (end - start)));\n }\n\n const voicedF0 = f0.filter((v) => v > 0);\n const voicedRatio = voicedF0.length / f0.length;\n\n // 2. F0 statistics (5 values)\n const f0Stats = condense(voicedF0);\n const f0Entropy = entropy(voicedF0);\n const f0Features = [f0Stats.mean, f0Stats.variance, f0Stats.skewness, f0Stats.kurtosis, f0Entropy];\n\n // 3. F0 delta statistics (4 values)\n const f0Delta = derivative(voicedF0);\n const f0DeltaStats = condense(f0Delta);\n const f0DeltaFeatures = [f0DeltaStats.mean, f0DeltaStats.variance, f0DeltaStats.skewness, f0DeltaStats.kurtosis];\n\n // 4. Jitter (4 values)\n const jitterFeatures = computeJitter(periods);\n\n // 5. Shimmer (4 values)\n const shimmerFeatures = computeShimmer(amplitudes, f0);\n\n // 6. HNR statistics (5 values)\n const hnrValues = computeHNR(normalizedSamples, sampleRate, f0);\n const hnrStats = condense(hnrValues);\n const hnrEntropy = entropy(hnrValues);\n const hnrFeatures = [hnrStats.mean, hnrStats.variance, hnrStats.skewness, hnrStats.kurtosis, hnrEntropy];\n\n // 7. Formant ratios (8 values)\n const { f1f2, f2f3 } = extractFormantRatios(normalizedSamples, sampleRate, frameSize, hopSize);\n const f1f2Stats = condense(f1f2);\n const f2f3Stats = condense(f2f3);\n const formantFeatures = [\n f1f2Stats.mean, f1f2Stats.variance, f1f2Stats.skewness, f1f2Stats.kurtosis,\n f2f3Stats.mean, f2f3Stats.variance, f2f3Stats.skewness, f2f3Stats.kurtosis,\n ];\n\n // 8. LTAS (8 values)\n const ltasFeatures = await computeLTAS(samples, sampleRate);\n\n // 9. Voicing ratio (1 value)\n const voicingFeatures = [voicedRatio];\n\n // 10. Amplitude statistics (5 values)\n const ampStats = condense(amplitudes);\n const ampEntropy = entropy(amplitudes);\n const ampFeatures = [ampStats.mean, ampStats.variance, ampStats.skewness, ampStats.kurtosis, ampEntropy];\n\n const features = [\n ...f0Features, // 5\n ...f0DeltaFeatures, // 4\n ...jitterFeatures, // 4\n ...shimmerFeatures, // 4\n ...hnrFeatures, // 5\n ...formantFeatures, // 8\n ...ltasFeatures, // 8\n ...voicingFeatures, // 1\n ...ampFeatures, // 5\n ]; // = 44\n\n return { features, f0Contour: f0 };\n}\n\n/**\n * Extracts 44 speaker features. Backward-compatible wrapper that discards\n * the F0 contour; use `extractSpeakerFeaturesDetailed` when the contour is\n * needed (e.g. for Tier 2 server-side cross-modal analysis).\n */\nexport async function extractSpeakerFeatures(audio: AudioCapture): Promise<number[]> {\n const { features } = await extractSpeakerFeaturesDetailed(audio);\n return features;\n}\n\nexport { SPEAKER_FEATURE_COUNT };\n","import type { MotionSample, TouchSample } from \"../sensor/types\";\nimport { condense, variance, entropy } from \"./statistics\";\n\n/**\n * Compute per-sample acceleration magnitude |a| = √(ax² + ay² + az²) and\n * linearly resample to a target frame count. Used for Tier 2 cross-modal\n * temporal analysis against the F0 contour; the two time-series must share\n * the same frame count for direct correlation.\n *\n * Returns an empty array if motion data is absent or too short.\n */\nexport function extractAccelerationMagnitude(\n samples: MotionSample[],\n targetFrameCount: number,\n): number[] {\n if (samples.length < 2 || targetFrameCount < 2) return [];\n\n const magnitudes = samples.map((s) => Math.sqrt(s.ax * s.ax + s.ay * s.ay + s.az * s.az));\n\n if (magnitudes.length === targetFrameCount) return magnitudes;\n\n // Linear resample: map target index i to source position (i / (target-1)) * (source-1)\n const out = new Array<number>(targetFrameCount);\n const srcLen = magnitudes.length;\n const scale = (srcLen - 1) / (targetFrameCount - 1);\n for (let i = 0; i < targetFrameCount; i++) {\n const pos = i * scale;\n const lo = Math.floor(pos);\n const hi = Math.min(lo + 1, srcLen - 1);\n const t = pos - lo;\n out[i] = magnitudes[lo]! * (1 - t) + magnitudes[hi]! * t;\n }\n return out;\n}\n\n/**\n * Extract kinematic features from motion (IMU) data.\n * Computes jerk (3rd derivative) and jounce (4th derivative) of acceleration,\n * then condenses each axis into statistics.\n *\n * Returns: ~54 values (6 axes × 2 derivatives × 4 stats + 6 jitter variance values)\n */\nexport function extractMotionFeatures(samples: MotionSample[]): number[] {\n if (samples.length < 5) return new Array(54).fill(0);\n\n // Extract acceleration and rotation time series\n const axes = {\n ax: samples.map((s) => s.ax),\n ay: samples.map((s) => s.ay),\n az: samples.map((s) => s.az),\n gx: samples.map((s) => s.gx),\n gy: samples.map((s) => s.gy),\n gz: samples.map((s) => s.gz),\n };\n\n const features: number[] = [];\n\n for (const values of Object.values(axes)) {\n // Jerk = 3rd derivative of position = 1st derivative of acceleration\n const jerk = derivative(values);\n // Jounce = 4th derivative of position = 2nd derivative of acceleration\n const jounce = derivative(jerk);\n\n const jerkStats = condense(jerk);\n const jounceStats = condense(jounce);\n\n features.push(\n jerkStats.mean,\n jerkStats.variance,\n jerkStats.skewness,\n jerkStats.kurtosis,\n jounceStats.mean,\n jounceStats.variance,\n jounceStats.skewness,\n jounceStats.kurtosis\n );\n }\n\n // Jitter variance per axis: variance of windowed jerk variance.\n // Real human tremor fluctuates over time (high jitter variance).\n // Synthetic/replay data has constant jitter (low jitter variance).\n for (const values of Object.values(axes)) {\n const jerk = derivative(values);\n const windowSize = Math.max(5, Math.floor(jerk.length / 4));\n const windowVariances: number[] = [];\n for (let i = 0; i <= jerk.length - windowSize; i += windowSize) {\n windowVariances.push(variance(jerk.slice(i, i + windowSize)));\n }\n features.push(windowVariances.length >= 2 ? variance(windowVariances) : 0);\n }\n\n return features;\n}\n\n/**\n * Extract kinematic features from touch data.\n * Computes velocity and acceleration of touch coordinates,\n * plus pressure and area statistics.\n *\n * Returns: ~36 values (32 base + 4 jitter variance for x, y, pressure, area)\n */\nexport function extractTouchFeatures(samples: TouchSample[]): number[] {\n if (samples.length < 5) return new Array(36).fill(0);\n\n const x = samples.map((s) => s.x);\n const y = samples.map((s) => s.y);\n const pressure = samples.map((s) => s.pressure);\n const area = samples.map((s) => s.width * s.height);\n\n const features: number[] = [];\n\n // X velocity and acceleration\n const vx = derivative(x);\n const accX = derivative(vx);\n features.push(...Object.values(condense(vx)));\n features.push(...Object.values(condense(accX)));\n\n // Y velocity and acceleration\n const vy = derivative(y);\n const accY = derivative(vy);\n features.push(...Object.values(condense(vy)));\n features.push(...Object.values(condense(accY)));\n\n // Pressure statistics\n features.push(...Object.values(condense(pressure)));\n\n // Contact area statistics\n features.push(...Object.values(condense(area)));\n\n // Jerk of touch path\n const jerkX = derivative(accX);\n const jerkY = derivative(accY);\n features.push(...Object.values(condense(jerkX)));\n features.push(...Object.values(condense(jerkY)));\n\n // Jitter variance for touch signals: detects synthetic smoothness\n for (const values of [vx, vy, pressure, area]) {\n const windowSize = Math.max(5, Math.floor(values.length / 4));\n const windowVariances: number[] = [];\n for (let i = 0; i <= values.length - windowSize; i += windowSize) {\n windowVariances.push(variance(values.slice(i, i + windowSize)));\n }\n features.push(windowVariances.length >= 2 ? variance(windowVariances) : 0);\n }\n\n return features;\n}\n\n/** Compute discrete derivative (differences between consecutive values) */\nfunction derivative(values: number[]): number[] {\n const d: number[] = [];\n for (let i = 1; i < values.length; i++) {\n d.push((values[i] ?? 0) - (values[i - 1] ?? 0));\n }\n return d;\n}\n\n/**\n * Extract mouse dynamics features as a desktop replacement for motion sensor data.\n * Captures behavioral patterns from mouse/pointer movement that are user-specific:\n * path curvature, speed patterns, micro-corrections, pause behavior.\n *\n * Returns: 54 values (matches motion feature dimension for consistent SimHash input)\n */\nexport function extractMouseDynamics(samples: TouchSample[]): number[] {\n if (samples.length < 10) return new Array(54).fill(0);\n\n const x = samples.map((s) => s.x);\n const y = samples.map((s) => s.y);\n const pressure = samples.map((s) => s.pressure);\n const area = samples.map((s) => s.width * s.height);\n\n // Velocity\n const vx = derivative(x);\n const vy = derivative(y);\n const speed = vx.map((dx, i) => Math.sqrt(dx * dx + (vy[i] ?? 0) * (vy[i] ?? 0)));\n\n // Acceleration\n const accX = derivative(vx);\n const accY = derivative(vy);\n const acc = accX.map((ax, i) => Math.sqrt(ax * ax + (accY[i] ?? 0) * (accY[i] ?? 0)));\n\n // Jerk (derivative of acceleration)\n const jerkX = derivative(accX);\n const jerkY = derivative(accY);\n const jerk = jerkX.map((jx, i) => Math.sqrt(jx * jx + (jerkY[i] ?? 0) * (jerkY[i] ?? 0)));\n\n // Path curvature: angle change between consecutive movement vectors\n const curvatures: number[] = [];\n for (let i = 1; i < vx.length; i++) {\n const angle1 = Math.atan2(vy[i - 1] ?? 0, vx[i - 1] ?? 0);\n const angle2 = Math.atan2(vy[i] ?? 0, vx[i] ?? 0);\n let diff = angle2 - angle1;\n while (diff > Math.PI) diff -= 2 * Math.PI;\n while (diff < -Math.PI) diff += 2 * Math.PI;\n curvatures.push(Math.abs(diff));\n }\n\n // Movement directions for directional entropy\n const directions = vx.map((dx, i) => Math.atan2(vy[i] ?? 0, dx));\n\n // Micro-corrections: direction reversals\n let reversals = 0;\n for (let i = 2; i < directions.length; i++) {\n const d1 = directions[i - 1]! - directions[i - 2]!;\n const d2 = directions[i]! - directions[i - 1]!;\n if (d1 * d2 < 0) reversals++;\n }\n const reversalRate = directions.length > 2 ? reversals / (directions.length - 2) : 0;\n const reversalMagnitude = curvatures.length > 0\n ? curvatures.reduce((a, b) => a + b, 0) / curvatures.length\n : 0;\n\n // Pause detection: frames where speed is near zero\n const speedThreshold = 0.5;\n const pauseFrames = speed.filter((s) => s < speedThreshold).length;\n const pauseRatio = speed.length > 0 ? pauseFrames / speed.length : 0;\n\n // Path efficiency: straight-line distance / total path length\n const totalPathLength = speed.reduce((a, b) => a + b, 0);\n const straightLine = Math.sqrt(\n (x[x.length - 1]! - x[0]!) ** 2 + (y[y.length - 1]! - y[0]!) ** 2\n );\n const pathEfficiency = totalPathLength > 0 ? straightLine / totalPathLength : 0;\n\n // Movement durations between pauses\n const movementDurations: number[] = [];\n let currentDuration = 0;\n for (const s of speed) {\n if (s >= speedThreshold) {\n currentDuration++;\n } else if (currentDuration > 0) {\n movementDurations.push(currentDuration);\n currentDuration = 0;\n }\n }\n if (currentDuration > 0) movementDurations.push(currentDuration);\n\n // Segment lengths between direction changes\n const segmentLengths: number[] = [];\n let segLen = 0;\n for (let i = 1; i < directions.length; i++) {\n segLen += speed[i] ?? 0;\n const angleDiff = Math.abs(directions[i]! - directions[i - 1]!);\n if (angleDiff > Math.PI / 4) {\n segmentLengths.push(segLen);\n segLen = 0;\n }\n }\n if (segLen > 0) segmentLengths.push(segLen);\n\n // Windowed jitter variance of speed\n const windowSize = Math.max(5, Math.floor(speed.length / 4));\n const windowVariances: number[] = [];\n for (let i = 0; i + windowSize <= speed.length; i += windowSize) {\n const window = speed.slice(i, i + windowSize);\n windowVariances.push(variance(window));\n }\n const speedJitter = windowVariances.length > 1 ? variance(windowVariances) : 0;\n\n // Path length normalized by capture duration\n const duration = samples.length > 1\n ? (samples[samples.length - 1]!.timestamp - samples[0]!.timestamp) / 1000\n : 1;\n const normalizedPathLength = totalPathLength / Math.max(duration, 0.001);\n\n // Angle autocorrelation at lags 1, 2, 3\n const angleAutoCorr: number[] = [];\n for (let lag = 1; lag <= 3; lag++) {\n if (directions.length <= lag) {\n angleAutoCorr.push(0);\n continue;\n }\n const n = directions.length - lag;\n const meanDir = directions.reduce((a, b) => a + b, 0) / directions.length;\n let num = 0;\n let den = 0;\n for (let i = 0; i < n; i++) {\n num += (directions[i]! - meanDir) * (directions[i + lag]! - meanDir);\n den += (directions[i]! - meanDir) ** 2;\n }\n angleAutoCorr.push(den > 0 ? num / den : 0);\n }\n\n // Assemble 54 features\n const curvatureStats = condense(curvatures); // 4\n const dirEntropy = entropy(directions, 16); // 1\n const speedStats = condense(speed); // 4\n const accStats = condense(acc); // 4\n // micro-corrections: reversalRate + reversalMagnitude // 2\n // pauseRatio // 1\n // pathEfficiency // 1\n // speedJitter // 1\n const jerkStats = condense(jerk); // 4\n const vxStats = condense(vx); // 4\n const vyStats = condense(vy); // 4\n const accXStats = condense(accX); // 4\n const accYStats = condense(accY); // 4\n const pressureStats = condense(pressure); // 4\n const moveDurStats = condense(movementDurations); // 4\n const segLenStats = condense(segmentLengths); // 4\n // angleAutoCorr[0..2] // 3\n // normalizedPathLength // 1\n // Total: 4+1+4+4+2+1+1+1+4+4+4+4+4+4+4+4+3+1 = 54\n\n return [\n curvatureStats.mean, curvatureStats.variance, curvatureStats.skewness, curvatureStats.kurtosis,\n dirEntropy,\n speedStats.mean, speedStats.variance, speedStats.skewness, speedStats.kurtosis,\n accStats.mean, accStats.variance, accStats.skewness, accStats.kurtosis,\n reversalRate, reversalMagnitude,\n pauseRatio,\n pathEfficiency,\n speedJitter,\n jerkStats.mean, jerkStats.variance, jerkStats.skewness, jerkStats.kurtosis,\n vxStats.mean, vxStats.variance, vxStats.skewness, vxStats.kurtosis,\n vyStats.mean, vyStats.variance, vyStats.skewness, vyStats.kurtosis,\n accXStats.mean, accXStats.variance, accXStats.skewness, accXStats.kurtosis,\n accYStats.mean, accYStats.variance, accYStats.skewness, accYStats.kurtosis,\n pressureStats.mean, pressureStats.variance, pressureStats.skewness, pressureStats.kurtosis,\n moveDurStats.mean, moveDurStats.variance, moveDurStats.skewness, moveDurStats.kurtosis,\n segLenStats.mean, segLenStats.variance, segLenStats.skewness, segLenStats.kurtosis,\n angleAutoCorr[0] ?? 0, angleAutoCorr[1] ?? 0, angleAutoCorr[2] ?? 0,\n normalizedPathLength,\n ];\n}\n","import { FINGERPRINT_BITS, SIMHASH_SEED } from \"../config\";\nimport { sdkWarn } from \"../log\";\nimport type { TemporalFingerprint } from \"./types\";\n\n// Mulberry32 PRNG: deterministic, fast, good distribution\nfunction mulberry32(seed: number): () => number {\n let state = seed | 0;\n return () => {\n state = (state + 0x6d2b79f5) | 0;\n let t = Math.imul(state ^ (state >>> 15), 1 | state);\n t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;\n return ((t ^ (t >>> 14)) >>> 0) / 4294967296;\n };\n}\n\n// Derive a numeric seed from the protocol seed string\nfunction deriveSeed(seedStr: string): number {\n let hash = 0;\n for (let i = 0; i < seedStr.length; i++) {\n const ch = seedStr.charCodeAt(i);\n hash = ((hash << 5) - hash + ch) | 0;\n }\n return hash;\n}\n\nlet cachedHyperplanes: number[][] | null = null;\nlet cachedDimension = 0;\n\nfunction getHyperplanes(dimension: number): number[][] {\n if (cachedHyperplanes && cachedDimension === dimension) {\n return cachedHyperplanes;\n }\n\n const rng = mulberry32(deriveSeed(SIMHASH_SEED));\n const planes: number[][] = [];\n\n for (let i = 0; i < FINGERPRINT_BITS; i++) {\n const plane: number[] = [];\n for (let j = 0; j < dimension; j++) {\n // Random value in [-1, 1]\n plane.push(rng() * 2 - 1);\n }\n planes.push(plane);\n }\n\n cachedHyperplanes = planes;\n cachedDimension = dimension;\n return planes;\n}\n\n/**\n * Compute a 256-bit SimHash fingerprint from a feature vector.\n * Uses deterministic random hyperplanes seeded from the protocol constant.\n * Similar feature vectors produce fingerprints with low Hamming distance.\n */\nconst EXPECTED_FEATURE_DIMENSION = 134; // 44 speaker + 54 motion/mouse + 36 touch\n\nexport function simhash(features: number[]): TemporalFingerprint {\n if (features.length === 0) {\n return new Array(FINGERPRINT_BITS).fill(0);\n }\n\n if (features.length !== EXPECTED_FEATURE_DIMENSION) {\n sdkWarn(\n `[Entros SDK] Feature vector has ${features.length} dimensions, expected ${EXPECTED_FEATURE_DIMENSION}. ` +\n `Fingerprint quality may be degraded.`\n );\n }\n\n const planes = getHyperplanes(features.length);\n const fingerprint: TemporalFingerprint = [];\n\n for (let i = 0; i < FINGERPRINT_BITS; i++) {\n const plane = planes[i];\n let dot = 0;\n for (let j = 0; j < features.length; j++) {\n dot += (features[j] ?? 0) * (plane?.[j] ?? 0);\n }\n fingerprint.push(dot >= 0 ? 1 : 0);\n }\n\n return fingerprint;\n}\n\n/**\n * Compute Hamming distance between two fingerprints.\n */\nexport function hammingDistance(\n a: TemporalFingerprint,\n b: TemporalFingerprint\n): number {\n let distance = 0;\n for (let i = 0; i < a.length; i++) {\n if (a[i] !== b[i]) distance++;\n }\n return distance;\n}\n","import { BN254_SCALAR_FIELD, FINGERPRINT_BITS } from \"../config\";\nimport type { PackedFingerprint, TBH, TemporalFingerprint } from \"./types\";\n\n// Lazy-initialized Poseidon instance\nlet poseidonInstance: any = null;\n\nasync function getPoseidon(): Promise<any> {\n if (!poseidonInstance) {\n const circomlibjs = await import(\"circomlibjs\");\n poseidonInstance = await (circomlibjs as any).buildPoseidon();\n }\n return poseidonInstance;\n}\n\n/**\n * Pack 256-bit fingerprint into two 128-bit field elements.\n * Little-endian bit ordering within each chunk (matches circuit's Bits2Num).\n */\nexport function packBits(fingerprint: TemporalFingerprint): PackedFingerprint {\n let lo = BigInt(0);\n for (let i = 0; i < 128; i++) {\n if (fingerprint[i] === 1) {\n lo += BigInt(1) << BigInt(i);\n }\n }\n\n let hi = BigInt(0);\n for (let i = 0; i < 128; i++) {\n if (fingerprint[128 + i] === 1) {\n hi += BigInt(1) << BigInt(i);\n }\n }\n\n return { lo, hi };\n}\n\n/**\n * Compute Poseidon commitment: Poseidon(pack_lo, pack_hi, salt).\n * Matches the circuit's CommitmentCheck template exactly.\n */\nexport async function computeCommitment(\n fingerprint: TemporalFingerprint,\n salt: bigint\n): Promise<bigint> {\n const poseidon = await getPoseidon();\n const { lo, hi } = packBits(fingerprint);\n const hash = poseidon([lo, hi, salt]);\n return poseidon.F.toObject(hash) as bigint;\n}\n\n/**\n * Generate a random salt within the BN254 scalar field.\n */\nexport function generateSalt(): bigint {\n const bytes = new Uint8Array(31);\n crypto.getRandomValues(bytes);\n let val = BigInt(0);\n for (let i = 0; i < bytes.length; i++) {\n val = (val << BigInt(8)) + BigInt(bytes[i] ?? 0);\n }\n return val % BN254_SCALAR_FIELD;\n}\n\n/**\n * Convert a BigInt to a 32-byte big-endian Uint8Array.\n */\nexport function bigintToBytes32(n: bigint): Uint8Array {\n const bytes = new Uint8Array(32);\n let val = n;\n for (let i = 31; i >= 0; i--) {\n bytes[i] = Number(val & BigInt(0xff));\n val >>= BigInt(8);\n }\n return bytes;\n}\n\n/**\n * Generate a complete TBH from a fingerprint.\n */\nexport async function generateTBH(\n fingerprint: TemporalFingerprint,\n salt?: bigint\n): Promise<TBH> {\n const s = salt ?? generateSalt();\n const commitment = await computeCommitment(fingerprint, s);\n return {\n fingerprint,\n salt: s,\n commitment,\n commitmentBytes: bigintToBytes32(commitment),\n };\n}\n","import {\n BN254_BASE_FIELD,\n PROOF_A_SIZE,\n PROOF_B_SIZE,\n PROOF_C_SIZE,\n TOTAL_PROOF_SIZE,\n NUM_PUBLIC_INPUTS,\n} from \"../config\";\nimport type { RawProof, SolanaProof } from \"./types\";\n\n/**\n * Convert a decimal string to a 32-byte big-endian Uint8Array.\n */\nexport function toBigEndian32(decStr: string): Uint8Array {\n let n = BigInt(decStr);\n const bytes = new Uint8Array(32);\n for (let i = 31; i >= 0; i--) {\n bytes[i] = Number(n & BigInt(0xff));\n n >>= BigInt(8);\n }\n return bytes;\n}\n\n/**\n * Negate a G1 y-coordinate for groth16-solana proof_a format.\n */\nfunction negateG1Y(yDecStr: string): Uint8Array {\n const y = BigInt(yDecStr);\n const yNeg = (BN254_BASE_FIELD - y) % BN254_BASE_FIELD;\n return toBigEndian32(yNeg.toString());\n}\n\n/**\n * Serialize an snarkjs proof into the 256-byte format groth16-solana expects.\n *\n * proof_a: 64 bytes (x + negated y)\n * proof_b: 128 bytes (G2 with reversed coordinate ordering: c1 before c0)\n * proof_c: 64 bytes (x + y)\n */\nexport function serializeProof(\n proof: RawProof,\n publicSignals: string[]\n): SolanaProof {\n if (publicSignals.length !== NUM_PUBLIC_INPUTS) {\n throw new Error(\n `Expected ${NUM_PUBLIC_INPUTS} public signals, got ${publicSignals.length}`\n );\n }\n\n // proof_a: x (32 bytes) + negated y (32 bytes)\n const a0 = toBigEndian32(proof.pi_a[0]!);\n const a1 = negateG1Y(proof.pi_a[1]!);\n const proofA = new Uint8Array(PROOF_A_SIZE);\n proofA.set(a0, 0);\n proofA.set(a1, 32);\n\n // proof_b: G2 reversed coordinate ordering\n const b00 = toBigEndian32(proof.pi_b[0]![1]!); // c1 first\n const b01 = toBigEndian32(proof.pi_b[0]![0]!); // c0 second\n const b10 = toBigEndian32(proof.pi_b[1]![1]!);\n const b11 = toBigEndian32(proof.pi_b[1]![0]!);\n const proofB = new Uint8Array(PROOF_B_SIZE);\n proofB.set(b00, 0);\n proofB.set(b01, 32);\n proofB.set(b10, 64);\n proofB.set(b11, 96);\n\n // proof_c: x + y (no negation)\n const c0 = toBigEndian32(proof.pi_c[0]!);\n const c1 = toBigEndian32(proof.pi_c[1]!);\n const proofC = new Uint8Array(PROOF_C_SIZE);\n proofC.set(c0, 0);\n proofC.set(c1, 32);\n\n // Combine into single 256-byte blob\n const proofBytes = new Uint8Array(TOTAL_PROOF_SIZE);\n proofBytes.set(proofA, 0);\n proofBytes.set(proofB, PROOF_A_SIZE);\n proofBytes.set(proofC, PROOF_A_SIZE + PROOF_B_SIZE);\n\n // Public inputs as 32-byte big-endian arrays\n const publicInputs = publicSignals.map((s) => toBigEndian32(s));\n\n return { proofBytes, publicInputs };\n}\n","import type { TBH } from \"../hashing/types\";\nimport type { CircuitInput, ProofResult, SolanaProof } from \"./types\";\nimport { serializeProof } from \"./serializer\";\nimport { DEFAULT_THRESHOLD, DEFAULT_MIN_DISTANCE } from \"../config\";\n\n// Use dynamic import for snarkjs (it's a CJS module)\nlet snarkjsModule: any = null;\n\nasync function getSnarkjs(): Promise<any> {\n if (!snarkjsModule) {\n snarkjsModule = await import(\"snarkjs\");\n }\n return snarkjsModule;\n}\n\n/**\n * Prepare circuit input from current and previous TBH data.\n */\nexport function prepareCircuitInput(\n current: TBH,\n previous: TBH,\n threshold: number = DEFAULT_THRESHOLD,\n minDistance: number = DEFAULT_MIN_DISTANCE\n): CircuitInput {\n return {\n ft_new: current.fingerprint,\n ft_prev: previous.fingerprint,\n salt_new: current.salt.toString(),\n salt_prev: previous.salt.toString(),\n commitment_new: current.commitment.toString(),\n commitment_prev: previous.commitment.toString(),\n threshold: threshold.toString(),\n min_distance: minDistance.toString(),\n };\n}\n\n/**\n * Generate a Groth16 proof for the Hamming distance circuit.\n *\n * @param input - Circuit input (fingerprints, salts, commitments, threshold)\n * @param wasmPath - Path or URL to entros_hamming.wasm\n * @param zkeyPath - Path or URL to entros_hamming_final.zkey\n */\nexport async function generateProof(\n input: CircuitInput,\n wasmPath: string,\n zkeyPath: string\n): Promise<ProofResult> {\n const snarkjs = await getSnarkjs();\n const { proof, publicSignals } = await snarkjs.groth16.fullProve(\n input,\n wasmPath,\n zkeyPath\n );\n return { proof, publicSignals };\n}\n\n/**\n * Generate a proof and serialize it for Solana submission.\n */\nexport async function generateSolanaProof(\n current: TBH,\n previous: TBH,\n wasmPath: string,\n zkeyPath: string,\n threshold?: number\n): Promise<SolanaProof> {\n const input = prepareCircuitInput(current, previous, threshold);\n const { proof, publicSignals } = await generateProof(\n input,\n wasmPath,\n zkeyPath\n );\n return serializeProof(proof, publicSignals);\n}\n\n/**\n * Verify a proof locally using snarkjs (for debugging/testing).\n * Caller is responsible for loading the verification key.\n */\nexport async function verifyProofLocally(\n proof: any,\n publicSignals: string[],\n vkey: Record<string, unknown>\n): Promise<boolean> {\n const snarkjs = await getSnarkjs();\n return snarkjs.groth16.verify(vkey, publicSignals, proof);\n}\n","import type { SignedReceiptDto } from \"./types\";\n\n/**\n * Expected byte lengths for the receipt's three hex-encoded fields. Values\n * are pinned at the wire format defined by `entros_validation::receipts`\n * and verified on-chain in `entros_anchor::verify_mint_receipt`.\n *\n * Pubkey: Ed25519 public key (32B). Signature: Ed25519 signature (64B).\n * Message: `wallet_pubkey (32) || commitment_new (32) || validated_at i64 LE (8) = 72B`.\n */\nconst PUBKEY_BYTES = 32;\nconst SIGNATURE_BYTES = 64;\nconst MESSAGE_BYTES = 72;\n\n/**\n * Lowercase hex encoding without `0x` prefix. Matches the validator's\n * `hex::encode` output exactly (lowercase, no separators) so the receipt's\n * `commitment_new_hex` round-trips byte-identical between SDK and validator.\n */\nexport function bytesToHex(bytes: Uint8Array): string {\n let out = \"\";\n for (let i = 0; i < bytes.length; i += 1) {\n out += (bytes[i] ?? 0).toString(16).padStart(2, \"0\");\n }\n return out;\n}\n\n/**\n * Decode a hex string into a Uint8Array of the expected byte length. Returns\n * `null` on malformed input (odd length, non-hex characters, wrong length).\n * Permissive about a leading `0x` because some integrations may strip or\n * preserve it inconsistently.\n */\nfunction hexToBytes(hex: string, expectedLen: number): Uint8Array | null {\n const trimmed = hex.startsWith(\"0x\") || hex.startsWith(\"0X\") ? hex.slice(2) : hex;\n if (trimmed.length !== expectedLen * 2) return null;\n if (!/^[0-9a-fA-F]+$/.test(trimmed)) return null;\n const out = new Uint8Array(expectedLen);\n for (let i = 0; i < expectedLen; i += 1) {\n out[i] = parseInt(trimmed.substr(i * 2, 2), 16);\n }\n return out;\n}\n\n/**\n * Decoded byte form of a `SignedReceiptDto`. `null` slots indicate the\n * caller should treat the receipt as unusable and fall back to the\n * no-receipt mint flow (Phase 3 on-chain check logs and proceeds).\n */\nexport interface DecodedReceipt {\n publicKey: Uint8Array;\n signature: Uint8Array;\n message: Uint8Array;\n}\n\n/**\n * Decode a `SignedReceiptDto` from hex strings into raw bytes. Returns `null`\n * if any field is malformed — callers should skip Ed25519 ix construction in\n * that case rather than building an ix the on-chain parser will reject.\n */\nexport function decodeSignedReceipt(receipt: SignedReceiptDto): DecodedReceipt | null {\n const publicKey = hexToBytes(receipt.validator_pubkey_hex, PUBKEY_BYTES);\n const signature = hexToBytes(receipt.signature_hex, SIGNATURE_BYTES);\n const message = hexToBytes(receipt.message_hex, MESSAGE_BYTES);\n if (!publicKey || !signature || !message) return null;\n return { publicKey, signature, message };\n}\n\n/**\n * Build the `Ed25519Program::verify` instruction that binds a validator-signed\n * mint receipt to the immediately-following `mint_anchor` instruction\n * (master-list #146 Phase 4).\n *\n * Returns `null` if the receipt fails to decode — caller should fall back to\n * sending `mint_anchor` without an Ed25519 prefix. Phase 3's on-chain check\n * is log-only, so the fallback still works on the deployed program; once\n * Phase 5 enforcement flips, missing receipts hard-fail and the SDK's no-op\n * fallback becomes a deliberate \"no-receipt\" path that mint_anchor rejects.\n *\n * Web3.js's `Ed25519Program.createInstructionWithPublicKey` defaults the\n * three `*_instruction_index` fields to `0xFFFF`, which is the exact\n * \"current instruction\" sentinel the on-chain parser pins to. Cross-ix\n * substitution attacks are closed by that sentinel — we never build a\n * receipt that points at another ix's data.\n */\nexport async function buildEd25519ReceiptIx(\n receipt: SignedReceiptDto,\n): Promise<import(\"@solana/web3.js\").TransactionInstruction | null> {\n const decoded = decodeSignedReceipt(receipt);\n if (!decoded) return null;\n\n const { Ed25519Program } = await import(\"@solana/web3.js\");\n return Ed25519Program.createInstructionWithPublicKey({\n publicKey: decoded.publicKey,\n message: decoded.message,\n signature: decoded.signature,\n });\n}\n","/* eslint-disable @typescript-eslint/no-explicit-any */\n// Anchor program interactions use runtime IDL fetching, requiring dynamic typing.\nimport type { SolanaProof } from \"../proof/types\";\nimport type { SignedReceiptDto, SubmissionResult } from \"./types\";\nimport { PROGRAM_IDS } from \"../config\";\nimport { sdkLog, sdkWarn } from \"../log\";\nimport { buildEd25519ReceiptIx } from \"./receipt\";\n\n/**\n * Best-effort SAS attestation request. POSTs to the executor's `/attest`\n * endpoint with the wallet's public key, an optional server-issued challenge\n * nonce, and an `Entros-ATTEST:{wallet}:{timestamp}` ownership signature.\n *\n * Returns the attestation tx signature on success, `undefined` on any\n * failure (attestation is non-fatal — the on-chain tx has already confirmed\n * by the time this is called).\n */\nasync function requestSasAttestation(\n wallet: any,\n walletAddress: string,\n relayerUrl: string,\n relayerApiKey: string | undefined,\n serverNonce: number[] | undefined,\n): Promise<string | undefined> {\n try {\n const attestHeaders: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n };\n if (relayerApiKey) {\n attestHeaders[\"X-API-Key\"] = relayerApiKey;\n }\n\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), 15_000);\n\n const baseUrl = new URL(relayerUrl);\n const attestUrl = `${baseUrl.origin}/attest`;\n\n const attestBody: Record<string, unknown> = { wallet_address: walletAddress };\n if (serverNonce) attestBody.nonce = serverNonce;\n\n if (wallet?.signMessage) {\n try {\n const timestamp = Math.floor(Date.now() / 1000);\n const attestMessage = `Entros-ATTEST:${walletAddress}:${timestamp}`;\n const messageBytes = new TextEncoder().encode(attestMessage);\n const sigBytes: Uint8Array = await wallet.signMessage(messageBytes);\n const sigHex = Array.from(sigBytes)\n .map((b) => b.toString(16).padStart(2, \"0\"))\n .join(\"\");\n attestBody.signature = sigHex;\n attestBody.message = attestMessage;\n } catch {\n sdkWarn(\"Wallet signMessage failed, skipping ownership proof\");\n }\n }\n\n const attestRes = await fetch(attestUrl, {\n method: \"POST\",\n headers: attestHeaders,\n body: JSON.stringify(attestBody),\n signal: controller.signal,\n });\n\n clearTimeout(timer);\n\n if (attestRes.ok) {\n const attestData = (await attestRes.json()) as {\n success?: boolean;\n attestation_tx?: string;\n };\n if (attestData.success && attestData.attestation_tx) {\n return attestData.attestation_tx;\n }\n }\n } catch (err) {\n // Attestation is best-effort; on-chain tx already confirmed. Log the\n // failure cause so operators / integrators can distinguish \"not\n // configured\" (returned undefined silently) from \"configured but\n // failed\" (network error, 5xx, malformed response).\n const msg = err instanceof Error ? err.message : String(err);\n sdkWarn(`[Entros SDK] SAS attestation request failed: ${msg}`);\n }\n return undefined;\n}\n\n/**\n * Submit a proof on-chain via a connected wallet (wallet-connected mode).\n * Uses Anchor SDK to construct and send the transaction.\n *\n * Flow for re-verification: single batched transaction containing\n * ComputeBudget → create_challenge → verify_proof → update_anchor\n * Flow for first verification: mint_anchor (already 1 transaction)\n */\nexport async function submitViaWallet(\n proof: SolanaProof,\n commitment: Uint8Array,\n options: {\n wallet: any;\n connection: any;\n isFirstVerification: boolean;\n relayerUrl?: string;\n relayerApiKey?: string;\n /**\n * Validator-signed mint receipt (master-list #146 Phase 4). Consumed\n * only on the first-verification path: when present, the SDK prepends\n * an `Ed25519Program::verify` instruction so on-chain `mint_anchor`\n * can confirm the commitment was endorsed by the configured validator.\n * Re-verification ignores the field entirely — `update_anchor` enforces\n * binding via the VerificationResult PDA instead.\n */\n signedReceipt?: SignedReceiptDto;\n }\n): Promise<SubmissionResult> {\n try {\n const anchor = await import(\"@coral-xyz/anchor\");\n const {\n PublicKey,\n SystemProgram,\n Transaction,\n ComputeBudgetProgram,\n SYSVAR_INSTRUCTIONS_PUBKEY,\n } = await import(\"@solana/web3.js\");\n\n const provider = new anchor.AnchorProvider(\n options.connection,\n options.wallet,\n { commitment: \"confirmed\" }\n );\n\n const anchorProgramId = new PublicKey(PROGRAM_IDS.entrosAnchor);\n\n let txSig: string | undefined;\n let serverNonce = false;\n let nonce: number[] = [];\n\n if (!options.isFirstVerification) {\n // Re-verification: batch create_challenge + verify_proof + update_anchor\n // into a single transaction (1 wallet prompt instead of 3)\n const verifierProgramId = new PublicKey(PROGRAM_IDS.entrosVerifier);\n\n // Fetch server-generated nonce (prevents pre-computation attacks).\n // Falls back to client-generated nonce if executor is unreachable.\n if (options.relayerUrl) {\n try {\n const baseUrl = new URL(options.relayerUrl);\n const challengeHeaders: Record<string, string> = {};\n if (options.relayerApiKey) {\n challengeHeaders[\"X-API-Key\"] = options.relayerApiKey;\n }\n const challengeController = new AbortController();\n const challengeTimer = setTimeout(() => challengeController.abort(), 5_000);\n const challengeRes = await fetch(\n `${baseUrl.origin}/challenge?wallet=${provider.wallet.publicKey.toBase58()}`,\n { headers: challengeHeaders, signal: challengeController.signal }\n );\n clearTimeout(challengeTimer);\n if (challengeRes.ok) {\n const challengeData = (await challengeRes.json()) as { nonce?: number[] };\n if (challengeData.nonce && challengeData.nonce.length === 32) {\n nonce = challengeData.nonce;\n serverNonce = true;\n sdkLog(\"Using server-generated challenge nonce\");\n } else {\n nonce = Array.from(crypto.getRandomValues(new Uint8Array(32)));\n sdkWarn(\"Server returned invalid nonce, using client-generated\");\n }\n } else {\n nonce = Array.from(crypto.getRandomValues(new Uint8Array(32)));\n sdkWarn(\"Challenge endpoint returned error, using client-generated nonce\");\n }\n } catch {\n nonce = Array.from(crypto.getRandomValues(new Uint8Array(32)));\n sdkWarn(\"Challenge fetch failed, using client-generated nonce\");\n }\n } else {\n nonce = Array.from(crypto.getRandomValues(new Uint8Array(32)));\n }\n\n const [challengePda] = PublicKey.findProgramAddressSync(\n [\n new TextEncoder().encode(\"challenge\"),\n provider.wallet.publicKey.toBuffer(),\n new Uint8Array(nonce),\n ],\n verifierProgramId\n );\n\n const [verificationPda] = PublicKey.findProgramAddressSync(\n [\n new TextEncoder().encode(\"verification\"),\n provider.wallet.publicKey.toBuffer(),\n new Uint8Array(nonce),\n ],\n verifierProgramId\n );\n\n const [identityPda] = PublicKey.findProgramAddressSync(\n [new TextEncoder().encode(\"identity\"), provider.wallet.publicKey.toBuffer()],\n anchorProgramId\n );\n\n const registryProgramId = new PublicKey(PROGRAM_IDS.entrosRegistry);\n const [protocolConfigPda] = PublicKey.findProgramAddressSync(\n [new TextEncoder().encode(\"protocol_config\")],\n registryProgramId\n );\n const [treasuryPda] = PublicKey.findProgramAddressSync(\n [new TextEncoder().encode(\"protocol_treasury\")],\n registryProgramId\n );\n\n // Fetch both IDLs\n const [verifierIdl, anchorIdl] = await Promise.all([\n anchor.Program.fetchIdl(verifierProgramId, provider),\n anchor.Program.fetchIdl(anchorProgramId, provider),\n ]);\n if (!verifierIdl) {\n return {\n success: false,\n error: `Failed to fetch entros-verifier IDL from Solana (program ${PROGRAM_IDS.entrosVerifier}). Check your RPC endpoint is reachable and on the correct cluster.`,\n };\n }\n if (!anchorIdl) {\n return {\n success: false,\n error: `Failed to fetch entros-anchor IDL from Solana (program ${PROGRAM_IDS.entrosAnchor}). Check your RPC endpoint is reachable and on the correct cluster.`,\n };\n }\n\n const verifierProgram: any = new anchor.Program(verifierIdl, provider);\n const anchorProgram: any = new anchor.Program(anchorIdl, provider);\n const { Buffer: SolBuffer } = await import(\"buffer\");\n\n // Build all three instructions without sending\n const createChallengeIx = await verifierProgram.methods\n .createChallenge(nonce)\n .accounts({\n challenger: provider.wallet.publicKey,\n challenge: challengePda,\n systemProgram: SystemProgram.programId,\n })\n .instruction();\n\n // Anchor 0.32.1 uses buffer-layout v1.2 which requires Node.js Buffer\n // (not Uint8Array) for Blob.encode on Vec<u8> fields.\n const verifyProofIx = await verifierProgram.methods\n .verifyProof(\n SolBuffer.from(proof.proofBytes),\n proof.publicInputs.map((pi) => SolBuffer.from(pi)),\n nonce\n )\n .accounts({\n verifier: provider.wallet.publicKey,\n challenge: challengePda,\n verificationResult: verificationPda,\n systemProgram: SystemProgram.programId,\n })\n .instruction();\n\n // updateAnchor post-2026-04-20 binding patch takes the verification\n // nonce as a second arg and requires the VerificationResult PDA as an\n // account. Without these, the instruction would accept any commitment\n // with no biometric proof — see protocol-core AUDIT.md for details.\n const updateAnchorIx = await anchorProgram.methods\n .updateAnchor(Array.from(commitment), nonce)\n .accounts({\n authority: provider.wallet.publicKey,\n identityState: identityPda,\n verificationResult: verificationPda,\n protocolConfig: protocolConfigPda,\n treasury: treasuryPda,\n systemProgram: SystemProgram.programId,\n })\n .instruction();\n\n // Batch: compute budget + 3 program instructions → 1 wallet prompt\n // Total CU ~205K; request 250K to exceed the 200K default limit.\n const tx = new Transaction();\n tx.add(ComputeBudgetProgram.setComputeUnitLimit({ units: 250_000 }));\n tx.add(createChallengeIx);\n tx.add(verifyProofIx);\n tx.add(updateAnchorIx);\n\n tx.feePayer = provider.wallet.publicKey;\n tx.recentBlockhash = (\n await options.connection.getLatestBlockhash(\"confirmed\")\n ).blockhash;\n\n txSig = await options.wallet.sendTransaction(tx, options.connection, {\n skipPreflight: true,\n });\n await options.connection.confirmTransaction(txSig, \"confirmed\");\n } else {\n // First verification: mint anchor. Bundles an `Ed25519Program::verify`\n // instruction before `mint_anchor` when the validator returned a\n // signed receipt (master-list #146 Phase 4). The on-chain program\n // inspects the preceding instruction via the Instructions sysvar to\n // confirm the validator endorsed (wallet, commitment, validated_at)\n // before allowing the mint.\n //\n // Transaction shape:\n // [0] (optional) Ed25519Program::verify(receipt)\n // [1] mint_anchor(initial_commitment)\n //\n // The `instructions_sysvar` account is required by the on-chain\n // `MintAnchor` accounts struct as of Phase 3 — it must be present\n // even when no receipt is bundled (the on-chain check is log-only\n // until Phase 5 enforcement flips, but the Anchor framework itself\n // requires the account match the IDL).\n const anchorIdl = await anchor.Program.fetchIdl(anchorProgramId, provider);\n if (!anchorIdl) {\n return {\n success: false,\n error: `Failed to fetch entros-anchor IDL from Solana (program ${PROGRAM_IDS.entrosAnchor}). Check your RPC endpoint is reachable and on the correct cluster.`,\n };\n }\n\n const anchorProgram: any = new anchor.Program(anchorIdl, provider);\n\n const [identityPda] = PublicKey.findProgramAddressSync(\n [new TextEncoder().encode(\"identity\"), provider.wallet.publicKey.toBuffer()],\n anchorProgramId\n );\n const [mintPda] = PublicKey.findProgramAddressSync(\n [new TextEncoder().encode(\"mint\"), provider.wallet.publicKey.toBuffer()],\n anchorProgramId\n );\n const [mintAuthority] = PublicKey.findProgramAddressSync(\n [new TextEncoder().encode(\"mint_authority\")],\n anchorProgramId\n );\n\n const registryProgramId = new PublicKey(PROGRAM_IDS.entrosRegistry);\n const [protocolConfigPda] = PublicKey.findProgramAddressSync(\n [new TextEncoder().encode(\"protocol_config\")],\n registryProgramId\n );\n const [treasuryPda] = PublicKey.findProgramAddressSync(\n [new TextEncoder().encode(\"protocol_treasury\")],\n registryProgramId\n );\n\n const TOKEN_2022_PROGRAM_ID = new PublicKey(\n \"TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb\"\n );\n\n const { getAssociatedTokenAddressSync } = await import(\"@solana/spl-token\");\n const ata = getAssociatedTokenAddressSync(\n mintPda,\n provider.wallet.publicKey,\n false,\n TOKEN_2022_PROGRAM_ID\n );\n\n const mintAnchorIx = await anchorProgram.methods\n .mintAnchor(Array.from(commitment))\n .accounts({\n user: provider.wallet.publicKey,\n identityState: identityPda,\n mint: mintPda,\n mintAuthority,\n tokenAccount: ata,\n associatedTokenProgram: new PublicKey(\n \"ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL\"\n ),\n tokenProgram: TOKEN_2022_PROGRAM_ID,\n systemProgram: SystemProgram.programId,\n protocolConfig: protocolConfigPda,\n treasury: treasuryPda,\n instructionsSysvar: SYSVAR_INSTRUCTIONS_PUBKEY,\n })\n .instruction();\n\n let ed25519Ix: import(\"@solana/web3.js\").TransactionInstruction | null = null;\n if (options.signedReceipt) {\n ed25519Ix = await buildEd25519ReceiptIx(options.signedReceipt);\n if (ed25519Ix) {\n sdkLog(\n \"[Entros SDK] Bundling validator-signed mint receipt before mint_anchor\"\n );\n } else {\n sdkWarn(\n \"[Entros SDK] signedReceipt provided but failed to decode; minting without binding\"\n );\n }\n } else {\n // Phase 3 on-chain check is log-only when no preceding Ed25519 ix\n // is present. Once Phase 5 enforcement flips, this code path will\n // produce a hard rejection — keep the no-receipt fallback as a\n // safety net for upgraded validators briefly omitting the field\n // (e.g. Railway redeploy in progress).\n sdkLog(\n \"[Entros SDK] No validator receipt available; minting without binding (Phase 3 log-only)\"\n );\n }\n\n const tx = new Transaction();\n if (ed25519Ix) tx.add(ed25519Ix);\n tx.add(mintAnchorIx);\n\n tx.feePayer = provider.wallet.publicKey;\n tx.recentBlockhash = (\n await options.connection.getLatestBlockhash(\"confirmed\")\n ).blockhash;\n\n txSig = await options.wallet.sendTransaction(tx, options.connection, {\n skipPreflight: true,\n });\n await options.connection.confirmTransaction(txSig, \"confirmed\");\n }\n\n const attestationTx = options.relayerUrl\n ? await requestSasAttestation(\n options.wallet,\n provider.wallet.publicKey.toBase58(),\n options.relayerUrl,\n options.relayerApiKey,\n serverNonce ? nonce : undefined,\n )\n : undefined;\n\n return { success: true, txSignature: txSig, attestationTx };\n } catch (err: any) {\n return { success: false, error: err.message ?? String(err) };\n }\n}\n\n/**\n * Submit a baseline reset on-chain via a connected wallet.\n *\n * Fires when the on-chain IdentityState exists for the wallet but the\n * device's local encrypted fingerprint envelope is unrecoverable. The\n * ZK Hamming proof used by `update_anchor` needs the previous\n * fingerprint's bits as a private witness; without them, re-verification\n * is blocked. `reset_identity_state` rotates `current_commitment`\n * in place, zeroes verification_count / trust_score / recent_timestamps,\n * and sets a 7-day cooldown before the next reset.\n *\n * Transaction shape: single instruction (no challenge / verify_proof /\n * ZK proof required). Humanness evidence comes from the Tier 1\n * validation pipeline invoked at the /attest step (same as mint and\n * update).\n */\nexport async function submitResetViaWallet(\n commitment: Uint8Array,\n options: {\n wallet: any;\n connection: any;\n relayerUrl?: string;\n relayerApiKey?: string;\n }\n): Promise<SubmissionResult> {\n try {\n const anchor = await import(\"@coral-xyz/anchor\");\n const { PublicKey, SystemProgram, Transaction, ComputeBudgetProgram } =\n await import(\"@solana/web3.js\");\n\n const provider = new anchor.AnchorProvider(\n options.connection,\n options.wallet,\n { commitment: \"confirmed\" }\n );\n\n const anchorProgramId = new PublicKey(PROGRAM_IDS.entrosAnchor);\n const registryProgramId = new PublicKey(PROGRAM_IDS.entrosRegistry);\n\n const [identityPda] = PublicKey.findProgramAddressSync(\n [new TextEncoder().encode(\"identity\"), provider.wallet.publicKey.toBuffer()],\n anchorProgramId\n );\n const [protocolConfigPda] = PublicKey.findProgramAddressSync(\n [new TextEncoder().encode(\"protocol_config\")],\n registryProgramId\n );\n const [treasuryPda] = PublicKey.findProgramAddressSync(\n [new TextEncoder().encode(\"protocol_treasury\")],\n registryProgramId\n );\n\n const anchorIdl = await anchor.Program.fetchIdl(anchorProgramId, provider);\n if (!anchorIdl) {\n return {\n success: false,\n error: `Failed to fetch entros-anchor IDL from Solana (program ${PROGRAM_IDS.entrosAnchor}). Check your RPC endpoint is reachable and on the correct cluster.`,\n };\n }\n const anchorProgram: any = new anchor.Program(anchorIdl, provider);\n\n const resetIx = await anchorProgram.methods\n .resetIdentityState(Array.from(commitment))\n .accounts({\n authority: provider.wallet.publicKey,\n identityState: identityPda,\n protocolConfig: protocolConfigPda,\n treasury: treasuryPda,\n systemProgram: SystemProgram.programId,\n })\n .instruction();\n\n // Reset does no ZK verification; budget is well under the 200K default.\n // Keep an explicit limit for determinism and to match batched-tx ergonomics.\n const tx = new Transaction();\n tx.add(ComputeBudgetProgram.setComputeUnitLimit({ units: 150_000 }));\n tx.add(resetIx);\n\n tx.feePayer = provider.wallet.publicKey;\n tx.recentBlockhash = (\n await options.connection.getLatestBlockhash(\"confirmed\")\n ).blockhash;\n\n const txSig: string = await options.wallet.sendTransaction(\n tx,\n options.connection,\n { skipPreflight: true }\n );\n await options.connection.confirmTransaction(txSig, \"confirmed\");\n\n // Request a fresh SAS attestation. The executor's /attest handler\n // closes any prior attestation for this wallet and creates a new one\n // bound to the current commitment.\n const attestationTx = options.relayerUrl\n ? await requestSasAttestation(\n options.wallet,\n provider.wallet.publicKey.toBase58(),\n options.relayerUrl,\n options.relayerApiKey,\n undefined,\n )\n : undefined;\n\n return { success: true, txSignature: txSig, attestationTx };\n } catch (err: any) {\n return { success: false, error: err.message ?? String(err) };\n }\n}\n","import type { SolanaProof } from \"../proof/types\";\nimport type { SubmissionResult } from \"./types\";\n\nconst RELAYER_TIMEOUT_MS = 30_000;\n\n/**\n * Submit a proof via the Entros relayer API (walletless mode).\n * The relayer submits the on-chain transaction using the integrator's funded account.\n * The user needs no wallet, no SOL, no crypto knowledge.\n */\nexport async function submitViaRelayer(\n proof: SolanaProof,\n commitment: Uint8Array,\n options: {\n relayerUrl: string;\n apiKey?: string;\n isFirstVerification: boolean;\n }\n): Promise<SubmissionResult> {\n try {\n const body = {\n proof_bytes: Array.from(proof.proofBytes),\n public_inputs: proof.publicInputs.map((pi) => Array.from(pi)),\n commitment: Array.from(commitment),\n is_first_verification: options.isFirstVerification,\n };\n\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n };\n\n if (options.apiKey) {\n headers[\"X-API-Key\"] = options.apiKey;\n }\n\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), RELAYER_TIMEOUT_MS);\n\n const response = await fetch(options.relayerUrl, {\n method: \"POST\",\n headers,\n body: JSON.stringify(body),\n signal: controller.signal,\n });\n\n clearTimeout(timer);\n\n if (!response.ok) {\n const errorText = await response.text();\n return {\n success: false,\n error: `Relayer returned HTTP ${response.status} from ${options.relayerUrl}: ${errorText}. Check relayerUrl and apiKey in PulseConfig.`,\n };\n }\n\n const result = (await response.json()) as {\n success?: boolean;\n tx_signature?: string;\n verified?: boolean;\n registered?: boolean;\n };\n\n if (result.success !== true) {\n return {\n success: false,\n error: \"Relayer accepted the request but reported failure. Typically means proof verification failed on-chain — check the relayer logs.\",\n };\n }\n\n return {\n success: true,\n txSignature: result.tx_signature,\n };\n } catch (err: any) {\n if (err.name === \"AbortError\") {\n return {\n success: false,\n error: `Relayer request timed out after ${RELAYER_TIMEOUT_MS / 1000}s. Check network connectivity and relayerUrl reachability.`,\n };\n }\n return { success: false, error: err.message ?? String(err) };\n }\n}\n","/**\n * Client-side encryption for stored verification data.\n *\n * Uses AES-256-GCM via Web Crypto API with a non-extractable CryptoKey\n * stored in IndexedDB. The key cannot be exported or exfiltrated — only\n * the browser's internal crypto engine can use it for encrypt/decrypt\n * on the same origin.\n */\n\nconst DB_NAME = \"entros-protocol-keystore\";\n// Bumped to 2 on 2026-04-20 to force `onupgradeneeded` on pre-existing DBs\n// whose `keys` object store went missing (observed in the wild — browser\n// interrupted an earlier upgrade or a concurrent-tab race left the DB\n// partially initialized). Existing users with a healthy v1 DB upgrade\n// cleanly — the handler below is idempotent.\nconst DB_VERSION = 2;\nconst STORE_NAME = \"keys\";\nconst KEY_ID = \"encryption-key\";\n\n// --- Capability detection ---\n\nexport function hasCryptoSupport(): boolean {\n return (\n typeof globalThis.crypto?.subtle !== \"undefined\" &&\n typeof globalThis.indexedDB !== \"undefined\"\n );\n}\n\n// --- IndexedDB key management ---\n\nfunction openAtVersion(version: number): Promise<IDBDatabase> {\n return new Promise((resolve, reject) => {\n const request = indexedDB.open(DB_NAME, version);\n request.onupgradeneeded = () => {\n const db = request.result;\n // Idempotent: only create if missing. Preserves existing key+data on\n // version bumps that don't require a schema change.\n if (!db.objectStoreNames.contains(STORE_NAME)) {\n db.createObjectStore(STORE_NAME);\n }\n };\n request.onsuccess = () => resolve(request.result);\n request.onerror = () => reject(request.error);\n });\n}\n\nasync function openKeyStore(): Promise<IDBDatabase> {\n const db = await openAtVersion(DB_VERSION);\n // Defensive post-open check: if the DB somehow arrives at the current\n // version without the required store (observed in the wild — browser\n // interrupted an earlier upgrade, concurrent-tab race, manual DevTools\n // deletion), close and reopen at version+1 to force `onupgradeneeded`\n // to fire and recreate the store. Without this, every subsequent\n // `transaction(STORE_NAME, ...)` would throw `NotFoundError` forever.\n if (!db.objectStoreNames.contains(STORE_NAME)) {\n const nextVersion = db.version + 1;\n db.close();\n return openAtVersion(nextVersion);\n }\n return db;\n}\n\nfunction getKey(db: IDBDatabase): Promise<CryptoKey | null> {\n return new Promise((resolve, reject) => {\n const tx = db.transaction(STORE_NAME, \"readonly\");\n const store = tx.objectStore(STORE_NAME);\n const request = store.get(KEY_ID);\n request.onsuccess = () => resolve(request.result ?? null);\n request.onerror = () => reject(request.error);\n });\n}\n\nfunction putKey(db: IDBDatabase, key: CryptoKey): Promise<void> {\n return new Promise((resolve, reject) => {\n const tx = db.transaction(STORE_NAME, \"readwrite\");\n const store = tx.objectStore(STORE_NAME);\n const request = store.put(key, KEY_ID);\n request.onsuccess = () => resolve();\n request.onerror = () => reject(request.error);\n });\n}\n\nexport async function getOrCreateEncryptionKey(): Promise<CryptoKey | null> {\n try {\n const db = await openKeyStore();\n try {\n const existing = await getKey(db);\n if (existing) return existing;\n\n const key = await crypto.subtle.generateKey(\n { name: \"AES-GCM\", length: 256 },\n false, // non-extractable\n [\"encrypt\", \"decrypt\"]\n );\n\n await putKey(db, key);\n return key;\n } finally {\n db.close();\n }\n } catch {\n return null;\n }\n}\n\n// --- AES-256-GCM encrypt / decrypt ---\n\nexport async function encrypt(\n plaintext: string,\n key: CryptoKey\n): Promise<{ iv: string; ct: string }> {\n const iv = crypto.getRandomValues(new Uint8Array(12));\n const encoded = new TextEncoder().encode(plaintext);\n const ciphertext = await crypto.subtle.encrypt(\n { name: \"AES-GCM\", iv },\n key,\n encoded\n );\n return {\n iv: toBase64(iv),\n ct: toBase64(new Uint8Array(ciphertext)),\n };\n}\n\nexport async function decrypt(\n iv: string,\n ct: string,\n key: CryptoKey\n): Promise<string> {\n const ivBytes = fromBase64(iv);\n const ctBytes = fromBase64(ct);\n const plaintext = await crypto.subtle.decrypt(\n { name: \"AES-GCM\", iv: ivBytes.buffer as ArrayBuffer },\n key,\n ctBytes.buffer as ArrayBuffer\n );\n return new TextDecoder().decode(plaintext);\n}\n\n// --- Base64 helpers (browser-only, no deps) ---\n\nfunction toBase64(bytes: Uint8Array): string {\n let binary = \"\";\n for (let i = 0; i < bytes.length; i++) {\n binary += String.fromCharCode(bytes[i]!);\n }\n return btoa(binary);\n}\n\nfunction fromBase64(b64: string): Uint8Array {\n const binary = atob(b64);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) {\n bytes[i] = binary.charCodeAt(i);\n }\n return bytes;\n}\n","import { PROGRAM_IDS } from \"../config\";\nimport { sdkWarn } from \"../log\";\nimport type { IdentityState, StoredVerificationData } from \"./types\";\nimport {\n hasCryptoSupport,\n getOrCreateEncryptionKey,\n encrypt,\n decrypt,\n} from \"./crypto\";\n\nconst STORAGE_KEY = \"entros-protocol-verification-data\";\nconst ENCRYPTED_VERSION = 2;\n\n// In-memory fallback for environments without localStorage (Node.js, SSR,\n// private browsing on some browsers). Data is lost on page reload — users\n// in private browsing mode must re-enroll on each session.\nlet inMemoryStore: StoredVerificationData | null = null;\n\n// Module-level privacy-fallback callback. Set by PulseSDK constructor via\n// `setPrivacyFallback`. Mirrors the `setDebug` pattern in `log.ts` so\n// `storeVerificationData` can be called without threading the config\n// through every layer.\nlet privacyFallbackCallback: (() => Promise<boolean>) | null = null;\n\nexport function setPrivacyFallback(\n cb: (() => Promise<boolean>) | null | undefined\n): void {\n privacyFallbackCallback = cb ?? null;\n}\n\n// --- Envelope detection ---\n\ninterface EncryptedEnvelope {\n v: 2;\n iv: string;\n ct: string;\n}\n\nfunction isEncryptedEnvelope(obj: unknown): obj is EncryptedEnvelope {\n if (typeof obj !== \"object\" || obj === null) return false;\n const o = obj as Record<string, unknown>;\n return (\n o.v === ENCRYPTED_VERSION &&\n typeof o.iv === \"string\" &&\n o.iv.length > 0 &&\n typeof o.ct === \"string\" &&\n o.ct.length > 0\n );\n}\n\nfunction isPlaintextData(obj: unknown): obj is StoredVerificationData {\n if (typeof obj !== \"object\" || obj === null) return false;\n const o = obj as Record<string, unknown>;\n // Require all four fields with correct types. The previous `Array.isArray`\n // check on `fingerprint` alone passed envelopes with missing salt or\n // wrong-typed timestamp, which would crash later during use.\n if (!Array.isArray(o.fingerprint)) return false;\n if (!o.fingerprint.every((bit) => typeof bit === \"number\")) return false;\n if (typeof o.salt !== \"string\" || o.salt.length === 0) return false;\n if (typeof o.commitment !== \"string\" || o.commitment.length === 0) return false;\n if (typeof o.timestamp !== \"number\" || !Number.isFinite(o.timestamp)) return false;\n return true;\n}\n\n// --- Public API ---\n\n/**\n * Fetch identity state from the on-chain IdentityState PDA.\n */\nexport async function fetchIdentityState(\n walletPubkey: string,\n connection: any\n): Promise<IdentityState | null> {\n try {\n const { PublicKey } = await import(\"@solana/web3.js\");\n const anchor = await import(\"@coral-xyz/anchor\");\n\n const programId = new PublicKey(PROGRAM_IDS.entrosAnchor);\n const [identityPda] = PublicKey.findProgramAddressSync(\n [new TextEncoder().encode(\"identity\"), new PublicKey(walletPubkey).toBuffer()],\n programId\n );\n\n const accountInfo = await connection.getAccountInfo(identityPda);\n if (!accountInfo) return null;\n\n const idl = await anchor.Program.fetchIdl(programId, {\n connection,\n } as any);\n if (!idl) return null;\n\n const coder = new anchor.BorshAccountsCoder(idl);\n const decoded = coder.decode(\"identityState\", accountInfo.data);\n\n return {\n owner: decoded.owner.toBase58(),\n creationTimestamp: decoded.creationTimestamp.toNumber(),\n lastVerificationTimestamp: decoded.lastVerificationTimestamp.toNumber(),\n verificationCount: decoded.verificationCount,\n trustScore: decoded.trustScore,\n currentCommitment: new Uint8Array(decoded.currentCommitment),\n mint: decoded.mint.toBase58(),\n // Anchor's Borsh coder returns the raw BN for i64 fields; .toNumber()\n // is safe here because Unix timestamps fit in Number.MAX_SAFE_INTEGER\n // until year 275760.\n lastResetTimestamp: decoded.lastResetTimestamp?.toNumber?.() ?? 0,\n };\n } catch {\n return null;\n }\n}\n\n/**\n * Store verification data locally for re-verification.\n *\n * Storage tiers (preferred first):\n * 1. Encrypted localStorage envelope (Web Crypto available).\n * 2. If crypto unavailable AND `onPrivacyFallback` callback registered\n * AND the callback resolves true, plaintext localStorage. The host\n * app is responsible for surfacing the privacy tradeoff to the user\n * before approving the fallback.\n * 3. Otherwise, in-memory only (lost on reload). Safer default —\n * never silently writes plaintext to localStorage.\n */\nexport async function storeVerificationData(data: StoredVerificationData): Promise<void> {\n try {\n if (!hasCryptoSupport()) {\n // Crypto unavailable → consult the host-provided privacy callback.\n // No callback registered → default to in-memory only (safer than\n // the previous behavior of silently writing plaintext).\n const allowPlaintext = privacyFallbackCallback\n ? await privacyFallbackCallback().catch(() => false)\n : false;\n if (allowPlaintext) {\n sdkWarn(\n \"[Entros SDK] Crypto unavailable; user-approved plaintext storage\"\n );\n localStorage.setItem(STORAGE_KEY, JSON.stringify(data));\n } else {\n sdkWarn(\n \"[Entros SDK] Crypto unavailable and no privacy-fallback approval — using in-memory storage (data lost on reload)\"\n );\n inMemoryStore = data;\n }\n return;\n }\n\n const key = await getOrCreateEncryptionKey();\n if (!key) {\n // Encryption key unavailable for this session — same fallback flow.\n const allowPlaintext = privacyFallbackCallback\n ? await privacyFallbackCallback().catch(() => false)\n : false;\n if (allowPlaintext) {\n sdkWarn(\n \"[Entros SDK] Encryption key unavailable; user-approved plaintext storage\"\n );\n localStorage.setItem(STORAGE_KEY, JSON.stringify(data));\n } else {\n sdkWarn(\n \"[Entros SDK] Encryption key unavailable and no privacy-fallback approval — using in-memory storage\"\n );\n inMemoryStore = data;\n }\n return;\n }\n\n const { iv, ct } = await encrypt(JSON.stringify(data), key);\n const envelope: EncryptedEnvelope = { v: ENCRYPTED_VERSION, iv, ct };\n localStorage.setItem(STORAGE_KEY, JSON.stringify(envelope));\n } catch {\n inMemoryStore = data;\n }\n}\n\n/**\n * Load previously stored verification data.\n * Decrypts if encrypted, migrates plaintext to encrypted on first load.\n */\nexport async function loadVerificationData(): Promise<StoredVerificationData | null> {\n try {\n const raw = localStorage.getItem(STORAGE_KEY);\n if (!raw) return inMemoryStore;\n\n const parsed: unknown = JSON.parse(raw);\n\n // Encrypted envelope\n if (isEncryptedEnvelope(parsed)) {\n if (!hasCryptoSupport()) {\n sdkWarn(\"[Entros SDK] Encrypted data found but crypto unavailable\");\n return inMemoryStore;\n }\n const key = await getOrCreateEncryptionKey();\n if (!key) {\n // Preserve the envelope. If the IndexedDB key is temporarily\n // unavailable (transient storage issue, permission prompt denied\n // once, etc.), a future load with a recovered key can still decrypt.\n // Silently deleting was the previous behavior and caused permanent\n // baseline loss for wallet-connected users whose IndexedDB got\n // corrupted into a post-patch recoverable state (DB_VERSION bump\n // in crypto.ts now self-heals the store, but the envelope must\n // survive the broken window to benefit).\n sdkWarn(\n \"[Entros SDK] Encryption key unavailable — keeping envelope for recovery. \" +\n \"If this persists across reloads, check IndexedDB state via DevTools.\"\n );\n return inMemoryStore;\n }\n try {\n const plaintext = await decrypt(parsed.iv, parsed.ct, key);\n return JSON.parse(plaintext) as StoredVerificationData;\n } catch {\n // Same rationale as above: decrypt failure is often transient\n // (IndexedDB hiccup, key re-derivation edge case). Preserve the\n // envelope so the next successful decrypt can recover the data.\n // If the data truly cannot be decrypted by this device, a user-\n // triggered baseline reset (or manual \"Clear site data\") is the\n // right path — not a silent delete on the SDK's initiative.\n sdkWarn(\n \"[Entros SDK] Decryption failed — keeping envelope for recovery. \" +\n \"Trigger a baseline reset or Clear site data if this is persistent.\"\n );\n return inMemoryStore;\n }\n }\n\n // Plaintext legacy data — migrate to encrypted\n if (isPlaintextData(parsed)) {\n await storeVerificationData(parsed);\n return parsed;\n }\n\n // Unrecognized format\n sdkWarn(\"[Entros SDK] Unrecognized verification data format — clearing\");\n localStorage.removeItem(STORAGE_KEY);\n return inMemoryStore;\n } catch {\n return inMemoryStore;\n }\n}\n","import type { PulseConfig } from \"./config\";\nimport { DEFAULT_THRESHOLD, DEFAULT_CAPTURE_MS, PROGRAM_IDS } from \"./config\";\nimport { setDebug, sdkLog, sdkWarn } from \"./log\";\nimport type { SensorData, AudioCapture, MotionSample, TouchSample, StageState } from \"./sensor/types\";\nimport type { TBH } from \"./hashing/types\";\nimport type { SolanaProof } from \"./proof/types\";\nimport type { SignedReceiptDto, VerificationResult } from \"./submit/types\";\nimport type { StoredVerificationData } from \"./identity/types\";\n\nimport { captureAudio } from \"./sensor/audio\";\nimport { encodeAudioAsBase64 } from \"./sensor/encode\";\nimport { captureMotion, requestMotionPermission } from \"./sensor/motion\";\nimport { captureTouch } from \"./sensor/touch\";\nimport { extractSpeakerFeaturesDetailed, SPEAKER_FEATURE_COUNT } from \"./extraction/speaker\";\nimport {\n extractMotionFeatures,\n extractTouchFeatures,\n extractMouseDynamics,\n extractAccelerationMagnitude,\n} from \"./extraction/kinematic\";\nimport { fuseFeatures, fuseRawFeatures } from \"./extraction/statistics\";\nimport { simhash, hammingDistance } from \"./hashing/simhash\";\nimport { generateTBH, bigintToBytes32 } from \"./hashing/poseidon\";\nimport { prepareCircuitInput, generateProof } from \"./proof/prover\";\nimport { serializeProof } from \"./proof/serializer\";\nimport { submitViaWallet, submitResetViaWallet } from \"./submit/wallet\";\nimport { submitViaRelayer } from \"./submit/relayer\";\nimport { bytesToHex } from \"./submit/receipt\";\nimport {\n storeVerificationData,\n loadVerificationData,\n setPrivacyFallback,\n} from \"./identity/anchor\";\n\n// Build-time constant. Replaced by tsup `define` (true when IAM_INTERNAL_TEST=1)\n// and by vitest `define`. In default builds (npm publish path) this is `false`\n// and any test hook short-circuits to throw — guaranteeing the harness-only\n// injection path is unreachable in published artifacts.\ndeclare const __IAM_INTERNAL_TEST__: boolean;\n\ntype ResolvedConfig = Required<Pick<PulseConfig, \"cluster\" | \"threshold\">> &\n PulseConfig;\n\ninterface ExtractedFeatures {\n /** Raw features in physical units (Hz, ratios, dB, px/frame). For server-side validation. */\n raw: number[];\n /** Z-score normalized features. For SimHash fingerprint computation. */\n normalized: number[];\n /**\n * F0 (fundamental frequency) contour per audio frame (~10ms hop).\n * Sent to the validation service for cross-modal temporal analysis.\n * Empty array when audio is invalid or too short.\n */\n f0Contour: number[];\n /**\n * Acceleration magnitude (√(ax²+ay²+az²)) resampled to match the F0 frame count.\n * Paired with `f0Contour` for server-side lagged cross-correlation.\n * Empty array when motion data is absent.\n */\n accelMagnitude: number[];\n}\n\n/**\n * Extract features from sensor data. Returns both raw (physical units)\n * and normalized (z-scored) feature vectors.\n */\nasync function extractFeatures(data: SensorData): Promise<ExtractedFeatures> {\n if (!data.audio) {\n throw new Error(\n \"Audio data missing. Capture audio via session.startAudio() before extracting features.\",\n );\n }\n const { features: audioFeatures, f0Contour } = await extractSpeakerFeaturesDetailed(\n data.audio,\n );\n\n const hasMotion = data.motion.length >= MIN_MOTION_SAMPLES;\n const hasTouch = data.touch.length >= MIN_TOUCH_SAMPLES;\n\n const motionFeatures =\n hasMotion && hasTouch\n ? extractMouseDynamics(data.touch)\n : hasMotion\n ? extractMotionFeatures(data.motion)\n : extractMouseDynamics(data.touch);\n\n const touchFeatures = extractTouchFeatures(data.touch);\n\n // Align acceleration magnitude to the F0 frame count for direct cross-correlation.\n // Empty if motion absent or F0 extraction produced no frames (e.g. silent capture).\n const accelMagnitude =\n hasMotion && f0Contour.length > 0\n ? extractAccelerationMagnitude(data.motion, f0Contour.length)\n : [];\n\n return {\n raw: fuseRawFeatures(audioFeatures, motionFeatures, touchFeatures),\n normalized: fuseFeatures(audioFeatures, motionFeatures, touchFeatures),\n f0Contour,\n accelMagnitude,\n };\n}\n\n/**\n * Shared pipeline: features → simhash → TBH → proof → submit.\n * Used by both PulseSDK.verify() and PulseSession.complete().\n */\n// Minimum sample counts for meaningful feature extraction.\n// Exported so consumers (including the internal-build-only red team harness)\n// can enforce the same thresholds upstream and surface clearer errors than\n// the SDK's data-quality gate would.\nexport const MIN_AUDIO_SAMPLES = 16000; // ~1 second at 16 kHz\nexport const MIN_MOTION_SAMPLES = 10;\nexport const MIN_TOUCH_SAMPLES = 10;\n\ntype ExtractionResult =\n | {\n ok: true;\n features: number[];\n f0Contour: number[];\n accelMagnitude: number[];\n fingerprint: number[];\n tbh: TBH;\n /**\n * Validator-signed mint receipt (master-list #146 Phase 4). Present\n * only when the request reached the validator with `commitment_new_hex`\n * AND the validator has a signing key configured. `undefined` indicates\n * the SDK should mint without an Ed25519 prefix; while Phase 3 is\n * log-only on-chain this is harmless, but once Phase 5 enforcement\n * flips, missing receipts cause `mint_anchor` to hard-fail.\n */\n signedReceipt?: SignedReceiptDto;\n }\n | { ok: false; error: string; reason?: string };\n\n/**\n * Shared front half of the verification pipeline, covering feature\n * extraction, server-side feature validation (if configured), and\n * TBH (Poseidon commitment) generation. Used by both the normal\n * verify path and the reset path — the back half diverges after this\n * point (proof generation + update_anchor for verify, direct\n * reset_identity_state for reset).\n *\n * `walletAddress` is the base58-encoded public key sent to the\n * validator's `/validate-features` endpoint as `wallet_id`. Pass\n * `undefined` for walletless mode to skip server validation.\n */\nasync function extractFingerprintAndValidate(\n sensorData: SensorData,\n config: ResolvedConfig,\n walletAddress: string | undefined,\n onProgress?: (stage: string) => void,\n): Promise<ExtractionResult> {\n onProgress?.(\"Extracting features...\");\n const {\n raw: features,\n normalized: normalizedFeatures,\n f0Contour,\n accelMagnitude,\n } = await extractFeatures(sensorData);\n\n // Diagnostic: log feature vector composition\n const nonZero = features.filter((v) => v !== 0).length;\n sdkLog(\n `[Entros SDK] Feature vector: ${features.length} dimensions, ${nonZero} non-zero. ` +\n `Audio[0..43]: ${features.slice(0, 44).filter((v) => v !== 0).length} non-zero. ` +\n `Motion/Mouse[44..97]: ${features.slice(44, 98).filter((v) => v !== 0).length} non-zero. ` +\n `Touch[98..133]: ${features.slice(98, 134).filter((v) => v !== 0).length} non-zero.`\n );\n\n // Compute the SimHash fingerprint and Poseidon TBH commitment BEFORE the\n // validation POST (master-list #146 Phase 4). The validator signs a\n // (wallet, commitment, validated_at) receipt that the SDK bundles before\n // `mint_anchor` in the same atomic transaction; for the validator to sign\n // the right commitment, we must transmit it in the request. SimHash +\n // Poseidon together cost ~20ms — trivial overhead even on rejection paths.\n const fingerprint = simhash(normalizedFeatures);\n const tbh = await generateTBH(fingerprint);\n\n let signedReceipt: SignedReceiptDto | undefined;\n\n onProgress?.(\"Validating...\");\n if (config.relayerUrl && walletAddress) {\n try {\n const baseUrl = new URL(config.relayerUrl);\n const validateUrl = `${baseUrl.origin}/validate-features`;\n const validateHeaders: Record<string, string> = { \"Content-Type\": \"application/json\" };\n if (config.relayerApiKey) {\n validateHeaders[\"X-API-Key\"] = config.relayerApiKey;\n }\n\n // Encode captured audio for server-side phrase content binding\n // (master-list #89). Validation runs Whisper-tiny on the samples and\n // phoneme-matches against the server-issued challenge phrase (which\n // the executor looks up server-side via the wallet-keyed nonce\n // registry). If audio is absent, the validation service skips the\n // phrase check — preserving backward compatibility for older SDKs.\n //\n // We also transmit the actual `sampleRate` from the capture — browsers\n // occasionally ignore the 16kHz AudioContext request (Safari with\n // Bluetooth codec negotiation, some Android devices) and deliver 44.1k\n // or 48k. The validator resamples to 16kHz internally before feeding\n // Whisper, so transmitting the true rate avoids silent transcription\n // quality loss.\n const audioSamplesB64 = sensorData.audio?.samples\n ? encodeAudioAsBase64(sensorData.audio.samples)\n : undefined;\n const audioSampleRateHz = sensorData.audio?.sampleRate;\n\n // Hex-encode the 32-byte commitment for the validator's signing\n // input (master-list #146 Phase 4). The validator only signs when\n // this field is present AND its own signing key is configured; the\n // SDK only consumes the receipt on first-verification, so sending\n // it on every wallet-connected request is harmless on the re-verify\n // path (validator signs cheaply, executor passes through, SDK\n // ignores the field for `update_anchor`).\n const commitmentNewHex = bytesToHex(tbh.commitmentBytes);\n\n // Whisper-tiny inference adds ~1s to the validation round trip.\n // Extend timeout from 10s to 15s to tolerate cold-start model load\n // without aborting on legitimate requests.\n const validateController = new AbortController();\n const validateTimer = setTimeout(() => validateController.abort(), 15_000);\n\n const validateResponse = await fetch(validateUrl, {\n method: \"POST\",\n headers: validateHeaders,\n body: JSON.stringify({\n features,\n f0_contour: f0Contour,\n accel_magnitude: accelMagnitude,\n wallet_id: walletAddress,\n audio_samples_b64: audioSamplesB64,\n audio_sample_rate_hz: audioSampleRateHz,\n commitment_new_hex: commitmentNewHex,\n }),\n signal: validateController.signal,\n });\n\n clearTimeout(validateTimer);\n\n if (!validateResponse.ok) {\n const errorBody = await validateResponse.json().catch(() => ({}));\n sdkWarn(\"[Entros SDK] Feature validation rejected by server\");\n return {\n ok: false,\n error: (errorBody as Record<string, string>).error || \"Feature validation failed\",\n reason: (errorBody as Record<string, string>).reason,\n };\n }\n\n // Parse the validator's success body for the signed receipt\n // (master-list #146 Phase 4). Older validator deploys omit the field\n // entirely — the SDK proceeds without a receipt and Phase 3's\n // log-only on-chain check writes \"no preceding instruction\" to the\n // tx logs. After Phase 5 enforcement flips, missing receipts will\n // hard-fail mint_anchor; the executor + validator deploys must\n // therefore be brought up to receipt-supporting versions before\n // the on-chain enforcement flag flips.\n try {\n const successBody = (await validateResponse.json()) as {\n signed_receipt?: SignedReceiptDto;\n };\n if (successBody.signed_receipt) {\n signedReceipt = successBody.signed_receipt;\n }\n } catch {\n // Body wasn't JSON — older validator returning empty 200, or\n // proxy mangling. Treat as no-receipt and move on.\n }\n } catch (err) {\n // Network failure / timeout / abort. Previously this silently\n // continued and skipped server-side validation, which let a\n // network-failure attacker bypass Tier 1 / Tier 2 + phrase\n // binding entirely. Return as a recoverable error instead;\n // the host app can surface a retry CTA. The reason category\n // `validation_unavailable` is client-side only (distinct from\n // any server-side `ReasonCode`) and is intended for soft-fail\n // UX similar to a transient network error.\n const msg = err instanceof Error ? err.message : String(err);\n sdkWarn(`[Entros SDK] Feature validation unavailable: ${msg}`);\n return {\n ok: false,\n error: \"Validation service unreachable. Please check your connection and try again.\",\n reason: \"validation_unavailable\",\n };\n }\n }\n\n return { ok: true, features, f0Contour, accelMagnitude, fingerprint, tbh, signedReceipt };\n}\n\nasync function processSensorData(\n sensorData: SensorData,\n config: ResolvedConfig,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Solana types are optional peer deps\n wallet?: any,\n connection?: any,\n onProgress?: (stage: string) => void,\n): Promise<VerificationResult> {\n // Data quality gate: reject if insufficient behavioral data captured\n const audioSamples = sensorData.audio?.samples.length ?? 0;\n const motionSamples = sensorData.motion.length;\n const touchSamples = sensorData.touch.length;\n\n // Need at least audio OR (motion + touch) to produce a meaningful fingerprint\n const hasAudio = audioSamples >= MIN_AUDIO_SAMPLES;\n const hasMotion = motionSamples >= MIN_MOTION_SAMPLES;\n const hasTouch = touchSamples >= MIN_TOUCH_SAMPLES;\n\n if (!hasAudio && !hasMotion && !hasTouch) {\n return {\n success: false,\n commitment: new Uint8Array(32),\n isFirstVerification: true,\n error: \"Insufficient behavioral data. Please speak the phrase and trace the curve during capture.\",\n };\n }\n\n if (!hasAudio) {\n return {\n success: false,\n commitment: new Uint8Array(32),\n isFirstVerification: true,\n error: \"No voice data detected. Please speak the phrase clearly during capture.\",\n };\n }\n\n // Re-verification requires audio + at least one other modality.\n // Audio-only fingerprints lack inter-session variance from motion/touch,\n // producing identical SimHash results that fail the min_distance constraint.\n let hasPreviousData: boolean;\n if (wallet && connection) {\n const walletPubkey = wallet.adapter?.publicKey ?? wallet.publicKey;\n if (walletPubkey) {\n try {\n const { PublicKey } = await import(\"@solana/web3.js\");\n const programId = new PublicKey(PROGRAM_IDS.entrosAnchor);\n const [identityPda] = PublicKey.findProgramAddressSync(\n [new TextEncoder().encode(\"identity\"), walletPubkey.toBuffer()],\n programId\n );\n const accountInfo = await connection.getAccountInfo(identityPda);\n hasPreviousData = !!accountInfo;\n } catch {\n hasPreviousData = (await loadVerificationData()) !== null;\n }\n } else {\n hasPreviousData = (await loadVerificationData()) !== null;\n }\n } else {\n hasPreviousData = (await loadVerificationData()) !== null;\n }\n if (hasPreviousData && !hasMotion && !hasTouch) {\n return {\n success: false,\n commitment: new Uint8Array(32),\n isFirstVerification: false,\n error: \"Insufficient sensor data for re-verification. Please trace the curve and allow motion access.\",\n };\n }\n\n const walletAddress = wallet?.adapter?.publicKey?.toBase58?.()\n ?? wallet?.publicKey?.toBase58?.();\n const extraction = await extractFingerprintAndValidate(\n sensorData,\n config,\n walletAddress,\n onProgress,\n );\n if (!extraction.ok) {\n return {\n success: false,\n commitment: new Uint8Array(32),\n isFirstVerification: false,\n error: extraction.error,\n reason: extraction.reason,\n };\n }\n const { fingerprint, tbh, features, signedReceipt } = extraction;\n\n // Determine if this is a first verification.\n // Wallet-connected: check on-chain IdentityState PDA (source of truth).\n // Walletless: check localStorage for stored fingerprint.\n let isFirstVerification: boolean;\n const previousData = await loadVerificationData();\n\n if (wallet && connection) {\n const walletPubkey = wallet.adapter?.publicKey ?? wallet.publicKey;\n if (walletPubkey) {\n // Check if IdentityState PDA exists on-chain (simple existence check, no IDL needed)\n try {\n const { PublicKey } = await import(\"@solana/web3.js\");\n const programId = new PublicKey(PROGRAM_IDS.entrosAnchor);\n const [identityPda] = PublicKey.findProgramAddressSync(\n [new TextEncoder().encode(\"identity\"), walletPubkey.toBuffer()],\n programId\n );\n const accountInfo = await connection.getAccountInfo(identityPda);\n isFirstVerification = !accountInfo;\n } catch {\n isFirstVerification = !previousData;\n }\n } else {\n isFirstVerification = !previousData;\n }\n } else {\n isFirstVerification = !previousData;\n }\n\n // Edge case: on-chain identity exists but local fingerprint is missing\n // (cleared browser data, new device, different browser). Can't generate\n // Hamming distance proof without the previous fingerprint.\n if (!isFirstVerification && !previousData) {\n return {\n success: false,\n commitment: tbh.commitmentBytes,\n isFirstVerification: false,\n error: \"Previous behavioral fingerprint not found on this device. Your Entros Anchor exists on-chain but the local baseline is missing. Reset your baseline to re-enroll from this device, or verify from the device that has the original baseline.\",\n };\n }\n\n let solanaProof: SolanaProof | null = null;\n\n if (!isFirstVerification && previousData) {\n onProgress?.(\"Computing proof...\");\n const previousTBH: TBH = {\n fingerprint: previousData.fingerprint,\n salt: BigInt(previousData.salt),\n commitment: BigInt(previousData.commitment),\n commitmentBytes: bigintToBytes32(BigInt(previousData.commitment)),\n };\n\n const distance = hammingDistance(fingerprint, previousData.fingerprint);\n sdkLog(\n `[Entros SDK] Re-verification: Hamming distance = ${distance} / 256 bits (threshold = ${config.threshold})`\n );\n\n const circuitInput = prepareCircuitInput(\n tbh,\n previousTBH,\n config.threshold\n );\n\n const wasmPath = config.wasmUrl;\n const zkeyPath = config.zkeyUrl;\n\n if (!wasmPath || !zkeyPath) {\n return {\n success: false,\n commitment: tbh.commitmentBytes,\n isFirstVerification: false,\n error: \"Re-verification requires wasmUrl and zkeyUrl in PulseConfig. Host the entros_hamming.wasm and entros_hamming_final.zkey circuit artifacts at public URLs.\",\n };\n }\n\n try {\n const { proof, publicSignals } = await generateProof(\n circuitInput,\n wasmPath,\n zkeyPath\n );\n solanaProof = serializeProof(proof, publicSignals);\n } catch (proofErr: any) {\n // Include diagnostics in error for mobile debugging (no devtools)\n const audioNZ = features.slice(0, 44).filter((v) => v !== 0).length;\n const motionNZ = features.slice(44, 98).filter((v) => v !== 0).length;\n const touchNZ = features.slice(98, 134).filter((v) => v !== 0).length;\n const rawAudio = sensorData.audio?.samples.length ?? 0;\n const rawMotion = sensorData.motion.length;\n const rawTouch = sensorData.touch.length;\n // First 3 feature values as a fingerprint to detect identical data\n const sig = features.slice(0, 3).map((v) => v.toFixed(4)).join(\",\");\n return {\n success: false,\n commitment: tbh.commitmentBytes,\n isFirstVerification: false,\n error: `Proof generation failed: ${proofErr?.message ?? proofErr}. Check wasmUrl/zkeyUrl reachability. Diagnostics: dist=${distance}, nz=${audioNZ}/${motionNZ}/${touchNZ}, raw=${rawAudio}/${rawMotion}/${rawTouch}, sig=${sig}`,\n };\n }\n }\n\n // Submit\n onProgress?.(\"Submitting to Solana...\");\n let submission;\n\n if (wallet && connection) {\n if (isFirstVerification) {\n // Pass the validator-signed receipt (when present) so submitViaWallet\n // can bundle an `Ed25519Program::verify` instruction before\n // `mint_anchor` in the same atomic transaction (master-list #146\n // Phase 4). Re-verification doesn't need the receipt — the binding\n // is already enforced via the VerificationResult PDA path that\n // `update_anchor` consumes.\n submission = await submitViaWallet(\n solanaProof ?? { proofBytes: new Uint8Array(0), publicInputs: [] },\n tbh.commitmentBytes,\n {\n wallet,\n connection,\n isFirstVerification: true,\n relayerUrl: config.relayerUrl,\n relayerApiKey: config.relayerApiKey,\n signedReceipt,\n }\n );\n } else {\n submission = await submitViaWallet(solanaProof!, tbh.commitmentBytes, {\n wallet,\n connection,\n isFirstVerification: false,\n relayerUrl: config.relayerUrl,\n relayerApiKey: config.relayerApiKey,\n });\n }\n } else if (config.relayerUrl) {\n submission = await submitViaRelayer(\n solanaProof ?? { proofBytes: new Uint8Array(0), publicInputs: [] },\n tbh.commitmentBytes,\n { relayerUrl: config.relayerUrl, apiKey: config.relayerApiKey, isFirstVerification }\n );\n } else {\n return {\n success: false,\n commitment: tbh.commitmentBytes,\n isFirstVerification,\n error: \"No submission path available. Pass wallet+connection to verify() for wallet-connected mode, or set relayerUrl in PulseConfig for walletless mode.\",\n };\n }\n\n // Store verification data locally for next re-verification\n if (submission.success) {\n await storeVerificationData({\n fingerprint: tbh.fingerprint,\n salt: tbh.salt.toString(),\n commitment: tbh.commitment.toString(),\n timestamp: Date.now(),\n });\n }\n\n return {\n success: submission.success,\n commitment: tbh.commitmentBytes,\n txSignature: submission.txSignature,\n attestationTx: submission.attestationTx,\n isFirstVerification,\n error: submission.error,\n };\n}\n\n/**\n * Reset pipeline: features → simhash → TBH → reset_identity_state → store.\n * Mirrors `processSensorData()` but skips the Hamming ZK proof (there is no\n * prior fingerprint to bind against) and substitutes `submitResetViaWallet`\n * for the wallet submission path.\n *\n * Humanness is enforced server-side: the /validate-features and /attest\n * endpoints on the executor reject synthetic captures identically to the\n * normal verify flow.\n */\nasync function processResetSensorData(\n sensorData: SensorData,\n config: ResolvedConfig,\n wallet: any,\n connection: any,\n onProgress?: (stage: string) => void,\n): Promise<VerificationResult> {\n const audioSamples = sensorData.audio?.samples.length ?? 0;\n const motionSamples = sensorData.motion.length;\n const touchSamples = sensorData.touch.length;\n\n const hasAudio = audioSamples >= MIN_AUDIO_SAMPLES;\n const hasMotion = motionSamples >= MIN_MOTION_SAMPLES;\n const hasTouch = touchSamples >= MIN_TOUCH_SAMPLES;\n\n if (!hasAudio && !hasMotion && !hasTouch) {\n return {\n success: false,\n commitment: new Uint8Array(32),\n isFirstVerification: true,\n error: \"Insufficient behavioral data. Please speak the phrase and trace the curve during capture.\",\n };\n }\n\n if (!hasAudio) {\n return {\n success: false,\n commitment: new Uint8Array(32),\n isFirstVerification: true,\n error: \"No voice data detected. Please speak the phrase clearly during capture.\",\n };\n }\n\n // Reset requires the full multi-modal capture just like a fresh mint, so\n // the on-chain baseline is established from a meaningful fingerprint.\n if (!hasMotion && !hasTouch) {\n return {\n success: false,\n commitment: new Uint8Array(32),\n isFirstVerification: true,\n error: \"Insufficient sensor data for baseline reset. Please trace the curve and allow motion access.\",\n };\n }\n\n const walletAddress = wallet.adapter?.publicKey?.toBase58?.()\n ?? wallet.publicKey?.toBase58?.();\n const extraction = await extractFingerprintAndValidate(\n sensorData,\n config,\n walletAddress,\n onProgress,\n );\n if (!extraction.ok) {\n return {\n success: false,\n commitment: new Uint8Array(32),\n isFirstVerification: true,\n error: extraction.error,\n reason: extraction.reason,\n };\n }\n const { tbh } = extraction;\n\n onProgress?.(\"Submitting reset to Solana...\");\n const submission = await submitResetViaWallet(tbh.commitmentBytes, {\n wallet,\n connection,\n relayerUrl: config.relayerUrl,\n relayerApiKey: config.relayerApiKey,\n });\n\n // Persist the new local baseline on on-chain success. A throw here would\n // leave the user with an on-chain commitment they can't prove locally;\n // surface the failure explicitly instead of swallowing it so the UI can\n // prompt the user to reset again (after the 7-day cooldown) or transfer\n // the baseline from another device.\n if (submission.success) {\n try {\n await storeVerificationData({\n fingerprint: tbh.fingerprint,\n salt: tbh.salt.toString(),\n commitment: tbh.commitment.toString(),\n timestamp: Date.now(),\n });\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n sdkWarn(`[Entros SDK] Reset succeeded on chain but local baseline persistence failed: ${msg}`);\n return {\n success: false,\n commitment: tbh.commitmentBytes,\n txSignature: submission.txSignature,\n attestationTx: submission.attestationTx,\n isFirstVerification: true,\n error:\n \"Reset confirmed on chain, but saving the new baseline to this device failed. \" +\n \"Re-verification from this device will not work. Try clearing site data and \" +\n \"resetting again after the 7-day cooldown, or transfer a baseline from another \" +\n \"device.\",\n };\n }\n }\n\n return {\n success: submission.success,\n commitment: tbh.commitmentBytes,\n txSignature: submission.txSignature,\n attestationTx: submission.attestationTx,\n // Semantically this is a fresh baseline enrollment from the UX\n // perspective. `isFirstVerification: true` lets the caller render\n // success copy that matches first-time flows.\n isFirstVerification: true,\n error: submission.error,\n };\n}\n\n/**\n * PulseSession — event-driven staged capture session.\n *\n * Gives the caller control over when each sensor stage starts and stops.\n * After all stages complete, call complete() to run the processing pipeline.\n *\n * Usage:\n * const session = pulse.createSession(touchElement);\n * await session.startAudio();\n * // ... user speaks ...\n * await session.stopAudio();\n * await session.startMotion();\n * // ... user holds device ...\n * await session.stopMotion();\n * await session.startTouch();\n * // ... user traces curve ...\n * await session.stopTouch();\n * const result = await session.complete(wallet, connection);\n */\nexport class PulseSession {\n private config: ResolvedConfig;\n private touchElement: HTMLElement | undefined;\n\n private audioStageState: StageState = \"idle\";\n private motionStageState: StageState = \"idle\";\n private touchStageState: StageState = \"idle\";\n\n private audioController: AbortController | null = null;\n private motionController: AbortController | null = null;\n private touchController: AbortController | null = null;\n\n private audioPromise: Promise<AudioCapture | null> | null = null;\n private motionPromise: Promise<MotionSample[]> | null = null;\n private touchPromise: Promise<TouchSample[]> | null = null;\n\n private audioData: AudioCapture | null = null;\n private motionData: MotionSample[] = [];\n private touchData: TouchSample[] = [];\n\n constructor(config: ResolvedConfig, touchElement?: HTMLElement) {\n this.config = config;\n this.touchElement = touchElement;\n }\n\n // --- Audio ---\n\n async startAudio(onAudioLevel?: (rms: number) => void): Promise<void> {\n if (this.audioStageState !== \"idle\")\n throw new Error(\n \"Audio capture already in progress. Call stopAudio() before starting a new capture.\",\n );\n\n // Acquire microphone permission within the user gesture context.\n // Awaited so the caller knows audio is ready before proceeding.\n // State transitions happen AFTER permission succeeds to avoid zombie state.\n const stream = await navigator.mediaDevices.getUserMedia({\n audio: {\n sampleRate: 16000,\n channelCount: 1,\n echoCancellation: false,\n noiseSuppression: false,\n autoGainControl: false,\n },\n });\n\n this.audioStageState = \"capturing\";\n this.audioController = new AbortController();\n this.audioPromise = captureAudio({\n signal: this.audioController.signal,\n onAudioLevel,\n stream,\n }).catch(() => {\n stream.getTracks().forEach((t) => t.stop());\n return null;\n });\n }\n\n async stopAudio(): Promise<AudioCapture | null> {\n if (this.audioStageState !== \"capturing\")\n throw new Error(\n \"No active audio capture to stop. Call startAudio() first.\",\n );\n this.audioController!.abort();\n this.audioData = await this.audioPromise!;\n this.audioStageState = \"captured\";\n return this.audioData;\n }\n\n // Audio is mandatory — no skipAudio() method.\n // If startAudio() fails, the verification cannot proceed.\n\n // --- Motion ---\n\n async startMotion(): Promise<void> {\n if (this.motionStageState !== \"idle\")\n throw new Error(\n \"Motion capture already in progress. Call stopMotion() before starting a new capture.\",\n );\n\n // Request motion permission within the user gesture context (iOS 13+).\n // Awaited so the capture timer doesn't start before the user approves.\n const hasPermission = await requestMotionPermission();\n if (!hasPermission) {\n this.motionStageState = \"skipped\";\n return;\n }\n\n this.motionStageState = \"capturing\";\n this.motionController = new AbortController();\n this.motionPromise = captureMotion({\n signal: this.motionController.signal,\n permissionGranted: true,\n }).catch(() => []);\n }\n\n async stopMotion(): Promise<MotionSample[]> {\n if (this.motionStageState !== \"capturing\")\n throw new Error(\n \"No active motion capture to stop. Call startMotion() first.\",\n );\n this.motionController!.abort();\n this.motionData = await this.motionPromise!;\n this.motionStageState = \"captured\";\n return this.motionData;\n }\n\n skipMotion(): void {\n if (this.motionStageState !== \"idle\")\n throw new Error(\n \"Cannot skip motion: capture already started. skipMotion() must be called before startMotion().\",\n );\n this.motionStageState = \"skipped\";\n }\n\n isMotionCapturing(): boolean {\n return this.motionStageState === \"capturing\";\n }\n\n // --- Touch ---\n\n async startTouch(): Promise<void> {\n if (this.touchStageState !== \"idle\")\n throw new Error(\n \"Touch capture already in progress. Call stopTouch() before starting a new capture.\",\n );\n if (!this.touchElement)\n throw new Error(\n \"No touch element provided to session. Pass an HTMLElement to createSession() to enable touch capture.\",\n );\n this.touchStageState = \"capturing\";\n this.touchController = new AbortController();\n this.touchPromise = captureTouch(this.touchElement, {\n signal: this.touchController.signal,\n }).catch(() => []);\n }\n\n async stopTouch(): Promise<TouchSample[]> {\n if (this.touchStageState !== \"capturing\")\n throw new Error(\n \"No active touch capture to stop. Call startTouch() first.\",\n );\n this.touchController!.abort();\n this.touchData = await this.touchPromise!;\n this.touchStageState = \"captured\";\n return this.touchData;\n }\n\n skipTouch(): void {\n if (this.touchStageState !== \"idle\")\n throw new Error(\n \"Cannot skip touch: capture already started. skipTouch() must be called before startTouch().\",\n );\n this.touchStageState = \"skipped\";\n }\n\n // --- Test hooks (internal builds only) ---\n\n /**\n * @internal Test-only. Primes the session with pre-captured sensor data,\n * bypassing browser capture APIs. Throws unless built with IAM_INTERNAL_TEST=1.\n * Stripped from the published .d.ts so npm consumers never see it. Used by the\n * red team harness to drive the real verification pipeline (extraction →\n * SimHash → TBH → proof → submit) against synthetic sensor data — never\n * available to npm consumers.\n */\n __injectSensorData(data: {\n audio: AudioCapture;\n motion: MotionSample[];\n touch: TouchSample[];\n }): void {\n // typeof guard tolerates the constant being undeclared at runtime (e.g.\n // direct ts-node/tsx execution that bypasses tsup/vitest `define`).\n // Without this, a missing build-time replacement throws ReferenceError\n // before the user-facing message can fire.\n if (typeof __IAM_INTERNAL_TEST__ !== \"boolean\" || !__IAM_INTERNAL_TEST__) {\n throw new Error(\n \"PulseSession.__injectSensorData is only available in internal test builds. \" +\n \"Set IAM_INTERNAL_TEST=1 when building pulse-sdk from source.\",\n );\n }\n const conflicts: string[] = [];\n if (this.audioStageState === \"capturing\") conflicts.push(\"audio\");\n if (this.motionStageState === \"capturing\") conflicts.push(\"motion\");\n if (this.touchStageState === \"capturing\") conflicts.push(\"touch\");\n if (conflicts.length > 0) {\n throw new Error(\n `__injectSensorData: cannot inject while stages are capturing: ${conflicts.join(\", \")}. ` +\n `Create a fresh session via sdk.createSession() and inject before any startAudio/startMotion/startTouch call.`,\n );\n }\n if (!data.audio || data.audio.samples.length < MIN_AUDIO_SAMPLES) {\n throw new Error(\n `__injectSensorData: audio required, minimum ${MIN_AUDIO_SAMPLES} samples (got ${data.audio?.samples.length ?? 0}).`,\n );\n }\n if (data.motion.length < MIN_MOTION_SAMPLES) {\n throw new Error(\n `__injectSensorData: motion required, minimum ${MIN_MOTION_SAMPLES} samples (got ${data.motion.length}).`,\n );\n }\n if (data.touch.length < MIN_TOUCH_SAMPLES) {\n throw new Error(\n `__injectSensorData: touch required, minimum ${MIN_TOUCH_SAMPLES} samples (got ${data.touch.length}).`,\n );\n }\n this.audioData = data.audio;\n this.motionData = data.motion;\n this.touchData = data.touch;\n this.audioStageState = \"captured\";\n this.motionStageState = \"captured\";\n this.touchStageState = \"captured\";\n }\n\n // --- Complete ---\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Solana types are optional peer deps\n async complete(wallet?: any, connection?: any, onProgress?: (stage: string) => void): Promise<VerificationResult> {\n const active: string[] = [];\n if (this.audioStageState === \"capturing\") active.push(\"audio\");\n if (this.motionStageState === \"capturing\") active.push(\"motion\");\n if (this.touchStageState === \"capturing\") active.push(\"touch\");\n if (active.length > 0) {\n throw new Error(\n `Cannot complete: stages still capturing: ${active.join(\", \")}`\n );\n }\n\n const sensorData: SensorData = {\n audio: this.audioData,\n motion: this.motionData,\n touch: this.touchData,\n modalities: {\n audio: this.audioData !== null,\n motion: this.motionData.length > 0,\n touch: this.touchData.length > 0,\n },\n };\n\n return processSensorData(sensorData, this.config, wallet, connection, onProgress);\n }\n\n /**\n * Complete the session as a baseline RESET instead of a normal verify.\n *\n * Use when the wallet has an on-chain IdentityState but the device has\n * no recoverable local baseline (cleared site data, new device, etc).\n * Skips the Hamming ZK proof; submits `reset_identity_state` on chain,\n * which rotates the commitment and zeros verification history.\n *\n * Requires a connected wallet + Solana connection. Rejects if either\n * is missing — reset is a wallet-mode-only operation since it writes\n * to the user's on-chain account.\n */\n async completeReset(\n wallet: any,\n connection: any,\n onProgress?: (stage: string) => void\n ): Promise<VerificationResult> {\n const active: string[] = [];\n if (this.audioStageState === \"capturing\") active.push(\"audio\");\n if (this.motionStageState === \"capturing\") active.push(\"motion\");\n if (this.touchStageState === \"capturing\") active.push(\"touch\");\n if (active.length > 0) {\n throw new Error(\n `Cannot complete reset: stages still capturing: ${active.join(\", \")}`\n );\n }\n\n if (!wallet || !connection) {\n return {\n success: false,\n commitment: new Uint8Array(32),\n isFirstVerification: true,\n error:\n \"Baseline reset requires a connected wallet and Solana connection. \" +\n \"Reset cannot be performed in walletless mode.\",\n };\n }\n\n const sensorData: SensorData = {\n audio: this.audioData,\n motion: this.motionData,\n touch: this.touchData,\n modalities: {\n audio: this.audioData !== null,\n motion: this.motionData.length > 0,\n touch: this.touchData.length > 0,\n },\n };\n\n return processResetSensorData(sensorData, this.config, wallet, connection, onProgress);\n }\n}\n\n/**\n * PulseSDK — main entry point for Entros Protocol verification.\n *\n * Two usage modes:\n * 1. Simple (backward-compatible): pulse.verify(touchElement) — captures all sensors\n * for DEFAULT_CAPTURE_MS in parallel, then processes.\n * 2. Staged (event-driven): pulse.createSession(touchElement) — caller controls\n * when each sensor stage starts and stops.\n */\nexport class PulseSDK {\n private config: ResolvedConfig;\n\n constructor(config: PulseConfig) {\n this.config = {\n threshold: DEFAULT_THRESHOLD,\n ...config,\n };\n setDebug(config.debug ?? false);\n setPrivacyFallback(config.onPrivacyFallback);\n }\n\n /**\n * Create a staged capture session for event-driven control.\n */\n createSession(touchElement?: HTMLElement): PulseSession {\n return new PulseSession(this.config, touchElement);\n }\n\n /**\n * Run a full verification with automatic timed capture (backward-compatible).\n * Captures all sensors in parallel for DEFAULT_CAPTURE_MS, then processes.\n */\n async verify(\n touchElement?: HTMLElement,\n wallet?: any,\n connection?: any\n ): Promise<VerificationResult> {\n try {\n const session = this.createSession(touchElement);\n const stopPromises: Promise<void>[] = [];\n\n // Motion first — requires user gesture on iOS (gesture expires after getUserMedia)\n try {\n await session.startMotion();\n } catch {\n /* unexpected error — motion already skipped or idle */\n }\n if (session.isMotionCapturing()) {\n stopPromises.push(\n new Promise<void>((r) => setTimeout(r, DEFAULT_CAPTURE_MS))\n .then(() => session.stopMotion())\n .then(() => {})\n );\n }\n\n // Audio second — getUserMedia works without a gesture on secure origins\n try {\n await session.startAudio();\n stopPromises.push(\n new Promise<void>((r) => setTimeout(r, DEFAULT_CAPTURE_MS))\n .then(() => session.stopAudio())\n .then(() => {})\n );\n } catch (err: any) {\n throw new Error(\n `Audio capture failed: ${err?.message ?? \"microphone unavailable\"}. Ensure microphone permission is granted and no other app is using it.`,\n );\n }\n\n // Touch\n if (touchElement) {\n try {\n await session.startTouch();\n stopPromises.push(\n new Promise<void>((r) => setTimeout(r, DEFAULT_CAPTURE_MS))\n .then(() => session.stopTouch())\n .then(() => {})\n );\n } catch {\n session.skipTouch();\n }\n } else {\n session.skipTouch();\n }\n\n await Promise.all(stopPromises);\n return session.complete(wallet, connection);\n } catch (err: any) {\n return {\n success: false,\n commitment: new Uint8Array(32),\n isFirstVerification: true,\n error: err.message ?? String(err),\n };\n }\n }\n\n /**\n * Reset the wallet's on-chain baseline using a fresh capture.\n *\n * Convenience wrapper that mirrors `verify()` but routes the captured\n * sensor data through `reset_identity_state` instead of `update_anchor`.\n * Use when the wallet has an on-chain IdentityState but the local\n * encrypted baseline is unrecoverable.\n *\n * For fine-grained control, call `createSession()` and `completeReset()`\n * directly — the session API exposes per-stage start/stop hooks that\n * this convenience wrapper trades away for simplicity.\n */\n async resetBaseline(\n touchElement: HTMLElement | undefined,\n wallet: any,\n connection: any,\n onProgress?: (stage: string) => void\n ): Promise<VerificationResult> {\n try {\n const session = this.createSession(touchElement);\n const stopPromises: Promise<void>[] = [];\n\n try {\n await session.startMotion();\n } catch {\n /* unexpected error — motion already skipped or idle */\n }\n if (session.isMotionCapturing()) {\n stopPromises.push(\n new Promise<void>((r) => setTimeout(r, DEFAULT_CAPTURE_MS))\n .then(() => session.stopMotion())\n .then(() => {})\n );\n }\n\n try {\n await session.startAudio();\n stopPromises.push(\n new Promise<void>((r) => setTimeout(r, DEFAULT_CAPTURE_MS))\n .then(() => session.stopAudio())\n .then(() => {})\n );\n } catch (err: any) {\n throw new Error(\n `Audio capture failed: ${err?.message ?? \"microphone unavailable\"}. Ensure microphone permission is granted and no other app is using it.`,\n );\n }\n\n if (touchElement) {\n try {\n await session.startTouch();\n stopPromises.push(\n new Promise<void>((r) => setTimeout(r, DEFAULT_CAPTURE_MS))\n .then(() => session.stopTouch())\n .then(() => {})\n );\n } catch {\n session.skipTouch();\n }\n } else {\n session.skipTouch();\n }\n\n await Promise.all(stopPromises);\n return session.completeReset(wallet, connection, onProgress);\n } catch (err: any) {\n return {\n success: false,\n commitment: new Uint8Array(32),\n isFirstVerification: true,\n error: err.message ?? String(err),\n };\n }\n }\n}\n","/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { SAS_CONFIG } from \"../config\";\n\n/** Decoded Entros attestation from the Solana Attestation Service */\nexport interface EntrosAttestation {\n isHuman: boolean;\n trustScore: number;\n verifiedAt: number;\n mode: string;\n expired: boolean;\n}\n\n/**\n * Check if a wallet has a valid Entros attestation via SAS.\n *\n * Derives the attestation PDA, fetches the account, deserializes\n * the attestation data, and checks expiry.\n *\n * @param walletAddress - Base58 Solana wallet address\n * @param connection - Solana web3.js Connection instance\n * @returns Decoded attestation or null if none exists\n */\nexport async function verifyEntrosAttestation(\n walletAddress: string,\n connection: any\n): Promise<EntrosAttestation | null> {\n try {\n const { PublicKey } = await import(\"@solana/web3.js\");\n\n const sasProgramId = new PublicKey(SAS_CONFIG.programId);\n const credentialPda = new PublicKey(SAS_CONFIG.entrosCredentialPda);\n const schemaPda = new PublicKey(SAS_CONFIG.entrosSchemaPda);\n const userWallet = new PublicKey(walletAddress);\n\n // Derive attestation PDA: [\"attestation\", credential, schema, nonce(wallet)]\n const [attestationPda] = PublicKey.findProgramAddressSync(\n [\n new TextEncoder().encode(\"attestation\"),\n credentialPda.toBuffer(),\n schemaPda.toBuffer(),\n userWallet.toBuffer(),\n ],\n sasProgramId\n );\n\n const accountInfo = await connection.getAccountInfo(attestationPda);\n if (!accountInfo) return null;\n\n return deserializeSasAttestation(new Uint8Array(accountInfo.data));\n } catch {\n return null;\n }\n}\n\n/** Read a u16 from a Uint8Array at the given offset (little-endian) */\nfunction readU16LE(data: Uint8Array, offset: number): number {\n return data[offset]! | (data[offset + 1]! << 8);\n}\n\n/** Read a u32 from a Uint8Array at the given offset (little-endian) */\nfunction readU32LE(data: Uint8Array, offset: number): number {\n return (\n data[offset]! |\n (data[offset + 1]! << 8) |\n (data[offset + 2]! << 16) |\n ((data[offset + 3]! << 24) >>> 0)\n );\n}\n\n/** Read an i64 from a Uint8Array at the given offset (little-endian, safe for JS number range) */\nfunction readI64LE(data: Uint8Array, offset: number): number {\n const low = readU32LE(data, offset);\n const high = readU32LE(data, offset + 4);\n // Convert high word to signed for proper negative handling\n const signedHigh = high > 0x7FFFFFFF ? high - 0x100000000 : high;\n return signedHigh * 0x100000000 + low;\n}\n\n/**\n * Deserialize a SAS Attestation account into EntrosAttestation fields.\n *\n * SAS Attestation account layout (borsh):\n * 1 byte: discriminator (u8)\n * 32 bytes: nonce (Pubkey)\n * 32 bytes: credential (Pubkey)\n * 32 bytes: schema (Pubkey)\n * 4 bytes: data length (u32 LE) + N bytes: data (Vec<u8>)\n * 32 bytes: signer (Pubkey)\n * 8 bytes: expiry (i64 LE)\n * 32 bytes: token_account (Pubkey)\n *\n * Entros attestation data layout (inside the data Vec):\n * 1 byte: isHuman (bool)\n * 2 bytes: trustScore (u16 LE)\n * 8 bytes: verifiedAt (i64 LE)\n * 4 bytes: mode length (u32 LE) + N bytes: mode (UTF-8 string)\n */\nfunction deserializeSasAttestation(raw: Uint8Array): EntrosAttestation | null {\n // Minimum account size: 1 + 32 + 32 + 32 + 4 + 0 + 32 + 8 + 32 = 173 bytes\n if (raw.length < 173) return null;\n\n let offset = 0;\n\n // Skip discriminator (1 byte)\n offset += 1;\n\n // Skip nonce, credential, schema (32 + 32 + 32 = 96 bytes)\n offset += 96;\n\n // Read data Vec<u8>: 4-byte LE length prefix\n const dataLen = readU32LE(raw, offset);\n offset += 4;\n\n if (raw.length < offset + dataLen + 32 + 8 + 32) return null;\n\n const attestationData = raw.slice(offset, offset + dataLen);\n offset += dataLen;\n\n // Skip signer (32 bytes)\n offset += 32;\n\n // Read expiry (i64 LE)\n const expiry = readI64LE(raw, offset);\n\n // Parse Entros attestation data: [bool, u16, i64, string]\n if (attestationData.length < 11) return null;\n\n let dataOffset = 0;\n\n // isHuman: bool (1 byte)\n const isHuman = attestationData[dataOffset] === 1;\n dataOffset += 1;\n\n // trustScore: u16 LE (2 bytes)\n const trustScore = readU16LE(attestationData, dataOffset);\n dataOffset += 2;\n\n // verifiedAt: i64 LE (8 bytes)\n const verifiedAt = readI64LE(attestationData, dataOffset);\n dataOffset += 8;\n\n // mode: string (4-byte LE length + UTF-8)\n let mode = \"unknown\";\n if (dataOffset + 4 <= attestationData.length) {\n const modeLen = readU32LE(attestationData, dataOffset);\n dataOffset += 4;\n if (dataOffset + modeLen <= attestationData.length) {\n mode = new TextDecoder().decode(\n attestationData.slice(dataOffset, dataOffset + modeLen)\n );\n }\n }\n\n const now = Math.floor(Date.now() / 1000);\n const expired = expiry > 0 && now >= expiry;\n\n return { isHuman, trustScore, verifiedAt, mode, expired };\n}\n","/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { PROGRAM_IDS, AGENT_REGISTRY_CONFIG } from \"../config\";\nimport type { PulseConfig } from \"../config\";\n\nfunction getRegistryProgramId(cluster?: PulseConfig[\"cluster\"]): string {\n return cluster === \"mainnet-beta\"\n ? AGENT_REGISTRY_CONFIG.programIdMainnet\n : AGENT_REGISTRY_CONFIG.programIdDevnet;\n}\n\n/** Metadata written to an AI agent linking it to a verified human operator */\nexport interface AgentHumanOperator {\n anchorPda: string;\n trustScore: number;\n verifiedAt: number;\n wallet: string;\n}\n\n/**\n * Compute SHA256 hash, browser-compatible via SubtleCrypto.\n */\nasync function sha256(data: Uint8Array): Promise<Uint8Array> {\n const ab = new ArrayBuffer(data.length);\n new Uint8Array(ab).set(data);\n return new Uint8Array(await crypto.subtle.digest(\"SHA-256\", ab));\n}\n\n/**\n * Attest that a verified Entros human operates an AI agent on the Solana Agent Registry.\n *\n * Reads the user's on-chain IdentityState PDA, builds metadata JSON, and writes\n * it to the agent's metadata via a manually constructed set_metadata_pda instruction.\n * The metadata is immutable once set, permanently linking the agent to its human operator.\n *\n * The wallet must own both the Entros Anchor and the agent's Metaplex Core NFT.\n *\n * @param agentAsset - Base58 pubkey of the agent's Metaplex Core NFT\n * @param options - Wallet adapter and Solana connection\n * @returns Transaction signature on success\n */\nexport async function attestAgentOperator(\n agentAsset: string,\n options: {\n wallet: any;\n connection: any;\n cluster?: PulseConfig[\"cluster\"];\n }\n): Promise<{ success: boolean; signature?: string; error?: string }> {\n try {\n const { PublicKey, Transaction, TransactionInstruction, SystemProgram } =\n await import(\"@solana/web3.js\");\n\n const walletPubkey =\n options.wallet.adapter?.publicKey ?? options.wallet.publicKey;\n if (!walletPubkey) {\n return {\n success: false,\n error: \"Wallet not connected. Call wallet.connect() before attestAgentOperator().\",\n };\n }\n\n // 1. Read Entros IdentityState PDA\n const programId = new PublicKey(PROGRAM_IDS.entrosAnchor);\n const [identityPda] = PublicKey.findProgramAddressSync(\n [new TextEncoder().encode(\"identity\"), walletPubkey.toBuffer()],\n programId\n );\n\n const accountInfo = await options.connection.getAccountInfo(identityPda);\n if (!accountInfo || accountInfo.data.length < 62) {\n return {\n success: false,\n error: \"No Entros Anchor found. Complete a verification first.\",\n };\n }\n\n // 2. Deserialize trust_score and last_verification_timestamp\n const data = accountInfo.data;\n const view = new DataView(data.buffer, data.byteOffset, data.byteLength);\n const lastVerificationTimestamp = Number(view.getBigInt64(48, true));\n const trustScore = view.getUint16(60, true);\n\n // 3. Build metadata JSON value\n const metadata: AgentHumanOperator = {\n anchorPda: identityPda.toBase58(),\n trustScore,\n verifiedAt: lastVerificationTimestamp,\n wallet: walletPubkey.toBase58(),\n };\n const metadataValue = JSON.stringify(metadata);\n const metadataKey = AGENT_REGISTRY_CONFIG.metadataKey;\n\n // 4. Derive PDAs for the 8004 Agent Registry\n const registryProgramId = new PublicKey(\n getRegistryProgramId(options.cluster)\n );\n const assetPubkey = new PublicKey(agentAsset);\n\n // Agent PDA: [\"agent\", asset]\n const [agentPda] = PublicKey.findProgramAddressSync(\n [new TextEncoder().encode(\"agent\"), assetPubkey.toBuffer()],\n registryProgramId\n );\n\n // Key hash: SHA256(key)[0..16]\n const keyBytes = new TextEncoder().encode(metadataKey);\n const keyHashFull = await sha256(keyBytes);\n const keyHash = keyHashFull.slice(0, 16);\n\n // Metadata entry PDA: [\"agent_meta\", asset, keyHash[0..16]]\n const [metadataEntryPda] = PublicKey.findProgramAddressSync(\n [\n new TextEncoder().encode(\"agent_meta\"),\n assetPubkey.toBuffer(),\n keyHash,\n ],\n registryProgramId\n );\n\n // 5. Build set_metadata_pda instruction data\n // Discriminator: [236, 60, 23, 48, 138, 69, 196, 153]\n // Args: key_hash ([u8; 16]), key (String), value (Vec<u8>), immutable (bool)\n const valueBytes = new TextEncoder().encode(metadataValue);\n const discriminator = new Uint8Array([236, 60, 23, 48, 138, 69, 196, 153]);\n\n const ixDataSize =\n 8 + // discriminator\n 16 + // key_hash [u8; 16]\n 4 + keyBytes.length + // key (Borsh string: 4-byte len + utf8)\n 4 + valueBytes.length + // value (Borsh Vec<u8>: 4-byte len + bytes)\n 1; // immutable (bool)\n\n const ixData = new Uint8Array(ixDataSize);\n const ixView = new DataView(ixData.buffer);\n let offset = 0;\n\n // Discriminator\n ixData.set(discriminator, offset);\n offset += 8;\n\n // key_hash: [u8; 16]\n ixData.set(keyHash, offset);\n offset += 16;\n\n // key: Borsh String (4-byte LE len + UTF-8)\n ixView.setUint32(offset, keyBytes.length, true);\n offset += 4;\n ixData.set(keyBytes, offset);\n offset += keyBytes.length;\n\n // value: Borsh Vec<u8> (4-byte LE len + bytes)\n ixView.setUint32(offset, valueBytes.length, true);\n offset += 4;\n ixData.set(valueBytes, offset);\n offset += valueBytes.length;\n\n // immutable: bool\n ixData[offset] = 1; // true\n offset += 1;\n\n // 6. Build instruction with 5 accounts\n const { Buffer: SolBuffer } = await import(\"buffer\");\n const instruction = new TransactionInstruction({\n programId: registryProgramId,\n keys: [\n { pubkey: metadataEntryPda, isSigner: false, isWritable: true },\n { pubkey: agentPda, isSigner: false, isWritable: false },\n { pubkey: assetPubkey, isSigner: false, isWritable: false },\n { pubkey: walletPubkey, isSigner: true, isWritable: true },\n {\n pubkey: SystemProgram.programId,\n isSigner: false,\n isWritable: false,\n },\n ],\n data: SolBuffer.from(ixData),\n });\n\n // 7. Build transaction, sign, send\n const tx = new Transaction().add(instruction);\n tx.feePayer = walletPubkey;\n const { blockhash } = await options.connection.getLatestBlockhash(\n \"confirmed\"\n );\n tx.recentBlockhash = blockhash;\n\n const signFn =\n options.wallet.adapter?.signTransaction ??\n options.wallet.signTransaction;\n if (!signFn) {\n return {\n success: false,\n error: \"Wallet adapter does not expose signTransaction. Use a wallet that implements the standard Solana Wallet Adapter interface (Phantom, Solflare, Backpack).\",\n };\n }\n const signed = await signFn.call(\n options.wallet.adapter ?? options.wallet,\n tx\n );\n\n const sig = await options.connection.sendRawTransaction(\n signed.serialize(),\n { skipPreflight: false, preflightCommitment: \"confirmed\" }\n );\n\n await options.connection.confirmTransaction(sig, \"confirmed\");\n\n return { success: true, signature: sig };\n } catch (err: any) {\n return { success: false, error: err.message ?? String(err) };\n }\n}\n\n/**\n * Query whether an AI agent has a verified human operator via Entros.\n *\n * Reads the \"entros:human-operator\" metadata from the agent's on-chain record\n * and returns the operator's Entros Anchor details.\n *\n * @param agentAsset - Base58 pubkey of the agent's Metaplex Core NFT\n * @param connection - Solana connection (optional, defaults to devnet)\n * @returns Operator metadata or null if no Entros attestation exists\n */\nexport async function getAgentHumanOperator(\n agentAsset: string,\n connection?: any,\n cluster?: PulseConfig[\"cluster\"],\n): Promise<AgentHumanOperator | null> {\n try {\n const { PublicKey } = await import(\"@solana/web3.js\");\n\n const registryProgramId = new PublicKey(\n getRegistryProgramId(cluster)\n );\n const assetPubkey = new PublicKey(agentAsset);\n const metadataKey = AGENT_REGISTRY_CONFIG.metadataKey;\n\n // Derive metadata entry PDA\n const keyBytes = new TextEncoder().encode(metadataKey);\n const keyHashFull = await sha256(keyBytes);\n const keyHash = keyHashFull.slice(0, 16);\n\n const [metadataEntryPda] = PublicKey.findProgramAddressSync(\n [\n new TextEncoder().encode(\"agent_meta\"),\n assetPubkey.toBuffer(),\n keyHash,\n ],\n registryProgramId\n );\n\n // Read account directly (no SDK dependency)\n const conn =\n connection ??\n new (await import(\"@solana/web3.js\")).Connection(\n \"https://api.devnet.solana.com\",\n \"confirmed\"\n );\n\n const accountInfo = await conn.getAccountInfo(metadataEntryPda);\n if (!accountInfo) return null;\n\n // Deserialize MetadataEntryPda\n // Layout: 8 (disc) + 32 (asset) + 1 (immutable) + 1 (bump) + 4+N (metadata_key) + 4+M (metadata_value)\n const raw = accountInfo.data;\n if (raw.length < 46) return null; // minimum size\n\n let offset = 8 + 32 + 1 + 1; // skip disc, asset, immutable, bump = 42\n\n // Read metadata_key (Borsh String: 4-byte LE len + UTF-8)\n const keyLen = new DataView(\n raw.buffer,\n raw.byteOffset + offset,\n 4\n ).getUint32(0, true);\n offset += 4 + keyLen;\n\n // Read metadata_value (Borsh Vec<u8>: 4-byte LE len + bytes)\n if (offset + 4 > raw.length) return null;\n const valueLen = new DataView(\n raw.buffer,\n raw.byteOffset + offset,\n 4\n ).getUint32(0, true);\n offset += 4;\n\n if (offset + valueLen > raw.length) return null;\n const valueBytes = raw.slice(offset, offset + valueLen);\n const valueStr = new TextDecoder().decode(valueBytes);\n\n return JSON.parse(valueStr) as AgentHumanOperator;\n } catch {\n return null;\n }\n}\n","// Phonetically-balanced nonsense syllables for the voice challenge — FALLBACK ONLY.\n//\n// The authoritative challenge phrase is server-issued by the executor's\n// `/challenge` endpoint (a 5-word phrase drawn from a curated English-word\n// dictionary — see `entros-validation/src/word_dict.rs` for the source of truth).\n// This client-side generator only fires when the executor is unreachable; in\n// that path the server has no record of the phrase and validation skips\n// phrase content binding entirely (Tier 1 acoustic + Tier 2 cross-modal still\n// run). The fallback intentionally stays nonsense to avoid shipping the\n// curated dictionary client-side — the JS bundle stays lean, and a degraded\n// session is visually distinct from a normal one for users / contributors\n// debugging.\nconst SYLLABLES = [\n \"ba\", \"da\", \"fa\", \"ga\", \"ha\", \"ja\", \"ka\", \"la\", \"ma\", \"na\",\n \"pa\", \"ra\", \"sa\", \"ta\", \"wa\", \"za\", \"be\", \"de\", \"fe\", \"ge\",\n \"ke\", \"le\", \"me\", \"ne\", \"pe\", \"re\", \"se\", \"te\", \"we\", \"ze\",\n \"bi\", \"di\", \"fi\", \"gi\", \"ki\", \"li\", \"mi\", \"ni\", \"pi\", \"ri\",\n \"si\", \"ti\", \"wi\", \"zi\", \"bo\", \"do\", \"fo\", \"go\", \"ko\", \"lo\",\n \"mo\", \"no\", \"po\", \"ro\", \"so\", \"to\", \"wo\", \"zo\", \"bu\", \"du\",\n \"fu\", \"gu\", \"ku\", \"lu\", \"mu\", \"nu\", \"pu\", \"ru\", \"su\", \"tu\",\n];\n\n/** Cryptographically random integer in [0, max) */\nfunction secureRandom(max: number): number {\n const arr = new Uint32Array(1);\n crypto.getRandomValues(arr);\n return arr[0]! % max;\n}\n\n/**\n * FALLBACK challenge-phrase generator. Used only when the executor's\n * `/challenge` endpoint is unreachable; the authoritative phrase comes from\n * the server (5 real words drawn from a curated English-word dictionary). On\n * this fallback path, validation skips server-side phrase content binding —\n * Tier 1 acoustic + Tier 2 cross-modal still run.\n *\n * Output is 5-6 syllable pairs, forming nonsensical but speakable words.\n * Uses crypto.getRandomValues for unpredictable challenge generation.\n */\nexport function generatePhrase(wordCount: number = 5): string {\n const words: string[] = [];\n for (let w = 0; w < wordCount; w++) {\n const syllableCount = 2 + secureRandom(2);\n let word = \"\";\n for (let s = 0; s < syllableCount; s++) {\n word += SYLLABLES[secureRandom(SYLLABLES.length)];\n }\n words.push(word);\n }\n return words.join(\" \");\n}\n\n/**\n * Generate a sequence of phrases for dynamic mid-session switching.\n * Each phrase uses a different syllable subset to prevent pre-computation.\n */\nexport function generatePhraseSequence(\n count: number = 3,\n wordCount: number = 4\n): string[] {\n const subsetSize = Math.floor(SYLLABLES.length / count);\n const phrases: string[] = [];\n\n for (let p = 0; p < count; p++) {\n const start = (p * subsetSize) % SYLLABLES.length;\n const subset = [\n ...SYLLABLES.slice(start, start + subsetSize),\n ...SYLLABLES.slice(0, Math.max(0, (start + subsetSize) - SYLLABLES.length)),\n ];\n\n const words: string[] = [];\n for (let w = 0; w < wordCount; w++) {\n const syllableCount = 2 + secureRandom(2);\n let word = \"\";\n for (let s = 0; s < syllableCount; s++) {\n word += subset[secureRandom(subset.length)];\n }\n words.push(word);\n }\n phrases.push(words.join(\" \"));\n }\n\n return phrases;\n}\n","/**\n * Generate Lissajous curve points for the touch tracing challenge.\n * The user traces this shape on screen while speaking the phrase.\n *\n * x(t) = A * sin(a*t + delta)\n * y(t) = B * sin(b*t)\n */\nexport interface LissajousParams {\n a: number;\n b: number;\n delta: number;\n points: number;\n}\n\nexport interface Point2D {\n x: number;\n y: number;\n}\n\n/**\n * Generate random Lissajous parameters for a challenge.\n */\nexport function randomLissajousParams(): LissajousParams {\n const ratios = [\n [1, 2],\n [2, 3],\n [3, 4],\n [3, 5],\n [4, 5],\n ];\n const arr = new Uint32Array(2);\n crypto.getRandomValues(arr);\n const pair = ratios[arr[0]! % ratios.length]!;\n return {\n a: pair[0]!,\n b: pair[1]!,\n delta: Math.PI * (0.25 + (arr[1]! / 0xFFFFFFFF) * 0.5),\n points: 200,\n };\n}\n\n/**\n * Generate Lissajous curve points normalized to [0, 1] range.\n */\nexport function generateLissajousPoints(params: LissajousParams): Point2D[] {\n const { a, b, delta, points } = params;\n const result: Point2D[] = [];\n\n for (let i = 0; i < points; i++) {\n const t = (i / points) * 2 * Math.PI;\n result.push({\n x: (Math.sin(a * t + delta) + 1) / 2,\n y: (Math.sin(b * t) + 1) / 2,\n });\n }\n\n return result;\n}\n\n/**\n * Generate a sequence of Lissajous curves for dynamic mid-session switching.\n * Each curve uses different parameters, preventing pre-computation.\n */\nexport function generateLissajousSequence(\n count: number = 2\n): { params: LissajousParams; points: Point2D[] }[] {\n const allRatios: [number, number][] = [\n [1, 2], [2, 3], [3, 4], [3, 5], [4, 5],\n [1, 3], [2, 5], [5, 6], [3, 7], [4, 7],\n ];\n\n // Fisher-Yates shuffle with crypto randomness\n const shuffled = [...allRatios];\n for (let i = shuffled.length - 1; i > 0; i--) {\n const arr = new Uint32Array(1);\n crypto.getRandomValues(arr);\n const j = arr[0]! % (i + 1);\n [shuffled[i], shuffled[j]] = [shuffled[j]!, shuffled[i]!];\n }\n\n const sequence: { params: LissajousParams; points: Point2D[] }[] = [];\n\n for (let i = 0; i < count; i++) {\n const pair = shuffled[i % shuffled.length]!;\n const deltaArr = new Uint32Array(1);\n crypto.getRandomValues(deltaArr);\n const params: LissajousParams = {\n a: pair[0],\n b: pair[1],\n delta: Math.PI * (0.1 + (deltaArr[0]! / 0xFFFFFFFF) * 0.8),\n points: 200,\n };\n sequence.push({ params, points: generateLissajousPoints(params) });\n }\n\n return sequence;\n}\n","/**\n * Fetch the server-issued challenge from the executor.\n *\n * The executor's `/challenge` endpoint returns a fresh nonce + 5-word phrase\n * bound to the wallet for a short TTL (default 60s). The phrase is drawn from\n * a curated English-word dictionary (source of truth at\n * `entros-validation/src/word_dict.rs`); shown to the user as the voice challenge\n * and looked up server-side at `/validate-features` to verify the audio\n * matches the issued phrase (master-list #89, phrase content binding).\n *\n * Server-issued phrases are the only safe design for content binding: if the\n * client generated the phrase and sent it to the server alongside the audio,\n * an attacker would submit their own phrase matching whatever content they\n * captured. With server issuance, the phrase is bound to the nonce and the\n * client cannot substitute it.\n */\n\nimport { sdkWarn } from \"../log\";\n\n/**\n * Server-issued challenge artifacts. Returned by `fetchChallenge`.\n */\nexport interface ChallengeResponse {\n /** 32-byte nonce used for on-chain `create_challenge` and the `/attest` handshake. */\n nonce: Uint8Array;\n /** Server-issued 5-word challenge phrase (drawn from a curated English-word dictionary) the user must speak aloud. */\n phrase: string;\n /** Nonce TTL in seconds (default 60). */\n expiresIn: number;\n}\n\n/**\n * Fetch a fresh nonce + phrase from the executor. Throws on network error or\n * non-2xx response so the caller can surface a retry UX.\n *\n * @param executorUrl - Base URL of the executor (e.g. `https://executor.entros.io`).\n * @param walletAddress - Base58-encoded wallet public key.\n * @param apiKey - Optional executor API key (`X-API-Key` header).\n */\nexport async function fetchChallenge(\n executorUrl: string,\n walletAddress: string,\n apiKey?: string,\n): Promise<ChallengeResponse> {\n const base = new URL(executorUrl);\n const url = new URL(\"/challenge\", base.origin);\n url.searchParams.set(\"wallet\", walletAddress);\n\n const headers: Record<string, string> = { Accept: \"application/json\" };\n if (apiKey) headers[\"X-API-Key\"] = apiKey;\n\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), 5_000);\n let response: Response;\n try {\n response = await fetch(url.toString(), {\n method: \"GET\",\n headers,\n signal: controller.signal,\n });\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n sdkWarn(`[Entros SDK] /challenge fetch failed: ${msg}`);\n throw new Error(`Unable to fetch challenge from executor: ${msg}`);\n } finally {\n clearTimeout(timer);\n }\n\n if (!response.ok) {\n throw new Error(\n `Executor returned ${response.status} for /challenge. Check the wallet address and try again.`,\n );\n }\n\n const body = (await response.json()) as {\n nonce: number[];\n expires_in: number;\n phrase: string;\n };\n\n if (!Array.isArray(body.nonce) || body.nonce.length !== 32) {\n throw new Error(\"Executor returned malformed nonce; expected 32-byte array\");\n }\n if (typeof body.phrase !== \"string\" || body.phrase.trim().length === 0) {\n throw new Error(\"Executor returned empty challenge phrase\");\n }\n\n return {\n nonce: Uint8Array.from(body.nonce),\n phrase: body.phrase,\n expiresIn: body.expires_in ?? 60,\n };\n}\n"],"mappings":"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","names":["mean","derivative","window"]}