@entros/pulse-sdk 2.0.0 → 3.0.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/mfcc.ts","../src/extraction/voice-quality.ts","../src/extraction/dct.ts","../src/yield.ts","../src/extraction/speaker.ts","../src/extraction/fft.ts","../src/extraction/kinematic.ts","../src/hashing/simhash.ts","../src/hashing/poseidon.ts","../src/proof/serializer.ts","../src/proof/prover.ts","../src/protocol/idl/entros_anchor.json","../src/protocol/idl/entros_verifier.json","../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 derived statistical\n * summary (314-element vector under the v2 pipeline) is the only audio-\n * related signal that crosses the device boundary. The single sanctioned\n * exception is the encoded base64 audio bytes sent to the validator's\n * `/validate-features` endpoint for server-side verification, which the\n * validator processes ephemerally — see entros.io for the privacy and\n * 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 // Capture without browser-side audio processing — preserves the\n // raw microphone signal for the SDK's downstream feature extraction\n // and for server-side validation. Audio cleanup intended for the\n // transcription path runs server-side, on a parallel path that\n // never feeds back to feature extraction. Matches the mobile SDK's\n // choice of Android's `MIC` source over `VOICE_RECOGNITION` —\n // same architectural decision, two platforms.\n echoCancellation: false,\n noiseSuppression: false,\n autoGainControl: false,\n // OS-level voice isolation request (W3C Media Capture Extensions,\n // 2024). Activates the platform DSP on Chrome 124+ / ChromeOS and\n // surfaces Apple Voice Isolation Mic Mode on Safari macOS Sonoma+\n // / iOS 17+ when the user has it enabled in Control Center.\n // Silently ignored on browsers/OSes without support, so the\n // constraint costs nothing where it doesn't help. Distinct\n // mechanism from `noiseSuppression` above — that flag controls\n // WebRTC's hand-tuned AudioProcessingModule, this requests the\n // OS-native neural effect.\n // @ts-expect-error -- W3C Media Capture Extensions property; not\n // yet in lib.dom.d.ts as of TypeScript 6.0. Removing this directive\n // becomes a compile error once lib.dom catches up, signaling that\n // it can be deleted.\n voiceIsolation: true,\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.\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 decodes the base64\n * payload and feeds the audio into server-side transcription. int16 is the\n * standard compact representation: 2 bytes per sample vs 4 for f32, halving\n * 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 * Per-frame analysis output: the 12 LPC coefficients always exist (one\n * autocorrelate + Levinson-Durbin pass per frame), and the formant tuple\n * exists when at least 3 valid candidates were detected within the\n * speech-formant band. Bandwidths are paired with the formants — they're\n * the imaginary-axis decay rates of the same complex roots that produce\n * F1/F2/F3.\n */\ninterface FrameAnalysis {\n /** LPC coefficients a[1..order]; a[0] = 1 implicitly. Always populated. */\n lpcCoefficients: number[];\n /** [F1, F2, F3] in Hz, or null if fewer than 3 valid candidates. */\n formants: [number, number, number] | null;\n /** [B1, B2, B3] in Hz, paired with formants. Null when formants are null. */\n bandwidths: [number, number, number] | null;\n}\n\n/**\n * Per-frame LPC analysis surfacing the full information set used downstream\n * by the v2 feature pipeline (LPC coefficients, formant frequencies,\n * formant bandwidths). Replaces the legacy `extractFormants()` which only\n * returned formant frequencies and discarded both the LPC coefficients\n * and the bandwidths.\n */\nfunction extractFrameAnalysis(\n frame: Float32Array,\n sampleRate: number,\n lpcOrder: number = 12,\n): FrameAnalysis {\n const r = autocorrelate(frame, lpcOrder);\n const coeffs = levinsonDurbin(r, lpcOrder);\n\n const roots = findRoots(coeffs);\n\n // Pair each candidate frequency with its corresponding bandwidth so we\n // can preserve the F1↔B1, F2↔B2, F3↔B3 alignment after sorting by\n // frequency. The LPC pole's imaginary-axis decay rate maps to formant\n // bandwidth via the same complex-magnitude → log relation; capturing it\n // is information-free vs. the existing computation.\n const candidates: { freq: number; bandwidth: 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 =\n (-sampleRate / (2 * Math.PI)) *\n 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 candidates.push({ freq, bandwidth });\n }\n }\n\n candidates.sort((a, b) => a.freq - b.freq);\n\n if (candidates.length < 3) {\n return { lpcCoefficients: coeffs, formants: null, bandwidths: null };\n }\n\n const formants: [number, number, number] = [\n candidates[0]!.freq,\n candidates[1]!.freq,\n candidates[2]!.freq,\n ];\n const bandwidths: [number, number, number] = [\n candidates[0]!.bandwidth,\n candidates[1]!.bandwidth,\n candidates[2]!.bandwidth,\n ];\n\n return { lpcCoefficients: coeffs, formants, bandwidths };\n}\n\n/**\n * Backward-compatible thin wrapper. Existing callers that only need\n * formant frequencies keep their signatures stable; the v2 feature pipeline\n * uses `extractFrameAnalysis` directly to surface the additional LPC and\n * bandwidth signal that the old wrapper discarded.\n */\nfunction extractFormants(\n frame: Float32Array,\n sampleRate: number,\n lpcOrder: number = 12,\n): [number, number, number] | null {\n return extractFrameAnalysis(frame, sampleRate, lpcOrder).formants;\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/**\n * Session-level output of the v2 LPC analysis. Each per-coefficient time\n * series has length `numFramesAnalyzed` (every frame contributes); the\n * formant time series may be shorter because frames with fewer than 3\n * valid candidates are skipped (matches `extractFormantRatios` behavior).\n */\nexport interface LpcAnalysis {\n /** lpcCoefficients[c][t] = c-th LPC coefficient at frame t. Shape: [order × frames]. */\n lpcCoefficients: number[][];\n /** F1/F2/F3 absolute frequencies in Hz, one entry per detected-formant frame. */\n f1: number[];\n f2: number[];\n f3: number[];\n /** B1/B2/B3 corresponding bandwidths in Hz, aligned with f1/f2/f3 by index. */\n b1: number[];\n b2: number[];\n b3: number[];\n /** Existing formant ratios, retained for backward-compat with the original 44-feature audio block. */\n f1f2: number[];\n f2f3: number[];\n /** Diagnostic: number of frames the analyzer ran over (independent of formant detection). */\n numFramesAnalyzed: number;\n}\n\n/**\n * Comprehensive session-level LPC + formant analysis. Surfaces the full\n * information set the v2 feature pipeline consumes: per-frame LPC\n * coefficients (12 time series), absolute formant frequencies (3 time\n * series), formant bandwidths (3 time series), and the existing F1/F2 +\n * F2/F3 ratios.\n *\n * Single pass over the samples — autocorrelate + Levinson-Durbin runs\n * once per frame, with all downstream signals derived from that single\n * coefficient set. CPU cost is identical to the legacy\n * `extractFormantRatios` (the formant filtering, root-finding, and ratio\n * derivation were always running; this function just RETAINS the\n * intermediate values that the legacy function discarded).\n */\nexport function extractLpcAnalysis(\n samples: Float32Array,\n sampleRate: number,\n frameSize: number,\n hopSize: number,\n lpcOrder: number = 12,\n): LpcAnalysis {\n const lpcCoefficients: number[][] = Array.from({ length: lpcOrder }, () => []);\n const f1: number[] = [];\n const f2: number[] = [];\n const f3: number[] = [];\n const b1: number[] = [];\n const b2: number[] = [];\n const b3: number[] = [];\n const f1f2: number[] = [];\n const f2f3: number[] = [];\n\n const numFrames = Math.floor((samples.length - frameSize) / hopSize) + 1;\n let numFramesAnalyzed = 0;\n\n if (numFrames < 1) {\n return {\n lpcCoefficients,\n f1, f2, f3, b1, b2, b3, f1f2, f2f3,\n numFramesAnalyzed: 0,\n };\n }\n\n // Pre-allocate the windowed frame buffer once (matches the optimization\n // in speaker.ts::computeLTAS — saves ~1200 Float32Array allocations\n // per session at ~10ms hop over 12 seconds).\n const windowed = new Float32Array(frameSize);\n\n for (let i = 0; i < numFrames; i++) {\n const start = i * hopSize;\n const frame = samples.subarray(start, start + frameSize);\n\n // Apply Hamming window in-place to the pre-allocated buffer.\n for (let j = 0; j < frameSize; j++) {\n windowed[j] =\n (frame[j] ?? 0) *\n (0.54 - 0.46 * Math.cos((2 * Math.PI * j) / (frameSize - 1)));\n }\n\n const analysis = extractFrameAnalysis(windowed, sampleRate, lpcOrder);\n numFramesAnalyzed++;\n\n // LPC coefficients are always populated.\n for (let c = 0; c < lpcOrder; c++) {\n const coeff = analysis.lpcCoefficients[c];\n if (Number.isFinite(coeff)) {\n lpcCoefficients[c]!.push(coeff!);\n }\n }\n\n // Formants and bandwidths are populated only when 3+ valid candidates\n // were detected. Push the triplet atomically (all three or none) so\n // index alignment between f1/f2/f3 and b1/b2/b3 is preserved.\n if (analysis.formants && analysis.bandwidths) {\n const [F1, F2, F3] = analysis.formants;\n const [B1, B2, B3] = analysis.bandwidths;\n f1.push(F1);\n f2.push(F2);\n f3.push(F3);\n b1.push(B1);\n b2.push(B2);\n b3.push(B3);\n if (F2 > 0) f1f2.push(F1 / F2);\n if (F3 > 0) f2f3.push(F2 / F3);\n }\n }\n\n return {\n lpcCoefficients,\n f1, f2, f3, b1, b2, b3, f1f2, f2f3,\n numFramesAnalyzed,\n };\n}\n","/**\n * MFCC (Mel-Frequency Cepstral Coefficient) feature extraction.\n *\n * MFCCs are the industry-standard speaker-recognition feature: they encode\n * the SHAPE of the vocal tract via cepstral coefficients on a perceptual\n * mel-frequency scale. Two adult humans speaking the same word produce\n * different MFCC trajectories the same way two violins produce different\n * timbres of the same note. The original 44-feature audio block omitted\n * MFCCs entirely — this is the largest single discriminative-power gap\n * the v2 feature pipeline closes (see\n * `docs/master/BLUEPRINT-feature-pipeline-v2.md` §1.1).\n *\n * Output of `extractMfccFeatures` is 78 statistical aggregates over the\n * per-frame MFCC time-series captured during a 12-second session:\n *\n * - 13 MFCC coefficients × 4 stats (mean, var, skewness, kurtosis) = 52\n * - 13 delta-MFCC coefficients × 2 stats (mean, var) = 26\n *\n * The deltas (first-order temporal derivatives via 9-frame regression\n * window) capture how the vocal tract shape CHANGES during articulation —\n * a complementary identity signal to the static MFCCs.\n *\n * @privacyGuarantee MFCCs are themselves a dimensionality reduction (FFT →\n * mel filter bank → log → DCT, keeping the first 13 coefficients). The\n * statistics across frames add a second reduction layer. Aggregated\n * MFCC stats cannot reconstruct intelligible audio without a separate\n * vocoder model, and even with one only a coarse approximation is\n * possible. This is the same privacy posture as the existing 44-feature\n * audio block: statistical aggregates of on-device-computed signals.\n */\nimport { condense, mean as meanOf, variance as varianceOf } from \"./statistics\";\nimport { sdkWarn } from \"../log\";\n\nconst NUM_MFCC_COEFFICIENTS = 13;\n/** Half-width of the regression window used to compute delta-MFCCs. The\n * standard speech-recognition value is 2 (window of 9 frames total: 4 on\n * each side plus the center). Larger N smooths more but lags behind\n * rapid articulation; 2 balances responsiveness against noise. */\nconst DELTA_REGRESSION_HALF_WIDTH = 2;\n\n/**\n * Total feature count produced by `extractMfccFeatures`. Imported by\n * speaker.ts when assembling the final audio feature vector.\n */\nexport const MFCC_FEATURE_COUNT =\n NUM_MFCC_COEFFICIENTS * 4 + // mean, var, skew, kurt per coefficient\n NUM_MFCC_COEFFICIENTS * 2; // mean, var per delta coefficient\n// = 52 + 26 = 78\n\n/**\n * Compute first-order delta (temporal derivative) of a per-frame time\n * series using a regression window. Standard speech-recognition formula\n * (Furui 1986):\n *\n * delta_t = Σ_{n=1..N} n × (x_{t+n} - x_{t-n}) / (2 × Σ_{n=1..N} n²)\n *\n * Equivalent to a least-squares fit of a line to the surrounding 2N+1\n * frames. The numerator is symmetric: contributions from `n=1..N` on each\n * side are weighted by `n`. The denominator `2 × Σ_{i=1..N} i² =\n * N(N+1)(2N+1)/3` normalizes so a series with constant slope produces a\n * delta equal to that slope (verified by the linear-input test in\n * mfcc.test.ts).\n *\n * Edge frames use truncated windows: when offset `k` would land outside\n * `[0, n)` on either side, the entire ±k pair is dropped from the\n * numerator AND `2k²` is subtracted from the denominator. This keeps the\n * result a valid (less precise, but unbiased toward zero) least-squares\n * estimate over the surviving symmetric offsets.\n */\nfunction computeDelta(series: number[], halfWidth: number): number[] {\n const n = series.length;\n const out: number[] = new Array(n);\n // Σ_{i=-N..N} i² = 2 × N(N+1)(2N+1)/6 = N(N+1)(2N+1)/3.\n // Computed once per series; constant across all frames except for\n // edge-truncation adjustments below.\n const fullDenom = (halfWidth * (halfWidth + 1) * (2 * halfWidth + 1)) / 3;\n for (let t = 0; t < n; t++) {\n let num = 0;\n let denom = fullDenom;\n for (let k = 1; k <= halfWidth; k++) {\n const tPlus = t + k;\n const tMinus = t - k;\n if (tPlus >= n || tMinus < 0) {\n // Edge: drop the symmetric pair from numerator and remove the\n // matching 2k² from the denominator. Without the adjustment edge\n // deltas would be biased toward zero (smaller numerator over an\n // unchanged denominator).\n denom -= 2 * k * k;\n continue;\n }\n num += k * (series[tPlus]! - series[tMinus]!);\n }\n if (denom <= 0) {\n // Pathological case — series too short for any symmetric window.\n // Deliver zero rather than NaN so downstream stats stay finite.\n out[t] = 0;\n continue;\n }\n out[t] = num / denom;\n }\n return out;\n}\n\n/**\n * Loaded lazily so SDK consumers that don't need audio extraction don't pay\n * the Meyda bundle cost. Mirrors the pattern in speaker.ts::getMeyda\n * exactly, including the `any` typing — Meyda's published types don't\n * surface the runtime `.extract` method on the module-default export\n * cleanly across bundler interop, and matching speaker.ts's existing\n * pragma keeps the integration consistent.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nlet meydaModule: any = null;\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\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 * Extract MFCC and delta-MFCC statistical features from an audio capture.\n *\n * Computes MFCCs frame-by-frame using Meyda's built-in extractor, then\n * applies regression-based delta to capture temporal dynamics. Aggregates\n * each per-coefficient time-series to a small set of moments suitable for\n * fingerprinting (resistant to phrase content; sensitive to vocal tract\n * shape).\n *\n * Returns 78 floats (see MFCC_FEATURE_COUNT above) in stable order:\n * [mean(c0), var(c0), skew(c0), kurt(c0),\n * mean(c1), var(c1), skew(c1), kurt(c1),\n * ...\n * mean(c12), var(c12), skew(c12), kurt(c12),\n * mean(d0), var(d0),\n * mean(d1), var(d1),\n * ...\n * mean(d12), var(d12)]\n *\n * On invalid input (zero-length samples, non-finite sample rate, or Meyda\n * unavailable) returns a zero vector of the correct length so the caller\n * can concatenate without conditional logic.\n */\nexport async function extractMfccFeatures(\n samples: Float32Array,\n sampleRate: number,\n frameSize: number,\n hopSize: number,\n): Promise<number[]> {\n if (\n !Number.isFinite(sampleRate) ||\n sampleRate <= 0 ||\n samples.length === 0 ||\n frameSize <= 0 ||\n hopSize <= 0\n ) {\n return new Array(MFCC_FEATURE_COUNT).fill(0);\n }\n\n const Meyda = await getMeyda();\n if (!Meyda) {\n sdkWarn(\"[Entros SDK] Meyda unavailable; MFCC features will be zeros.\");\n return new Array(MFCC_FEATURE_COUNT).fill(0);\n }\n\n const numFrames = Math.floor((samples.length - frameSize) / hopSize) + 1;\n if (numFrames < 5) {\n return new Array(MFCC_FEATURE_COUNT).fill(0);\n }\n\n // Per-coefficient time series: mfccTracks[i][t] is the i-th MFCC at frame t.\n const mfccTracks: number[][] = Array.from(\n { length: NUM_MFCC_COEFFICIENTS },\n () => [],\n );\n\n // Reusable frame buffer to avoid allocating per frame (matches the\n // pre-allocation pattern in speaker.ts::computeLTAS).\n const frame = new Float32Array(frameSize);\n\n // Meyda.extract's third argument is `previousSignal`, NOT options — passing\n // `{ sampleRate, bufferSize }` silently goes to that slot and is ignored.\n // Configure Meyda's globals before extracting so the mel filter bank is\n // built for the correct sample rate and frame size. Without this, Meyda\n // uses default sampleRate=44100 / bufferSize=512 — producing MFCCs that\n // are still self-consistent (same input → same output) but not aligned\n // with the actual frequency content of our 16 kHz / 2048-sample frames,\n // and not parity-comparable to librosa or other reference implementations.\n Meyda.bufferSize = frameSize;\n Meyda.sampleRate = sampleRate;\n\n for (let i = 0; i < numFrames; i++) {\n const start = i * hopSize;\n frame.set(samples.subarray(start, start + frameSize), 0);\n\n const result = Meyda.extract(\"mfcc\", frame) as number[] | null | undefined;\n\n if (!Array.isArray(result) || result.length !== NUM_MFCC_COEFFICIENTS) {\n // Skip frames where Meyda failed to extract MFCCs (typically silent\n // or pathologically small frames). Keeping per-coefficient track\n // lengths in sync — a frame is either added to ALL tracks or NONE.\n continue;\n }\n\n let allFinite = true;\n for (let c = 0; c < NUM_MFCC_COEFFICIENTS; c++) {\n if (!Number.isFinite(result[c]!)) {\n allFinite = false;\n break;\n }\n }\n if (!allFinite) continue;\n\n for (let c = 0; c < NUM_MFCC_COEFFICIENTS; c++) {\n mfccTracks[c]!.push(result[c]!);\n }\n }\n\n // Aggregate per-coefficient track using the existing repo statistics\n // helpers. Reusing condense/mean/variance keeps the moment formulas\n // (sample variance, statistically-correct skewness, excess-kurtosis-\n // corrected kurtosis) consistent with the existing 44 audio features\n // computed elsewhere in the speaker block.\n const out: number[] = [];\n out.length = MFCC_FEATURE_COUNT;\n let writeIdx = 0;\n\n // 13 × 4 = 52 features (mean, variance, skewness, kurtosis per coefficient).\n for (let c = 0; c < NUM_MFCC_COEFFICIENTS; c++) {\n const stats = condense(mfccTracks[c]!);\n out[writeIdx++] = stats.mean;\n out[writeIdx++] = stats.variance;\n out[writeIdx++] = stats.skewness;\n out[writeIdx++] = stats.kurtosis;\n }\n\n // 13 × 2 = 26 features (mean, variance per delta coefficient).\n for (let c = 0; c < NUM_MFCC_COEFFICIENTS; c++) {\n const delta = computeDelta(mfccTracks[c]!, DELTA_REGRESSION_HALF_WIDTH);\n const muDelta = meanOf(delta);\n out[writeIdx++] = muDelta;\n out[writeIdx++] = varianceOf(delta, muDelta);\n }\n\n return out;\n}\n","/**\n * Voice quality feature extraction.\n *\n * Captures identity-bearing voice characteristics that the existing 44\n * audio features and the new MFCC / LPC blocks don't directly target:\n *\n * - **Cepstral Peak Prominence (CPP)** — strongest single measure of\n * voice quality (breathy ↔ pressed phonation). Computed as the height\n * of the cepstral peak in the typical-F0 quefrency band, relative to\n * a linear regression baseline.\n * - **Spectral tilt** — slope of the log-magnitude spectrum vs log\n * frequency. Captures vocal \"brightness\" / spectral balance, an\n * individual-speaker signature.\n * - **H1-H2** — amplitude difference (in dB) between the first two\n * harmonics of the voice. Identifies phonation type (modal /\n * breathy / pressed) and is identity-bearing.\n * - **Sub-band energy ratios** — fraction of total energy in three\n * bands (low <1kHz, mid 1-3kHz, high 3-8kHz). Captures gross\n * spectral balance complementary to spectral tilt.\n *\n * Output: 9 floats (see `VOICE_QUALITY_FEATURE_COUNT`):\n * [cppMean, cppVar, tiltMean, tiltVar, h1h2Mean, h1h2Var,\n * lowBandRatio, midBandRatio, highBandRatio]\n *\n * @privacyGuarantee Each metric is a per-frame scalar; the output is\n * statistical aggregates over the per-frame time series. Same privacy\n * posture as the existing audio features: aggregates of aggregates of\n * frequency-domain transforms of on-device-captured audio. Cannot\n * reconstruct intelligible speech.\n */\nimport { mean as meanOf, variance as varianceOf } from \"./statistics\";\nimport { sdkWarn } from \"../log\";\n\nexport const VOICE_QUALITY_FEATURE_COUNT = 9;\n\n// Sub-band frequency boundaries in Hz. Tuned to capture distinct\n// spectral regions of human speech: low band covers F0 + first\n// formant region, mid covers F2-F3 (vowel quality), high covers\n// fricative + breathiness energy.\nconst LOW_BAND_HZ = 1000;\nconst MID_BAND_HZ = 3000;\nconst HIGH_BAND_HZ = 8000;\n\n// Quefrency band for CPP peak search (in samples). Corresponds to\n// typical fundamental-frequency range 60–400 Hz: quefrency q maps\n// to frequency sampleRate/q, so q in [sampleRate/400, sampleRate/60].\nfunction cppQuefrencyRange(sampleRate: number): { qMin: number; qMax: number } {\n return {\n qMin: Math.max(2, Math.floor(sampleRate / 400)),\n qMax: Math.floor(sampleRate / 60),\n };\n}\n\n/**\n * Lazy-import meyda mirroring speaker.ts::getMeyda. Meyda's published\n * types don't surface the runtime API on the default export cleanly\n * across bundler interop, so the `any` typing matches the existing\n * pattern.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nlet meydaModule: any = null;\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\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 * Compute Cepstral Peak Prominence for a single frame's power spectrum.\n *\n * CPP = peak_value − regression_baseline_at_peak_quefrency\n *\n * Where the cepstrum is computed as DCT-II of the log power spectrum\n * (mathematically equivalent to the real cepstrum for an even-symmetric\n * input, and faster than IFFT for our use case). The peak is searched\n * in the quefrency band corresponding to typical human F0 (60-400 Hz),\n * and the baseline is a linear regression fit to the cepstrum across\n * the search band.\n *\n * Returns 0 if the spectrum is too small or degenerate.\n */\nfunction cepstralPeakProminence(\n powerSpectrum: Float32Array | number[],\n sampleRate: number,\n): number {\n const N = powerSpectrum.length;\n if (N < 8) return 0;\n\n const { qMin, qMax } = cppQuefrencyRange(sampleRate);\n if (qMax >= N || qMax <= qMin) return 0;\n\n // Take log of power spectrum with a floor to avoid log(0).\n const FLOOR = 1e-12;\n const logPower: number[] = new Array(N);\n for (let i = 0; i < N; i++) {\n const p = Math.max(powerSpectrum[i]!, FLOOR);\n const l = Math.log(p);\n if (!Number.isFinite(l)) return 0;\n logPower[i] = l;\n }\n\n // Cepstrum via DCT-II of the log spectrum, computed ONLY over the\n // quefrency band we need. Naive `dctII(logPower, N)` is O(N²) ≈ 1M ops\n // per frame at N=1024; restricting the output range to [qMin..qMax]\n // (≈ 200 bins for typical F0 60-400 Hz at 16 kHz) drops the cost to\n // O(N × (qMax - qMin + 1)) ≈ 200k ops per frame — a 5× speedup. The\n // baseline regression and peak-finding still run only over the band,\n // so the full-N DCT was wasted work in the original implementation.\n const bandLen = qMax - qMin + 1;\n const cepstrumBand: number[] = new Array(bandLen);\n const piOverN = Math.PI / N;\n for (let bIdx = 0; bIdx < bandLen; bIdx++) {\n const k = qMin + bIdx;\n let sum = 0;\n for (let n = 0; n < N; n++) {\n sum += logPower[n]! * Math.cos(piOverN * (n + 0.5) * k);\n }\n cepstrumBand[bIdx] = sum;\n }\n\n // Find peak in the band.\n let peakBIdx = 0;\n let peakVal = cepstrumBand[0]!;\n for (let bIdx = 1; bIdx < bandLen; bIdx++) {\n if (cepstrumBand[bIdx]! > peakVal) {\n peakVal = cepstrumBand[bIdx]!;\n peakBIdx = bIdx;\n }\n }\n const peakQuefrency = qMin + peakBIdx;\n\n // Linear regression baseline: simple least-squares fit y = a + b × q\n // over the same band. CPP = peak − baseline_at_peak_q.\n const M = bandLen;\n let sx = 0;\n let sy = 0;\n let sxx = 0;\n let sxy = 0;\n for (let bIdx = 0; bIdx < bandLen; bIdx++) {\n const x = qMin + bIdx;\n const y = cepstrumBand[bIdx]!;\n sx += x;\n sy += y;\n sxx += x * x;\n sxy += x * y;\n }\n const denom = M * sxx - sx * sx;\n if (Math.abs(denom) < 1e-12) return 0;\n const slope = (M * sxy - sx * sy) / denom;\n const intercept = (sy - slope * sx) / M;\n const baselineAtPeak = intercept + slope * peakQuefrency;\n\n return peakVal - baselineAtPeak;\n}\n\n/**\n * Compute spectral tilt for a single frame: linear regression slope of\n * `log(power[k])` vs `log(frequency[k])` over the analysis band.\n *\n * Higher-magnitude (more negative) slope indicates a darker / breathier\n * voice; flatter slope indicates pressed / clearer voice. Identity-\n * bearing within a speaker's range.\n *\n * Returns 0 on degenerate input. Bands below 100 Hz are excluded\n * because they're dominated by DC + room noise.\n */\nfunction spectralTilt(\n powerSpectrum: Float32Array | number[],\n sampleRate: number,\n): number {\n const N = powerSpectrum.length;\n if (N < 8) return 0;\n // Frequency at bin k (assuming standard FFT bin spacing): k × (sampleRate / 2) / (N - 1)\n // for half-spectrum N. Meyda's amplitudeSpectrum/powerSpectrum has length\n // bufferSize/2, so binHz = k × sampleRate / bufferSize. Caller may pass\n // either; we assume standard interpretation: binHz = k × (sampleRate / 2) / (N - 1).\n // Mathematically the slope is unaffected by frequency-axis scaling\n // (since both x and ln-x scale together).\n const FLOOR = 1e-12;\n let sx = 0;\n let sy = 0;\n let sxx = 0;\n let sxy = 0;\n let count = 0;\n // Skip k=0 (DC) and the lowest bins (< 100 Hz) where noise dominates.\n const minBin = Math.max(1, Math.floor((100 * 2 * (N - 1)) / sampleRate));\n for (let k = minBin; k < N; k++) {\n const p = powerSpectrum[k]!;\n if (p < FLOOR) continue;\n const x = Math.log(k); // log-frequency proxy\n const y = Math.log(p); // log-power\n if (!Number.isFinite(x) || !Number.isFinite(y)) continue;\n sx += x;\n sy += y;\n sxx += x * x;\n sxy += x * y;\n count++;\n }\n if (count < 4) return 0;\n const denom = count * sxx - sx * sx;\n if (Math.abs(denom) < 1e-12) return 0;\n return (count * sxy - sx * sy) / denom;\n}\n\n/**\n * Compute H1-H2 (amplitude in dB of first vs second harmonic) for a\n * single frame given the power spectrum and the F0 estimate.\n *\n * Looks for the local peak in a small window around k_F0 (first\n * harmonic) and around k_2F0 (second harmonic), takes the max within\n * each window, converts to dB, returns difference.\n *\n * Returns 0 if F0 is invalid (≤ 0) or harmonics fall outside the\n * spectrum.\n */\nfunction h1MinusH2(\n powerSpectrum: Float32Array | number[],\n sampleRate: number,\n f0: number,\n): number {\n if (!Number.isFinite(f0) || f0 <= 0) return 0;\n const N = powerSpectrum.length;\n if (N < 8) return 0;\n\n // Bin index for frequency f: k = f × (N - 1) / (sampleRate / 2)\n const binPerHz = (2 * (N - 1)) / sampleRate;\n const k1 = Math.round(f0 * binPerHz);\n const k2 = Math.round(2 * f0 * binPerHz);\n\n // ±2-bin search window around each harmonic.\n const window = 2;\n\n function peakNear(k: number): number {\n let best = -Infinity;\n for (let i = k - window; i <= k + window; i++) {\n if (i <= 0 || i >= N) continue;\n const p = powerSpectrum[i]!;\n if (p > best) best = p;\n }\n return best;\n }\n\n const h1 = peakNear(k1);\n const h2 = peakNear(k2);\n if (!Number.isFinite(h1) || !Number.isFinite(h2) || h1 <= 0 || h2 <= 0) return 0;\n // dB difference of amplitudes: 10 × (log10(h1) - log10(h2)) since these\n // are powers (squared amplitudes); equivalent to 20 × log10(amp ratio).\n return 10 * Math.log10(h1 / h2);\n}\n\n/**\n * Compute sub-band energy ratios from the power spectrum. Returns\n * [low, mid, high] each in [0, 1] summing to ≤ 1 (can be < 1 if some\n * energy is above HIGH_BAND_HZ).\n */\nfunction subbandRatios(\n powerSpectrum: Float32Array | number[],\n sampleRate: number,\n): [number, number, number] {\n const N = powerSpectrum.length;\n if (N < 4) return [0, 0, 0];\n // Bin per Hz mapping: k = f × (N - 1) / (sampleRate / 2)\n const binPerHz = (2 * (N - 1)) / sampleRate;\n const lowBin = Math.min(N - 1, Math.round(LOW_BAND_HZ * binPerHz));\n const midBin = Math.min(N - 1, Math.round(MID_BAND_HZ * binPerHz));\n const highBin = Math.min(N - 1, Math.round(HIGH_BAND_HZ * binPerHz));\n\n let total = 0;\n let low = 0;\n let mid = 0;\n let high = 0;\n // Skip k=0 (DC) — never carries voice energy.\n for (let k = 1; k < N; k++) {\n const p = powerSpectrum[k]!;\n if (!Number.isFinite(p) || p < 0) continue;\n total += p;\n if (k <= lowBin) low += p;\n else if (k <= midBin) mid += p;\n else if (k <= highBin) high += p;\n }\n if (total < 1e-12) return [0, 0, 0];\n return [low / total, mid / total, high / total];\n}\n\n/**\n * Extract voice quality features from an audio capture.\n *\n * Per-frame: compute power spectrum (via Meyda), then derive CPP,\n * spectral tilt, H1-H2 (using the per-frame F0), and sub-band ratios.\n * Aggregate per-frame metrics over the session.\n *\n * Returns 9 floats in the order documented at the top of this module.\n * Returns all-zeros on invalid input or when Meyda is unavailable.\n *\n * @param samples — Float32Array of audio samples (peak-normalized\n * recommended; matches the speaker.ts pre-processing step).\n * @param sampleRate — sample rate in Hz.\n * @param frameSize — frame size in samples (must be a power of two for\n * Meyda's FFT).\n * @param hopSize — hop size in samples.\n * @param f0PerFrame — F0 (Hz) for each frame, indexed 0..numFrames-1.\n * Frames where F0 ≤ 0 are treated as unvoiced and skipped for H1-H2\n * only (CPP, tilt, sub-bands run on every frame). Length should match\n * the frame iteration in this function (numFrames = floor((samples.length\n * - frameSize) / hopSize) + 1).\n */\nexport async function extractVoiceQualityFeatures(\n samples: Float32Array,\n sampleRate: number,\n frameSize: number,\n hopSize: number,\n f0PerFrame: number[],\n): Promise<number[]> {\n if (\n !Number.isFinite(sampleRate) ||\n sampleRate <= 0 ||\n samples.length === 0 ||\n frameSize <= 0 ||\n hopSize <= 0\n ) {\n return new Array(VOICE_QUALITY_FEATURE_COUNT).fill(0);\n }\n\n const Meyda = await getMeyda();\n if (!Meyda) {\n sdkWarn(\"[Entros SDK] Meyda unavailable; voice quality features will be zeros.\");\n return new Array(VOICE_QUALITY_FEATURE_COUNT).fill(0);\n }\n\n const numFrames = Math.floor((samples.length - frameSize) / hopSize) + 1;\n if (numFrames < 5) {\n return new Array(VOICE_QUALITY_FEATURE_COUNT).fill(0);\n }\n\n const cppValues: number[] = [];\n const tiltValues: number[] = [];\n const h1h2Values: number[] = [];\n const lowRatios: number[] = [];\n const midRatios: number[] = [];\n const highRatios: number[] = [];\n\n // Reusable frame buffer (matches speaker.ts::computeLTAS).\n const frame = new Float32Array(frameSize);\n\n // Meyda.extract's third argument is `previousSignal`, NOT options — passing\n // `{ sampleRate, bufferSize }` there is silently ignored, leaving Meyda on\n // its default bufferSize=512 / sampleRate=44100. That truncates the visible\n // spectrum to bufferSize/2 = 256 bins regardless of input frame size, and\n // miscomputes any frequency-domain mapping. Set the globals before\n // extracting so the returned spectrum matches the input frame's actual\n // FFT geometry. (See speaker.ts::computeLTAS, which has the same misuse\n // pattern but only consumes scalar features so the bug is invisible there;\n // a follow-up commit aligns it.)\n Meyda.bufferSize = frameSize;\n Meyda.sampleRate = sampleRate;\n\n for (let i = 0; i < numFrames; i++) {\n const start = i * hopSize;\n frame.set(samples.subarray(start, start + frameSize), 0);\n\n const features = Meyda.extract(\"powerSpectrum\", frame);\n const power = features as Float32Array | undefined | null;\n if (!power || power.length === 0) continue;\n\n const cpp = cepstralPeakProminence(power, sampleRate);\n if (Number.isFinite(cpp)) cppValues.push(cpp);\n\n const tilt = spectralTilt(power, sampleRate);\n if (Number.isFinite(tilt)) tiltValues.push(tilt);\n\n const f0 = f0PerFrame[i] ?? 0;\n if (f0 > 0) {\n const h1h2 = h1MinusH2(power, sampleRate, f0);\n if (Number.isFinite(h1h2)) h1h2Values.push(h1h2);\n }\n\n const [low, mid, high] = subbandRatios(power, sampleRate);\n lowRatios.push(low);\n midRatios.push(mid);\n highRatios.push(high);\n }\n\n const cppMean = meanOf(cppValues);\n const cppVar = varianceOf(cppValues, cppMean);\n const tiltMean = meanOf(tiltValues);\n const tiltVar = varianceOf(tiltValues, tiltMean);\n const h1h2Mean = meanOf(h1h2Values);\n const h1h2Var = varianceOf(h1h2Values, h1h2Mean);\n const lowMean = meanOf(lowRatios);\n const midMean = meanOf(midRatios);\n const highMean = meanOf(highRatios);\n\n return [\n cppMean,\n cppVar,\n tiltMean,\n tiltVar,\n h1h2Mean,\n h1h2Var,\n lowMean,\n midMean,\n highMean,\n ];\n}\n","/**\n * Discrete Cosine Transform Type-II (DCT-II) and pitch-contour shape\n * encoding.\n *\n * Used by the v2 feature pipeline to capture the SHAPE of the per-session\n * F0 (pitch) contour as a small number of coefficients. Identity-bearing\n * because individual speakers have characteristic prosodic patterns —\n * rising/falling/modulated melodies — that the existing F0 statistics\n * (mean, variance, skew, kurtosis) don't reach. Closes the\n * \"no-pitch-trajectory-shape\" gap documented in\n * `docs/master/BLUEPRINT-feature-pipeline-v2.md` §1.1.\n *\n * @privacyGuarantee The output is a small fixed number of coefficients\n * (5 by default) capturing the lowest-frequency components of the pitch\n * contour. This is a strict dimensionality reduction (1200 frames → 5\n * coefficients) and cannot reconstruct the original contour, let alone\n * the underlying audio.\n */\n\n/**\n * Compute the first `numCoefficients` Type-II DCT coefficients of a 1D\n * signal:\n *\n * X_k = Σ_{n=0..N-1} x_n × cos((π/N) × (n + 0.5) × k), k = 0..K-1\n *\n * No orthonormalization factor applied — caller can divide by\n * `sqrt(N)` (or equivalent) for length-invariance if comparing across\n * variable-length inputs. For length-fixed contexts (like the per-session\n * F0 contour) the un-normalized form is fine.\n *\n * Direct O(N × K) implementation is faster than FFT-DCT for the small K\n * values (≤ 16) we use in the feature pipeline. For N=1200 frames and\n * K=5, the total cost is 6000 cosine evaluations + multiply-adds —\n * sub-millisecond on modern CPUs.\n *\n * Returns an array of length exactly `numCoefficients`. If `numCoefficients`\n * exceeds N, trailing positions are zero. If N is 0 or numCoefficients ≤ 0,\n * returns a zero-padded array of the requested length.\n */\nexport function dctII(input: number[], numCoefficients: number): number[] {\n const N = input.length;\n const K = Math.max(0, numCoefficients);\n const output = new Array(K).fill(0);\n if (N === 0 || K === 0) return output;\n\n const upper = Math.min(K, N);\n const piOverN = Math.PI / N;\n\n for (let k = 0; k < upper; k++) {\n let sum = 0;\n for (let n = 0; n < N; n++) {\n sum += input[n]! * Math.cos(piOverN * (n + 0.5) * k);\n }\n output[k] = sum;\n }\n return output;\n}\n\n/**\n * Encode the shape of a pitch contour as a small number of DCT\n * coefficients suitable for fingerprinting.\n *\n * Pre-processing:\n * 1. Strip unvoiced frames (F0 = 0). Pitch detectors mark frames\n * without detectable voicing as 0; including them in the DCT mixes\n * silence with prosody and dilutes the shape signal.\n * 2. Mean-center the surviving voiced frames so the DC coefficient (X_0)\n * captures shape deviation from the speaker's mean pitch, not the\n * speaker's absolute pitch (which is already encoded in the F0_STATS\n * block of the existing 44 features).\n * 3. Length-normalize the DCT output by `1/sqrt(N)` so two recordings of\n * different durations produce comparable shape vectors.\n *\n * Returns exactly `numCoefficients` floats. If too few voiced frames\n * exist (< 2 × numCoefficients), returns all zeros — short voiced\n * segments produce noisy shape estimates that would hurt\n * discrimination more than help.\n */\nexport function pitchContourShape(\n contour: number[],\n numCoefficients: number = 5,\n): number[] {\n if (numCoefficients <= 0) return [];\n const zero = () => new Array(numCoefficients).fill(0);\n\n // 1. Filter to voiced frames (F0 > 0) and finite values.\n const voiced: number[] = [];\n for (const v of contour) {\n if (Number.isFinite(v) && v > 0) voiced.push(v);\n }\n\n // Require enough voiced frames that the lowest few DCT coefficients are\n // statistically meaningful. 2 × numCoefficients is a coarse heuristic;\n // tighter would risk dropping legitimate short utterances.\n if (voiced.length < numCoefficients * 2) return zero();\n\n // 2. Mean-center.\n let sum = 0;\n for (const v of voiced) sum += v;\n const mu = sum / voiced.length;\n const centered = voiced.map((v) => v - mu);\n\n // 3. DCT and length-normalize.\n const N = centered.length;\n const norm = 1 / Math.sqrt(N);\n return dctII(centered, numCoefficients).map((c) => c * norm);\n}\n\n/**\n * Total feature count produced by `pitchContourShape` with the default\n * `numCoefficients = 5`. Imported by speaker.ts when assembling the\n * final audio feature vector.\n */\nexport const PITCH_CONTOUR_SHAPE_FEATURE_COUNT = 5;\n","/**\n * Cooperative yield to the host environment's event loop.\n *\n * Heavy synchronous work in feature extraction (F0 detection, HNR\n * autocorrelation, LPC formant analysis, Meyda spectral) blocks the\n * main thread for tens to hundreds of milliseconds on a single tight\n * loop. The verify UI sets `processingStage = \"Extracting features...\"`\n * but the spinner can't repaint while the thread is busy — leading to\n * the visible \"stuck\" stage the user reports.\n *\n * Calling `await yieldToMainThread()` between heavy stages hands control\n * back to the browser long enough to flush a paint frame, then resumes.\n * `MessageChannel` is the lowest-overhead path that still rounds through\n * a macrotask (microtasks don't yield to paint). Falls back to\n * `setTimeout(fn, 0)` for non-DOM environments (Node tests, React\n * Native) and a no-op when neither is available.\n */\nexport function yieldToMainThread(): Promise<void> {\n return new Promise<void>((resolve) => {\n if (typeof MessageChannel !== \"undefined\") {\n const channel = new MessageChannel();\n channel.port1.onmessage = () => {\n channel.port1.close();\n resolve();\n };\n channel.port2.postMessage(null);\n return;\n }\n if (typeof setTimeout !== \"undefined\") {\n setTimeout(resolve, 0);\n return;\n }\n resolve();\n });\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, mean as meanOf, variance as varianceOf } from \"./statistics\";\nimport { extractLpcAnalysis } from \"./lpc\";\nimport { extractMfccFeatures, MFCC_FEATURE_COUNT } from \"./mfcc\";\nimport {\n extractVoiceQualityFeatures,\n VOICE_QUALITY_FEATURE_COUNT,\n} from \"./voice-quality\";\nimport { pitchContourShape, PITCH_CONTOUR_SHAPE_FEATURE_COUNT } from \"./dct\";\nimport { yieldToMainThread } from \"../yield\";\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\n// Existing legacy 44 features (preserved at the start of the audio block so\n// the validator's named sub-range constants — JITTER, SHIMMER,\n// LTAS_FLATNESS_VAR, VOICING_RATIO, etc. — keep pointing at the same\n// indices and the TTS detector's threshold checks remain unchanged).\nconst LEGACY_SPEAKER_FEATURE_COUNT = 44;\n\n// LPC coefficient statistics: 12 coefficients × {mean, variance} per\n// coefficient time series.\nconst LPC_COEFFICIENT_STATS = 12 * 2;\n\n// Formant absolute values + dynamics: F1/F2/F3 absolute (6) + F1/F2/F3\n// derivative (6) + F1/F2 bandwidth (4) = 16. F3 bandwidth omitted because\n// LPC pole bandwidth on the 3rd formant is consistently noisier than the\n// underlying frequency signal — keeping it would dilute the block.\nconst FORMANT_TRAJECTORY_FEATURE_COUNT = 16;\n\nconst SPEAKER_FEATURE_COUNT =\n LEGACY_SPEAKER_FEATURE_COUNT +\n MFCC_FEATURE_COUNT +\n LPC_COEFFICIENT_STATS +\n FORMANT_TRAJECTORY_FEATURE_COUNT +\n VOICE_QUALITY_FEATURE_COUNT +\n PITCH_CONTOUR_SHAPE_FEATURE_COUNT;\n// = 44 + 78 + 24 + 16 + 9 + 5 = 176. See\n// docs/master/BLUEPRINT-feature-pipeline-v2.md §2.1.\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 * Frame batch size between cooperative yields inside `detectF0Contour`.\n * YIN at 16 kHz / 1024-sample frame is ~1 ms per frame on commodity\n * hardware, so 16 frames ≈ one 60 fps paint budget — yielding here keeps\n * the verify spinner repainting smoothly through the dominant block of\n * extraction work (which the user perceives as the freeze right after\n * the 12 s capture ends, before any other yield site fires).\n */\nconst F0_YIELD_EVERY_N_FRAMES = 16;\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 // Cooperative yield every N frames so the host UI gets a paint frame\n // mid-loop. Skipped on frame 0 (no work done yet) and the last frame\n // (the function returns immediately after).\n if (i > 0 && i < numFrames - 1 && (i % F0_YIELD_EVERY_N_FRAMES) === 0) {\n await yieldToMainThread();\n }\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 // Meyda.extract's third argument is `previousSignal`, NOT options — so\n // passing `{ sampleRate, bufferSize: frameSize }` there is silently\n // ignored. Without setting the globals here, Meyda would use whatever\n // bufferSize the previous extractor in the pipeline left behind (mfcc /\n // voice-quality both set 2048; if they ran first, this function would\n // see 2048; if they didn't run yet, it would see the default 512). That\n // call-order dependency makes the per-frame spectral extractors\n // non-deterministic across pipeline orderings — the exact bug the v2\n // pentest replay assertion (distance must be 0) caught. Set the globals\n // so this extractor is order-independent.\n Meyda.bufferSize = frameSize;\n Meyda.sampleRate = sampleRate;\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 );\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 that are stable across\n * different utterances from the same speaker. Content-independent by\n * 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 server-side analysis can pair it with\n * the motion time-series. Feature vector shape and semantics are\n * 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 // YIN pitch detection is the heaviest single block in the audio path\n // (~120 frames × O(frameSize²)). Yield before HNR + formant extraction\n // so the verify UI can repaint the \"Extracting features...\" spinner.\n await yieldToMainThread();\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 // HNR autocorrelation is per-frame and synchronous. Yield before LPC\n // formant extraction so a paint frame can land between the two heaviest\n // synchronous stages.\n await yieldToMainThread();\n\n // 7. Formant analysis — single LPC pass surfaces ratios (legacy\n // 8 features), LPC coefficients (24 new), absolute formants + dynamics\n // + bandwidths (16 new). All derived from one autocorrelate +\n // Levinson-Durbin per frame; CPU cost identical to the legacy\n // extractFormantRatios call but the output is much richer.\n const lpc = extractLpcAnalysis(normalizedSamples, sampleRate, frameSize, hopSize);\n const f1f2Stats = condense(lpc.f1f2);\n const f2f3Stats = condense(lpc.f2f3);\n const formantFeatures = [\n f1f2Stats.mean, f1f2Stats.variance, f1f2Stats.skewness, f1f2Stats.kurtosis,\n f2f3Stats.mean, f2f3Stats.variance, f2f3Stats.skewness, f2f3Stats.kurtosis,\n ];\n await yieldToMainThread();\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 // ----- v2 feature pipeline additions -----\n // Each new block appended to the end of the audio vector so the existing\n // 44-feature layout (and the validator's named sub-range constants) stays\n // pinned at indices 0..44.\n\n // 11. MFCC + delta-MFCC stats (78 values total: 13×4 + 13×2)\n await yieldToMainThread();\n const mfccFeatures = await extractMfccFeatures(\n normalizedSamples,\n sampleRate,\n frameSize,\n hopSize,\n );\n\n // 12. LPC coefficient statistics (24 values: 12 coefficients × mean, variance)\n // Derived from the single LPC pass that already ran for the formant block.\n const lpcStats: number[] = [];\n for (let c = 0; c < 12; c++) {\n const track = lpc.lpcCoefficients[c] ?? [];\n const mu = meanOf(track);\n lpcStats.push(mu, varianceOf(track, mu));\n }\n\n // 13. Formant trajectories (16 values):\n // F1/F2/F3 absolute mean+var (6) + derivative mean+var (6) + B1/B2 mean+var (4)\n const f1Stats = { mean: meanOf(lpc.f1), var: varianceOf(lpc.f1) };\n const f2Stats = { mean: meanOf(lpc.f2), var: varianceOf(lpc.f2) };\n const f3Stats = { mean: meanOf(lpc.f3), var: varianceOf(lpc.f3) };\n const f1Delta = derivative(lpc.f1);\n const f2Delta = derivative(lpc.f2);\n const f3Delta = derivative(lpc.f3);\n const f1DeltaMu = meanOf(f1Delta);\n const f2DeltaMu = meanOf(f2Delta);\n const f3DeltaMu = meanOf(f3Delta);\n const b1Mu = meanOf(lpc.b1);\n const b2Mu = meanOf(lpc.b2);\n const formantTrajectoryFeatures = [\n f1Stats.mean, f1Stats.var,\n f2Stats.mean, f2Stats.var,\n f3Stats.mean, f3Stats.var,\n f1DeltaMu, varianceOf(f1Delta, f1DeltaMu),\n f2DeltaMu, varianceOf(f2Delta, f2DeltaMu),\n f3DeltaMu, varianceOf(f3Delta, f3DeltaMu),\n b1Mu, varianceOf(lpc.b1, b1Mu),\n b2Mu, varianceOf(lpc.b2, b2Mu),\n ];\n\n // 14. Voice quality (9 values: CPP, tilt, H1-H2 each mean+var, plus low/mid/high band ratios)\n await yieldToMainThread();\n const voiceQualityFeatures = await extractVoiceQualityFeatures(\n normalizedSamples,\n sampleRate,\n frameSize,\n hopSize,\n f0,\n );\n\n // 15. Pitch contour shape (5 DCT coefficients of the F0 contour)\n // Strict dimensionality reduction: ~1200 voiced frames → 5 coefficients.\n // Captures prosodic shape (rising/falling/modulated) that the existing\n // F0_STATS block doesn't reach.\n const pitchShapeFeatures = pitchContourShape(f0, PITCH_CONTOUR_SHAPE_FEATURE_COUNT);\n\n const features = [\n ...f0Features, // 5 [0..5] F0_STATS\n ...f0DeltaFeatures, // 4 [5..9] F0_DELTA\n ...jitterFeatures, // 4 [9..13] JITTER\n ...shimmerFeatures, // 4 [13..17] SHIMMER\n ...hnrFeatures, // 5 [17..22] HNR\n ...formantFeatures, // 8 [22..30] FORMANT_RATIOS\n ...ltasFeatures, // 8 [30..38] LTAS\n ...voicingFeatures, // 1 [38] VOICING_RATIO\n ...ampFeatures, // 5 [39..44] AMPLITUDE\n ...mfccFeatures, // 78 [44..122] MFCC + delta-MFCC\n ...lpcStats, // 24 [122..146] LPC coefficient stats\n ...formantTrajectoryFeatures, // 16 [146..162] Formant absolutes + dynamics + bandwidths\n ...voiceQualityFeatures, // 9 [162..171] Voice quality\n ...pitchShapeFeatures, // 5 [171..176] Pitch contour shape DCT\n ]; // = 176\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 server-side 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","/**\n * Real-input radix-2 Cooley-Tukey FFT and frequency-band energy / peak\n * helpers used by the v2 kinematic feature pipeline.\n *\n * Used to extract physiological-tremor signatures and motion frequency-band\n * energies from IMU axes (~50–200 Hz sample rates, ~600–2400 sample\n * windows). See `docs/master/BLUEPRINT-feature-pipeline-v2.md` §2.2.\n *\n * Why a custom FFT and not Meyda: Meyda's spectral extractors are\n * tuned for audio frame sizes (≥ 512 samples at 16 kHz) and bake in\n * audio-specific assumptions (Hanning window, magnitude scaling, frame\n * indexing). Kinematic signals are short, low-rate, and analyzed once\n * per session — a self-contained radix-2 implementation is simpler\n * and avoids leaking Meyda's global state into the motion path\n * (which would interfere with the speaker-extractor invariants set up\n * in speaker.ts / mfcc.ts / voice-quality.ts).\n *\n * @privacyGuarantee This module operates on already-on-device sensor\n * arrays. Outputs are reduced to a small number of band-energy /\n * peak-frequency scalars before leaving the SDK; the FFT itself is\n * never transmitted.\n */\n\n/** Round up to the next power of two, minimum 2. */\nfunction nextPow2(n: number): number {\n if (n <= 2) return 2;\n let p = 2;\n while (p < n) p <<= 1;\n return p;\n}\n\n/**\n * Compute the radix-2 FFT of a real-valued input. Input is zero-padded (or\n * truncated) to the requested `size`, which must be a power of two — use\n * `nextPow2(input.length)` to pick a sensible size.\n *\n * Returns `{ real, imag }` arrays of length `size`. Bin k corresponds to\n * frequency `k × sampleRate / size` Hz. By Hermitian symmetry only the\n * first `size / 2 + 1` bins are physically meaningful for real input;\n * downstream helpers (`bandEnergy`, `peakInBand`) account for this\n * automatically.\n */\nexport function realFFT(\n input: number[],\n size: number,\n): { real: number[]; imag: number[] } {\n if (size <= 0 || (size & (size - 1)) !== 0) {\n throw new Error(`FFT size must be a positive power of two, got ${size}`);\n }\n\n const real = new Array<number>(size);\n const imag = new Array<number>(size).fill(0);\n\n for (let i = 0; i < size; i++) {\n real[i] = i < input.length ? (input[i] ?? 0) : 0;\n }\n\n // Bit-reversal permutation.\n for (let i = 1, j = 0; i < size; i++) {\n let bit = size >> 1;\n for (; j & bit; bit >>= 1) j ^= bit;\n j ^= bit;\n if (i < j) {\n const tr = real[i]!;\n real[i] = real[j]!;\n real[j] = tr;\n // imag is all-zero pre-permutation, so no swap needed there.\n }\n }\n\n // Cooley-Tukey butterflies.\n for (let halfSize = 1; halfSize < size; halfSize <<= 1) {\n const fullSize = halfSize << 1;\n const phaseStep = -Math.PI / halfSize;\n for (let chunkStart = 0; chunkStart < size; chunkStart += fullSize) {\n for (let k = 0; k < halfSize; k++) {\n const phase = phaseStep * k;\n const wr = Math.cos(phase);\n const wi = Math.sin(phase);\n const ar = real[chunkStart + k]!;\n const ai = imag[chunkStart + k]!;\n const br = real[chunkStart + k + halfSize]!;\n const bi = imag[chunkStart + k + halfSize]!;\n const tr = wr * br - wi * bi;\n const ti = wr * bi + wi * br;\n real[chunkStart + k] = ar + tr;\n imag[chunkStart + k] = ai + ti;\n real[chunkStart + k + halfSize] = ar - tr;\n imag[chunkStart + k + halfSize] = ai - ti;\n }\n }\n }\n\n return { real, imag };\n}\n\n/**\n * Sum the squared magnitudes of FFT bins falling inside the half-open\n * frequency interval [`fLow`, `fHigh`) Hz, NORMALIZED by `N²` so the\n * result is a per-bin power density in the same units as the squared\n * input signal (not Parseval N²-scaled energy).\n *\n * Why normalize: an unscaled `Σ|X[k]|²` grows as O(N²·A²) for a sine\n * of amplitude A on N samples, which would put band energies 10,000×\n * larger than other motion features (O(0.01-1)) and dominate the\n * z-score normalization in `statistics.ts::normalizeGroup`. Dividing\n * by `N²` aligns the band energy with the squared-signal scale and\n * lets it sit alongside other motion moments cleanly.\n *\n * Out-of-range or NaN/Infinity inputs return 0 — never throw — so a\n * malformed sensor capture downstream produces a deterministic zero\n * feature instead of a crash.\n */\nexport function bandEnergy(\n real: number[],\n imag: number[],\n sampleRate: number,\n fLow: number,\n fHigh: number,\n): number {\n const N = real.length;\n if (\n N === 0 ||\n !Number.isFinite(sampleRate) ||\n sampleRate <= 0 ||\n fLow >= fHigh ||\n fLow < 0\n ) {\n return 0;\n }\n\n // Bin k → frequency k × sampleRate / N. Only positive frequencies are\n // physically meaningful for real input.\n const binHz = sampleRate / N;\n const kLow = Math.max(0, Math.ceil(fLow / binHz));\n const kHigh = Math.min(Math.floor(N / 2), Math.floor((fHigh - 1e-9) / binHz));\n\n let energy = 0;\n for (let k = kLow; k <= kHigh; k++) {\n const re = real[k] ?? 0;\n const im = imag[k] ?? 0;\n energy += re * re + im * im;\n }\n return energy / (N * N);\n}\n\n/**\n * Return the dominant frequency (Hz) and its squared-magnitude amplitude\n * (normalized by `N²` for the same reason as `bandEnergy`) in the\n * half-open frequency interval [`fLow`, `fHigh`) Hz.\n *\n * If no bin falls inside the band (e.g. capture is too short to resolve\n * the requested band), returns `{ freq: 0, amplitude: 0 }`. Used by the\n * kinematic tremor block to detect physiological-tremor signatures in\n * the 4–12 Hz range.\n */\nexport function peakInBand(\n real: number[],\n imag: number[],\n sampleRate: number,\n fLow: number,\n fHigh: number,\n): { freq: number; amplitude: number } {\n const N = real.length;\n if (\n N === 0 ||\n !Number.isFinite(sampleRate) ||\n sampleRate <= 0 ||\n fLow >= fHigh ||\n fLow < 0\n ) {\n return { freq: 0, amplitude: 0 };\n }\n\n const binHz = sampleRate / N;\n const kLow = Math.max(0, Math.ceil(fLow / binHz));\n const kHigh = Math.min(Math.floor(N / 2), Math.floor((fHigh - 1e-9) / binHz));\n\n let bestK = -1;\n let bestAmp = -Infinity;\n for (let k = kLow; k <= kHigh; k++) {\n const re = real[k] ?? 0;\n const im = imag[k] ?? 0;\n const amp = re * re + im * im;\n if (amp > bestAmp) {\n bestAmp = amp;\n bestK = k;\n }\n }\n if (bestK < 0) return { freq: 0, amplitude: 0 };\n return { freq: bestK * binHz, amplitude: bestAmp / (N * N) };\n}\n\nexport { nextPow2 };\n","import type { MotionSample, TouchSample } from \"../sensor/types\";\nimport { condense, mean, variance, entropy, autocorrelation } from \"./statistics\";\nimport { realFFT, bandEnergy, peakInBand, nextPow2 } from \"./fft\";\n\n// v2 motion block widens 54 → 81: 54 legacy (jerk + jounce stats × 6 axes,\n// jitter variance × 6) followed by 27 new features. Order is fixed by\n// `MOTION_FEATURE_COUNT` and asserted in tests/extraction.test.ts.\nexport const MOTION_LEGACY_COUNT = 54;\nexport const MOTION_V2_ADDITIONS = 27;\nexport const MOTION_FEATURE_COUNT = MOTION_LEGACY_COUNT + MOTION_V2_ADDITIONS;\n\n// v2 touch block widens 36 → 57: 36 legacy followed by 21 new features.\nexport const TOUCH_LEGACY_COUNT = 36;\nexport const TOUCH_V2_ADDITIONS = 21;\nexport const TOUCH_FEATURE_COUNT = TOUCH_LEGACY_COUNT + TOUCH_V2_ADDITIONS;\n\n// Mouse-dynamics keeps width parity with the motion block so that desktop\n// captures fuse cleanly into the same fingerprint slot as mobile IMU\n// captures. The first 54 entries are the legacy mouse-dynamics features;\n// the remaining 27 are zero (no IMU on desktop).\n//\n// Why zero-padding doesn't break SimHash bit-influence parity (verified\n// algebraically): `normalizeGroup` z-scores the 81-element block. With 27\n// zeros, the padded variance equals (54/81) × pure_variance, so the\n// padded std equals √(2/3) × pure_std ≈ 0.816 × pure_std. After dividing\n// by the padded std, real features scale by 1/0.816 ≈ 1.225, and zero\n// padding stays at -mean/std (≈ 0 when the real-feature mean is small).\n// The collective variance of the 81-element normalized block is exactly\n// 1 by construction (z-score guarantee), so the modality contributes the\n// same expected variance to the SimHash random-projection dot product\n// as the mobile case (also a unit-variance 81-element block). The\n// per-feature magnitude of real features inflates by 22% on desktop;\n// the per-modality bit-influence share stays equal.\nexport const MOUSE_DYNAMICS_FEATURE_COUNT = MOTION_FEATURE_COUNT;\n\n/**\n * Compute per-sample acceleration magnitude |a| = √(ax² + ay² + az²) and\n * linearly resample to a target frame count. Surfaced for server-side\n * analysis paired against the F0 contour; the two time-series must share\n * the same frame count when consumed downstream.\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 *\n * Layout (`MOTION_FEATURE_COUNT = 81`):\n * `[0..48)` legacy: 6 axes × (jerk stats 4 + jounce stats 4)\n * `[48..54)` legacy: jitter variance per axis (6)\n * `[54..60)` v2: cross-axis covariance (6 selected pairs)\n * `[60..72)` v2: FFT band energy in {0-2, 2-6, 6-12, 12-30} Hz × {ax, ay, az}\n * `[72..74)` v2: physiological tremor peak frequency + amplitude (4-12 Hz)\n * `[74..76)` v2: direction-reversal rate per axis: mean, variance across {ax, ay, az}\n * `[76]` v2: mean angular velocity (|gyro| over the capture)\n * `[77..81)` v2: motion-magnitude autocorrelation at lags {1, 5, 10, 25}\n *\n * @privacyGuarantee Operates on already-on-device IMU samples and emits\n * statistical / spectral aggregates (variances, covariances, band sums,\n * autocorrelation scalars). The full sample stream is never transmitted.\n */\nexport function extractMotionFeatures(samples: MotionSample[]): number[] {\n if (samples.length < 5) return new Array(MOTION_FEATURE_COUNT).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 // Captures temporal fluctuation in the motion signal.\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 // ---- v2 additions ----\n features.push(...computeMotionV2(axes, samples));\n\n return features;\n}\n\n/**\n * v2 motion additions (27 features). Pulled into a dedicated helper so the\n * legacy 54-feature block stays isolated and visually identifiable in the\n * git history of `extractMotionFeatures`.\n */\nfunction computeMotionV2(\n axes: Record<\"ax\" | \"ay\" | \"az\" | \"gx\" | \"gy\" | \"gz\", number[]>,\n samples: MotionSample[]\n): number[] {\n const out: number[] = [];\n\n // 1. Cross-axis covariance — 6 selected pairs (per blueprint §2.2). The\n // pairs target identity-bearing motor coordinations: accel-gyro coupling\n // (ax-gy, ay-gx, az-gz) for natural hand sway, accel-accel coupling\n // (ax-az, ay-az) for axis-of-grip leakage, and gyro-gyro coupling\n // (gx-gy) for wrist-rotation patterns.\n const covPairs: Array<[number[], number[]]> = [\n [axes.ax, axes.gy],\n [axes.ay, axes.gx],\n [axes.az, axes.gz],\n [axes.ax, axes.az],\n [axes.ay, axes.az],\n [axes.gx, axes.gy],\n ];\n for (const [a, b] of covPairs) out.push(covariance(a, b));\n\n // 2. FFT band energy on the 3 accelerometer axes.\n // Sample rate is recovered from timestamps so we report energy in\n // physical Hz rather than bin units (IMU rates vary 50-200 Hz across\n // devices).\n const sampleRate = sampleRateFromTimestamps(samples.map((s) => s.timestamp));\n const fftSize = nextPow2(Math.max(64, axes.ax.length));\n const bands: Array<[number, number]> = [\n [0, 2],\n [2, 6],\n [6, 12],\n [12, 30],\n ];\n\n // Pre-FFT each accel axis once; reuse the spectra for both band-energy\n // and the magnitude path below.\n const accelSpectra = [axes.ax, axes.ay, axes.az].map((axis) =>\n realFFT(meanCenter(axis), fftSize)\n );\n for (const spectrum of accelSpectra) {\n for (const [lo, hi] of bands) {\n out.push(bandEnergy(spectrum.real, spectrum.imag, sampleRate, lo, hi));\n }\n }\n\n // 3. Physiological-tremor peak (4-12 Hz) on motion magnitude.\n const magnitude = samples.map((s) =>\n Math.sqrt(s.ax * s.ax + s.ay * s.ay + s.az * s.az)\n );\n const magSpectrum = realFFT(meanCenter(magnitude), fftSize);\n const tremor = peakInBand(\n magSpectrum.real,\n magSpectrum.imag,\n sampleRate,\n 4,\n 12\n );\n out.push(tremor.freq, tremor.amplitude);\n\n // 4. Direction-reversal rate per second per accel axis (mean, variance).\n // A \"reversal\" here is a sign change of jerk (= the derivative of\n // acceleration). Counting on jerk rather than raw acceleration removes\n // the gravity DC bias on the vertical axis (raw az hovers around -9.8\n // and rarely crosses zero) and captures the rate of micro-correction\n // events on each axis. Rate is normalized by capture duration so it's\n // dimension-stable across IMU sample-rates. Mean + variance over the\n // 3 accel axes captures both how busy the user's motion is and which\n // axis dominates — a per-axis dominance pattern that's identity-bearing.\n const duration = captureDurationSec(samples);\n const reversalRates = [axes.ax, axes.ay, axes.az].map((axis) =>\n duration > 0 ? signChangeCount(derivative(axis)) / duration : 0\n );\n out.push(mean(reversalRates), variance(reversalRates));\n\n // 5. Mean angular velocity (|gyro| over the capture).\n let gyroSum = 0;\n for (let i = 0; i < samples.length; i++) {\n const gx = samples[i]!.gx;\n const gy = samples[i]!.gy;\n const gz = samples[i]!.gz;\n gyroSum += Math.sqrt(gx * gx + gy * gy + gz * gz);\n }\n out.push(samples.length > 0 ? gyroSum / samples.length : 0);\n\n // 6. Motion-magnitude autocorrelation at lags 1, 5, 10, 25 — captures\n // periodic structure (gait, tremor harmonics) that escapes the\n // moment-based features. Lags chosen to span the physiological-tremor\n // band: at a typical 60 Hz IMU rate, lag 5 ≈ 83 ms (12 Hz cycle), lag\n // 10 ≈ 167 ms (6 Hz), lag 25 ≈ 417 ms (sub-tremor, gait-rate signal).\n // The asymmetry vs touch's autocorrelation lags (1, 3, 5) is intentional\n // — touch captures finer rhythms (50-100 ms inter-event coherence)\n // while motion captures slower oscillatory patterns.\n for (const lag of [1, 5, 10, 25]) {\n out.push(autocorrelation(magnitude, lag));\n }\n\n return out;\n}\n\n/**\n * Extract kinematic features from touch data.\n *\n * Layout (`TOUCH_FEATURE_COUNT = 57`):\n * `[0..32)` legacy: velocity / accel / pressure / area / jerk stats (32)\n * `[32..36)` legacy: jitter variance for {vx, vy, pressure, area} (4)\n * `[36..40)` v2: pressure first-derivative stats (mean, var, skew, kurt)\n * `[40..42)` v2: contact aspect-ratio stats (mean, var)\n * `[42..44)` v2: contact-area first-derivative stats (mean, var)\n * `[44..47)` v2: trajectory curvature stats (mean, var, skew)\n * `[47..50)` v2: velocity autocorrelation at lags {1, 3, 5}\n * `[50..54)` v2: inter-touch gap duration stats (mean, var, skew, kurt)\n * `[54]` v2: path efficiency (straight-line / total path length)\n * `[55..57)` v2: per-stroke total path length: mean, variance\n *\n * @privacyGuarantee Operates on already-on-device touch samples and emits\n * statistical aggregates only. The full coordinate stream is never\n * transmitted; downstream phase-content (e.g. typed text) is not\n * recoverable from the per-stroke summaries.\n */\nexport function extractTouchFeatures(samples: TouchSample[]): number[] {\n if (samples.length < 5) return new Array(TOUCH_FEATURE_COUNT).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 // ---- v2 additions ----\n features.push(...computeTouchV2(samples, vx, vy));\n\n return features;\n}\n\n/**\n * v2 touch additions (21 features). Pulled into a helper so the legacy\n * 36-feature block stays a visually identifiable unit.\n */\nfunction computeTouchV2(\n samples: TouchSample[],\n vx: number[],\n vy: number[]\n): number[] {\n const out: number[] = [];\n\n // 1. Pressure first-derivative stats (4) — temporal RATE of pressure\n // variation, complementing the existing pressure mean/var/skew/kurt.\n const pressure = samples.map((s) => s.pressure);\n const dPressure = derivative(pressure);\n out.push(...Object.values(condense(dPressure)));\n\n // 2. Contact aspect ratio stats (mean, variance). width/height captures\n // finger-vs-thumb-vs-stylus identity even when raw area drifts.\n const aspect = samples.map((s) => {\n const h = s.height;\n return h > 0 ? s.width / h : 0;\n });\n out.push(mean(aspect), variance(aspect));\n\n // 3. Contact-area first-derivative stats (mean, variance) — rate of\n // pressure-spread change, a finer-grained signal than raw area moments.\n const area = samples.map((s) => s.width * s.height);\n const dArea = derivative(area);\n out.push(mean(dArea), variance(dArea));\n\n // 4. Trajectory curvature stats (mean, var, skew). Curvature is the\n // absolute angle change between successive velocity vectors —\n // identity-bearing motor coordination. Skip rest-frames where either\n // velocity vector is below `CURVATURE_REST_EPS` because `atan2(0, 0)`\n // returns 0 silently, which would inject a spurious large curvature\n // spike whenever motion resumes from a pause.\n const CURVATURE_REST_EPS = 1e-3;\n const curvatures: number[] = [];\n for (let i = 1; i < vx.length; i++) {\n const v1x = vx[i - 1] ?? 0;\n const v1y = vy[i - 1] ?? 0;\n const v2x = vx[i] ?? 0;\n const v2y = vy[i] ?? 0;\n if (\n Math.hypot(v1x, v1y) < CURVATURE_REST_EPS ||\n Math.hypot(v2x, v2y) < CURVATURE_REST_EPS\n ) {\n continue;\n }\n const a1 = Math.atan2(v1y, v1x);\n const a2 = Math.atan2(v2y, v2x);\n let d = a2 - a1;\n while (d > Math.PI) d -= 2 * Math.PI;\n while (d < -Math.PI) d += 2 * Math.PI;\n curvatures.push(Math.abs(d));\n }\n const curvStats = condense(curvatures);\n out.push(curvStats.mean, curvStats.variance, curvStats.skewness);\n\n // 5. Velocity-magnitude autocorrelation at short lags — captures rhythm\n // in touch motion below the resolution of moment statistics.\n const speed = vx.map((dx, i) => {\n const dy = vy[i] ?? 0;\n return Math.sqrt(dx * dx + dy * dy);\n });\n for (const lag of [1, 3, 5]) out.push(autocorrelation(speed, lag));\n\n // 6. Inter-touch gap duration stats (mean, var, skew, kurt). Gaps are\n // the millisecond intervals between successive touch events — touch\n // rhythm is highly individual (think tap cadence vs swipe cadence).\n const gaps: number[] = [];\n for (let i = 1; i < samples.length; i++) {\n gaps.push((samples[i]?.timestamp ?? 0) - (samples[i - 1]?.timestamp ?? 0));\n }\n out.push(...Object.values(condense(gaps)));\n\n // 7. Path efficiency = straight-line displacement / total path length.\n // 1.0 = perfectly straight movement, near-0 = highly tortuous.\n const totalPath = speed.reduce((a, b) => a + b, 0);\n const dx = (samples[samples.length - 1]?.x ?? 0) - (samples[0]?.x ?? 0);\n const dy = (samples[samples.length - 1]?.y ?? 0) - (samples[0]?.y ?? 0);\n const straight = Math.sqrt(dx * dx + dy * dy);\n out.push(totalPath > 0 ? straight / totalPath : 0);\n\n // 8. Per-stroke total path length: split on speed troughs (≤ 0.5 px/sample\n // from rest, matching the mouse-dynamics pause threshold), then take\n // mean and variance. Captures motor-planning style — burst-then-pause\n // vs continuous-glide users.\n const strokeLengths = perStrokePathLengths(speed);\n out.push(mean(strokeLengths), variance(strokeLengths));\n\n return out;\n}\n\n/** Split a speed series into stroke segments at rest-points and return\n * the cumulative speed (≈ path length in pixels) of each stroke.\n * A \"stroke\" is a contiguous run of speed ≥ threshold. */\nfunction perStrokePathLengths(speed: number[]): number[] {\n const PAUSE_THRESHOLD = 0.5;\n const lengths: number[] = [];\n let acc = 0;\n let inStroke = false;\n for (const s of speed) {\n if (s >= PAUSE_THRESHOLD) {\n acc += s;\n inStroke = true;\n } else if (inStroke) {\n lengths.push(acc);\n acc = 0;\n inStroke = false;\n }\n }\n if (inStroke && acc > 0) lengths.push(acc);\n return lengths;\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/** Subtract the arithmetic mean from a series; returns a new array. */\nfunction meanCenter(values: number[]): number[] {\n if (values.length === 0) return [];\n let sum = 0;\n for (const v of values) sum += v;\n const m = sum / values.length;\n return values.map((v) => v - m);\n}\n\n/** Sample covariance Cov(a, b) = mean((a-mean(a))(b-mean(b))). */\nfunction covariance(a: number[], b: number[]): number {\n const n = Math.min(a.length, b.length);\n if (n < 2) return 0;\n let sumA = 0;\n let sumB = 0;\n for (let i = 0; i < n; i++) {\n sumA += a[i] ?? 0;\n sumB += b[i] ?? 0;\n }\n const meanA = sumA / n;\n const meanB = sumB / n;\n let cov = 0;\n for (let i = 0; i < n; i++) {\n cov += ((a[i] ?? 0) - meanA) * ((b[i] ?? 0) - meanB);\n }\n return cov / (n - 1);\n}\n\n/** Count strict sign changes (zero-crossings excluding zero-runs). */\nfunction signChangeCount(values: number[]): number {\n let count = 0;\n let last = 0;\n for (const v of values) {\n if (v > 0 && last < 0) count++;\n else if (v < 0 && last > 0) count++;\n if (v !== 0) last = v;\n }\n return count;\n}\n\n/**\n * Recover the sample rate (Hz) from a millisecond-timestamped sensor\n * stream. Returns 0 when the input is too short to estimate or contains\n * non-monotone timestamps (defensive — pulse.ts caps this with a default\n * downstream so 0 propagates as \"no spectral feature available\").\n */\nfunction sampleRateFromTimestamps(timestampsMs: number[]): number {\n if (timestampsMs.length < 2) return 0;\n const span = (timestampsMs[timestampsMs.length - 1] ?? 0) - (timestampsMs[0] ?? 0);\n if (!Number.isFinite(span) || span <= 0) return 0;\n return ((timestampsMs.length - 1) * 1000) / span;\n}\n\n/** Capture duration in seconds from a millisecond-timestamped sample set. */\nfunction captureDurationSec(\n samples: Array<{ timestamp: number }>\n): number {\n if (samples.length < 2) return 0;\n const span =\n (samples[samples.length - 1]?.timestamp ?? 0) -\n (samples[0]?.timestamp ?? 0);\n return Number.isFinite(span) && span > 0 ? span / 1000 : 0;\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: `MOUSE_DYNAMICS_FEATURE_COUNT` (= `MOTION_FEATURE_COUNT`) values.\n * The first 54 entries are the legacy mouse-dynamics signal; the trailing\n * v2-block slots stay zero on desktop so the per-modality bit-influence\n * share matches a mobile IMU capture under the new pipeline.\n */\nexport function extractMouseDynamics(samples: TouchSample[]): number[] {\n if (samples.length < 10) return new Array(MOUSE_DYNAMICS_FEATURE_COUNT).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 const legacyMouseDynamics = [\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 // Pad to MOUSE_DYNAMICS_FEATURE_COUNT so the desktop fingerprint slot\n // has the same width as a mobile IMU capture. The padding zeros are\n // consistent across all desktop sessions (no IMU available), so they\n // don't introduce per-session noise — they just keep the bit-influence\n // share per modality identical across device classes.\n const padding = MOUSE_DYNAMICS_FEATURE_COUNT - legacyMouseDynamics.length;\n return padding > 0\n ? [...legacyMouseDynamics, ...new Array(padding).fill(0)]\n : legacyMouseDynamics;\n}\n","import { FINGERPRINT_BITS, SIMHASH_SEED } from \"../config\";\nimport { SPEAKER_FEATURE_COUNT } from \"../extraction/speaker\";\nimport {\n MOTION_FEATURE_COUNT,\n TOUCH_FEATURE_COUNT,\n} from \"../extraction/kinematic\";\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 */\n// v2 feature pipeline: composed from the canonical per-modality counts\n// exported by their respective extractors so a future modality bump in\n// `speaker.ts` or `kinematic.ts` propagates without manual sync.\n// - Speaker (Sprint 1): 44 legacy + 78 MFCC + 24 LPC + 16 formant\n// trajectories + 9 voice quality + 5 pitch DCT = 176.\n// - Motion (Sprint 2): 54 legacy + 27 v2 (cross-axis covariance,\n// FFT band energy, tremor peak, direction-reversal stats, motion\n// autocorrelation) = 81.\n// - Touch (Sprint 2): 36 legacy + 21 v2 (pressure derivative, contact\n// geometry, curvature, velocity autocorrelation, gap distribution,\n// path efficiency) = 57.\n// Total: 314. The constant is a soft warning gate (mismatch logs but\n// the hash still computes), so a stale-baseline session under an\n// upgrading SDK degrades gracefully rather than failing — the user\n// routes through the existing reset-baseline migration path.\nconst EXPECTED_FEATURE_DIMENSION =\n SPEAKER_FEATURE_COUNT + MOTION_FEATURE_COUNT + TOUCH_FEATURE_COUNT;\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","{\n \"address\": \"GZYwTp2ozeuRA5Gof9vs4ya961aANcJBdUzB7LN6q4b2\",\n \"metadata\": {\n \"name\": \"entros_anchor\",\n \"version\": \"0.1.0\",\n \"spec\": \"0.1.0\",\n \"description\": \"Non-transferable identity token for Entros Protocol\"\n },\n \"docs\": [\n \"Mint account space for Token-2022 with NonTransferable extension.\",\n \"Base mint = 82 bytes, account type = 1 byte, extension type (2) + length (2) = 4 bytes,\",\n \"NonTransferable data = 0 bytes. Plus multisig padding from Token-2022.\",\n \"We use a constant derived from the Token-2022 spec.\"\n ],\n \"instructions\": [\n {\n \"name\": \"authorize_new_wallet\",\n \"docs\": [\n \"Authorize a new wallet by 2 signers. This can be done many times before invoking migrate_identity()\"\n ],\n \"discriminator\": [\n 178,\n 186,\n 185,\n 108,\n 51,\n 219,\n 107,\n 197\n ],\n \"accounts\": [\n {\n \"name\": \"signer\",\n \"writable\": true,\n \"signer\": true\n },\n {\n \"name\": \"identity_state\",\n \"writable\": true,\n \"pda\": {\n \"seeds\": [\n {\n \"kind\": \"const\",\n \"value\": [\n 105,\n 100,\n 101,\n 110,\n 116,\n 105,\n 116,\n 121\n ]\n },\n {\n \"kind\": \"account\",\n \"path\": \"signer\"\n }\n ]\n }\n },\n {\n \"name\": \"signer_new\",\n \"writable\": true,\n \"signer\": true\n },\n {\n \"name\": \"token_program\"\n },\n {\n \"name\": \"mint\",\n \"writable\": true,\n \"pda\": {\n \"seeds\": [\n {\n \"kind\": \"const\",\n \"value\": [\n 109,\n 105,\n 110,\n 116\n ]\n },\n {\n \"kind\": \"account\",\n \"path\": \"signer\"\n }\n ]\n }\n },\n {\n \"name\": \"token_account\",\n \"writable\": true,\n \"pda\": {\n \"seeds\": [\n {\n \"kind\": \"account\",\n \"path\": \"signer\"\n },\n {\n \"kind\": \"account\",\n \"path\": \"token_program\"\n },\n {\n \"kind\": \"account\",\n \"path\": \"mint\"\n }\n ],\n \"program\": {\n \"kind\": \"const\",\n \"value\": [\n 140,\n 151,\n 37,\n 143,\n 78,\n 36,\n 137,\n 241,\n 187,\n 61,\n 16,\n 41,\n 20,\n 142,\n 13,\n 131,\n 11,\n 90,\n 19,\n 153,\n 218,\n 255,\n 16,\n 132,\n 4,\n 142,\n 123,\n 216,\n 219,\n 233,\n 248,\n 89\n ]\n }\n }\n }\n ],\n \"args\": []\n },\n {\n \"name\": \"migrate_identity\",\n \"docs\": [\n \"Migrate from an user's old Anchor IdentityState PDA to a new one\",\n \"After this function call, the orphaned 0-balance ATA, pointing at a closed mint, locks ~0.002 SOL of rent. This ATA can be recovered by the old wallet calling closeAccount()\"\n ],\n \"discriminator\": [\n 161,\n 192,\n 70,\n 80,\n 47,\n 37,\n 26,\n 10\n ],\n \"accounts\": [\n {\n \"name\": \"user\",\n \"writable\": true,\n \"signer\": true\n },\n {\n \"name\": \"identity_state\",\n \"writable\": true,\n \"pda\": {\n \"seeds\": [\n {\n \"kind\": \"const\",\n \"value\": [\n 105,\n 100,\n 101,\n 110,\n 116,\n 105,\n 116,\n 121\n ]\n },\n {\n \"kind\": \"account\",\n \"path\": \"user\"\n }\n ]\n }\n },\n {\n \"name\": \"mint\",\n \"docs\": [\n \"initialization ordering. PDA seeds ensure uniqueness per user.\"\n ],\n \"writable\": true,\n \"pda\": {\n \"seeds\": [\n {\n \"kind\": \"const\",\n \"value\": [\n 109,\n 105,\n 110,\n 116\n ]\n },\n {\n \"kind\": \"account\",\n \"path\": \"user\"\n }\n ]\n }\n },\n {\n \"name\": \"mint_authority\",\n \"pda\": {\n \"seeds\": [\n {\n \"kind\": \"const\",\n \"value\": [\n 109,\n 105,\n 110,\n 116,\n 95,\n 97,\n 117,\n 116,\n 104,\n 111,\n 114,\n 105,\n 116,\n 121\n ]\n }\n ]\n }\n },\n {\n \"name\": \"token_account\",\n \"writable\": true\n },\n {\n \"name\": \"associated_token_program\",\n \"address\": \"ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL\"\n },\n {\n \"name\": \"token_program\"\n },\n {\n \"name\": \"system_program\",\n \"address\": \"11111111111111111111111111111111\"\n },\n {\n \"name\": \"protocol_config\",\n \"pda\": {\n \"seeds\": [\n {\n \"kind\": \"const\",\n \"value\": [\n 112,\n 114,\n 111,\n 116,\n 111,\n 99,\n 111,\n 108,\n 95,\n 99,\n 111,\n 110,\n 102,\n 105,\n 103\n ]\n }\n ],\n \"program\": {\n \"kind\": \"const\",\n \"value\": [\n 81,\n 130,\n 250,\n 230,\n 30,\n 253,\n 246,\n 69,\n 82,\n 96,\n 7,\n 173,\n 78,\n 160,\n 131,\n 188,\n 70,\n 106,\n 173,\n 59,\n 102,\n 163,\n 198,\n 189,\n 82,\n 37,\n 225,\n 38,\n 52,\n 233,\n 157,\n 117\n ]\n }\n }\n },\n {\n \"name\": \"treasury\",\n \"writable\": true,\n \"pda\": {\n \"seeds\": [\n {\n \"kind\": \"const\",\n \"value\": [\n 112,\n 114,\n 111,\n 116,\n 111,\n 99,\n 111,\n 108,\n 95,\n 116,\n 114,\n 101,\n 97,\n 115,\n 117,\n 114,\n 121\n ]\n }\n ],\n \"program\": {\n \"kind\": \"const\",\n \"value\": [\n 81,\n 130,\n 250,\n 230,\n 30,\n 253,\n 246,\n 69,\n 82,\n 96,\n 7,\n 173,\n 78,\n 160,\n 131,\n 188,\n 70,\n 106,\n 173,\n 59,\n 102,\n 163,\n 198,\n 189,\n 82,\n 37,\n 225,\n 38,\n 52,\n 233,\n 157,\n 117\n ]\n }\n }\n },\n {\n \"name\": \"wallet_old\",\n \"writable\": true\n },\n {\n \"name\": \"identity_state_old\",\n \"writable\": true,\n \"pda\": {\n \"seeds\": [\n {\n \"kind\": \"const\",\n \"value\": [\n 105,\n 100,\n 101,\n 110,\n 116,\n 105,\n 116,\n 121\n ]\n },\n {\n \"kind\": \"account\",\n \"path\": \"wallet_old\"\n }\n ]\n }\n },\n {\n \"name\": \"mint_old\",\n \"writable\": true,\n \"pda\": {\n \"seeds\": [\n {\n \"kind\": \"const\",\n \"value\": [\n 109,\n 105,\n 110,\n 116\n ]\n },\n {\n \"kind\": \"account\",\n \"path\": \"wallet_old\"\n }\n ]\n }\n },\n {\n \"name\": \"token_account_old\",\n \"writable\": true,\n \"pda\": {\n \"seeds\": [\n {\n \"kind\": \"account\",\n \"path\": \"wallet_old\"\n },\n {\n \"kind\": \"account\",\n \"path\": \"token_program\"\n },\n {\n \"kind\": \"account\",\n \"path\": \"mint_old\"\n }\n ],\n \"program\": {\n \"kind\": \"const\",\n \"value\": [\n 140,\n 151,\n 37,\n 143,\n 78,\n 36,\n 137,\n 241,\n 187,\n 61,\n 16,\n 41,\n 20,\n 142,\n 13,\n 131,\n 11,\n 90,\n 19,\n 153,\n 218,\n 255,\n 16,\n 132,\n 4,\n 142,\n 123,\n 216,\n 219,\n 233,\n 248,\n 89\n ]\n }\n }\n }\n ],\n \"args\": []\n },\n {\n \"name\": \"mint_anchor\",\n \"docs\": [\n \"Mint a new Entros Anchor identity for the caller.\",\n \"Creates a NonTransferable Token-2022 mint, mints 1 token to the user's ATA,\",\n \"and initializes the IdentityState PDA.\"\n ],\n \"discriminator\": [\n 68,\n 56,\n 113,\n 102,\n 236,\n 152,\n 146,\n 60\n ],\n \"accounts\": [\n {\n \"name\": \"user\",\n \"writable\": true,\n \"signer\": true\n },\n {\n \"name\": \"identity_state\",\n \"writable\": true,\n \"pda\": {\n \"seeds\": [\n {\n \"kind\": \"const\",\n \"value\": [\n 105,\n 100,\n 101,\n 110,\n 116,\n 105,\n 116,\n 121\n ]\n },\n {\n \"kind\": \"account\",\n \"path\": \"user\"\n }\n ]\n }\n },\n {\n \"name\": \"mint\",\n \"docs\": [\n \"initialization ordering. PDA seeds ensure uniqueness per user.\"\n ],\n \"writable\": true,\n \"pda\": {\n \"seeds\": [\n {\n \"kind\": \"const\",\n \"value\": [\n 109,\n 105,\n 110,\n 116\n ]\n },\n {\n \"kind\": \"account\",\n \"path\": \"user\"\n }\n ]\n }\n },\n {\n \"name\": \"mint_authority\",\n \"pda\": {\n \"seeds\": [\n {\n \"kind\": \"const\",\n \"value\": [\n 109,\n 105,\n 110,\n 116,\n 95,\n 97,\n 117,\n 116,\n 104,\n 111,\n 114,\n 105,\n 116,\n 121\n ]\n }\n ]\n }\n },\n {\n \"name\": \"token_account\",\n \"writable\": true\n },\n {\n \"name\": \"associated_token_program\",\n \"address\": \"ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL\"\n },\n {\n \"name\": \"token_program\"\n },\n {\n \"name\": \"system_program\",\n \"address\": \"11111111111111111111111111111111\"\n },\n {\n \"name\": \"protocol_config\",\n \"pda\": {\n \"seeds\": [\n {\n \"kind\": \"const\",\n \"value\": [\n 112,\n 114,\n 111,\n 116,\n 111,\n 99,\n 111,\n 108,\n 95,\n 99,\n 111,\n 110,\n 102,\n 105,\n 103\n ]\n }\n ],\n \"program\": {\n \"kind\": \"const\",\n \"value\": [\n 81,\n 130,\n 250,\n 230,\n 30,\n 253,\n 246,\n 69,\n 82,\n 96,\n 7,\n 173,\n 78,\n 160,\n 131,\n 188,\n 70,\n 106,\n 173,\n 59,\n 102,\n 163,\n 198,\n 189,\n 82,\n 37,\n 225,\n 38,\n 52,\n 233,\n 157,\n 117\n ]\n }\n }\n },\n {\n \"name\": \"treasury\",\n \"writable\": true,\n \"pda\": {\n \"seeds\": [\n {\n \"kind\": \"const\",\n \"value\": [\n 112,\n 114,\n 111,\n 116,\n 111,\n 99,\n 111,\n 108,\n 95,\n 116,\n 114,\n 101,\n 97,\n 115,\n 117,\n 114,\n 121\n ]\n }\n ],\n \"program\": {\n \"kind\": \"const\",\n \"value\": [\n 81,\n 130,\n 250,\n 230,\n 30,\n 253,\n 246,\n 69,\n 82,\n 96,\n 7,\n 173,\n 78,\n 160,\n 131,\n 188,\n 70,\n 106,\n 173,\n 59,\n 102,\n 163,\n 198,\n 189,\n 82,\n 37,\n 225,\n 38,\n 52,\n 233,\n 157,\n 117\n ]\n }\n }\n },\n {\n \"name\": \"instructions_sysvar\",\n \"docs\": [\n \"receipt verification (master-list #146 Phase 3) to inspect the\",\n \"preceding Ed25519Program::verify instruction in the same tx.\",\n \"Address is constrained to the canonical sysvar pubkey, so the\",\n \"program is guaranteed to be reading the real sysvar regardless of\",\n \"what the client passes.\"\n ],\n \"address\": \"Sysvar1nstructions1111111111111111111111111\"\n }\n ],\n \"args\": [\n {\n \"name\": \"initial_commitment\",\n \"type\": {\n \"array\": [\n \"u8\",\n 32\n ]\n }\n }\n ]\n },\n {\n \"name\": \"reset_identity_state\",\n \"docs\": [\n \"Reset the caller's identity state to a fresh baseline.\",\n \"\",\n \"Recovery path for users whose client-side fingerprint envelope is\",\n \"unrecoverable (cleared site data, new device, corrupted keystore).\",\n \"Without this instruction the only answer is \\\"mint a new wallet,\\\"\",\n \"which discards on-chain history and the SAS attestation. Reset\",\n \"rotates `current_commitment` in place and zeroes verification\",\n \"history so a compromised wallet cannot inherit reputation.\",\n \"\",\n \"Defenses:\",\n \"- Signer constraint on `authority` proves wallet ownership.\",\n \"- 7-day cooldown (`RESET_COOLDOWN_SECS`) bounds abuse frequency.\",\n \"- Full zero of `verification_count`, `trust_score`, and\",\n \"`recent_timestamps` means an attacker who compromises the\",\n \"wallet key and passes Tier 1 validation starts from zero.\",\n \"- Verification fee charged, matching mint/update economics.\",\n \"\",\n \"No ZK proof is consumed: there is no prior fingerprint to\",\n \"Hamming-compare against, and the Hamming circuit's\",\n \"`min_distance ≥ 3` constraint would reject a same-fingerprint\",\n \"proof anyway. Live-humanness evidence comes from the Tier 1\",\n \"validation pipeline at the SAS attestation step (handled by\",\n \"the off-chain executor, not this instruction).\"\n ],\n \"discriminator\": [\n 26,\n 78,\n 86,\n 143,\n 247,\n 132,\n 85,\n 203\n ],\n \"accounts\": [\n {\n \"name\": \"authority\",\n \"writable\": true,\n \"signer\": true\n },\n {\n \"name\": \"identity_state\",\n \"docs\": [\n \"may realloc legacy-layout accounts (207 or 543 bytes) to the current\",\n \"551-byte layout before deserialization. PDA validated by seeds;\",\n \"ownership verified in instruction body after deserialization.\"\n ],\n \"writable\": true,\n \"pda\": {\n \"seeds\": [\n {\n \"kind\": \"const\",\n \"value\": [\n 105,\n 100,\n 101,\n 110,\n 116,\n 105,\n 116,\n 121\n ]\n },\n {\n \"kind\": \"account\",\n \"path\": \"authority\"\n }\n ]\n }\n },\n {\n \"name\": \"protocol_config\",\n \"docs\": [\n \"Supplies the verification fee amount charged on reset.\"\n ],\n \"pda\": {\n \"seeds\": [\n {\n \"kind\": \"const\",\n \"value\": [\n 112,\n 114,\n 111,\n 116,\n 111,\n 99,\n 111,\n 108,\n 95,\n 99,\n 111,\n 110,\n 102,\n 105,\n 103\n ]\n }\n ],\n \"program\": {\n \"kind\": \"const\",\n \"value\": [\n 81,\n 130,\n 250,\n 230,\n 30,\n 253,\n 246,\n 69,\n 82,\n 96,\n 7,\n 173,\n 78,\n 160,\n 131,\n 188,\n 70,\n 106,\n 173,\n 59,\n 102,\n 163,\n 198,\n 189,\n 82,\n 37,\n 225,\n 38,\n 52,\n 233,\n 157,\n 117\n ]\n }\n }\n },\n {\n \"name\": \"treasury\",\n \"writable\": true,\n \"pda\": {\n \"seeds\": [\n {\n \"kind\": \"const\",\n \"value\": [\n 112,\n 114,\n 111,\n 116,\n 111,\n 99,\n 111,\n 108,\n 95,\n 116,\n 114,\n 101,\n 97,\n 115,\n 117,\n 114,\n 121\n ]\n }\n ],\n \"program\": {\n \"kind\": \"const\",\n \"value\": [\n 81,\n 130,\n 250,\n 230,\n 30,\n 253,\n 246,\n 69,\n 82,\n 96,\n 7,\n 173,\n 78,\n 160,\n 131,\n 188,\n 70,\n 106,\n 173,\n 59,\n 102,\n 163,\n 198,\n 189,\n 82,\n 37,\n 225,\n 38,\n 52,\n 233,\n 157,\n 117\n ]\n }\n }\n },\n {\n \"name\": \"system_program\",\n \"address\": \"11111111111111111111111111111111\"\n }\n ],\n \"args\": [\n {\n \"name\": \"new_commitment\",\n \"type\": {\n \"array\": [\n \"u8\",\n 32\n ]\n }\n }\n ]\n },\n {\n \"name\": \"update_anchor\",\n \"docs\": [\n \"Update the identity state after a successful proof verification.\",\n \"\",\n \"Trust score is computed automatically from verification history and protocol config.\",\n \"Handles transparent migration from old (10-slot) to new (52-slot) account layouts.\",\n \"\",\n \"Requires a matching, fresh `VerificationResult` PDA (owned by entros-verifier)\",\n \"whose `commitment_new` equals `new_commitment` and whose `commitment_prev`\",\n \"equals the identity's current stored commitment. Without this binding the\",\n \"instruction would accept any commitment with no biometric proof — allowing\",\n \"trust-score farming via per-call fee payment, which contradicts the\",\n \"protocol's economic deterrence model. See AUDIT.md for details.\",\n \"\",\n \"The `verification_nonce` argument supplies the challenge nonce used to\",\n \"derive the VerificationResult PDA (`seeds = [b\\\"verification\\\", authority, nonce]`).\",\n \"Single-use is enforced implicitly: after this call, `current_commitment`\",\n \"rotates to `new_commitment`, so the consumed VerificationResult's\",\n \"`commitment_prev` no longer matches on any future call.\"\n ],\n \"discriminator\": [\n 120,\n 192,\n 72,\n 245,\n 112,\n 246,\n 119,\n 135\n ],\n \"accounts\": [\n {\n \"name\": \"authority\",\n \"writable\": true,\n \"signer\": true\n },\n {\n \"name\": \"identity_state\",\n \"docs\": [\n \"from old (10-slot) to new (52-slot) account layouts. PDA validated by seeds.\",\n \"Ownership verified in instruction body after deserialization.\"\n ],\n \"writable\": true,\n \"pda\": {\n \"seeds\": [\n {\n \"kind\": \"const\",\n \"value\": [\n 105,\n 100,\n 101,\n 110,\n 116,\n 105,\n 116,\n 121\n ]\n },\n {\n \"kind\": \"account\",\n \"path\": \"authority\"\n }\n ]\n }\n },\n {\n \"name\": \"verification_result\",\n \"docs\": [\n \"PDA seeds validated by Anchor; layout + owner + cross-field constraints\",\n \"validated in instruction body. Binds the ZK proof to this specific\",\n \"update — without this account, update_anchor would accept any commitment\",\n \"with no proof.\"\n ],\n \"pda\": {\n \"seeds\": [\n {\n \"kind\": \"const\",\n \"value\": [\n 118,\n 101,\n 114,\n 105,\n 102,\n 105,\n 99,\n 97,\n 116,\n 105,\n 111,\n 110\n ]\n },\n {\n \"kind\": \"account\",\n \"path\": \"authority\"\n },\n {\n \"kind\": \"arg\",\n \"path\": \"verification_nonce\"\n }\n ],\n \"program\": {\n \"kind\": \"const\",\n \"value\": [\n 48,\n 50,\n 94,\n 115,\n 90,\n 162,\n 108,\n 8,\n 240,\n 151,\n 76,\n 223,\n 101,\n 176,\n 170,\n 86,\n 254,\n 247,\n 252,\n 28,\n 240,\n 145,\n 60,\n 108,\n 42,\n 129,\n 105,\n 32,\n 232,\n 212,\n 226,\n 52\n ]\n }\n }\n },\n {\n \"name\": \"protocol_config\",\n \"docs\": [\n \"Validated by seeds + owner via seeds::program.\"\n ],\n \"pda\": {\n \"seeds\": [\n {\n \"kind\": \"const\",\n \"value\": [\n 112,\n 114,\n 111,\n 116,\n 111,\n 99,\n 111,\n 108,\n 95,\n 99,\n 111,\n 110,\n 102,\n 105,\n 103\n ]\n }\n ],\n \"program\": {\n \"kind\": \"const\",\n \"value\": [\n 81,\n 130,\n 250,\n 230,\n 30,\n 253,\n 246,\n 69,\n 82,\n 96,\n 7,\n 173,\n 78,\n 160,\n 131,\n 188,\n 70,\n 106,\n 173,\n 59,\n 102,\n 163,\n 198,\n 189,\n 82,\n 37,\n 225,\n 38,\n 52,\n 233,\n 157,\n 117\n ]\n }\n }\n },\n {\n \"name\": \"treasury\",\n \"writable\": true,\n \"pda\": {\n \"seeds\": [\n {\n \"kind\": \"const\",\n \"value\": [\n 112,\n 114,\n 111,\n 116,\n 111,\n 99,\n 111,\n 108,\n 95,\n 116,\n 114,\n 101,\n 97,\n 115,\n 117,\n 114,\n 121\n ]\n }\n ],\n \"program\": {\n \"kind\": \"const\",\n \"value\": [\n 81,\n 130,\n 250,\n 230,\n 30,\n 253,\n 246,\n 69,\n 82,\n 96,\n 7,\n 173,\n 78,\n 160,\n 131,\n 188,\n 70,\n 106,\n 173,\n 59,\n 102,\n 163,\n 198,\n 189,\n 82,\n 37,\n 225,\n 38,\n 52,\n 233,\n 157,\n 117\n ]\n }\n }\n },\n {\n \"name\": \"system_program\",\n \"address\": \"11111111111111111111111111111111\"\n }\n ],\n \"args\": [\n {\n \"name\": \"new_commitment\",\n \"type\": {\n \"array\": [\n \"u8\",\n 32\n ]\n }\n },\n {\n \"name\": \"verification_nonce\",\n \"type\": {\n \"array\": [\n \"u8\",\n 32\n ]\n }\n }\n ]\n }\n ],\n \"accounts\": [\n {\n \"name\": \"IdentityState\",\n \"discriminator\": [\n 156,\n 32,\n 87,\n 93,\n 52,\n 155,\n 248,\n 207\n ]\n }\n ],\n \"events\": [\n {\n \"name\": \"AnchorMinted\",\n \"discriminator\": [\n 11,\n 188,\n 6,\n 169,\n 20,\n 50,\n 128,\n 172\n ]\n },\n {\n \"name\": \"AnchorReset\",\n \"discriminator\": [\n 183,\n 48,\n 146,\n 155,\n 112,\n 20,\n 140,\n 31\n ]\n },\n {\n \"name\": \"AnchorUpdated\",\n \"discriminator\": [\n 112,\n 73,\n 210,\n 183,\n 57,\n 84,\n 103,\n 59\n ]\n },\n {\n \"name\": \"MigrateIdentityEvent\",\n \"discriminator\": [\n 33,\n 239,\n 166,\n 187,\n 108,\n 47,\n 49,\n 139\n ]\n }\n ],\n \"errors\": [\n {\n \"code\": 6000,\n \"name\": \"InvalidCommitment\",\n \"msg\": \"Invalid commitment: must be 32 non-zero bytes\"\n },\n {\n \"code\": 6001,\n \"name\": \"Unauthorized\",\n \"msg\": \"Unauthorized: caller is not the identity owner\"\n },\n {\n \"code\": 6002,\n \"name\": \"ArithmeticOverflow\",\n \"msg\": \"Arithmetic overflow\"\n },\n {\n \"code\": 6003,\n \"name\": \"InvalidProtocolConfig\",\n \"msg\": \"Invalid protocol config account\"\n },\n {\n \"code\": 6004,\n \"name\": \"InvalidIdentityState\",\n \"msg\": \"Identity state account failed to deserialize\"\n },\n {\n \"code\": 6005,\n \"name\": \"IdentitySerializationFailed\",\n \"msg\": \"Identity state account failed to serialize\"\n },\n {\n \"code\": 6006,\n \"name\": \"VerificationResultWrongOwner\",\n \"msg\": \"VerificationResult account is owned by the wrong program\"\n },\n {\n \"code\": 6007,\n \"name\": \"StaleVerificationResult\",\n \"msg\": \"VerificationResult account has stale layout (pre-binding-patch)\"\n },\n {\n \"code\": 6008,\n \"name\": \"VerifierMismatch\",\n \"msg\": \"VerificationResult verifier does not match the signing authority\"\n },\n {\n \"code\": 6009,\n \"name\": \"ProofExpired\",\n \"msg\": \"Proof is too old to consume (MAX_PROOF_AGE_SECS exceeded)\"\n },\n {\n \"code\": 6010,\n \"name\": \"CommitmentMismatch\",\n \"msg\": \"Proof commitment_new does not match the submitted new_commitment\"\n },\n {\n \"code\": 6011,\n \"name\": \"PrevCommitmentMismatch\",\n \"msg\": \"Proof commitment_prev does not match the identity's current_commitment\"\n },\n {\n \"code\": 6012,\n \"name\": \"ResetCooldownActive\",\n \"msg\": \"Reset cooldown has not elapsed since the last reset\"\n },\n {\n \"code\": 6013,\n \"name\": \"UnauthorizedNewWallet\",\n \"msg\": \"caller is not authorized by the old identity\"\n },\n {\n \"code\": 6014,\n \"name\": \"ProofFromFuture\",\n \"msg\": \"VerificationResult.verified_at is in the future relative to the cluster clock\"\n },\n {\n \"code\": 6015,\n \"name\": \"MissingValidatorReceipt\",\n \"msg\": \"mint_anchor expected a preceding Ed25519Program::verify instruction with a validator-signed receipt; none found\"\n },\n {\n \"code\": 6016,\n \"name\": \"ReceiptValidatorMismatch\",\n \"msg\": \"Receipt was signed by a key that does not match ProtocolConfig.validator_pubkey\"\n },\n {\n \"code\": 6017,\n \"name\": \"ReceiptCommitmentMismatch\",\n \"msg\": \"Receipt commitment does not match the mint_anchor commitment argument\"\n },\n {\n \"code\": 6018,\n \"name\": \"ReceiptWalletMismatch\",\n \"msg\": \"Receipt wallet does not match the mint signer\"\n },\n {\n \"code\": 6019,\n \"name\": \"ReceiptExpired\",\n \"msg\": \"Receipt has aged past MAX_RECEIPT_AGE_SECS\"\n },\n {\n \"code\": 6020,\n \"name\": \"ReceiptFromFuture\",\n \"msg\": \"Receipt validated_at is in the future relative to the cluster clock\"\n },\n {\n \"code\": 6021,\n \"name\": \"MalformedReceiptMessage\",\n \"msg\": \"Receipt message has malformed length or layout\"\n }\n ],\n \"types\": [\n {\n \"name\": \"AnchorMinted\",\n \"type\": {\n \"kind\": \"struct\",\n \"fields\": [\n {\n \"name\": \"owner\",\n \"type\": \"pubkey\"\n },\n {\n \"name\": \"mint\",\n \"type\": \"pubkey\"\n },\n {\n \"name\": \"commitment\",\n \"type\": {\n \"array\": [\n \"u8\",\n 32\n ]\n }\n }\n ]\n }\n },\n {\n \"name\": \"AnchorReset\",\n \"type\": {\n \"kind\": \"struct\",\n \"fields\": [\n {\n \"name\": \"owner\",\n \"type\": \"pubkey\"\n },\n {\n \"name\": \"mint\",\n \"type\": \"pubkey\"\n },\n {\n \"name\": \"commitment\",\n \"type\": {\n \"array\": [\n \"u8\",\n 32\n ]\n }\n }\n ]\n }\n },\n {\n \"name\": \"AnchorUpdated\",\n \"type\": {\n \"kind\": \"struct\",\n \"fields\": [\n {\n \"name\": \"owner\",\n \"type\": \"pubkey\"\n },\n {\n \"name\": \"verification_count\",\n \"type\": \"u32\"\n },\n {\n \"name\": \"trust_score\",\n \"type\": \"u16\"\n },\n {\n \"name\": \"commitment\",\n \"type\": {\n \"array\": [\n \"u8\",\n 32\n ]\n }\n }\n ]\n }\n },\n {\n \"name\": \"IdentityState\",\n \"type\": {\n \"kind\": \"struct\",\n \"fields\": [\n {\n \"name\": \"owner\",\n \"docs\": [\n \"The user's wallet pubkey\"\n ],\n \"type\": \"pubkey\"\n },\n {\n \"name\": \"creation_timestamp\",\n \"docs\": [\n \"When the identity was first minted\"\n ],\n \"type\": \"i64\"\n },\n {\n \"name\": \"last_verification_timestamp\",\n \"docs\": [\n \"Most recent successful verification\"\n ],\n \"type\": \"i64\"\n },\n {\n \"name\": \"verification_count\",\n \"docs\": [\n \"Total successful verifications\"\n ],\n \"type\": \"u32\"\n },\n {\n \"name\": \"trust_score\",\n \"docs\": [\n \"Computed reputation metric\"\n ],\n \"type\": \"u16\"\n },\n {\n \"name\": \"current_commitment\",\n \"docs\": [\n \"Latest Poseidon commitment H_TBH\"\n ],\n \"type\": {\n \"array\": [\n \"u8\",\n 32\n ]\n }\n },\n {\n \"name\": \"mint\",\n \"docs\": [\n \"The NonTransferable mint associated with this identity\"\n ],\n \"type\": \"pubkey\"\n },\n {\n \"name\": \"bump\",\n \"docs\": [\n \"PDA bump seed\"\n ],\n \"type\": \"u8\"\n },\n {\n \"name\": \"recent_timestamps\",\n \"docs\": [\n \"Timestamps of last 52 verifications (newest at index 0).\",\n \"52 slots covers 1 year of weekly or 4+ years of monthly verifications.\",\n \"Older entries contribute negligible score due to exponential recency decay.\"\n ],\n \"type\": {\n \"array\": [\n \"i64\",\n 52\n ]\n }\n },\n {\n \"name\": \"last_reset_timestamp\",\n \"docs\": [\n \"Most recent `reset_identity_state` invocation. Zero when the identity\",\n \"has never been reset (including freshly minted accounts and accounts\",\n \"created before this field existed and then realloc'd in-place).\"\n ],\n \"type\": \"i64\"\n },\n {\n \"name\": \"new_wallet\",\n \"docs\": [\n \"new wallet for migrate_identity()\"\n ],\n \"type\": \"pubkey\"\n }\n ]\n }\n },\n {\n \"name\": \"MigrateIdentityEvent\",\n \"type\": {\n \"kind\": \"struct\",\n \"fields\": [\n {\n \"name\": \"wallet_old\",\n \"type\": \"pubkey\"\n },\n {\n \"name\": \"wallet_new\",\n \"type\": \"pubkey\"\n },\n {\n \"name\": \"identity_old\",\n \"type\": \"pubkey\"\n },\n {\n \"name\": \"identity_new\",\n \"type\": \"pubkey\"\n }\n ]\n }\n }\n ]\n}","{\n \"address\": \"4F97jNoxQzT2qRbkWpW3ztC3Nz2TtKj3rnKG8ExgnrfV\",\n \"metadata\": {\n \"name\": \"entros_verifier\",\n \"version\": \"0.1.0\",\n \"spec\": \"0.1.0\",\n \"description\": \"ZK proof verification program for Entros Protocol\"\n },\n \"instructions\": [\n {\n \"name\": \"close_challenge\",\n \"docs\": [\n \"Close a used or expired challenge account to reclaim rent.\"\n ],\n \"discriminator\": [\n 29,\n 156,\n 109,\n 17,\n 41,\n 99,\n 71,\n 236\n ],\n \"accounts\": [\n {\n \"name\": \"challenger\",\n \"writable\": true,\n \"signer\": true\n },\n {\n \"name\": \"challenge\",\n \"writable\": true\n }\n ],\n \"args\": []\n },\n {\n \"name\": \"close_verification_result\",\n \"docs\": [\n \"Close a verification result account to reclaim rent.\"\n ],\n \"discriminator\": [\n 202,\n 203,\n 62,\n 127,\n 7,\n 157,\n 143,\n 12\n ],\n \"accounts\": [\n {\n \"name\": \"verifier\",\n \"writable\": true,\n \"signer\": true\n },\n {\n \"name\": \"verification_result\",\n \"writable\": true\n }\n ],\n \"args\": []\n },\n {\n \"name\": \"create_challenge\",\n \"docs\": [\n \"Create a verification challenge with a client-generated nonce.\"\n ],\n \"discriminator\": [\n 170,\n 244,\n 47,\n 1,\n 1,\n 15,\n 173,\n 239\n ],\n \"accounts\": [\n {\n \"name\": \"challenger\",\n \"writable\": true,\n \"signer\": true\n },\n {\n \"name\": \"challenge\",\n \"writable\": true,\n \"pda\": {\n \"seeds\": [\n {\n \"kind\": \"const\",\n \"value\": [\n 99,\n 104,\n 97,\n 108,\n 108,\n 101,\n 110,\n 103,\n 101\n ]\n },\n {\n \"kind\": \"account\",\n \"path\": \"challenger\"\n },\n {\n \"kind\": \"arg\",\n \"path\": \"nonce\"\n }\n ]\n }\n },\n {\n \"name\": \"system_program\",\n \"address\": \"11111111111111111111111111111111\"\n }\n ],\n \"args\": [\n {\n \"name\": \"nonce\",\n \"type\": {\n \"array\": [\n \"u8\",\n 32\n ]\n }\n }\n ]\n },\n {\n \"name\": \"verify_proof\",\n \"docs\": [\n \"Verify a proof against a challenge.\",\n \"Validates the challenge is unused and not expired, runs mock verification,\",\n \"and stores the result.\"\n ],\n \"discriminator\": [\n 217,\n 211,\n 191,\n 110,\n 144,\n 13,\n 186,\n 98\n ],\n \"accounts\": [\n {\n \"name\": \"verifier\",\n \"writable\": true,\n \"signer\": true\n },\n {\n \"name\": \"challenge\",\n \"writable\": true,\n \"pda\": {\n \"seeds\": [\n {\n \"kind\": \"const\",\n \"value\": [\n 99,\n 104,\n 97,\n 108,\n 108,\n 101,\n 110,\n 103,\n 101\n ]\n },\n {\n \"kind\": \"account\",\n \"path\": \"verifier\"\n },\n {\n \"kind\": \"arg\",\n \"path\": \"nonce\"\n }\n ]\n }\n },\n {\n \"name\": \"verification_result\",\n \"writable\": true,\n \"pda\": {\n \"seeds\": [\n {\n \"kind\": \"const\",\n \"value\": [\n 118,\n 101,\n 114,\n 105,\n 102,\n 105,\n 99,\n 97,\n 116,\n 105,\n 111,\n 110\n ]\n },\n {\n \"kind\": \"account\",\n \"path\": \"verifier\"\n },\n {\n \"kind\": \"arg\",\n \"path\": \"nonce\"\n }\n ]\n }\n },\n {\n \"name\": \"system_program\",\n \"address\": \"11111111111111111111111111111111\"\n }\n ],\n \"args\": [\n {\n \"name\": \"proof_bytes\",\n \"type\": \"bytes\"\n },\n {\n \"name\": \"public_inputs\",\n \"type\": {\n \"vec\": {\n \"array\": [\n \"u8\",\n 32\n ]\n }\n }\n },\n {\n \"name\": \"nonce\",\n \"type\": {\n \"array\": [\n \"u8\",\n 32\n ]\n }\n }\n ]\n }\n ],\n \"accounts\": [\n {\n \"name\": \"Challenge\",\n \"discriminator\": [\n 119,\n 250,\n 161,\n 121,\n 119,\n 81,\n 22,\n 208\n ]\n },\n {\n \"name\": \"VerificationResult\",\n \"discriminator\": [\n 104,\n 111,\n 80,\n 172,\n 219,\n 191,\n 162,\n 38\n ]\n }\n ],\n \"events\": [\n {\n \"name\": \"ChallengeCreated\",\n \"discriminator\": [\n 166,\n 178,\n 174,\n 178,\n 11,\n 172,\n 98,\n 243\n ]\n },\n {\n \"name\": \"VerificationComplete\",\n \"discriminator\": [\n 22,\n 74,\n 77,\n 232,\n 220,\n 46,\n 59,\n 120\n ]\n }\n ],\n \"errors\": [\n {\n \"code\": 6000,\n \"name\": \"InvalidProofFormat\",\n \"msg\": \"Invalid proof format\"\n },\n {\n \"code\": 6001,\n \"name\": \"ProofVerificationFailed\",\n \"msg\": \"Proof verification failed\"\n },\n {\n \"code\": 6002,\n \"name\": \"ChallengeExpired\",\n \"msg\": \"Challenge has expired\"\n },\n {\n \"code\": 6003,\n \"name\": \"ChallengeAlreadyUsed\",\n \"msg\": \"Challenge already used\"\n },\n {\n \"code\": 6004,\n \"name\": \"InvalidPublicInputs\",\n \"msg\": \"Invalid public inputs\"\n },\n {\n \"code\": 6005,\n \"name\": \"ChallengeNotUsed\",\n \"msg\": \"Challenge must be used before closing\"\n },\n {\n \"code\": 6006,\n \"name\": \"InvalidNonce\",\n \"msg\": \"Invalid nonce: must not be all zeros\"\n },\n {\n \"code\": 6007,\n \"name\": \"ArithmeticOverflow\",\n \"msg\": \"Arithmetic overflow\"\n }\n ],\n \"types\": [\n {\n \"name\": \"Challenge\",\n \"type\": {\n \"kind\": \"struct\",\n \"fields\": [\n {\n \"name\": \"challenger\",\n \"docs\": [\n \"The user who requested the challenge\"\n ],\n \"type\": \"pubkey\"\n },\n {\n \"name\": \"nonce\",\n \"docs\": [\n \"Random nonce for anti-replay\"\n ],\n \"type\": {\n \"array\": [\n \"u8\",\n 32\n ]\n }\n },\n {\n \"name\": \"created_at\",\n \"docs\": [\n \"Unix timestamp when challenge was created\"\n ],\n \"type\": \"i64\"\n },\n {\n \"name\": \"expires_at\",\n \"docs\": [\n \"Unix timestamp when challenge expires\"\n ],\n \"type\": \"i64\"\n },\n {\n \"name\": \"used\",\n \"docs\": [\n \"Whether this challenge has been consumed\"\n ],\n \"type\": \"bool\"\n },\n {\n \"name\": \"bump\",\n \"docs\": [\n \"PDA bump seed\"\n ],\n \"type\": \"u8\"\n }\n ]\n }\n },\n {\n \"name\": \"ChallengeCreated\",\n \"type\": {\n \"kind\": \"struct\",\n \"fields\": [\n {\n \"name\": \"challenger\",\n \"type\": \"pubkey\"\n },\n {\n \"name\": \"nonce\",\n \"type\": {\n \"array\": [\n \"u8\",\n 32\n ]\n }\n },\n {\n \"name\": \"expires_at\",\n \"type\": \"i64\"\n }\n ]\n }\n },\n {\n \"name\": \"VerificationComplete\",\n \"type\": {\n \"kind\": \"struct\",\n \"fields\": [\n {\n \"name\": \"verifier\",\n \"type\": \"pubkey\"\n },\n {\n \"name\": \"is_valid\",\n \"type\": \"bool\"\n },\n {\n \"name\": \"nonce\",\n \"type\": {\n \"array\": [\n \"u8\",\n 32\n ]\n }\n }\n ]\n }\n },\n {\n \"name\": \"VerificationResult\",\n \"type\": {\n \"kind\": \"struct\",\n \"fields\": [\n {\n \"name\": \"verifier\",\n \"docs\": [\n \"Who submitted the proof\"\n ],\n \"type\": \"pubkey\"\n },\n {\n \"name\": \"proof_hash\",\n \"docs\": [\n \"Hash of the proof bytes for audit trail\"\n ],\n \"type\": {\n \"array\": [\n \"u8\",\n 32\n ]\n }\n },\n {\n \"name\": \"verified_at\",\n \"docs\": [\n \"Unix timestamp of verification\"\n ],\n \"type\": \"i64\"\n },\n {\n \"name\": \"is_valid\",\n \"docs\": [\n \"Whether the proof was valid.\",\n \"Always true for persisted records — invalid proofs revert the transaction\",\n \"and never create a VerificationResult. Retained for account layout stability.\"\n ],\n \"type\": \"bool\"\n },\n {\n \"name\": \"challenge_nonce\",\n \"docs\": [\n \"The challenge nonce that was consumed\"\n ],\n \"type\": {\n \"array\": [\n \"u8\",\n 32\n ]\n }\n },\n {\n \"name\": \"bump\",\n \"docs\": [\n \"PDA bump seed\"\n ],\n \"type\": \"u8\"\n },\n {\n \"name\": \"commitment_new\",\n \"docs\": [\n \"New fingerprint commitment from public_inputs[0]. Read cross-program\",\n \"by entros-anchor::update_anchor to bind the proof to the identity update.\"\n ],\n \"type\": {\n \"array\": [\n \"u8\",\n 32\n ]\n }\n },\n {\n \"name\": \"commitment_prev\",\n \"docs\": [\n \"Previous fingerprint commitment from public_inputs[1]. Read cross-program\",\n \"by entros-anchor::update_anchor to bind to the identity's stored commitment.\"\n ],\n \"type\": {\n \"array\": [\n \"u8\",\n 32\n ]\n }\n },\n {\n \"name\": \"threshold\",\n \"docs\": [\n \"Hamming threshold from public_inputs[2]. Bounded at proof time to prevent\",\n \"attacker-chosen circuit parameters.\"\n ],\n \"type\": \"u16\"\n },\n {\n \"name\": \"min_distance\",\n \"docs\": [\n \"Hamming min_distance from public_inputs[3]. Bounded at proof time to\",\n \"prevent replay (Hamming=0) attacks via attacker-chosen min_distance=0.\"\n ],\n \"type\": \"u16\"\n }\n ]\n }\n }\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-lowercase-hex characters, wrong\n * length). Permissive about a leading `0x` because some integrations may\n * strip or preserve it inconsistently. Strict on case so a future validator\n * regression that emits uppercase hex surfaces immediately rather than\n * silently accepting drift from the wire-format contract (Rust `hex::encode`\n * is canonically lowercase).\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-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 (the on-chain check is currently log-only and\n * proceeds when no preceding Ed25519 ix is present).\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 *\n * Returns `null` if the receipt fails to decode — caller should fall back to\n * sending `mint_anchor` without an Ed25519 prefix. The on-chain check is\n * currently log-only, so the fallback still works on the deployed program;\n * once enforcement is enabled, missing receipts hard-fail and the SDK's\n * no-op fallback becomes a deliberate \"no-receipt\" path that `mint_anchor`\n * 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 are typed dynamically because the SDK's\n// peer dep on @coral-xyz/anchor + @solana/web3.js is loaded via dynamic\n// import (avoiding a hard dep for tree-shaking).\nimport type { Idl } from \"@coral-xyz/anchor\";\nimport type { SolanaProof } from \"../proof/types\";\nimport type { SignedReceiptDto, SubmissionResult } from \"./types\";\nimport { PROGRAM_IDS } from \"../config\";\nimport { sdkLog, sdkWarn } from \"../log\";\nimport { entrosAnchorIdl, entrosVerifierIdl } from \"../protocol/idl\";\nimport { buildEd25519ReceiptIx } from \"./receipt\";\n\n/**\n * Wait for a tx to confirm AND throw if the chain-side execution errored.\n * web3.js 1.x's `connection.confirmTransaction` resolves successfully even\n * when the tx reverted on chain (it only checks signature inclusion); the\n * caller MUST inspect `value.err`. Without this, on-chain Anchor errors\n * (CommitmentMismatch, MissingValidatorReceipt, ResetCooldownActive,\n * InsufficientFunds, etc.) are silently swallowed and `submitViaWallet`\n * returns a \"successful\" txSignature for\n * a tx that never mutated state — a credibility hit. The thrown message\n * preserves the JSON `InstructionError` shape so downstream regex parsing\n * can extract the `Custom` code.\n */\nasync function confirmAndCheck(\n connection: any,\n signature: string | undefined,\n): Promise<void> {\n if (!signature) {\n throw new Error(\"confirmAndCheck called without a transaction signature\");\n }\n const confirmation = await connection.confirmTransaction(signature, \"confirmed\");\n if (confirmation?.value?.err != null) {\n throw new Error(\n `Transaction failed on chain: ${JSON.stringify(confirmation.value.err)} (sig=${signature})`,\n );\n }\n}\n\n/**\n * Best-effort SAS attestation request. POSTs to the executor's `/attest`\n * endpoint with the wallet's public key, a server-issued challenge nonce,\n * 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 *\n * Wallet-only path: the executor's `/attest` endpoint requires nonce +\n * signature + message on every request (walletless tier no longer writes\n * to SAS). If any of those is unavailable on the client side — wallet\n * adapter has no `signMessage`, signing throws, or no server nonce was\n * issued during this verification — we skip the request entirely instead\n * of sending a doomed-to-400 call.\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 if (!serverNonce) {\n sdkLog(\"[Entros SDK] Skipping SAS attestation: no server-issued nonce\");\n return undefined;\n }\n if (!wallet?.signMessage) {\n sdkLog(\"[Entros SDK] Skipping SAS attestation: wallet does not support signMessage\");\n return undefined;\n }\n\n let signature: string;\n let message: string;\n try {\n const timestamp = Math.floor(Date.now() / 1000);\n message = `Entros-ATTEST:${walletAddress}:${timestamp}`;\n const messageBytes = new TextEncoder().encode(message);\n const sigBytes: Uint8Array = await wallet.signMessage(messageBytes);\n signature = Array.from(sigBytes)\n .map((b) => b.toString(16).padStart(2, \"0\"))\n .join(\"\");\n } catch {\n sdkWarn(\"[Entros SDK] Wallet signMessage failed, skipping SAS attestation\");\n return undefined;\n }\n\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> = {\n wallet_address: walletAddress,\n nonce: serverNonce,\n signature,\n message,\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. Consumed only on the first-verification\n * path: when present, the SDK prepends an `Ed25519Program::verify`\n * instruction so on-chain `mint_anchor` can confirm the commitment was\n * endorsed by the configured validator. Re-verification ignores the\n * field entirely — `update_anchor` enforces binding via the\n * 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 const verifierProgram: any = new anchor.Program(\n entrosVerifierIdl as Idl,\n provider,\n );\n const anchorProgram: any = new anchor.Program(\n entrosAnchorIdl as Idl,\n provider,\n );\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 confirmAndCheck(options.connection, txSig);\n } else {\n // First verification: mint anchor. Bundles an `Ed25519Program::verify`\n // instruction before `mint_anchor` when the validator returned a\n // signed receipt. The on-chain program inspects the preceding\n // instruction via the Instructions sysvar to confirm the validator\n // endorsed (wallet, commitment, validated_at) before allowing the\n // mint.\n //\n // The `instructions_sysvar` account is required by the on-chain\n // `MintAnchor` accounts struct unconditionally — it must be present\n // even when no receipt is bundled (the on-chain check is currently\n // log-only, but the Anchor framework itself requires every account\n // listed in the IDL to be supplied).\n const anchorProgram: any = new anchor.Program(\n entrosAnchorIdl as Idl,\n provider,\n );\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 // Decode the receipt up front so we can hard-fail if the validator\n // returned malformed bytes. Silently falling back to a no-receipt\n // mint when the caller expected a binding would mask validator bugs\n // and, once on-chain enforcement is enabled, would produce a\n // confusing on-chain reject after the user has already approved a\n // wallet signature. Fail-fast lets the caller surface a clear error\n // and retry once the validator is healthy.\n let ed25519Ix: import(\"@solana/web3.js\").TransactionInstruction | null = null;\n if (options.signedReceipt) {\n ed25519Ix = await buildEd25519ReceiptIx(options.signedReceipt);\n if (!ed25519Ix) {\n return {\n success: false,\n error:\n \"Validator returned a signed receipt that failed to decode (malformed hex or wrong byte length). Refusing to mint without a valid binding. The validator service may be misconfigured — check the validation-service logs.\",\n };\n }\n sdkLog(\n \"[Entros SDK] Bundling validator-signed mint receipt before mint_anchor\"\n );\n } else {\n // No receipt is the legitimate \"older validator\" path. The on-chain\n // check is currently log-only so the mint still succeeds; once\n // enforcement is enabled, this will turn into a hard reject and\n // operators must ensure the validator is configured for receipt\n // signing.\n sdkLog(\n \"[Entros SDK] No validator receipt available; minting without binding (on-chain check is log-only today)\"\n );\n }\n\n // Transaction shape:\n // [0] ComputeBudgetProgram.setComputeUnitLimit\n // [1] (optional) Ed25519Program::verify(receipt)\n // [2] mint_anchor(initial_commitment)\n //\n // Including an explicit compute-budget ix at index 0 prevents wallet\n // adapters that lazily inject one from inserting it between the\n // Ed25519 ix and `mint_anchor`. The on-chain receipt parser locates\n // the receipt at `current_instruction_index - 1`, so any ix between\n // the Ed25519 prefix and `mint_anchor` would silently break the\n // binding while the check is log-only or hard-fail the mint once\n // enforcement is enabled. 200K covers the mint_anchor compute cost;\n // the Ed25519 precompile runs in the runtime, not against the\n // program's CU budget.\n const tx = new Transaction();\n tx.add(ComputeBudgetProgram.setComputeUnitLimit({ units: 200_000 }));\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 confirmAndCheck(options.connection, txSig);\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 validation\n * pipeline invoked at the /attest step (same as mint and 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 anchorProgram: any = new anchor.Program(\n entrosAnchorIdl as Idl,\n provider,\n );\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 confirmAndCheck(options.connection, txSig);\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 type { Idl } from \"@coral-xyz/anchor\";\nimport { PROGRAM_IDS } from \"../config\";\nimport { sdkWarn } from \"../log\";\nimport { entrosAnchorIdl } from \"../protocol/idl\";\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 *\n * Uses the bundled `entros_anchor.json` IDL (copied verbatim from\n * `protocol-core/target/idl/`) instead of `Program.fetchIdl`, which\n * adds a 150-300ms RPC round-trip per call to fetch the IDL from chain.\n * Account decoding is identical; the only difference is that IDL changes\n * now require an SDK bump rather than a chain-side IDL upload — in\n * practice that's already true since on-chain Anchor changes need\n * matching SDK updates anyway.\n *\n * When the on-chain `entros_anchor` program changes, re-copy\n * `protocol-core/target/idl/entros_anchor.json` into `src/protocol/idl/`\n * and bump the SDK minor version.\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 coder = new anchor.BorshAccountsCoder(entrosAnchorIdl as 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 MOTION_FEATURE_COUNT,\n TOUCH_FEATURE_COUNT,\n} from \"./extraction/kinematic\";\nimport { fuseFeatures, fuseRawFeatures } from \"./extraction/statistics\";\nimport { yieldToMainThread } from \"./yield\";\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 analysis.\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 // The audio path is the dominant cost. Yield once it's done so the\n // verify-flow spinner gets a paint frame before motion/touch extraction\n // resumes the main-thread work.\n await yieldToMainThread();\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 await yieldToMainThread();\n\n const touchFeatures = extractTouchFeatures(data.touch);\n await yieldToMainThread();\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. Present only when the request\n * reached the validator with `commitment_new_hex` AND the validator\n * has a signing key configured. `undefined` indicates the SDK\n * should mint without an Ed25519 prefix; while the on-chain check\n * is log-only this is harmless, but once enforcement is enabled\n * 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 // Let React render the new stage label before we re-enter the heavy\n // synchronous extraction path. Without this, the host UI sets the\n // string but the main thread is captured by extractFeatures before\n // the spinner can repaint, and the user sees the previous stage's\n // label until extraction completes.\n await yieldToMainThread();\n const {\n raw: features,\n normalized: normalizedFeatures,\n f0Contour,\n accelMagnitude,\n } = await extractFeatures(sensorData);\n\n // Diagnostic: log feature vector composition. Block boundaries follow the\n // v2 layout, derived from the canonical per-modality counts so any future\n // modality bump propagates automatically (no hand-sync drift).\n const AUDIO_END = SPEAKER_FEATURE_COUNT;\n const MOTION_END = AUDIO_END + MOTION_FEATURE_COUNT;\n const TOUCH_END = MOTION_END + TOUCH_FEATURE_COUNT;\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..${AUDIO_END - 1}]: ${features.slice(0, AUDIO_END).filter((v) => v !== 0).length} non-zero. ` +\n `Motion/Mouse[${AUDIO_END}..${MOTION_END - 1}]: ${features.slice(AUDIO_END, MOTION_END).filter((v) => v !== 0).length} non-zero. ` +\n `Touch[${MOTION_END}..${TOUCH_END - 1}]: ${features.slice(MOTION_END, TOUCH_END).filter((v) => v !== 0).length} non-zero.`\n );\n\n // Compute the SimHash fingerprint and Poseidon TBH commitment BEFORE the\n // validation POST. The validator signs a (wallet, commitment, validated_at)\n // receipt that the SDK bundles before `mint_anchor` in the same atomic\n // transaction; for the validator to sign the right commitment, we must\n // transmit it in the request. SimHash + Poseidon together cost ~20ms —\n // 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 // Same rationale as the \"Extracting features...\" yield above — give\n // React a paint opportunity before we encode the audio buffer to base64\n // (~16k samples), which is the next synchronous chunk on the main thread.\n await yieldToMainThread();\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 verification. The\n // validator transcribes the audio and matches it against the\n // server-issued challenge phrase (which the executor looks up by\n // nonce). 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. The validator only signs when this field is present AND\n // its own signing key is configured; the SDK only consumes the\n // receipt on first-verification, so sending it on every\n // wallet-connected request is harmless on the re-verify path\n // (validator signs cheaply, executor passes through, SDK ignores\n // the field for `update_anchor`).\n const commitmentNewHex = bytesToHex(tbh.commitmentBytes);\n\n // Server-side transcription 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. Older\n // validator deploys omit the field entirely — the SDK proceeds\n // without a receipt and the on-chain log-only check writes \"no\n // preceding instruction\" to the tx logs. Once on-chain enforcement\n // is enabled, missing receipts will hard-fail mint_anchor; the\n // executor + validator deploys must therefore be brought up to\n // receipt-supporting versions before the 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 (err) {\n // Body wasn't JSON — typically an older validator returning an\n // empty 200, or a proxy mangling the response. Surface a warn\n // so operators can distinguish \"validator-too-old\" from a real\n // validator misconfiguration. Treat as no-receipt and proceed.\n const msg = err instanceof Error ? err.message : String(err);\n sdkWarn(\n `[Entros SDK] /validate-features returned 200 but body was not parseable JSON; proceeding without receipt: ${msg}`\n );\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 server-side checks entirely.\n // 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 // Block boundaries derived from extractor constants so they stay in\n // sync with the v2 layout if any modality count shifts.\n const motionStart = SPEAKER_FEATURE_COUNT;\n const touchStart = motionStart + MOTION_FEATURE_COUNT;\n const touchEnd = touchStart + TOUCH_FEATURE_COUNT;\n const audioNZ = features.slice(0, motionStart).filter((v) => v !== 0).length;\n const motionNZ = features.slice(motionStart, touchStart).filter((v) => v !== 0).length;\n const touchNZ = features.slice(touchStart, touchEnd).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. Re-verification\n // doesn't need the receipt — the binding is already enforced via\n // the VerificationResult PDA path that `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 // Capture constraints kept in lock-step with `sensor/audio.ts` —\n // the two entry points (standalone capture vs session-based\n // capture) must agree or the verify flow and direct-API\n // consumers diverge.\n echoCancellation: false,\n noiseSuppression: false,\n autoGainControl: false,\n // @ts-expect-error -- W3C Media Capture Extensions property; not\n // yet in lib.dom.d.ts as of TypeScript 6.0.\n voiceIsolation: true,\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). This client-side generator only fires when the executor is\n// unreachable; in that path the server has no record of the phrase and the\n// phrase verification step is skipped while other server-side checks 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 the phrase verification step —\n * other server-side checks 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, 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.\n *\n * Server-issued phrases are the only safe design here: if the client generated\n * the phrase and sent it to the server alongside the audio, an attacker would\n * submit their own phrase matching whatever content they captured. With server\n * issuance, the phrase is bound to the nonce and the 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","meydaModule","getMeyda","window","meydaModule","getMeyda","derivative","dx","dy","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/mfcc.ts","../src/extraction/voice-quality.ts","../src/extraction/dct.ts","../src/yield.ts","../src/extraction/speaker.ts","../src/extraction/fft.ts","../src/extraction/kinematic.ts","../src/hashing/simhash.ts","../src/hashing/poseidon.ts","../src/proof/serializer.ts","../src/proof/prover.ts","../src/protocol/idl/entros_anchor.json","../src/protocol/idl/entros_verifier.json","../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 * Target RMS level the captured audio is normalized to before being\n * surfaced as `AudioCapture.samples`. Stays well inside Float32's\n * `[-1, 1]` range (no clipping risk on transients) and lands at the low\n * end of Whisper-tiny.en's amplitude sweet spot of `[0.05, 0.15]`. The\n * validator's VAD gate then applies a clean ~2× gain to reach its own\n * `0.1` target instead of the ~30× it had to apply to raw mic input.\n */\nconst TARGET_CAPTURE_RMS = 0.05;\n\n/**\n * Below this RMS, the capture is treated as effective silence and the\n * normalization step is skipped — never amplify the noise floor of a\n * muted or unplugged mic into apparent signal. Mirrors\n * `entros-validation::vad::VAD_NORMALIZE_MIN_RMS`.\n */\nconst MIN_RMS_FOR_NORMALIZATION = 1e-4;\n\n/**\n * Cap on the gain factor applied during normalization. Mirrors\n * `entros-validation::vad::VAD_NORMALIZE_MAX_GAIN` so a capture that the\n * SDK can't fully normalize also gets the same partial-gain treatment\n * server-side without further amplification surprises.\n */\nconst MAX_NORMALIZATION_GAIN = 50;\n\n/**\n * Scale the capture buffer so its RMS lands at `TARGET_CAPTURE_RMS`,\n * with safety guards: empty input passes through unchanged, near-silent\n * input passes through unchanged (so we don't amplify noise floor), and\n * the per-sample multiply is clamped to `[-1, 1]` so a transient peak\n * × gain can't overflow into clipping artifacts.\n *\n * Rationale: prior to this normalization, `extractSpeakerFeaturesDetailed`\n * computed amplitude features from raw mic input — which carries mic-\n * setup identity (gain × distance × mic class) rather than biological\n * identity. After normalization, all downstream feature extraction\n * operates on amplitude-stable input and the validator's Whisper path\n * sees consistent loudness across captures. Exported so the unit test\n * suite can pin the contract directly without driving the full\n * `getUserMedia` stack.\n */\nexport function normalizeCaptureRMS(samples: Float32Array): Float32Array {\n if (samples.length === 0) return samples;\n let sumSq = 0;\n for (let i = 0; i < samples.length; i++) {\n const s = samples[i]!;\n sumSq += s * s;\n }\n const rms = Math.sqrt(sumSq / samples.length);\n if (rms < MIN_RMS_FOR_NORMALIZATION) return samples;\n const gain = Math.min(TARGET_CAPTURE_RMS / rms, MAX_NORMALIZATION_GAIN);\n const out = new Float32Array(samples.length);\n for (let i = 0; i < samples.length; i++) {\n out[i] = Math.max(-1, Math.min(1, samples[i]! * gain));\n }\n return out;\n}\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 derived statistical\n * summary (308-element vector under the v3 pipeline) is the only audio-\n * related signal that crosses the device boundary. The single sanctioned\n * exception is the encoded base64 audio bytes sent to the validator's\n * `/validate-features` endpoint for server-side verification, which the\n * validator processes ephemerally — see entros.io for the privacy and\n * 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 // Capture without browser-side audio processing — preserves the\n // raw microphone signal for the SDK's downstream feature extraction\n // and for server-side validation. Audio cleanup intended for the\n // transcription path runs server-side, on a parallel path that\n // never feeds back to feature extraction. Matches the mobile SDK's\n // choice of Android's `MIC` source over `VOICE_RECOGNITION` —\n // same architectural decision, two platforms.\n echoCancellation: false,\n noiseSuppression: false,\n autoGainControl: false,\n // OS-level voice isolation request (W3C Media Capture Extensions,\n // 2024). Activates the platform DSP on Chrome 124+ / ChromeOS and\n // surfaces Apple Voice Isolation Mic Mode on Safari macOS Sonoma+\n // / iOS 17+ when the user has it enabled in Control Center.\n // Silently ignored on browsers/OSes without support, so the\n // constraint costs nothing where it doesn't help. Distinct\n // mechanism from `noiseSuppression` above — that flag controls\n // WebRTC's hand-tuned AudioProcessingModule, this requests the\n // OS-native neural effect.\n // @ts-expect-error -- W3C Media Capture Extensions property; not\n // yet in lib.dom.d.ts as of TypeScript 6.0. Removing this directive\n // becomes a compile error once lib.dom catches up, signaling that\n // it can be deleted.\n voiceIsolation: true,\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 // Normalize loudness at the SDK source so feature extraction and\n // the validator's Whisper path both operate on amplitude-stable\n // input regardless of mic gain / distance / class.\n const normalized = normalizeCaptureRMS(samples);\n\n resolve({\n samples: normalized,\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.\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 decodes the base64\n * payload and feeds the audio into server-side transcription. int16 is the\n * standard compact representation: 2 bytes per sample vs 4 for f32, halving\n * 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\n// Cap on the absolute value of skewness emitted to the feature vector.\n// Real human behavioral signals (voice prosody, motion, touch) produce\n// skewness in [-5, +5]; values beyond ±20 indicate near-zero variance\n// pathological frames (silent windows, near-constant signals) where the\n// standardized third moment becomes numerically unstable. Unbounded\n// outliers in this position were the root cause of the May-2026\n// cross-person fingerprint collapse: a single feature with raw skewness\n// ≈ 7,000 dominates the per-modality z-score in the validator and forces\n// ~half the audio bits to a deterministic value across all users.\nconst SKEWNESS_BOUND = 20;\n\n// Cap on kurtosis. Real human kurtosis is typically [0, 15]; values\n// above 50 indicate extreme outliers in low-variance signals that don't\n// carry identity-bearing information. Empirical: production LTAS\n// kurtosis on a near-silent capture hit 153,881 — well outside any\n// physically meaningful range — and dominated the audio block z-score.\nconst KURTOSIS_LOWER = 0;\nconst KURTOSIS_UPPER = 50;\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 const raw = (n / ((n - 1) * (n - 2))) * sum;\n return Math.max(-SKEWNESS_BOUND, Math.min(SKEWNESS_BOUND, raw));\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 Math.max(KURTOSIS_LOWER, Math.min(KURTOSIS_UPPER, 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 * Per-frame analysis output: the 12 LPC coefficients always exist (one\n * autocorrelate + Levinson-Durbin pass per frame), and the formant tuple\n * exists when at least 3 valid candidates were detected within the\n * speech-formant band. Bandwidths are paired with the formants — they're\n * the imaginary-axis decay rates of the same complex roots that produce\n * F1/F2/F3.\n */\ninterface FrameAnalysis {\n /** LPC coefficients a[1..order]; a[0] = 1 implicitly. Always populated. */\n lpcCoefficients: number[];\n /** [F1, F2, F3] in Hz, or null if fewer than 3 valid candidates. */\n formants: [number, number, number] | null;\n /** [B1, B2, B3] in Hz, paired with formants. Null when formants are null. */\n bandwidths: [number, number, number] | null;\n}\n\n/**\n * Per-frame LPC analysis surfacing the full information set used downstream\n * by the v2 feature pipeline (LPC coefficients, formant frequencies,\n * formant bandwidths). Replaces the legacy `extractFormants()` which only\n * returned formant frequencies and discarded both the LPC coefficients\n * and the bandwidths.\n */\nfunction extractFrameAnalysis(\n frame: Float32Array,\n sampleRate: number,\n lpcOrder: number = 12,\n): FrameAnalysis {\n const r = autocorrelate(frame, lpcOrder);\n const coeffs = levinsonDurbin(r, lpcOrder);\n\n const roots = findRoots(coeffs);\n\n // Pair each candidate frequency with its corresponding bandwidth so we\n // can preserve the F1↔B1, F2↔B2, F3↔B3 alignment after sorting by\n // frequency. The LPC pole's imaginary-axis decay rate maps to formant\n // bandwidth via the same complex-magnitude → log relation; capturing it\n // is information-free vs. the existing computation.\n const candidates: { freq: number; bandwidth: 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 =\n (-sampleRate / (2 * Math.PI)) *\n 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 candidates.push({ freq, bandwidth });\n }\n }\n\n candidates.sort((a, b) => a.freq - b.freq);\n\n if (candidates.length < 3) {\n return { lpcCoefficients: coeffs, formants: null, bandwidths: null };\n }\n\n const formants: [number, number, number] = [\n candidates[0]!.freq,\n candidates[1]!.freq,\n candidates[2]!.freq,\n ];\n const bandwidths: [number, number, number] = [\n candidates[0]!.bandwidth,\n candidates[1]!.bandwidth,\n candidates[2]!.bandwidth,\n ];\n\n return { lpcCoefficients: coeffs, formants, bandwidths };\n}\n\n/**\n * Backward-compatible thin wrapper. Existing callers that only need\n * formant frequencies keep their signatures stable; the v2 feature pipeline\n * uses `extractFrameAnalysis` directly to surface the additional LPC and\n * bandwidth signal that the old wrapper discarded.\n */\nfunction extractFormants(\n frame: Float32Array,\n sampleRate: number,\n lpcOrder: number = 12,\n): [number, number, number] | null {\n return extractFrameAnalysis(frame, sampleRate, lpcOrder).formants;\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/**\n * Session-level output of the v2 LPC analysis. Each per-coefficient time\n * series has length `numFramesAnalyzed` (every frame contributes); the\n * formant time series may be shorter because frames with fewer than 3\n * valid candidates are skipped (matches `extractFormantRatios` behavior).\n */\nexport interface LpcAnalysis {\n /** lpcCoefficients[c][t] = c-th LPC coefficient at frame t. Shape: [order × frames]. */\n lpcCoefficients: number[][];\n /** F1/F2/F3 absolute frequencies in Hz, one entry per detected-formant frame. */\n f1: number[];\n f2: number[];\n f3: number[];\n /** B1/B2/B3 corresponding bandwidths in Hz, aligned with f1/f2/f3 by index. */\n b1: number[];\n b2: number[];\n b3: number[];\n /** Existing formant ratios, retained for backward-compat with the original 44-feature audio block. */\n f1f2: number[];\n f2f3: number[];\n /** Diagnostic: number of frames the analyzer ran over (independent of formant detection). */\n numFramesAnalyzed: number;\n}\n\n/**\n * Comprehensive session-level LPC + formant analysis. Surfaces the full\n * information set the v2 feature pipeline consumes: per-frame LPC\n * coefficients (12 time series), absolute formant frequencies (3 time\n * series), formant bandwidths (3 time series), and the existing F1/F2 +\n * F2/F3 ratios.\n *\n * Single pass over the samples — autocorrelate + Levinson-Durbin runs\n * once per frame, with all downstream signals derived from that single\n * coefficient set. CPU cost is identical to the legacy\n * `extractFormantRatios` (the formant filtering, root-finding, and ratio\n * derivation were always running; this function just RETAINS the\n * intermediate values that the legacy function discarded).\n */\nexport function extractLpcAnalysis(\n samples: Float32Array,\n sampleRate: number,\n frameSize: number,\n hopSize: number,\n lpcOrder: number = 12,\n): LpcAnalysis {\n const lpcCoefficients: number[][] = Array.from({ length: lpcOrder }, () => []);\n const f1: number[] = [];\n const f2: number[] = [];\n const f3: number[] = [];\n const b1: number[] = [];\n const b2: number[] = [];\n const b3: number[] = [];\n const f1f2: number[] = [];\n const f2f3: number[] = [];\n\n const numFrames = Math.floor((samples.length - frameSize) / hopSize) + 1;\n let numFramesAnalyzed = 0;\n\n if (numFrames < 1) {\n return {\n lpcCoefficients,\n f1, f2, f3, b1, b2, b3, f1f2, f2f3,\n numFramesAnalyzed: 0,\n };\n }\n\n // Pre-allocate the windowed frame buffer once (matches the optimization\n // in speaker.ts::computeLTAS — saves ~1200 Float32Array allocations\n // per session at ~10ms hop over 12 seconds).\n const windowed = new Float32Array(frameSize);\n\n for (let i = 0; i < numFrames; i++) {\n const start = i * hopSize;\n const frame = samples.subarray(start, start + frameSize);\n\n // Apply Hamming window in-place to the pre-allocated buffer.\n for (let j = 0; j < frameSize; j++) {\n windowed[j] =\n (frame[j] ?? 0) *\n (0.54 - 0.46 * Math.cos((2 * Math.PI * j) / (frameSize - 1)));\n }\n\n const analysis = extractFrameAnalysis(windowed, sampleRate, lpcOrder);\n numFramesAnalyzed++;\n\n // LPC coefficients are always populated.\n for (let c = 0; c < lpcOrder; c++) {\n const coeff = analysis.lpcCoefficients[c];\n if (Number.isFinite(coeff)) {\n lpcCoefficients[c]!.push(coeff!);\n }\n }\n\n // Formants and bandwidths are populated only when 3+ valid candidates\n // were detected. Push the triplet atomically (all three or none) so\n // index alignment between f1/f2/f3 and b1/b2/b3 is preserved.\n if (analysis.formants && analysis.bandwidths) {\n const [F1, F2, F3] = analysis.formants;\n const [B1, B2, B3] = analysis.bandwidths;\n f1.push(F1);\n f2.push(F2);\n f3.push(F3);\n b1.push(B1);\n b2.push(B2);\n b3.push(B3);\n if (F2 > 0) f1f2.push(F1 / F2);\n if (F3 > 0) f2f3.push(F2 / F3);\n }\n }\n\n return {\n lpcCoefficients,\n f1, f2, f3, b1, b2, b3, f1f2, f2f3,\n numFramesAnalyzed,\n };\n}\n","/**\n * MFCC (Mel-Frequency Cepstral Coefficient) feature extraction.\n *\n * MFCCs are the industry-standard speaker-recognition feature: they encode\n * the SHAPE of the vocal tract via cepstral coefficients on a perceptual\n * mel-frequency scale. Two adult humans speaking the same word produce\n * different MFCC trajectories the same way two violins produce different\n * timbres of the same note. The original 44-feature audio block omitted\n * MFCCs entirely — this is the largest single discriminative-power gap\n * the v2 feature pipeline closes (see\n * `docs/master/BLUEPRINT-feature-pipeline-v2.md` §1.1).\n *\n * Output of `extractMfccFeatures` is 72 statistical aggregates over the\n * per-frame MFCC time-series captured during a 12-second session\n * (MFCC[0] is dropped as a cepstral DC term — see MFCC_DROP_LEADING):\n *\n * - 12 used MFCC coefficients × 4 stats (mean, var, skewness, kurtosis) = 48\n * - 12 used delta-MFCC coefficients × 2 stats (mean, var) = 24\n *\n * The deltas (first-order temporal derivatives via 9-frame regression\n * window) capture how the vocal tract shape CHANGES during articulation —\n * a complementary identity signal to the static MFCCs.\n *\n * @privacyGuarantee MFCCs are themselves a dimensionality reduction (FFT →\n * mel filter bank → log → DCT, keeping the first 13 coefficients). The\n * statistics across frames add a second reduction layer. Aggregated\n * MFCC stats cannot reconstruct intelligible audio without a separate\n * vocoder model, and even with one only a coarse approximation is\n * possible. This is the same privacy posture as the existing 44-feature\n * audio block: statistical aggregates of on-device-computed signals.\n */\nimport { condense, mean as meanOf, variance as varianceOf } from \"./statistics\";\nimport { sdkWarn } from \"../log\";\n\nconst NUM_MFCC_COEFFICIENTS = 13;\n/** Drop the leading MFCC[0] (cepstral DC term, log-energy proxy). It's\n * dominated by frame energy and mic gain rather than vocal-tract\n * identity, sits at 1-3 orders of magnitude larger than MFCC[1..12], and\n * was a contributing outlier to the per-modality z-score collapse the\n * validator-side winsorize defends against. Standard Kaldi / sidekit\n * speaker-recognition pipelines drop C0; we follow the convention. */\nconst MFCC_DROP_LEADING = 1;\n/** Coefficients actually retained for downstream stats (12 = 13 - 1). */\nconst NUM_USED_MFCC = NUM_MFCC_COEFFICIENTS - MFCC_DROP_LEADING;\n/** Half-width of the regression window used to compute delta-MFCCs. The\n * standard speech-recognition value is 2 (window of 9 frames total: 4 on\n * each side plus the center). Larger N smooths more but lags behind\n * rapid articulation; 2 balances responsiveness against noise. */\nconst DELTA_REGRESSION_HALF_WIDTH = 2;\n\n/**\n * Total feature count produced by `extractMfccFeatures`. Imported by\n * speaker.ts when assembling the final audio feature vector.\n */\nexport const MFCC_FEATURE_COUNT =\n NUM_USED_MFCC * 4 + // mean, var, skew, kurt per coefficient\n NUM_USED_MFCC * 2; // mean, var per delta coefficient\n// = 48 + 24 = 72 (down from 78 after dropping MFCC[0])\n\n/**\n * Apply standard pre-emphasis filter `H(z) = 1 - 0.97 z^-1` to the raw\n * sample stream before MFCC framing. Boosts the high-frequency content\n * where speaker-individual differences (F2/F3 formants, fricatives,\n * breathiness) live; without it MFCCs are dominated by the F1 vocal-tract\n * resonance which is less speaker-discriminative. Standard Kaldi/sidekit\n * pipelines apply this; Meyda's MFCC extractor does not.\n *\n * Filter coefficient 0.97 is the conventional speech-recognition value\n * (Furui 1981, ETSI ES 201 108). Returns a new buffer; does not mutate\n * the input.\n */\nfunction applyPreEmphasis(samples: Float32Array): Float32Array {\n const out = new Float32Array(samples.length);\n if (samples.length === 0) return out;\n out[0] = samples[0]!;\n for (let i = 1; i < samples.length; i++) {\n out[i] = samples[i]! - 0.97 * samples[i - 1]!;\n }\n return out;\n}\n\n/**\n * Compute first-order delta (temporal derivative) of a per-frame time\n * series using a regression window. Standard speech-recognition formula\n * (Furui 1986):\n *\n * delta_t = Σ_{n=1..N} n × (x_{t+n} - x_{t-n}) / (2 × Σ_{n=1..N} n²)\n *\n * Equivalent to a least-squares fit of a line to the surrounding 2N+1\n * frames. The numerator is symmetric: contributions from `n=1..N` on each\n * side are weighted by `n`. The denominator `2 × Σ_{i=1..N} i² =\n * N(N+1)(2N+1)/3` normalizes so a series with constant slope produces a\n * delta equal to that slope (verified by the linear-input test in\n * mfcc.test.ts).\n *\n * Edge frames use truncated windows: when offset `k` would land outside\n * `[0, n)` on either side, the entire ±k pair is dropped from the\n * numerator AND `2k²` is subtracted from the denominator. This keeps the\n * result a valid (less precise, but unbiased toward zero) least-squares\n * estimate over the surviving symmetric offsets.\n */\nfunction computeDelta(series: number[], halfWidth: number): number[] {\n const n = series.length;\n const out: number[] = new Array(n);\n // Σ_{i=-N..N} i² = 2 × N(N+1)(2N+1)/6 = N(N+1)(2N+1)/3.\n // Computed once per series; constant across all frames except for\n // edge-truncation adjustments below.\n const fullDenom = (halfWidth * (halfWidth + 1) * (2 * halfWidth + 1)) / 3;\n for (let t = 0; t < n; t++) {\n let num = 0;\n let denom = fullDenom;\n for (let k = 1; k <= halfWidth; k++) {\n const tPlus = t + k;\n const tMinus = t - k;\n if (tPlus >= n || tMinus < 0) {\n // Edge: drop the symmetric pair from numerator and remove the\n // matching 2k² from the denominator. Without the adjustment edge\n // deltas would be biased toward zero (smaller numerator over an\n // unchanged denominator).\n denom -= 2 * k * k;\n continue;\n }\n num += k * (series[tPlus]! - series[tMinus]!);\n }\n if (denom <= 0) {\n // Pathological case — series too short for any symmetric window.\n // Deliver zero rather than NaN so downstream stats stay finite.\n out[t] = 0;\n continue;\n }\n out[t] = num / denom;\n }\n return out;\n}\n\n/**\n * Loaded lazily so SDK consumers that don't need audio extraction don't pay\n * the Meyda bundle cost. Mirrors the pattern in speaker.ts::getMeyda\n * exactly, including the `any` typing — Meyda's published types don't\n * surface the runtime `.extract` method on the module-default export\n * cleanly across bundler interop, and matching speaker.ts's existing\n * pragma keeps the integration consistent.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nlet meydaModule: any = null;\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\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 * Extract MFCC and delta-MFCC statistical features from an audio capture.\n *\n * Computes MFCCs frame-by-frame using Meyda's built-in extractor, then\n * applies regression-based delta to capture temporal dynamics. Aggregates\n * each per-coefficient time-series to a small set of moments suitable for\n * fingerprinting (resistant to phrase content; sensitive to vocal tract\n * shape).\n *\n * Returns 72 floats (see MFCC_FEATURE_COUNT above) in stable order over\n * coefficients C1..C12 (C0 is intentionally dropped — see MFCC_DROP_LEADING):\n * [mean(c1), var(c1), skew(c1), kurt(c1),\n * mean(c2), var(c2), skew(c2), kurt(c2),\n * ...\n * mean(c12), var(c12), skew(c12), kurt(c12),\n * mean(d1), var(d1),\n * mean(d2), var(d2),\n * ...\n * mean(d12), var(d12)]\n *\n * On invalid input (zero-length samples, non-finite sample rate, or Meyda\n * unavailable) returns a zero vector of the correct length so the caller\n * can concatenate without conditional logic.\n */\nexport async function extractMfccFeatures(\n samples: Float32Array,\n sampleRate: number,\n frameSize: number,\n hopSize: number,\n): Promise<number[]> {\n if (\n !Number.isFinite(sampleRate) ||\n sampleRate <= 0 ||\n samples.length === 0 ||\n frameSize <= 0 ||\n hopSize <= 0\n ) {\n return new Array(MFCC_FEATURE_COUNT).fill(0);\n }\n\n const Meyda = await getMeyda();\n if (!Meyda) {\n sdkWarn(\"[Entros SDK] Meyda unavailable; MFCC features will be zeros.\");\n return new Array(MFCC_FEATURE_COUNT).fill(0);\n }\n\n const numFrames = Math.floor((samples.length - frameSize) / hopSize) + 1;\n if (numFrames < 5) {\n return new Array(MFCC_FEATURE_COUNT).fill(0);\n }\n\n // Per-coefficient time series: mfccTracks[i][t] is the (i + MFCC_DROP_LEADING)-th\n // MFCC at frame t. Indexed by the USED coefficient slot, not Meyda's raw\n // [0..NUM_MFCC_COEFFICIENTS) range.\n const mfccTracks: number[][] = Array.from(\n { length: NUM_USED_MFCC },\n () => [],\n );\n\n // Reusable frame buffer to avoid allocating per frame (matches the\n // pre-allocation pattern in speaker.ts::computeLTAS).\n const frame = new Float32Array(frameSize);\n\n // Meyda.extract's third argument is `previousSignal`, NOT options — passing\n // `{ sampleRate, bufferSize }` silently goes to that slot and is ignored.\n // Configure Meyda's globals before extracting so the mel filter bank is\n // built for the correct sample rate and frame size. Without this, Meyda\n // uses default sampleRate=44100 / bufferSize=512 — producing MFCCs that\n // are still self-consistent (same input → same output) but not aligned\n // with the actual frequency content of our 16 kHz / 2048-sample frames,\n // and not parity-comparable to librosa or other reference implementations.\n Meyda.bufferSize = frameSize;\n Meyda.sampleRate = sampleRate;\n\n // Apply pre-emphasis once over the whole capture before framing. Boosts\n // high-frequency content where F2/F3 + fricative differences between\n // speakers live; without it MFCCs are dominated by F1 resonance which\n // is less speaker-discriminative. Cheap (one O(n) pass), allocates one\n // Float32Array of the input length.\n const emphasized = applyPreEmphasis(samples);\n\n for (let i = 0; i < numFrames; i++) {\n const start = i * hopSize;\n frame.set(emphasized.subarray(start, start + frameSize), 0);\n\n const result = Meyda.extract(\"mfcc\", frame) as number[] | null | undefined;\n\n if (!Array.isArray(result) || result.length !== NUM_MFCC_COEFFICIENTS) {\n // Skip frames where Meyda failed to extract MFCCs (typically silent\n // or pathologically small frames). Keeping per-coefficient track\n // lengths in sync — a frame is either added to ALL tracks or NONE.\n continue;\n }\n\n let allFinite = true;\n for (let c = 0; c < NUM_MFCC_COEFFICIENTS; c++) {\n if (!Number.isFinite(result[c]!)) {\n allFinite = false;\n break;\n }\n }\n if (!allFinite) continue;\n\n // Skip MFCC[0..MFCC_DROP_LEADING) — the cepstral DC term carries\n // mic-energy noise rather than vocal-tract identity. Read from\n // `result[c + MFCC_DROP_LEADING]` so track index `c` corresponds to\n // the c-th USED coefficient (C1..C12 with the default drop).\n for (let c = 0; c < NUM_USED_MFCC; c++) {\n mfccTracks[c]!.push(result[c + MFCC_DROP_LEADING]!);\n }\n }\n\n // Aggregate per-coefficient track using the existing repo statistics\n // helpers. Reusing condense/mean/variance keeps the moment formulas\n // (sample variance, statistically-correct skewness, excess-kurtosis-\n // corrected kurtosis) consistent with the existing 44 audio features\n // computed elsewhere in the speaker block.\n const out: number[] = [];\n out.length = MFCC_FEATURE_COUNT;\n let writeIdx = 0;\n\n // 12 × 4 = 48 features (mean, variance, skewness, kurtosis per used coefficient).\n for (let c = 0; c < NUM_USED_MFCC; c++) {\n const stats = condense(mfccTracks[c]!);\n out[writeIdx++] = stats.mean;\n out[writeIdx++] = stats.variance;\n out[writeIdx++] = stats.skewness;\n out[writeIdx++] = stats.kurtosis;\n }\n\n // 12 × 2 = 24 features (mean, variance per delta of each used coefficient).\n for (let c = 0; c < NUM_USED_MFCC; c++) {\n const delta = computeDelta(mfccTracks[c]!, DELTA_REGRESSION_HALF_WIDTH);\n const muDelta = meanOf(delta);\n out[writeIdx++] = muDelta;\n out[writeIdx++] = varianceOf(delta, muDelta);\n }\n\n return out;\n}\n","/**\n * Voice quality feature extraction.\n *\n * Captures identity-bearing voice characteristics that the existing 44\n * audio features and the new MFCC / LPC blocks don't directly target:\n *\n * - **Cepstral Peak Prominence (CPP)** — strongest single measure of\n * voice quality (breathy ↔ pressed phonation). Computed as the height\n * of the cepstral peak in the typical-F0 quefrency band, relative to\n * a linear regression baseline.\n * - **Spectral tilt** — slope of the log-magnitude spectrum vs log\n * frequency. Captures vocal \"brightness\" / spectral balance, an\n * individual-speaker signature.\n * - **H1-H2** — amplitude difference (in dB) between the first two\n * harmonics of the voice. Identifies phonation type (modal /\n * breathy / pressed) and is identity-bearing.\n * - **Sub-band energy ratios** — fraction of total energy in three\n * bands (low <1kHz, mid 1-3kHz, high 3-8kHz). Captures gross\n * spectral balance complementary to spectral tilt.\n *\n * Output: 9 floats (see `VOICE_QUALITY_FEATURE_COUNT`):\n * [cppMean, cppVar, tiltMean, tiltVar, h1h2Mean, h1h2Var,\n * lowBandRatio, midBandRatio, highBandRatio]\n *\n * @privacyGuarantee Each metric is a per-frame scalar; the output is\n * statistical aggregates over the per-frame time series. Same privacy\n * posture as the existing audio features: aggregates of aggregates of\n * frequency-domain transforms of on-device-captured audio. Cannot\n * reconstruct intelligible speech.\n */\nimport { mean as meanOf, variance as varianceOf } from \"./statistics\";\nimport { sdkWarn } from \"../log\";\n\nexport const VOICE_QUALITY_FEATURE_COUNT = 9;\n\n// Sub-band frequency boundaries in Hz. Tuned to capture distinct\n// spectral regions of human speech: low band covers F0 + first\n// formant region, mid covers F2-F3 (vowel quality), high covers\n// fricative + breathiness energy.\nconst LOW_BAND_HZ = 1000;\nconst MID_BAND_HZ = 3000;\nconst HIGH_BAND_HZ = 8000;\n\n// Quefrency band for CPP peak search (in samples). Corresponds to\n// typical fundamental-frequency range 60–400 Hz: quefrency q maps\n// to frequency sampleRate/q, so q in [sampleRate/400, sampleRate/60].\nfunction cppQuefrencyRange(sampleRate: number): { qMin: number; qMax: number } {\n return {\n qMin: Math.max(2, Math.floor(sampleRate / 400)),\n qMax: Math.floor(sampleRate / 60),\n };\n}\n\n/**\n * Lazy-import meyda mirroring speaker.ts::getMeyda. Meyda's published\n * types don't surface the runtime API on the default export cleanly\n * across bundler interop, so the `any` typing matches the existing\n * pattern.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nlet meydaModule: any = null;\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\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 * Compute Cepstral Peak Prominence for a single frame's power spectrum.\n *\n * CPP = peak_value − regression_baseline_at_peak_quefrency\n *\n * Where the cepstrum is computed as DCT-II of the log power spectrum\n * (mathematically equivalent to the real cepstrum for an even-symmetric\n * input, and faster than IFFT for our use case). The peak is searched\n * in the quefrency band corresponding to typical human F0 (60-400 Hz),\n * and the baseline is a linear regression fit to the cepstrum across\n * the search band.\n *\n * Returns 0 if the spectrum is too small or degenerate.\n */\nfunction cepstralPeakProminence(\n powerSpectrum: Float32Array | number[],\n sampleRate: number,\n): number {\n const N = powerSpectrum.length;\n if (N < 8) return 0;\n\n const { qMin, qMax } = cppQuefrencyRange(sampleRate);\n if (qMax >= N || qMax <= qMin) return 0;\n\n // Take log of power spectrum with a floor to avoid log(0).\n const FLOOR = 1e-12;\n const logPower: number[] = new Array(N);\n for (let i = 0; i < N; i++) {\n const p = Math.max(powerSpectrum[i]!, FLOOR);\n const l = Math.log(p);\n if (!Number.isFinite(l)) return 0;\n logPower[i] = l;\n }\n\n // Cepstrum via DCT-II of the log spectrum, computed ONLY over the\n // quefrency band we need. Naive `dctII(logPower, N)` is O(N²) ≈ 1M ops\n // per frame at N=1024; restricting the output range to [qMin..qMax]\n // (≈ 200 bins for typical F0 60-400 Hz at 16 kHz) drops the cost to\n // O(N × (qMax - qMin + 1)) ≈ 200k ops per frame — a 5× speedup. The\n // baseline regression and peak-finding still run only over the band,\n // so the full-N DCT was wasted work in the original implementation.\n const bandLen = qMax - qMin + 1;\n const cepstrumBand: number[] = new Array(bandLen);\n const piOverN = Math.PI / N;\n for (let bIdx = 0; bIdx < bandLen; bIdx++) {\n const k = qMin + bIdx;\n let sum = 0;\n for (let n = 0; n < N; n++) {\n sum += logPower[n]! * Math.cos(piOverN * (n + 0.5) * k);\n }\n cepstrumBand[bIdx] = sum;\n }\n\n // Find peak in the band.\n let peakBIdx = 0;\n let peakVal = cepstrumBand[0]!;\n for (let bIdx = 1; bIdx < bandLen; bIdx++) {\n if (cepstrumBand[bIdx]! > peakVal) {\n peakVal = cepstrumBand[bIdx]!;\n peakBIdx = bIdx;\n }\n }\n const peakQuefrency = qMin + peakBIdx;\n\n // Linear regression baseline: simple least-squares fit y = a + b × q\n // over the same band. CPP = peak − baseline_at_peak_q.\n const M = bandLen;\n let sx = 0;\n let sy = 0;\n let sxx = 0;\n let sxy = 0;\n for (let bIdx = 0; bIdx < bandLen; bIdx++) {\n const x = qMin + bIdx;\n const y = cepstrumBand[bIdx]!;\n sx += x;\n sy += y;\n sxx += x * x;\n sxy += x * y;\n }\n const denom = M * sxx - sx * sx;\n if (Math.abs(denom) < 1e-12) return 0;\n const slope = (M * sxy - sx * sy) / denom;\n const intercept = (sy - slope * sx) / M;\n const baselineAtPeak = intercept + slope * peakQuefrency;\n\n return peakVal - baselineAtPeak;\n}\n\n/**\n * Compute spectral tilt for a single frame: linear regression slope of\n * `log(power[k])` vs `log(frequency[k])` over the analysis band.\n *\n * Higher-magnitude (more negative) slope indicates a darker / breathier\n * voice; flatter slope indicates pressed / clearer voice. Identity-\n * bearing within a speaker's range.\n *\n * Returns 0 on degenerate input. Bands below 100 Hz are excluded\n * because they're dominated by DC + room noise.\n */\nfunction spectralTilt(\n powerSpectrum: Float32Array | number[],\n sampleRate: number,\n): number {\n const N = powerSpectrum.length;\n if (N < 8) return 0;\n // Frequency at bin k (assuming standard FFT bin spacing): k × (sampleRate / 2) / (N - 1)\n // for half-spectrum N. Meyda's amplitudeSpectrum/powerSpectrum has length\n // bufferSize/2, so binHz = k × sampleRate / bufferSize. Caller may pass\n // either; we assume standard interpretation: binHz = k × (sampleRate / 2) / (N - 1).\n // Mathematically the slope is unaffected by frequency-axis scaling\n // (since both x and ln-x scale together).\n const FLOOR = 1e-12;\n let sx = 0;\n let sy = 0;\n let sxx = 0;\n let sxy = 0;\n let count = 0;\n // Skip k=0 (DC) and the lowest bins (< 100 Hz) where noise dominates.\n const minBin = Math.max(1, Math.floor((100 * 2 * (N - 1)) / sampleRate));\n for (let k = minBin; k < N; k++) {\n const p = powerSpectrum[k]!;\n if (p < FLOOR) continue;\n const x = Math.log(k); // log-frequency proxy\n const y = Math.log(p); // log-power\n if (!Number.isFinite(x) || !Number.isFinite(y)) continue;\n sx += x;\n sy += y;\n sxx += x * x;\n sxy += x * y;\n count++;\n }\n if (count < 4) return 0;\n const denom = count * sxx - sx * sx;\n if (Math.abs(denom) < 1e-12) return 0;\n return (count * sxy - sx * sy) / denom;\n}\n\n/**\n * Compute H1-H2 (amplitude in dB of first vs second harmonic) for a\n * single frame given the power spectrum and the F0 estimate.\n *\n * Looks for the local peak in a small window around k_F0 (first\n * harmonic) and around k_2F0 (second harmonic), takes the max within\n * each window, converts to dB, returns difference.\n *\n * Returns 0 if F0 is invalid (≤ 0) or harmonics fall outside the\n * spectrum.\n */\nfunction h1MinusH2(\n powerSpectrum: Float32Array | number[],\n sampleRate: number,\n f0: number,\n): number {\n if (!Number.isFinite(f0) || f0 <= 0) return 0;\n const N = powerSpectrum.length;\n if (N < 8) return 0;\n\n // Bin index for frequency f: k = f × (N - 1) / (sampleRate / 2)\n const binPerHz = (2 * (N - 1)) / sampleRate;\n const k1 = Math.round(f0 * binPerHz);\n const k2 = Math.round(2 * f0 * binPerHz);\n\n // ±2-bin search window around each harmonic.\n const window = 2;\n\n function peakNear(k: number): number {\n let best = -Infinity;\n for (let i = k - window; i <= k + window; i++) {\n if (i <= 0 || i >= N) continue;\n const p = powerSpectrum[i]!;\n if (p > best) best = p;\n }\n return best;\n }\n\n const h1 = peakNear(k1);\n const h2 = peakNear(k2);\n if (!Number.isFinite(h1) || !Number.isFinite(h2) || h1 <= 0 || h2 <= 0) return 0;\n // dB difference of amplitudes: 10 × (log10(h1) - log10(h2)) since these\n // are powers (squared amplitudes); equivalent to 20 × log10(amp ratio).\n return 10 * Math.log10(h1 / h2);\n}\n\n/**\n * Compute sub-band energy ratios from the power spectrum. Returns\n * [low, mid, high] each in [0, 1] summing to ≤ 1 (can be < 1 if some\n * energy is above HIGH_BAND_HZ).\n */\nfunction subbandRatios(\n powerSpectrum: Float32Array | number[],\n sampleRate: number,\n): [number, number, number] {\n const N = powerSpectrum.length;\n if (N < 4) return [0, 0, 0];\n // Bin per Hz mapping: k = f × (N - 1) / (sampleRate / 2)\n const binPerHz = (2 * (N - 1)) / sampleRate;\n const lowBin = Math.min(N - 1, Math.round(LOW_BAND_HZ * binPerHz));\n const midBin = Math.min(N - 1, Math.round(MID_BAND_HZ * binPerHz));\n const highBin = Math.min(N - 1, Math.round(HIGH_BAND_HZ * binPerHz));\n\n let total = 0;\n let low = 0;\n let mid = 0;\n let high = 0;\n // Skip k=0 (DC) — never carries voice energy.\n for (let k = 1; k < N; k++) {\n const p = powerSpectrum[k]!;\n if (!Number.isFinite(p) || p < 0) continue;\n total += p;\n if (k <= lowBin) low += p;\n else if (k <= midBin) mid += p;\n else if (k <= highBin) high += p;\n }\n if (total < 1e-12) return [0, 0, 0];\n return [low / total, mid / total, high / total];\n}\n\n/**\n * Extract voice quality features from an audio capture.\n *\n * Per-frame: compute power spectrum (via Meyda), then derive CPP,\n * spectral tilt, H1-H2 (using the per-frame F0), and sub-band ratios.\n * Aggregate per-frame metrics over the session.\n *\n * Returns 9 floats in the order documented at the top of this module.\n * Returns all-zeros on invalid input or when Meyda is unavailable.\n *\n * @param samples — Float32Array of audio samples (peak-normalized\n * recommended; matches the speaker.ts pre-processing step).\n * @param sampleRate — sample rate in Hz.\n * @param frameSize — frame size in samples (must be a power of two for\n * Meyda's FFT).\n * @param hopSize — hop size in samples.\n * @param f0PerFrame — F0 (Hz) for each frame, indexed 0..numFrames-1.\n * Frames where F0 ≤ 0 are treated as unvoiced and skipped for H1-H2\n * only (CPP, tilt, sub-bands run on every frame). Length should match\n * the frame iteration in this function (numFrames = floor((samples.length\n * - frameSize) / hopSize) + 1).\n */\nexport async function extractVoiceQualityFeatures(\n samples: Float32Array,\n sampleRate: number,\n frameSize: number,\n hopSize: number,\n f0PerFrame: number[],\n): Promise<number[]> {\n if (\n !Number.isFinite(sampleRate) ||\n sampleRate <= 0 ||\n samples.length === 0 ||\n frameSize <= 0 ||\n hopSize <= 0\n ) {\n return new Array(VOICE_QUALITY_FEATURE_COUNT).fill(0);\n }\n\n const Meyda = await getMeyda();\n if (!Meyda) {\n sdkWarn(\"[Entros SDK] Meyda unavailable; voice quality features will be zeros.\");\n return new Array(VOICE_QUALITY_FEATURE_COUNT).fill(0);\n }\n\n const numFrames = Math.floor((samples.length - frameSize) / hopSize) + 1;\n if (numFrames < 5) {\n return new Array(VOICE_QUALITY_FEATURE_COUNT).fill(0);\n }\n\n const cppValues: number[] = [];\n const tiltValues: number[] = [];\n const h1h2Values: number[] = [];\n const lowRatios: number[] = [];\n const midRatios: number[] = [];\n const highRatios: number[] = [];\n\n // Reusable frame buffer (matches speaker.ts::computeLTAS).\n const frame = new Float32Array(frameSize);\n\n // Meyda.extract's third argument is `previousSignal`, NOT options — passing\n // `{ sampleRate, bufferSize }` there is silently ignored, leaving Meyda on\n // its default bufferSize=512 / sampleRate=44100. That truncates the visible\n // spectrum to bufferSize/2 = 256 bins regardless of input frame size, and\n // miscomputes any frequency-domain mapping. Set the globals before\n // extracting so the returned spectrum matches the input frame's actual\n // FFT geometry. (See speaker.ts::computeLTAS, which has the same misuse\n // pattern but only consumes scalar features so the bug is invisible there;\n // a follow-up commit aligns it.)\n Meyda.bufferSize = frameSize;\n Meyda.sampleRate = sampleRate;\n\n for (let i = 0; i < numFrames; i++) {\n const start = i * hopSize;\n frame.set(samples.subarray(start, start + frameSize), 0);\n\n const features = Meyda.extract(\"powerSpectrum\", frame);\n const power = features as Float32Array | undefined | null;\n if (!power || power.length === 0) continue;\n\n const cpp = cepstralPeakProminence(power, sampleRate);\n if (Number.isFinite(cpp)) cppValues.push(cpp);\n\n const tilt = spectralTilt(power, sampleRate);\n if (Number.isFinite(tilt)) tiltValues.push(tilt);\n\n const f0 = f0PerFrame[i] ?? 0;\n if (f0 > 0) {\n const h1h2 = h1MinusH2(power, sampleRate, f0);\n if (Number.isFinite(h1h2)) h1h2Values.push(h1h2);\n }\n\n const [low, mid, high] = subbandRatios(power, sampleRate);\n lowRatios.push(low);\n midRatios.push(mid);\n highRatios.push(high);\n }\n\n const cppMean = meanOf(cppValues);\n const cppVar = varianceOf(cppValues, cppMean);\n const tiltMean = meanOf(tiltValues);\n const tiltVar = varianceOf(tiltValues, tiltMean);\n const h1h2Mean = meanOf(h1h2Values);\n const h1h2Var = varianceOf(h1h2Values, h1h2Mean);\n const lowMean = meanOf(lowRatios);\n const midMean = meanOf(midRatios);\n const highMean = meanOf(highRatios);\n\n return [\n cppMean,\n cppVar,\n tiltMean,\n tiltVar,\n h1h2Mean,\n h1h2Var,\n lowMean,\n midMean,\n highMean,\n ];\n}\n","/**\n * Discrete Cosine Transform Type-II (DCT-II) and pitch-contour shape\n * encoding.\n *\n * Used by the v2 feature pipeline to capture the SHAPE of the per-session\n * F0 (pitch) contour as a small number of coefficients. Identity-bearing\n * because individual speakers have characteristic prosodic patterns —\n * rising/falling/modulated melodies — that the existing F0 statistics\n * (mean, variance, skew, kurtosis) don't reach. Closes the\n * \"no-pitch-trajectory-shape\" gap documented in\n * `docs/master/BLUEPRINT-feature-pipeline-v2.md` §1.1.\n *\n * @privacyGuarantee The output is a small fixed number of coefficients\n * (5 by default) capturing the lowest-frequency components of the pitch\n * contour. This is a strict dimensionality reduction (1200 frames → 5\n * coefficients) and cannot reconstruct the original contour, let alone\n * the underlying audio.\n */\n\n/**\n * Compute the first `numCoefficients` Type-II DCT coefficients of a 1D\n * signal:\n *\n * X_k = Σ_{n=0..N-1} x_n × cos((π/N) × (n + 0.5) × k), k = 0..K-1\n *\n * No orthonormalization factor applied — caller can divide by\n * `sqrt(N)` (or equivalent) for length-invariance if comparing across\n * variable-length inputs. For length-fixed contexts (like the per-session\n * F0 contour) the un-normalized form is fine.\n *\n * Direct O(N × K) implementation is faster than FFT-DCT for the small K\n * values (≤ 16) we use in the feature pipeline. For N=1200 frames and\n * K=5, the total cost is 6000 cosine evaluations + multiply-adds —\n * sub-millisecond on modern CPUs.\n *\n * Returns an array of length exactly `numCoefficients`. If `numCoefficients`\n * exceeds N, trailing positions are zero. If N is 0 or numCoefficients ≤ 0,\n * returns a zero-padded array of the requested length.\n */\nexport function dctII(input: number[], numCoefficients: number): number[] {\n const N = input.length;\n const K = Math.max(0, numCoefficients);\n const output = new Array(K).fill(0);\n if (N === 0 || K === 0) return output;\n\n const upper = Math.min(K, N);\n const piOverN = Math.PI / N;\n\n for (let k = 0; k < upper; k++) {\n let sum = 0;\n for (let n = 0; n < N; n++) {\n sum += input[n]! * Math.cos(piOverN * (n + 0.5) * k);\n }\n output[k] = sum;\n }\n return output;\n}\n\n/**\n * Encode the shape of a pitch contour as a small number of DCT\n * coefficients suitable for fingerprinting.\n *\n * Pre-processing:\n * 1. Strip unvoiced frames (F0 = 0). Pitch detectors mark frames\n * without detectable voicing as 0; including them in the DCT mixes\n * silence with prosody and dilutes the shape signal.\n * 2. Mean-center the surviving voiced frames so the DC coefficient (X_0)\n * captures shape deviation from the speaker's mean pitch, not the\n * speaker's absolute pitch (which is already encoded in the F0_STATS\n * block of the existing 44 features).\n * 3. Length-normalize the DCT output by `1/sqrt(N)` so two recordings of\n * different durations produce comparable shape vectors.\n *\n * Returns exactly `numCoefficients` floats. If too few voiced frames\n * exist (< 2 × numCoefficients), returns all zeros — short voiced\n * segments produce noisy shape estimates that would hurt\n * discrimination more than help.\n */\nexport function pitchContourShape(\n contour: number[],\n numCoefficients: number = 5,\n): number[] {\n if (numCoefficients <= 0) return [];\n const zero = () => new Array(numCoefficients).fill(0);\n\n // 1. Filter to voiced frames (F0 > 0) and finite values.\n const voiced: number[] = [];\n for (const v of contour) {\n if (Number.isFinite(v) && v > 0) voiced.push(v);\n }\n\n // Require enough voiced frames that the lowest few DCT coefficients are\n // statistically meaningful. 2 × numCoefficients is a coarse heuristic;\n // tighter would risk dropping legitimate short utterances.\n if (voiced.length < numCoefficients * 2) return zero();\n\n // 2. Mean-center.\n let sum = 0;\n for (const v of voiced) sum += v;\n const mu = sum / voiced.length;\n const centered = voiced.map((v) => v - mu);\n\n // 3. DCT and length-normalize.\n const N = centered.length;\n const norm = 1 / Math.sqrt(N);\n return dctII(centered, numCoefficients).map((c) => c * norm);\n}\n\n/**\n * Total feature count produced by `pitchContourShape` with the default\n * `numCoefficients = 5`. Imported by speaker.ts when assembling the\n * final audio feature vector.\n */\nexport const PITCH_CONTOUR_SHAPE_FEATURE_COUNT = 5;\n","/**\n * Cooperative yield to the host environment's event loop.\n *\n * Heavy synchronous work in feature extraction (F0 detection, HNR\n * autocorrelation, LPC formant analysis, Meyda spectral) blocks the\n * main thread for tens to hundreds of milliseconds on a single tight\n * loop. The verify UI sets `processingStage = \"Extracting features...\"`\n * but the spinner can't repaint while the thread is busy — leading to\n * the visible \"stuck\" stage the user reports.\n *\n * Calling `await yieldToMainThread()` between heavy stages hands control\n * back to the browser long enough to flush a paint frame, then resumes.\n * `MessageChannel` is the lowest-overhead path that still rounds through\n * a macrotask (microtasks don't yield to paint). Falls back to\n * `setTimeout(fn, 0)` for non-DOM environments (Node tests, React\n * Native) and a no-op when neither is available.\n */\nexport function yieldToMainThread(): Promise<void> {\n return new Promise<void>((resolve) => {\n if (typeof MessageChannel !== \"undefined\") {\n const channel = new MessageChannel();\n channel.port1.onmessage = () => {\n channel.port1.close();\n resolve();\n };\n channel.port2.postMessage(null);\n return;\n }\n if (typeof setTimeout !== \"undefined\") {\n setTimeout(resolve, 0);\n return;\n }\n resolve();\n });\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, mean as meanOf, variance as varianceOf } from \"./statistics\";\nimport { extractLpcAnalysis } from \"./lpc\";\nimport { extractMfccFeatures, MFCC_FEATURE_COUNT } from \"./mfcc\";\nimport {\n extractVoiceQualityFeatures,\n VOICE_QUALITY_FEATURE_COUNT,\n} from \"./voice-quality\";\nimport { pitchContourShape, PITCH_CONTOUR_SHAPE_FEATURE_COUNT } from \"./dct\";\nimport { yieldToMainThread } from \"../yield\";\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\n// Existing legacy 44 features (preserved at the start of the audio block so\n// the validator's named sub-range constants — JITTER, SHIMMER,\n// LTAS_FLATNESS_VAR, VOICING_RATIO, etc. — keep pointing at the same\n// indices and the TTS detector's threshold checks remain unchanged).\nconst LEGACY_SPEAKER_FEATURE_COUNT = 44;\n\n// LPC coefficient statistics: 12 coefficients × {mean, variance} per\n// coefficient time series.\nconst LPC_COEFFICIENT_STATS = 12 * 2;\n\n// Formant absolute values + dynamics: F1/F2/F3 absolute (6) + F1/F2/F3\n// derivative (6) + F1/F2 bandwidth (4) = 16. F3 bandwidth omitted because\n// LPC pole bandwidth on the 3rd formant is consistently noisier than the\n// underlying frequency signal — keeping it would dilute the block.\nconst FORMANT_TRAJECTORY_FEATURE_COUNT = 16;\n\nconst SPEAKER_FEATURE_COUNT =\n LEGACY_SPEAKER_FEATURE_COUNT +\n MFCC_FEATURE_COUNT +\n LPC_COEFFICIENT_STATS +\n FORMANT_TRAJECTORY_FEATURE_COUNT +\n VOICE_QUALITY_FEATURE_COUNT +\n PITCH_CONTOUR_SHAPE_FEATURE_COUNT;\n// = 44 + 72 + 24 + 16 + 9 + 5 = 170. See\n// docs/master/BLUEPRINT-feature-pipeline-v2.md §2.1.\n// (Audio block shrank 176 → 170 in v3 when MFCC[0] was dropped — see\n// mfcc.ts::MFCC_DROP_LEADING.)\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 * Frame batch size between cooperative yields inside `detectF0Contour`.\n * YIN at 16 kHz / 1024-sample frame is ~1 ms per frame on commodity\n * hardware, so 16 frames ≈ one 60 fps paint budget — yielding here keeps\n * the verify spinner repainting smoothly through the dominant block of\n * extraction work (which the user perceives as the freeze right after\n * the 12 s capture ends, before any other yield site fires).\n */\nconst F0_YIELD_EVERY_N_FRAMES = 16;\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 // Cooperative yield every N frames so the host UI gets a paint frame\n // mid-loop. Skipped on frame 0 (no work done yet) and the last frame\n // (the function returns immediately after).\n if (i > 0 && i < numFrames - 1 && (i % F0_YIELD_EVERY_N_FRAMES) === 0) {\n await yieldToMainThread();\n }\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 // Meyda.extract's third argument is `previousSignal`, NOT options — so\n // passing `{ sampleRate, bufferSize: frameSize }` there is silently\n // ignored. Without setting the globals here, Meyda would use whatever\n // bufferSize the previous extractor in the pipeline left behind (mfcc /\n // voice-quality both set 2048; if they ran first, this function would\n // see 2048; if they didn't run yet, it would see the default 512). That\n // call-order dependency makes the per-frame spectral extractors\n // non-deterministic across pipeline orderings — the exact bug the v2\n // pentest replay assertion (distance must be 0) caught. Set the globals\n // so this extractor is order-independent.\n Meyda.bufferSize = frameSize;\n Meyda.sampleRate = sampleRate;\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 );\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 that are stable across\n * different utterances from the same speaker. Content-independent by\n * 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 server-side analysis can pair it with\n * the motion time-series. Feature vector shape and semantics are\n * 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 // YIN pitch detection is the heaviest single block in the audio path\n // (~120 frames × O(frameSize²)). Yield before HNR + formant extraction\n // so the verify UI can repaint the \"Extracting features...\" spinner.\n await yieldToMainThread();\n\n // Compute per-frame RMS amplitude from the peak-normalized buffer.\n // After the SDK's capture-time RMS normalization, the input `samples`\n // carries stable RMS = TARGET_CAPTURE_RMS for every speaker, so per-\n // frame mean amplitude computed off `samples` would converge to that\n // same value across all users — a wasted feature slot. The peak-\n // normalized `normalizedSamples` (peak = 0.9, variable RMS) preserves\n // dynamic-range identity instead: monotone speakers have higher mean\n // amplitude (more time near peak), expressive speakers have lower mean\n // (more time in valleys). Variance / skewness / kurtosis are scale-\n // invariant either way; switching the source affects only mean.\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, normalizedSamples.length);\n for (let j = start; j < end; j++) {\n sum += (normalizedSamples[j] ?? 0) * (normalizedSamples[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 // HNR autocorrelation is per-frame and synchronous. Yield before LPC\n // formant extraction so a paint frame can land between the two heaviest\n // synchronous stages.\n await yieldToMainThread();\n\n // 7. Formant analysis — single LPC pass surfaces ratios (legacy\n // 8 features), LPC coefficients (24 new), absolute formants + dynamics\n // + bandwidths (16 new). All derived from one autocorrelate +\n // Levinson-Durbin per frame; CPU cost identical to the legacy\n // extractFormantRatios call but the output is much richer.\n const lpc = extractLpcAnalysis(normalizedSamples, sampleRate, frameSize, hopSize);\n const f1f2Stats = condense(lpc.f1f2);\n const f2f3Stats = condense(lpc.f2f3);\n const formantFeatures = [\n f1f2Stats.mean, f1f2Stats.variance, f1f2Stats.skewness, f1f2Stats.kurtosis,\n f2f3Stats.mean, f2f3Stats.variance, f2f3Stats.skewness, f2f3Stats.kurtosis,\n ];\n await yieldToMainThread();\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 // ----- v2 feature pipeline additions -----\n // Each new block appended to the end of the audio vector so the existing\n // 44-feature layout (and the validator's named sub-range constants) stays\n // pinned at indices 0..44.\n\n // 11. MFCC + delta-MFCC stats (72 values total: 12×4 + 12×2 — MFCC[0] dropped)\n await yieldToMainThread();\n const mfccFeatures = await extractMfccFeatures(\n normalizedSamples,\n sampleRate,\n frameSize,\n hopSize,\n );\n\n // 12. LPC coefficient statistics (24 values: 12 coefficients × mean, variance)\n // Derived from the single LPC pass that already ran for the formant block.\n const lpcStats: number[] = [];\n for (let c = 0; c < 12; c++) {\n const track = lpc.lpcCoefficients[c] ?? [];\n const mu = meanOf(track);\n lpcStats.push(mu, varianceOf(track, mu));\n }\n\n // 13. Formant trajectories (16 values):\n // F1/F2/F3 absolute mean+var (6) + derivative mean+var (6) + B1/B2 mean+var (4)\n const f1Stats = { mean: meanOf(lpc.f1), var: varianceOf(lpc.f1) };\n const f2Stats = { mean: meanOf(lpc.f2), var: varianceOf(lpc.f2) };\n const f3Stats = { mean: meanOf(lpc.f3), var: varianceOf(lpc.f3) };\n const f1Delta = derivative(lpc.f1);\n const f2Delta = derivative(lpc.f2);\n const f3Delta = derivative(lpc.f3);\n const f1DeltaMu = meanOf(f1Delta);\n const f2DeltaMu = meanOf(f2Delta);\n const f3DeltaMu = meanOf(f3Delta);\n const b1Mu = meanOf(lpc.b1);\n const b2Mu = meanOf(lpc.b2);\n const formantTrajectoryFeatures = [\n f1Stats.mean, f1Stats.var,\n f2Stats.mean, f2Stats.var,\n f3Stats.mean, f3Stats.var,\n f1DeltaMu, varianceOf(f1Delta, f1DeltaMu),\n f2DeltaMu, varianceOf(f2Delta, f2DeltaMu),\n f3DeltaMu, varianceOf(f3Delta, f3DeltaMu),\n b1Mu, varianceOf(lpc.b1, b1Mu),\n b2Mu, varianceOf(lpc.b2, b2Mu),\n ];\n\n // 14. Voice quality (9 values: CPP, tilt, H1-H2 each mean+var, plus low/mid/high band ratios)\n await yieldToMainThread();\n const voiceQualityFeatures = await extractVoiceQualityFeatures(\n normalizedSamples,\n sampleRate,\n frameSize,\n hopSize,\n f0,\n );\n\n // 15. Pitch contour shape (5 DCT coefficients of the F0 contour)\n // Strict dimensionality reduction: ~1200 voiced frames → 5 coefficients.\n // Captures prosodic shape (rising/falling/modulated) that the existing\n // F0_STATS block doesn't reach.\n const pitchShapeFeatures = pitchContourShape(f0, PITCH_CONTOUR_SHAPE_FEATURE_COUNT);\n\n const features = [\n ...f0Features, // 5 [0..5] F0_STATS\n ...f0DeltaFeatures, // 4 [5..9] F0_DELTA\n ...jitterFeatures, // 4 [9..13] JITTER\n ...shimmerFeatures, // 4 [13..17] SHIMMER\n ...hnrFeatures, // 5 [17..22] HNR\n ...formantFeatures, // 8 [22..30] FORMANT_RATIOS\n ...ltasFeatures, // 8 [30..38] LTAS\n ...voicingFeatures, // 1 [38] VOICING_RATIO\n ...ampFeatures, // 5 [39..44] AMPLITUDE\n ...mfccFeatures, // 72 [44..116] MFCC + delta-MFCC (MFCC[0] dropped)\n ...lpcStats, // 24 [116..140] LPC coefficient stats\n ...formantTrajectoryFeatures, // 16 [140..156] Formant absolutes + dynamics + bandwidths\n ...voiceQualityFeatures, // 9 [156..165] Voice quality\n ...pitchShapeFeatures, // 5 [165..170] Pitch contour shape DCT\n ]; // = 170\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 server-side 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","/**\n * Real-input radix-2 Cooley-Tukey FFT and frequency-band energy / peak\n * helpers used by the v2 kinematic feature pipeline.\n *\n * Used to extract physiological-tremor signatures and motion frequency-band\n * energies from IMU axes (~50–200 Hz sample rates, ~600–2400 sample\n * windows). See `docs/master/BLUEPRINT-feature-pipeline-v2.md` §2.2.\n *\n * Why a custom FFT and not Meyda: Meyda's spectral extractors are\n * tuned for audio frame sizes (≥ 512 samples at 16 kHz) and bake in\n * audio-specific assumptions (Hanning window, magnitude scaling, frame\n * indexing). Kinematic signals are short, low-rate, and analyzed once\n * per session — a self-contained radix-2 implementation is simpler\n * and avoids leaking Meyda's global state into the motion path\n * (which would interfere with the speaker-extractor invariants set up\n * in speaker.ts / mfcc.ts / voice-quality.ts).\n *\n * @privacyGuarantee This module operates on already-on-device sensor\n * arrays. Outputs are reduced to a small number of band-energy /\n * peak-frequency scalars before leaving the SDK; the FFT itself is\n * never transmitted.\n */\n\n/** Round up to the next power of two, minimum 2. */\nfunction nextPow2(n: number): number {\n if (n <= 2) return 2;\n let p = 2;\n while (p < n) p <<= 1;\n return p;\n}\n\n/**\n * Compute the radix-2 FFT of a real-valued input. Input is zero-padded (or\n * truncated) to the requested `size`, which must be a power of two — use\n * `nextPow2(input.length)` to pick a sensible size.\n *\n * Returns `{ real, imag }` arrays of length `size`. Bin k corresponds to\n * frequency `k × sampleRate / size` Hz. By Hermitian symmetry only the\n * first `size / 2 + 1` bins are physically meaningful for real input;\n * downstream helpers (`bandEnergy`, `peakInBand`) account for this\n * automatically.\n */\nexport function realFFT(\n input: number[],\n size: number,\n): { real: number[]; imag: number[] } {\n if (size <= 0 || (size & (size - 1)) !== 0) {\n throw new Error(`FFT size must be a positive power of two, got ${size}`);\n }\n\n const real = new Array<number>(size);\n const imag = new Array<number>(size).fill(0);\n\n for (let i = 0; i < size; i++) {\n real[i] = i < input.length ? (input[i] ?? 0) : 0;\n }\n\n // Bit-reversal permutation.\n for (let i = 1, j = 0; i < size; i++) {\n let bit = size >> 1;\n for (; j & bit; bit >>= 1) j ^= bit;\n j ^= bit;\n if (i < j) {\n const tr = real[i]!;\n real[i] = real[j]!;\n real[j] = tr;\n // imag is all-zero pre-permutation, so no swap needed there.\n }\n }\n\n // Cooley-Tukey butterflies.\n for (let halfSize = 1; halfSize < size; halfSize <<= 1) {\n const fullSize = halfSize << 1;\n const phaseStep = -Math.PI / halfSize;\n for (let chunkStart = 0; chunkStart < size; chunkStart += fullSize) {\n for (let k = 0; k < halfSize; k++) {\n const phase = phaseStep * k;\n const wr = Math.cos(phase);\n const wi = Math.sin(phase);\n const ar = real[chunkStart + k]!;\n const ai = imag[chunkStart + k]!;\n const br = real[chunkStart + k + halfSize]!;\n const bi = imag[chunkStart + k + halfSize]!;\n const tr = wr * br - wi * bi;\n const ti = wr * bi + wi * br;\n real[chunkStart + k] = ar + tr;\n imag[chunkStart + k] = ai + ti;\n real[chunkStart + k + halfSize] = ar - tr;\n imag[chunkStart + k + halfSize] = ai - ti;\n }\n }\n }\n\n return { real, imag };\n}\n\n/**\n * Sum the squared magnitudes of FFT bins falling inside the half-open\n * frequency interval [`fLow`, `fHigh`) Hz, NORMALIZED by `N²` so the\n * result is a per-bin power density in the same units as the squared\n * input signal (not Parseval N²-scaled energy).\n *\n * Why normalize: an unscaled `Σ|X[k]|²` grows as O(N²·A²) for a sine\n * of amplitude A on N samples, which would put band energies 10,000×\n * larger than other motion features (O(0.01-1)) and dominate the\n * z-score normalization in `statistics.ts::normalizeGroup`. Dividing\n * by `N²` aligns the band energy with the squared-signal scale and\n * lets it sit alongside other motion moments cleanly.\n *\n * Out-of-range or NaN/Infinity inputs return 0 — never throw — so a\n * malformed sensor capture downstream produces a deterministic zero\n * feature instead of a crash.\n */\nexport function bandEnergy(\n real: number[],\n imag: number[],\n sampleRate: number,\n fLow: number,\n fHigh: number,\n): number {\n const N = real.length;\n if (\n N === 0 ||\n !Number.isFinite(sampleRate) ||\n sampleRate <= 0 ||\n fLow >= fHigh ||\n fLow < 0\n ) {\n return 0;\n }\n\n // Bin k → frequency k × sampleRate / N. Only positive frequencies are\n // physically meaningful for real input.\n const binHz = sampleRate / N;\n const kLow = Math.max(0, Math.ceil(fLow / binHz));\n const kHigh = Math.min(Math.floor(N / 2), Math.floor((fHigh - 1e-9) / binHz));\n\n let energy = 0;\n for (let k = kLow; k <= kHigh; k++) {\n const re = real[k] ?? 0;\n const im = imag[k] ?? 0;\n energy += re * re + im * im;\n }\n return energy / (N * N);\n}\n\n/**\n * Return the dominant frequency (Hz) and its squared-magnitude amplitude\n * (normalized by `N²` for the same reason as `bandEnergy`) in the\n * half-open frequency interval [`fLow`, `fHigh`) Hz.\n *\n * If no bin falls inside the band (e.g. capture is too short to resolve\n * the requested band), returns `{ freq: 0, amplitude: 0 }`. Used by the\n * kinematic tremor block to detect physiological-tremor signatures in\n * the 4–12 Hz range.\n */\nexport function peakInBand(\n real: number[],\n imag: number[],\n sampleRate: number,\n fLow: number,\n fHigh: number,\n): { freq: number; amplitude: number } {\n const N = real.length;\n if (\n N === 0 ||\n !Number.isFinite(sampleRate) ||\n sampleRate <= 0 ||\n fLow >= fHigh ||\n fLow < 0\n ) {\n return { freq: 0, amplitude: 0 };\n }\n\n const binHz = sampleRate / N;\n const kLow = Math.max(0, Math.ceil(fLow / binHz));\n const kHigh = Math.min(Math.floor(N / 2), Math.floor((fHigh - 1e-9) / binHz));\n\n let bestK = -1;\n let bestAmp = -Infinity;\n for (let k = kLow; k <= kHigh; k++) {\n const re = real[k] ?? 0;\n const im = imag[k] ?? 0;\n const amp = re * re + im * im;\n if (amp > bestAmp) {\n bestAmp = amp;\n bestK = k;\n }\n }\n if (bestK < 0) return { freq: 0, amplitude: 0 };\n return { freq: bestK * binHz, amplitude: bestAmp / (N * N) };\n}\n\nexport { nextPow2 };\n","import type { MotionSample, TouchSample } from \"../sensor/types\";\nimport { condense, mean, variance, entropy, autocorrelation } from \"./statistics\";\nimport { realFFT, bandEnergy, peakInBand, nextPow2 } from \"./fft\";\n\n// v2 motion block widens 54 → 81: 54 legacy (jerk + jounce stats × 6 axes,\n// jitter variance × 6) followed by 27 new features. Order is fixed by\n// `MOTION_FEATURE_COUNT` and asserted in tests/extraction.test.ts.\nexport const MOTION_LEGACY_COUNT = 54;\nexport const MOTION_V2_ADDITIONS = 27;\nexport const MOTION_FEATURE_COUNT = MOTION_LEGACY_COUNT + MOTION_V2_ADDITIONS;\n\n// v2 touch block widens 36 → 57: 36 legacy followed by 21 new features.\nexport const TOUCH_LEGACY_COUNT = 36;\nexport const TOUCH_V2_ADDITIONS = 21;\nexport const TOUCH_FEATURE_COUNT = TOUCH_LEGACY_COUNT + TOUCH_V2_ADDITIONS;\n\n// Mouse-dynamics keeps width parity with the motion block so that desktop\n// captures fuse cleanly into the same fingerprint slot as mobile IMU\n// captures. The first 54 entries are the legacy mouse-dynamics features;\n// the remaining 27 are zero (no IMU on desktop).\n//\n// Why zero-padding doesn't break SimHash bit-influence parity (verified\n// algebraically): `normalizeGroup` z-scores the 81-element block. With 27\n// zeros, the padded variance equals (54/81) × pure_variance, so the\n// padded std equals √(2/3) × pure_std ≈ 0.816 × pure_std. After dividing\n// by the padded std, real features scale by 1/0.816 ≈ 1.225, and zero\n// padding stays at -mean/std (≈ 0 when the real-feature mean is small).\n// The collective variance of the 81-element normalized block is exactly\n// 1 by construction (z-score guarantee), so the modality contributes the\n// same expected variance to the SimHash random-projection dot product\n// as the mobile case (also a unit-variance 81-element block). The\n// per-feature magnitude of real features inflates by 22% on desktop;\n// the per-modality bit-influence share stays equal.\nexport const MOUSE_DYNAMICS_FEATURE_COUNT = MOTION_FEATURE_COUNT;\n\n/**\n * Compute per-sample acceleration magnitude |a| = √(ax² + ay² + az²) and\n * linearly resample to a target frame count. Surfaced for server-side\n * analysis paired against the F0 contour; the two time-series must share\n * the same frame count when consumed downstream.\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 *\n * Layout (`MOTION_FEATURE_COUNT = 81`):\n * `[0..48)` legacy: 6 axes × (jerk stats 4 + jounce stats 4)\n * `[48..54)` legacy: jitter variance per axis (6)\n * `[54..60)` v2: cross-axis covariance (6 selected pairs)\n * `[60..72)` v2: FFT band energy in {0-2, 2-6, 6-12, 12-30} Hz × {ax, ay, az}\n * `[72..74)` v2: physiological tremor peak frequency + amplitude (4-12 Hz)\n * `[74..76)` v2: direction-reversal rate per axis: mean, variance across {ax, ay, az}\n * `[76]` v2: mean angular velocity (|gyro| over the capture)\n * `[77..81)` v2: motion-magnitude autocorrelation at lags {1, 5, 10, 25}\n *\n * @privacyGuarantee Operates on already-on-device IMU samples and emits\n * statistical / spectral aggregates (variances, covariances, band sums,\n * autocorrelation scalars). The full sample stream is never transmitted.\n */\nexport function extractMotionFeatures(samples: MotionSample[]): number[] {\n if (samples.length < 5) return new Array(MOTION_FEATURE_COUNT).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 // Captures temporal fluctuation in the motion signal.\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 // ---- v2 additions ----\n features.push(...computeMotionV2(axes, samples));\n\n return features;\n}\n\n/**\n * v2 motion additions (27 features). Pulled into a dedicated helper so the\n * legacy 54-feature block stays isolated and visually identifiable in the\n * git history of `extractMotionFeatures`.\n */\nfunction computeMotionV2(\n axes: Record<\"ax\" | \"ay\" | \"az\" | \"gx\" | \"gy\" | \"gz\", number[]>,\n samples: MotionSample[]\n): number[] {\n const out: number[] = [];\n\n // 1. Cross-axis covariance — 6 selected pairs (per blueprint §2.2). The\n // pairs target identity-bearing motor coordinations: accel-gyro coupling\n // (ax-gy, ay-gx, az-gz) for natural hand sway, accel-accel coupling\n // (ax-az, ay-az) for axis-of-grip leakage, and gyro-gyro coupling\n // (gx-gy) for wrist-rotation patterns.\n const covPairs: Array<[number[], number[]]> = [\n [axes.ax, axes.gy],\n [axes.ay, axes.gx],\n [axes.az, axes.gz],\n [axes.ax, axes.az],\n [axes.ay, axes.az],\n [axes.gx, axes.gy],\n ];\n for (const [a, b] of covPairs) out.push(covariance(a, b));\n\n // 2. FFT band energy on the 3 accelerometer axes.\n // Sample rate is recovered from timestamps so we report energy in\n // physical Hz rather than bin units (IMU rates vary 50-200 Hz across\n // devices).\n const sampleRate = sampleRateFromTimestamps(samples.map((s) => s.timestamp));\n const fftSize = nextPow2(Math.max(64, axes.ax.length));\n const bands: Array<[number, number]> = [\n [0, 2],\n [2, 6],\n [6, 12],\n [12, 30],\n ];\n\n // Pre-FFT each accel axis once; reuse the spectra for both band-energy\n // and the magnitude path below.\n const accelSpectra = [axes.ax, axes.ay, axes.az].map((axis) =>\n realFFT(meanCenter(axis), fftSize)\n );\n for (const spectrum of accelSpectra) {\n for (const [lo, hi] of bands) {\n out.push(bandEnergy(spectrum.real, spectrum.imag, sampleRate, lo, hi));\n }\n }\n\n // 3. Physiological-tremor peak (4-12 Hz) on motion magnitude.\n const magnitude = samples.map((s) =>\n Math.sqrt(s.ax * s.ax + s.ay * s.ay + s.az * s.az)\n );\n const magSpectrum = realFFT(meanCenter(magnitude), fftSize);\n const tremor = peakInBand(\n magSpectrum.real,\n magSpectrum.imag,\n sampleRate,\n 4,\n 12\n );\n out.push(tremor.freq, tremor.amplitude);\n\n // 4. Direction-reversal rate per second per accel axis (mean, variance).\n // A \"reversal\" here is a sign change of jerk (= the derivative of\n // acceleration). Counting on jerk rather than raw acceleration removes\n // the gravity DC bias on the vertical axis (raw az hovers around -9.8\n // and rarely crosses zero) and captures the rate of micro-correction\n // events on each axis. Rate is normalized by capture duration so it's\n // dimension-stable across IMU sample-rates. Mean + variance over the\n // 3 accel axes captures both how busy the user's motion is and which\n // axis dominates — a per-axis dominance pattern that's identity-bearing.\n const duration = captureDurationSec(samples);\n const reversalRates = [axes.ax, axes.ay, axes.az].map((axis) =>\n duration > 0 ? signChangeCount(derivative(axis)) / duration : 0\n );\n out.push(mean(reversalRates), variance(reversalRates));\n\n // 5. Mean angular velocity (|gyro| over the capture).\n let gyroSum = 0;\n for (let i = 0; i < samples.length; i++) {\n const gx = samples[i]!.gx;\n const gy = samples[i]!.gy;\n const gz = samples[i]!.gz;\n gyroSum += Math.sqrt(gx * gx + gy * gy + gz * gz);\n }\n out.push(samples.length > 0 ? gyroSum / samples.length : 0);\n\n // 6. Motion-magnitude autocorrelation at lags 1, 5, 10, 25 — captures\n // periodic structure (gait, tremor harmonics) that escapes the\n // moment-based features. Lags chosen to span the physiological-tremor\n // band: at a typical 60 Hz IMU rate, lag 5 ≈ 83 ms (12 Hz cycle), lag\n // 10 ≈ 167 ms (6 Hz), lag 25 ≈ 417 ms (sub-tremor, gait-rate signal).\n // The asymmetry vs touch's autocorrelation lags (1, 3, 5) is intentional\n // — touch captures finer rhythms (50-100 ms inter-event coherence)\n // while motion captures slower oscillatory patterns.\n for (const lag of [1, 5, 10, 25]) {\n out.push(autocorrelation(magnitude, lag));\n }\n\n return out;\n}\n\n/**\n * Extract kinematic features from touch data.\n *\n * Layout (`TOUCH_FEATURE_COUNT = 57`):\n * `[0..32)` legacy: velocity / accel / pressure / area / jerk stats (32)\n * `[32..36)` legacy: jitter variance for {vx, vy, pressure, area} (4)\n * `[36..40)` v2: pressure first-derivative stats (mean, var, skew, kurt)\n * `[40..42)` v2: contact aspect-ratio stats (mean, var)\n * `[42..44)` v2: contact-area first-derivative stats (mean, var)\n * `[44..47)` v2: trajectory curvature stats (mean, var, skew)\n * `[47..50)` v2: velocity autocorrelation at lags {1, 3, 5}\n * `[50..54)` v2: inter-touch gap duration stats (mean, var, skew, kurt)\n * `[54]` v2: path efficiency (straight-line / total path length)\n * `[55..57)` v2: per-stroke total path length: mean, variance\n *\n * @privacyGuarantee Operates on already-on-device touch samples and emits\n * statistical aggregates only. The full coordinate stream is never\n * transmitted; downstream phase-content (e.g. typed text) is not\n * recoverable from the per-stroke summaries.\n */\nexport function extractTouchFeatures(samples: TouchSample[]): number[] {\n if (samples.length < 5) return new Array(TOUCH_FEATURE_COUNT).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 // ---- v2 additions ----\n features.push(...computeTouchV2(samples, vx, vy));\n\n return features;\n}\n\n/**\n * v2 touch additions (21 features). Pulled into a helper so the legacy\n * 36-feature block stays a visually identifiable unit.\n */\nfunction computeTouchV2(\n samples: TouchSample[],\n vx: number[],\n vy: number[]\n): number[] {\n const out: number[] = [];\n\n // 1. Pressure first-derivative stats (4) — temporal RATE of pressure\n // variation, complementing the existing pressure mean/var/skew/kurt.\n const pressure = samples.map((s) => s.pressure);\n const dPressure = derivative(pressure);\n out.push(...Object.values(condense(dPressure)));\n\n // 2. Contact aspect ratio stats (mean, variance). width/height captures\n // finger-vs-thumb-vs-stylus identity even when raw area drifts.\n const aspect = samples.map((s) => {\n const h = s.height;\n return h > 0 ? s.width / h : 0;\n });\n out.push(mean(aspect), variance(aspect));\n\n // 3. Contact-area first-derivative stats (mean, variance) — rate of\n // pressure-spread change, a finer-grained signal than raw area moments.\n const area = samples.map((s) => s.width * s.height);\n const dArea = derivative(area);\n out.push(mean(dArea), variance(dArea));\n\n // 4. Trajectory curvature stats (mean, var, skew). Curvature is the\n // absolute angle change between successive velocity vectors —\n // identity-bearing motor coordination. Skip rest-frames where either\n // velocity vector is below `CURVATURE_REST_EPS` because `atan2(0, 0)`\n // returns 0 silently, which would inject a spurious large curvature\n // spike whenever motion resumes from a pause.\n const CURVATURE_REST_EPS = 1e-3;\n const curvatures: number[] = [];\n for (let i = 1; i < vx.length; i++) {\n const v1x = vx[i - 1] ?? 0;\n const v1y = vy[i - 1] ?? 0;\n const v2x = vx[i] ?? 0;\n const v2y = vy[i] ?? 0;\n if (\n Math.hypot(v1x, v1y) < CURVATURE_REST_EPS ||\n Math.hypot(v2x, v2y) < CURVATURE_REST_EPS\n ) {\n continue;\n }\n const a1 = Math.atan2(v1y, v1x);\n const a2 = Math.atan2(v2y, v2x);\n let d = a2 - a1;\n while (d > Math.PI) d -= 2 * Math.PI;\n while (d < -Math.PI) d += 2 * Math.PI;\n curvatures.push(Math.abs(d));\n }\n const curvStats = condense(curvatures);\n out.push(curvStats.mean, curvStats.variance, curvStats.skewness);\n\n // 5. Velocity-magnitude autocorrelation at short lags — captures rhythm\n // in touch motion below the resolution of moment statistics.\n const speed = vx.map((dx, i) => {\n const dy = vy[i] ?? 0;\n return Math.sqrt(dx * dx + dy * dy);\n });\n for (const lag of [1, 3, 5]) out.push(autocorrelation(speed, lag));\n\n // 6. Inter-touch gap duration stats (mean, var, skew, kurt). Gaps are\n // the millisecond intervals between successive touch events — touch\n // rhythm is highly individual (think tap cadence vs swipe cadence).\n const gaps: number[] = [];\n for (let i = 1; i < samples.length; i++) {\n gaps.push((samples[i]?.timestamp ?? 0) - (samples[i - 1]?.timestamp ?? 0));\n }\n out.push(...Object.values(condense(gaps)));\n\n // 7. Path efficiency = straight-line displacement / total path length.\n // 1.0 = perfectly straight movement, near-0 = highly tortuous.\n const totalPath = speed.reduce((a, b) => a + b, 0);\n const dx = (samples[samples.length - 1]?.x ?? 0) - (samples[0]?.x ?? 0);\n const dy = (samples[samples.length - 1]?.y ?? 0) - (samples[0]?.y ?? 0);\n const straight = Math.sqrt(dx * dx + dy * dy);\n out.push(totalPath > 0 ? straight / totalPath : 0);\n\n // 8. Per-stroke total path length: split on speed troughs (≤ 0.5 px/sample\n // from rest, matching the mouse-dynamics pause threshold), then take\n // mean and variance. Captures motor-planning style — burst-then-pause\n // vs continuous-glide users.\n const strokeLengths = perStrokePathLengths(speed);\n out.push(mean(strokeLengths), variance(strokeLengths));\n\n return out;\n}\n\n/** Split a speed series into stroke segments at rest-points and return\n * the cumulative speed (≈ path length in pixels) of each stroke.\n * A \"stroke\" is a contiguous run of speed ≥ threshold. */\nfunction perStrokePathLengths(speed: number[]): number[] {\n const PAUSE_THRESHOLD = 0.5;\n const lengths: number[] = [];\n let acc = 0;\n let inStroke = false;\n for (const s of speed) {\n if (s >= PAUSE_THRESHOLD) {\n acc += s;\n inStroke = true;\n } else if (inStroke) {\n lengths.push(acc);\n acc = 0;\n inStroke = false;\n }\n }\n if (inStroke && acc > 0) lengths.push(acc);\n return lengths;\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/** Subtract the arithmetic mean from a series; returns a new array. */\nfunction meanCenter(values: number[]): number[] {\n if (values.length === 0) return [];\n let sum = 0;\n for (const v of values) sum += v;\n const m = sum / values.length;\n return values.map((v) => v - m);\n}\n\n/** Sample covariance Cov(a, b) = mean((a-mean(a))(b-mean(b))). */\nfunction covariance(a: number[], b: number[]): number {\n const n = Math.min(a.length, b.length);\n if (n < 2) return 0;\n let sumA = 0;\n let sumB = 0;\n for (let i = 0; i < n; i++) {\n sumA += a[i] ?? 0;\n sumB += b[i] ?? 0;\n }\n const meanA = sumA / n;\n const meanB = sumB / n;\n let cov = 0;\n for (let i = 0; i < n; i++) {\n cov += ((a[i] ?? 0) - meanA) * ((b[i] ?? 0) - meanB);\n }\n return cov / (n - 1);\n}\n\n/** Count strict sign changes (zero-crossings excluding zero-runs). */\nfunction signChangeCount(values: number[]): number {\n let count = 0;\n let last = 0;\n for (const v of values) {\n if (v > 0 && last < 0) count++;\n else if (v < 0 && last > 0) count++;\n if (v !== 0) last = v;\n }\n return count;\n}\n\n/**\n * Recover the sample rate (Hz) from a millisecond-timestamped sensor\n * stream. Returns 0 when the input is too short to estimate or contains\n * non-monotone timestamps (defensive — pulse.ts caps this with a default\n * downstream so 0 propagates as \"no spectral feature available\").\n */\nfunction sampleRateFromTimestamps(timestampsMs: number[]): number {\n if (timestampsMs.length < 2) return 0;\n const span = (timestampsMs[timestampsMs.length - 1] ?? 0) - (timestampsMs[0] ?? 0);\n if (!Number.isFinite(span) || span <= 0) return 0;\n return ((timestampsMs.length - 1) * 1000) / span;\n}\n\n/** Capture duration in seconds from a millisecond-timestamped sample set. */\nfunction captureDurationSec(\n samples: Array<{ timestamp: number }>\n): number {\n if (samples.length < 2) return 0;\n const span =\n (samples[samples.length - 1]?.timestamp ?? 0) -\n (samples[0]?.timestamp ?? 0);\n return Number.isFinite(span) && span > 0 ? span / 1000 : 0;\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: `MOUSE_DYNAMICS_FEATURE_COUNT` (= `MOTION_FEATURE_COUNT`) values.\n * The first 54 entries are the legacy mouse-dynamics signal; the trailing\n * v2-block slots stay zero on desktop so the per-modality bit-influence\n * share matches a mobile IMU capture under the new pipeline.\n */\nexport function extractMouseDynamics(samples: TouchSample[]): number[] {\n if (samples.length < 10) return new Array(MOUSE_DYNAMICS_FEATURE_COUNT).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 const legacyMouseDynamics = [\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 // Mouse V2 additions — 27 features mirroring `computeMotionV2`'s layout\n // exactly so desktop and mobile fingerprints share parallel structure\n // in the same indices. Replaces the original zero-padding scheme that\n // contributed ~85 deterministic bits across all desktop users (the\n // May-2026 cross-person Hamming collision contributor for the motion\n // block). Real signals fill every slot from the same mouse data the\n // legacy 54 features already consume, so no new sensor access required.\n const v2 = computeMouseV2(samples, vx, vy, accX, accY, speed, acc, jerk, directions);\n return [...legacyMouseDynamics, ...v2];\n}\n\n/**\n * v2 mouse-dynamics additions (27 features). Pulled into a dedicated\n * helper that mirrors `computeMotionV2` index-for-index so desktop and\n * mobile fingerprints have parallel semantic structure. All inputs are\n * already computed in the calling `extractMouseDynamics` scope; passing\n * them through avoids a second pass over the touch sample stream.\n *\n * Layout (relative to mouse block start):\n * `[54..60)` cross-axis covariance: 6 pairs from {vx, vy, accX, accY}\n * `[60..72)` FFT band energy {0-2, 2-6, 6-12, 12-30} Hz × {speed, acc, jerk}\n * `[72..74)` physiological tremor peak (4-12 Hz) on speed: freq + amplitude\n * `[74..76)` reversal-rate-per-second per channel {vx, vy, speed}: mean + variance\n * `[76]` mean angular speed (mean |Δdirection|)\n * `[77..81)` speed-magnitude autocorrelation at lags {1, 5, 10, 25}\n */\nfunction computeMouseV2(\n samples: TouchSample[],\n vx: number[],\n vy: number[],\n accX: number[],\n accY: number[],\n speed: number[],\n acc: number[],\n jerk: number[],\n directions: number[],\n): number[] {\n const out: number[] = [];\n\n // 1. Cross-axis covariance — 6 unique pairs from the 4-channel\n // {vx, vy, accX, accY} basis. Captures motor-coordination signature:\n // vx-vy coupling (handedness), velocity-acceleration coupling per axis\n // (motor-control style), and X/Y acceleration coupling (cursor-gesture\n // diagonality preference). The mouse equivalent of `computeMotionV2`'s\n // accel-gyro-and-axes pairings.\n const covPairs: Array<[number[], number[]]> = [\n [vx, vy],\n [vx, accX],\n [vx, accY],\n [vy, accX],\n [vy, accY],\n [accX, accY],\n ];\n for (const [a, b] of covPairs) out.push(covariance(a, b));\n\n // 2. FFT band energy on 3 channels: speed, acc, jerk magnitudes. Sample\n // rate is recovered from timestamps so band boundaries are reported in\n // physical Hz across mouse-event rates that vary 60-125 Hz across\n // browsers and OSs. Pre-FFT each channel once; reuse the speed\n // spectrum for the tremor peak below.\n const sampleRate = sampleRateFromTimestamps(samples.map((s) => s.timestamp));\n const fftSize = nextPow2(Math.max(64, speed.length));\n const bands: Array<[number, number]> = [\n [0, 2],\n [2, 6],\n [6, 12],\n [12, 30],\n ];\n const speedSpectrum = realFFT(meanCenter(speed), fftSize);\n const accSpectrum = realFFT(meanCenter(acc), fftSize);\n const jerkSpectrum = realFFT(meanCenter(jerk), fftSize);\n for (const spectrum of [speedSpectrum, accSpectrum, jerkSpectrum]) {\n for (const [lo, hi] of bands) {\n out.push(bandEnergy(spectrum.real, spectrum.imag, sampleRate, lo, hi));\n }\n }\n\n // 3. Physiological-tremor peak (4-12 Hz) on speed magnitude. Mouse-using\n // hands carry the same 4-12 Hz physiological tremor as IMU-tracked hands;\n // it surfaces in cursor-speed envelope as a small periodic component\n // riding on top of intentional motion.\n const tremor = peakInBand(\n speedSpectrum.real,\n speedSpectrum.imag,\n sampleRate,\n 4,\n 12,\n );\n out.push(tremor.freq, tremor.amplitude);\n\n // 4. Reversal rate per second per channel (mean, variance across\n // {vx, vy, speed}). Sign change of the channel's first derivative\n // counts micro-corrections — wrist-style movements differ across\n // people in both rate and per-axis distribution.\n const duration = captureDurationSec(samples);\n const reversalRates = [vx, vy, speed].map((channel) =>\n duration > 0 ? signChangeCount(derivative(channel)) / duration : 0,\n );\n out.push(mean(reversalRates), variance(reversalRates));\n\n // 5. Mean angular speed: mean of unwrapped |Δdirection|. Captures\n // overall steering activity — looser-grip hands change direction more\n // often than precision-grip hands. Equivalent to motion's mean |gyro|.\n let dirAccum = 0;\n for (let i = 1; i < directions.length; i++) {\n let diff = directions[i]! - directions[i - 1]!;\n while (diff > Math.PI) diff -= 2 * Math.PI;\n while (diff < -Math.PI) diff += 2 * Math.PI;\n dirAccum += Math.abs(diff);\n }\n out.push(directions.length > 1 ? dirAccum / (directions.length - 1) : 0);\n\n // 6. Speed-magnitude autocorrelation at lags 1, 5, 10, 25 — captures\n // periodic structure (drag rhythms, repeated sub-gestures) that escapes\n // moment-based features. Lag choices match motion v2 so the fingerprint\n // band-by-band layout stays parallel across device classes.\n for (const lag of [1, 5, 10, 25]) {\n out.push(autocorrelation(speed, lag));\n }\n\n // Defensive finite-cast: any helper that hits an edge case (zero-length\n // spectrum, constant channel, sub-1-sample direction series) should\n // return 0 rather than NaN/Infinity, matching the SDK's \"feature vector\n // is always finite\" contract enforced by the validator's NonFinite check.\n return out.map((v) => (Number.isFinite(v) ? v : 0));\n}\n","import { FINGERPRINT_BITS, SIMHASH_SEED } from \"../config\";\nimport { SPEAKER_FEATURE_COUNT } from \"../extraction/speaker\";\nimport {\n MOTION_FEATURE_COUNT,\n TOUCH_FEATURE_COUNT,\n} from \"../extraction/kinematic\";\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 */\n// v3 feature pipeline: composed from the canonical per-modality counts\n// exported by their respective extractors so a future modality bump in\n// `speaker.ts` or `kinematic.ts` propagates without manual sync.\n// - Speaker: 44 legacy + 72 MFCC (12×4 + 12×2, MFCC[0] dropped)\n// + 24 LPC + 16 formant trajectories + 9 voice quality\n// + 5 pitch DCT = 170.\n// - Motion: 54 legacy + 27 v2 (cross-axis covariance,\n// FFT band energy, tremor peak, direction-reversal stats, motion\n// autocorrelation) = 81.\n// - Touch: 36 legacy + 21 v2 (pressure derivative, contact\n// geometry, curvature, velocity autocorrelation, gap distribution,\n// path efficiency) = 57.\n// Total: 308. The constant is a soft warning gate (mismatch logs but\n// the hash still computes), so a stale-baseline session under an\n// upgrading SDK degrades gracefully rather than failing — the user\n// routes through the existing reset-baseline migration path.\nconst EXPECTED_FEATURE_DIMENSION =\n SPEAKER_FEATURE_COUNT + MOTION_FEATURE_COUNT + TOUCH_FEATURE_COUNT;\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","{\n \"address\": \"GZYwTp2ozeuRA5Gof9vs4ya961aANcJBdUzB7LN6q4b2\",\n \"metadata\": {\n \"name\": \"entros_anchor\",\n \"version\": \"0.1.0\",\n \"spec\": \"0.1.0\",\n \"description\": \"Non-transferable identity token for Entros Protocol\"\n },\n \"docs\": [\n \"Mint account space for Token-2022 with NonTransferable extension.\",\n \"Base mint = 82 bytes, account type = 1 byte, extension type (2) + length (2) = 4 bytes,\",\n \"NonTransferable data = 0 bytes. Plus multisig padding from Token-2022.\",\n \"We use a constant derived from the Token-2022 spec.\"\n ],\n \"instructions\": [\n {\n \"name\": \"authorize_new_wallet\",\n \"docs\": [\n \"Authorize a new wallet by 2 signers. This can be done many times before invoking migrate_identity()\"\n ],\n \"discriminator\": [\n 178,\n 186,\n 185,\n 108,\n 51,\n 219,\n 107,\n 197\n ],\n \"accounts\": [\n {\n \"name\": \"signer\",\n \"writable\": true,\n \"signer\": true\n },\n {\n \"name\": \"identity_state\",\n \"writable\": true,\n \"pda\": {\n \"seeds\": [\n {\n \"kind\": \"const\",\n \"value\": [\n 105,\n 100,\n 101,\n 110,\n 116,\n 105,\n 116,\n 121\n ]\n },\n {\n \"kind\": \"account\",\n \"path\": \"signer\"\n }\n ]\n }\n },\n {\n \"name\": \"signer_new\",\n \"writable\": true,\n \"signer\": true\n },\n {\n \"name\": \"token_program\"\n },\n {\n \"name\": \"mint\",\n \"writable\": true,\n \"pda\": {\n \"seeds\": [\n {\n \"kind\": \"const\",\n \"value\": [\n 109,\n 105,\n 110,\n 116\n ]\n },\n {\n \"kind\": \"account\",\n \"path\": \"signer\"\n }\n ]\n }\n },\n {\n \"name\": \"token_account\",\n \"writable\": true,\n \"pda\": {\n \"seeds\": [\n {\n \"kind\": \"account\",\n \"path\": \"signer\"\n },\n {\n \"kind\": \"account\",\n \"path\": \"token_program\"\n },\n {\n \"kind\": \"account\",\n \"path\": \"mint\"\n }\n ],\n \"program\": {\n \"kind\": \"const\",\n \"value\": [\n 140,\n 151,\n 37,\n 143,\n 78,\n 36,\n 137,\n 241,\n 187,\n 61,\n 16,\n 41,\n 20,\n 142,\n 13,\n 131,\n 11,\n 90,\n 19,\n 153,\n 218,\n 255,\n 16,\n 132,\n 4,\n 142,\n 123,\n 216,\n 219,\n 233,\n 248,\n 89\n ]\n }\n }\n }\n ],\n \"args\": []\n },\n {\n \"name\": \"migrate_identity\",\n \"docs\": [\n \"Migrate from an user's old Anchor IdentityState PDA to a new one\",\n \"After this function call, the orphaned 0-balance ATA, pointing at a closed mint, locks ~0.002 SOL of rent. This ATA can be recovered by the old wallet calling closeAccount()\"\n ],\n \"discriminator\": [\n 161,\n 192,\n 70,\n 80,\n 47,\n 37,\n 26,\n 10\n ],\n \"accounts\": [\n {\n \"name\": \"user\",\n \"writable\": true,\n \"signer\": true\n },\n {\n \"name\": \"identity_state\",\n \"writable\": true,\n \"pda\": {\n \"seeds\": [\n {\n \"kind\": \"const\",\n \"value\": [\n 105,\n 100,\n 101,\n 110,\n 116,\n 105,\n 116,\n 121\n ]\n },\n {\n \"kind\": \"account\",\n \"path\": \"user\"\n }\n ]\n }\n },\n {\n \"name\": \"mint\",\n \"docs\": [\n \"initialization ordering. PDA seeds ensure uniqueness per user.\"\n ],\n \"writable\": true,\n \"pda\": {\n \"seeds\": [\n {\n \"kind\": \"const\",\n \"value\": [\n 109,\n 105,\n 110,\n 116\n ]\n },\n {\n \"kind\": \"account\",\n \"path\": \"user\"\n }\n ]\n }\n },\n {\n \"name\": \"mint_authority\",\n \"pda\": {\n \"seeds\": [\n {\n \"kind\": \"const\",\n \"value\": [\n 109,\n 105,\n 110,\n 116,\n 95,\n 97,\n 117,\n 116,\n 104,\n 111,\n 114,\n 105,\n 116,\n 121\n ]\n }\n ]\n }\n },\n {\n \"name\": \"token_account\",\n \"writable\": true\n },\n {\n \"name\": \"associated_token_program\",\n \"address\": \"ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL\"\n },\n {\n \"name\": \"token_program\"\n },\n {\n \"name\": \"system_program\",\n \"address\": \"11111111111111111111111111111111\"\n },\n {\n \"name\": \"protocol_config\",\n \"pda\": {\n \"seeds\": [\n {\n \"kind\": \"const\",\n \"value\": [\n 112,\n 114,\n 111,\n 116,\n 111,\n 99,\n 111,\n 108,\n 95,\n 99,\n 111,\n 110,\n 102,\n 105,\n 103\n ]\n }\n ],\n \"program\": {\n \"kind\": \"const\",\n \"value\": [\n 81,\n 130,\n 250,\n 230,\n 30,\n 253,\n 246,\n 69,\n 82,\n 96,\n 7,\n 173,\n 78,\n 160,\n 131,\n 188,\n 70,\n 106,\n 173,\n 59,\n 102,\n 163,\n 198,\n 189,\n 82,\n 37,\n 225,\n 38,\n 52,\n 233,\n 157,\n 117\n ]\n }\n }\n },\n {\n \"name\": \"treasury\",\n \"writable\": true,\n \"pda\": {\n \"seeds\": [\n {\n \"kind\": \"const\",\n \"value\": [\n 112,\n 114,\n 111,\n 116,\n 111,\n 99,\n 111,\n 108,\n 95,\n 116,\n 114,\n 101,\n 97,\n 115,\n 117,\n 114,\n 121\n ]\n }\n ],\n \"program\": {\n \"kind\": \"const\",\n \"value\": [\n 81,\n 130,\n 250,\n 230,\n 30,\n 253,\n 246,\n 69,\n 82,\n 96,\n 7,\n 173,\n 78,\n 160,\n 131,\n 188,\n 70,\n 106,\n 173,\n 59,\n 102,\n 163,\n 198,\n 189,\n 82,\n 37,\n 225,\n 38,\n 52,\n 233,\n 157,\n 117\n ]\n }\n }\n },\n {\n \"name\": \"wallet_old\",\n \"writable\": true\n },\n {\n \"name\": \"identity_state_old\",\n \"writable\": true,\n \"pda\": {\n \"seeds\": [\n {\n \"kind\": \"const\",\n \"value\": [\n 105,\n 100,\n 101,\n 110,\n 116,\n 105,\n 116,\n 121\n ]\n },\n {\n \"kind\": \"account\",\n \"path\": \"wallet_old\"\n }\n ]\n }\n },\n {\n \"name\": \"mint_old\",\n \"writable\": true,\n \"pda\": {\n \"seeds\": [\n {\n \"kind\": \"const\",\n \"value\": [\n 109,\n 105,\n 110,\n 116\n ]\n },\n {\n \"kind\": \"account\",\n \"path\": \"wallet_old\"\n }\n ]\n }\n },\n {\n \"name\": \"token_account_old\",\n \"writable\": true,\n \"pda\": {\n \"seeds\": [\n {\n \"kind\": \"account\",\n \"path\": \"wallet_old\"\n },\n {\n \"kind\": \"account\",\n \"path\": \"token_program\"\n },\n {\n \"kind\": \"account\",\n \"path\": \"mint_old\"\n }\n ],\n \"program\": {\n \"kind\": \"const\",\n \"value\": [\n 140,\n 151,\n 37,\n 143,\n 78,\n 36,\n 137,\n 241,\n 187,\n 61,\n 16,\n 41,\n 20,\n 142,\n 13,\n 131,\n 11,\n 90,\n 19,\n 153,\n 218,\n 255,\n 16,\n 132,\n 4,\n 142,\n 123,\n 216,\n 219,\n 233,\n 248,\n 89\n ]\n }\n }\n }\n ],\n \"args\": []\n },\n {\n \"name\": \"mint_anchor\",\n \"docs\": [\n \"Mint a new Entros Anchor identity for the caller.\",\n \"Creates a NonTransferable Token-2022 mint, mints 1 token to the user's ATA,\",\n \"and initializes the IdentityState PDA.\"\n ],\n \"discriminator\": [\n 68,\n 56,\n 113,\n 102,\n 236,\n 152,\n 146,\n 60\n ],\n \"accounts\": [\n {\n \"name\": \"user\",\n \"writable\": true,\n \"signer\": true\n },\n {\n \"name\": \"identity_state\",\n \"writable\": true,\n \"pda\": {\n \"seeds\": [\n {\n \"kind\": \"const\",\n \"value\": [\n 105,\n 100,\n 101,\n 110,\n 116,\n 105,\n 116,\n 121\n ]\n },\n {\n \"kind\": \"account\",\n \"path\": \"user\"\n }\n ]\n }\n },\n {\n \"name\": \"mint\",\n \"docs\": [\n \"initialization ordering. PDA seeds ensure uniqueness per user.\"\n ],\n \"writable\": true,\n \"pda\": {\n \"seeds\": [\n {\n \"kind\": \"const\",\n \"value\": [\n 109,\n 105,\n 110,\n 116\n ]\n },\n {\n \"kind\": \"account\",\n \"path\": \"user\"\n }\n ]\n }\n },\n {\n \"name\": \"mint_authority\",\n \"pda\": {\n \"seeds\": [\n {\n \"kind\": \"const\",\n \"value\": [\n 109,\n 105,\n 110,\n 116,\n 95,\n 97,\n 117,\n 116,\n 104,\n 111,\n 114,\n 105,\n 116,\n 121\n ]\n }\n ]\n }\n },\n {\n \"name\": \"token_account\",\n \"writable\": true\n },\n {\n \"name\": \"associated_token_program\",\n \"address\": \"ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL\"\n },\n {\n \"name\": \"token_program\"\n },\n {\n \"name\": \"system_program\",\n \"address\": \"11111111111111111111111111111111\"\n },\n {\n \"name\": \"protocol_config\",\n \"pda\": {\n \"seeds\": [\n {\n \"kind\": \"const\",\n \"value\": [\n 112,\n 114,\n 111,\n 116,\n 111,\n 99,\n 111,\n 108,\n 95,\n 99,\n 111,\n 110,\n 102,\n 105,\n 103\n ]\n }\n ],\n \"program\": {\n \"kind\": \"const\",\n \"value\": [\n 81,\n 130,\n 250,\n 230,\n 30,\n 253,\n 246,\n 69,\n 82,\n 96,\n 7,\n 173,\n 78,\n 160,\n 131,\n 188,\n 70,\n 106,\n 173,\n 59,\n 102,\n 163,\n 198,\n 189,\n 82,\n 37,\n 225,\n 38,\n 52,\n 233,\n 157,\n 117\n ]\n }\n }\n },\n {\n \"name\": \"treasury\",\n \"writable\": true,\n \"pda\": {\n \"seeds\": [\n {\n \"kind\": \"const\",\n \"value\": [\n 112,\n 114,\n 111,\n 116,\n 111,\n 99,\n 111,\n 108,\n 95,\n 116,\n 114,\n 101,\n 97,\n 115,\n 117,\n 114,\n 121\n ]\n }\n ],\n \"program\": {\n \"kind\": \"const\",\n \"value\": [\n 81,\n 130,\n 250,\n 230,\n 30,\n 253,\n 246,\n 69,\n 82,\n 96,\n 7,\n 173,\n 78,\n 160,\n 131,\n 188,\n 70,\n 106,\n 173,\n 59,\n 102,\n 163,\n 198,\n 189,\n 82,\n 37,\n 225,\n 38,\n 52,\n 233,\n 157,\n 117\n ]\n }\n }\n },\n {\n \"name\": \"instructions_sysvar\",\n \"docs\": [\n \"receipt verification (master-list #146 Phase 3) to inspect the\",\n \"preceding Ed25519Program::verify instruction in the same tx.\",\n \"Address is constrained to the canonical sysvar pubkey, so the\",\n \"program is guaranteed to be reading the real sysvar regardless of\",\n \"what the client passes.\"\n ],\n \"address\": \"Sysvar1nstructions1111111111111111111111111\"\n }\n ],\n \"args\": [\n {\n \"name\": \"initial_commitment\",\n \"type\": {\n \"array\": [\n \"u8\",\n 32\n ]\n }\n }\n ]\n },\n {\n \"name\": \"reset_identity_state\",\n \"docs\": [\n \"Reset the caller's identity state to a fresh baseline.\",\n \"\",\n \"Recovery path for users whose client-side fingerprint envelope is\",\n \"unrecoverable (cleared site data, new device, corrupted keystore).\",\n \"Without this instruction the only answer is \\\"mint a new wallet,\\\"\",\n \"which discards on-chain history and the SAS attestation. Reset\",\n \"rotates `current_commitment` in place and zeroes verification\",\n \"history so a compromised wallet cannot inherit reputation.\",\n \"\",\n \"Defenses:\",\n \"- Signer constraint on `authority` proves wallet ownership.\",\n \"- 7-day cooldown (`RESET_COOLDOWN_SECS`) bounds abuse frequency.\",\n \"- Full zero of `verification_count`, `trust_score`, and\",\n \"`recent_timestamps` means an attacker who compromises the\",\n \"wallet key and passes Tier 1 validation starts from zero.\",\n \"- Verification fee charged, matching mint/update economics.\",\n \"\",\n \"No ZK proof is consumed: there is no prior fingerprint to\",\n \"Hamming-compare against, and the Hamming circuit's\",\n \"`min_distance ≥ 3` constraint would reject a same-fingerprint\",\n \"proof anyway. Live-humanness evidence comes from the Tier 1\",\n \"validation pipeline at the SAS attestation step (handled by\",\n \"the off-chain executor, not this instruction).\"\n ],\n \"discriminator\": [\n 26,\n 78,\n 86,\n 143,\n 247,\n 132,\n 85,\n 203\n ],\n \"accounts\": [\n {\n \"name\": \"authority\",\n \"writable\": true,\n \"signer\": true\n },\n {\n \"name\": \"identity_state\",\n \"docs\": [\n \"may realloc legacy-layout accounts (207 or 543 bytes) to the current\",\n \"551-byte layout before deserialization. PDA validated by seeds;\",\n \"ownership verified in instruction body after deserialization.\"\n ],\n \"writable\": true,\n \"pda\": {\n \"seeds\": [\n {\n \"kind\": \"const\",\n \"value\": [\n 105,\n 100,\n 101,\n 110,\n 116,\n 105,\n 116,\n 121\n ]\n },\n {\n \"kind\": \"account\",\n \"path\": \"authority\"\n }\n ]\n }\n },\n {\n \"name\": \"protocol_config\",\n \"docs\": [\n \"Supplies the verification fee amount charged on reset.\"\n ],\n \"pda\": {\n \"seeds\": [\n {\n \"kind\": \"const\",\n \"value\": [\n 112,\n 114,\n 111,\n 116,\n 111,\n 99,\n 111,\n 108,\n 95,\n 99,\n 111,\n 110,\n 102,\n 105,\n 103\n ]\n }\n ],\n \"program\": {\n \"kind\": \"const\",\n \"value\": [\n 81,\n 130,\n 250,\n 230,\n 30,\n 253,\n 246,\n 69,\n 82,\n 96,\n 7,\n 173,\n 78,\n 160,\n 131,\n 188,\n 70,\n 106,\n 173,\n 59,\n 102,\n 163,\n 198,\n 189,\n 82,\n 37,\n 225,\n 38,\n 52,\n 233,\n 157,\n 117\n ]\n }\n }\n },\n {\n \"name\": \"treasury\",\n \"writable\": true,\n \"pda\": {\n \"seeds\": [\n {\n \"kind\": \"const\",\n \"value\": [\n 112,\n 114,\n 111,\n 116,\n 111,\n 99,\n 111,\n 108,\n 95,\n 116,\n 114,\n 101,\n 97,\n 115,\n 117,\n 114,\n 121\n ]\n }\n ],\n \"program\": {\n \"kind\": \"const\",\n \"value\": [\n 81,\n 130,\n 250,\n 230,\n 30,\n 253,\n 246,\n 69,\n 82,\n 96,\n 7,\n 173,\n 78,\n 160,\n 131,\n 188,\n 70,\n 106,\n 173,\n 59,\n 102,\n 163,\n 198,\n 189,\n 82,\n 37,\n 225,\n 38,\n 52,\n 233,\n 157,\n 117\n ]\n }\n }\n },\n {\n \"name\": \"system_program\",\n \"address\": \"11111111111111111111111111111111\"\n }\n ],\n \"args\": [\n {\n \"name\": \"new_commitment\",\n \"type\": {\n \"array\": [\n \"u8\",\n 32\n ]\n }\n }\n ]\n },\n {\n \"name\": \"update_anchor\",\n \"docs\": [\n \"Update the identity state after a successful proof verification.\",\n \"\",\n \"Trust score is computed automatically from verification history and protocol config.\",\n \"Handles transparent migration from old (10-slot) to new (52-slot) account layouts.\",\n \"\",\n \"Requires a matching, fresh `VerificationResult` PDA (owned by entros-verifier)\",\n \"whose `commitment_new` equals `new_commitment` and whose `commitment_prev`\",\n \"equals the identity's current stored commitment. Without this binding the\",\n \"instruction would accept any commitment with no biometric proof — allowing\",\n \"trust-score farming via per-call fee payment, which contradicts the\",\n \"protocol's economic deterrence model. See AUDIT.md for details.\",\n \"\",\n \"The `verification_nonce` argument supplies the challenge nonce used to\",\n \"derive the VerificationResult PDA (`seeds = [b\\\"verification\\\", authority, nonce]`).\",\n \"Single-use is enforced implicitly: after this call, `current_commitment`\",\n \"rotates to `new_commitment`, so the consumed VerificationResult's\",\n \"`commitment_prev` no longer matches on any future call.\"\n ],\n \"discriminator\": [\n 120,\n 192,\n 72,\n 245,\n 112,\n 246,\n 119,\n 135\n ],\n \"accounts\": [\n {\n \"name\": \"authority\",\n \"writable\": true,\n \"signer\": true\n },\n {\n \"name\": \"identity_state\",\n \"docs\": [\n \"from old (10-slot) to new (52-slot) account layouts. PDA validated by seeds.\",\n \"Ownership verified in instruction body after deserialization.\"\n ],\n \"writable\": true,\n \"pda\": {\n \"seeds\": [\n {\n \"kind\": \"const\",\n \"value\": [\n 105,\n 100,\n 101,\n 110,\n 116,\n 105,\n 116,\n 121\n ]\n },\n {\n \"kind\": \"account\",\n \"path\": \"authority\"\n }\n ]\n }\n },\n {\n \"name\": \"verification_result\",\n \"docs\": [\n \"PDA seeds validated by Anchor; layout + owner + cross-field constraints\",\n \"validated in instruction body. Binds the ZK proof to this specific\",\n \"update — without this account, update_anchor would accept any commitment\",\n \"with no proof.\"\n ],\n \"pda\": {\n \"seeds\": [\n {\n \"kind\": \"const\",\n \"value\": [\n 118,\n 101,\n 114,\n 105,\n 102,\n 105,\n 99,\n 97,\n 116,\n 105,\n 111,\n 110\n ]\n },\n {\n \"kind\": \"account\",\n \"path\": \"authority\"\n },\n {\n \"kind\": \"arg\",\n \"path\": \"verification_nonce\"\n }\n ],\n \"program\": {\n \"kind\": \"const\",\n \"value\": [\n 48,\n 50,\n 94,\n 115,\n 90,\n 162,\n 108,\n 8,\n 240,\n 151,\n 76,\n 223,\n 101,\n 176,\n 170,\n 86,\n 254,\n 247,\n 252,\n 28,\n 240,\n 145,\n 60,\n 108,\n 42,\n 129,\n 105,\n 32,\n 232,\n 212,\n 226,\n 52\n ]\n }\n }\n },\n {\n \"name\": \"protocol_config\",\n \"docs\": [\n \"Validated by seeds + owner via seeds::program.\"\n ],\n \"pda\": {\n \"seeds\": [\n {\n \"kind\": \"const\",\n \"value\": [\n 112,\n 114,\n 111,\n 116,\n 111,\n 99,\n 111,\n 108,\n 95,\n 99,\n 111,\n 110,\n 102,\n 105,\n 103\n ]\n }\n ],\n \"program\": {\n \"kind\": \"const\",\n \"value\": [\n 81,\n 130,\n 250,\n 230,\n 30,\n 253,\n 246,\n 69,\n 82,\n 96,\n 7,\n 173,\n 78,\n 160,\n 131,\n 188,\n 70,\n 106,\n 173,\n 59,\n 102,\n 163,\n 198,\n 189,\n 82,\n 37,\n 225,\n 38,\n 52,\n 233,\n 157,\n 117\n ]\n }\n }\n },\n {\n \"name\": \"treasury\",\n \"writable\": true,\n \"pda\": {\n \"seeds\": [\n {\n \"kind\": \"const\",\n \"value\": [\n 112,\n 114,\n 111,\n 116,\n 111,\n 99,\n 111,\n 108,\n 95,\n 116,\n 114,\n 101,\n 97,\n 115,\n 117,\n 114,\n 121\n ]\n }\n ],\n \"program\": {\n \"kind\": \"const\",\n \"value\": [\n 81,\n 130,\n 250,\n 230,\n 30,\n 253,\n 246,\n 69,\n 82,\n 96,\n 7,\n 173,\n 78,\n 160,\n 131,\n 188,\n 70,\n 106,\n 173,\n 59,\n 102,\n 163,\n 198,\n 189,\n 82,\n 37,\n 225,\n 38,\n 52,\n 233,\n 157,\n 117\n ]\n }\n }\n },\n {\n \"name\": \"system_program\",\n \"address\": \"11111111111111111111111111111111\"\n }\n ],\n \"args\": [\n {\n \"name\": \"new_commitment\",\n \"type\": {\n \"array\": [\n \"u8\",\n 32\n ]\n }\n },\n {\n \"name\": \"verification_nonce\",\n \"type\": {\n \"array\": [\n \"u8\",\n 32\n ]\n }\n }\n ]\n }\n ],\n \"accounts\": [\n {\n \"name\": \"IdentityState\",\n \"discriminator\": [\n 156,\n 32,\n 87,\n 93,\n 52,\n 155,\n 248,\n 207\n ]\n }\n ],\n \"events\": [\n {\n \"name\": \"AnchorMinted\",\n \"discriminator\": [\n 11,\n 188,\n 6,\n 169,\n 20,\n 50,\n 128,\n 172\n ]\n },\n {\n \"name\": \"AnchorReset\",\n \"discriminator\": [\n 183,\n 48,\n 146,\n 155,\n 112,\n 20,\n 140,\n 31\n ]\n },\n {\n \"name\": \"AnchorUpdated\",\n \"discriminator\": [\n 112,\n 73,\n 210,\n 183,\n 57,\n 84,\n 103,\n 59\n ]\n },\n {\n \"name\": \"MigrateIdentityEvent\",\n \"discriminator\": [\n 33,\n 239,\n 166,\n 187,\n 108,\n 47,\n 49,\n 139\n ]\n }\n ],\n \"errors\": [\n {\n \"code\": 6000,\n \"name\": \"InvalidCommitment\",\n \"msg\": \"Invalid commitment: must be 32 non-zero bytes\"\n },\n {\n \"code\": 6001,\n \"name\": \"Unauthorized\",\n \"msg\": \"Unauthorized: caller is not the identity owner\"\n },\n {\n \"code\": 6002,\n \"name\": \"ArithmeticOverflow\",\n \"msg\": \"Arithmetic overflow\"\n },\n {\n \"code\": 6003,\n \"name\": \"InvalidProtocolConfig\",\n \"msg\": \"Invalid protocol config account\"\n },\n {\n \"code\": 6004,\n \"name\": \"InvalidIdentityState\",\n \"msg\": \"Identity state account failed to deserialize\"\n },\n {\n \"code\": 6005,\n \"name\": \"IdentitySerializationFailed\",\n \"msg\": \"Identity state account failed to serialize\"\n },\n {\n \"code\": 6006,\n \"name\": \"VerificationResultWrongOwner\",\n \"msg\": \"VerificationResult account is owned by the wrong program\"\n },\n {\n \"code\": 6007,\n \"name\": \"StaleVerificationResult\",\n \"msg\": \"VerificationResult account has stale layout (pre-binding-patch)\"\n },\n {\n \"code\": 6008,\n \"name\": \"VerifierMismatch\",\n \"msg\": \"VerificationResult verifier does not match the signing authority\"\n },\n {\n \"code\": 6009,\n \"name\": \"ProofExpired\",\n \"msg\": \"Proof is too old to consume (MAX_PROOF_AGE_SECS exceeded)\"\n },\n {\n \"code\": 6010,\n \"name\": \"CommitmentMismatch\",\n \"msg\": \"Proof commitment_new does not match the submitted new_commitment\"\n },\n {\n \"code\": 6011,\n \"name\": \"PrevCommitmentMismatch\",\n \"msg\": \"Proof commitment_prev does not match the identity's current_commitment\"\n },\n {\n \"code\": 6012,\n \"name\": \"ResetCooldownActive\",\n \"msg\": \"Reset cooldown has not elapsed since the last reset\"\n },\n {\n \"code\": 6013,\n \"name\": \"UnauthorizedNewWallet\",\n \"msg\": \"caller is not authorized by the old identity\"\n },\n {\n \"code\": 6014,\n \"name\": \"ProofFromFuture\",\n \"msg\": \"VerificationResult.verified_at is in the future relative to the cluster clock\"\n },\n {\n \"code\": 6015,\n \"name\": \"MissingValidatorReceipt\",\n \"msg\": \"mint_anchor expected a preceding Ed25519Program::verify instruction with a validator-signed receipt; none found\"\n },\n {\n \"code\": 6016,\n \"name\": \"ReceiptValidatorMismatch\",\n \"msg\": \"Receipt was signed by a key that does not match ProtocolConfig.validator_pubkey\"\n },\n {\n \"code\": 6017,\n \"name\": \"ReceiptCommitmentMismatch\",\n \"msg\": \"Receipt commitment does not match the mint_anchor commitment argument\"\n },\n {\n \"code\": 6018,\n \"name\": \"ReceiptWalletMismatch\",\n \"msg\": \"Receipt wallet does not match the mint signer\"\n },\n {\n \"code\": 6019,\n \"name\": \"ReceiptExpired\",\n \"msg\": \"Receipt has aged past MAX_RECEIPT_AGE_SECS\"\n },\n {\n \"code\": 6020,\n \"name\": \"ReceiptFromFuture\",\n \"msg\": \"Receipt validated_at is in the future relative to the cluster clock\"\n },\n {\n \"code\": 6021,\n \"name\": \"MalformedReceiptMessage\",\n \"msg\": \"Receipt message has malformed length or layout\"\n }\n ],\n \"types\": [\n {\n \"name\": \"AnchorMinted\",\n \"type\": {\n \"kind\": \"struct\",\n \"fields\": [\n {\n \"name\": \"owner\",\n \"type\": \"pubkey\"\n },\n {\n \"name\": \"mint\",\n \"type\": \"pubkey\"\n },\n {\n \"name\": \"commitment\",\n \"type\": {\n \"array\": [\n \"u8\",\n 32\n ]\n }\n }\n ]\n }\n },\n {\n \"name\": \"AnchorReset\",\n \"type\": {\n \"kind\": \"struct\",\n \"fields\": [\n {\n \"name\": \"owner\",\n \"type\": \"pubkey\"\n },\n {\n \"name\": \"mint\",\n \"type\": \"pubkey\"\n },\n {\n \"name\": \"commitment\",\n \"type\": {\n \"array\": [\n \"u8\",\n 32\n ]\n }\n }\n ]\n }\n },\n {\n \"name\": \"AnchorUpdated\",\n \"type\": {\n \"kind\": \"struct\",\n \"fields\": [\n {\n \"name\": \"owner\",\n \"type\": \"pubkey\"\n },\n {\n \"name\": \"verification_count\",\n \"type\": \"u32\"\n },\n {\n \"name\": \"trust_score\",\n \"type\": \"u16\"\n },\n {\n \"name\": \"commitment\",\n \"type\": {\n \"array\": [\n \"u8\",\n 32\n ]\n }\n }\n ]\n }\n },\n {\n \"name\": \"IdentityState\",\n \"type\": {\n \"kind\": \"struct\",\n \"fields\": [\n {\n \"name\": \"owner\",\n \"docs\": [\n \"The user's wallet pubkey\"\n ],\n \"type\": \"pubkey\"\n },\n {\n \"name\": \"creation_timestamp\",\n \"docs\": [\n \"When the identity was first minted\"\n ],\n \"type\": \"i64\"\n },\n {\n \"name\": \"last_verification_timestamp\",\n \"docs\": [\n \"Most recent successful verification\"\n ],\n \"type\": \"i64\"\n },\n {\n \"name\": \"verification_count\",\n \"docs\": [\n \"Total successful verifications\"\n ],\n \"type\": \"u32\"\n },\n {\n \"name\": \"trust_score\",\n \"docs\": [\n \"Computed reputation metric\"\n ],\n \"type\": \"u16\"\n },\n {\n \"name\": \"current_commitment\",\n \"docs\": [\n \"Latest Poseidon commitment H_TBH\"\n ],\n \"type\": {\n \"array\": [\n \"u8\",\n 32\n ]\n }\n },\n {\n \"name\": \"mint\",\n \"docs\": [\n \"The NonTransferable mint associated with this identity\"\n ],\n \"type\": \"pubkey\"\n },\n {\n \"name\": \"bump\",\n \"docs\": [\n \"PDA bump seed\"\n ],\n \"type\": \"u8\"\n },\n {\n \"name\": \"recent_timestamps\",\n \"docs\": [\n \"Timestamps of last 52 verifications (newest at index 0).\",\n \"52 slots covers 1 year of weekly or 4+ years of monthly verifications.\",\n \"Older entries contribute negligible score due to exponential recency decay.\"\n ],\n \"type\": {\n \"array\": [\n \"i64\",\n 52\n ]\n }\n },\n {\n \"name\": \"last_reset_timestamp\",\n \"docs\": [\n \"Most recent `reset_identity_state` invocation. Zero when the identity\",\n \"has never been reset (including freshly minted accounts and accounts\",\n \"created before this field existed and then realloc'd in-place).\"\n ],\n \"type\": \"i64\"\n },\n {\n \"name\": \"new_wallet\",\n \"docs\": [\n \"new wallet for migrate_identity()\"\n ],\n \"type\": \"pubkey\"\n }\n ]\n }\n },\n {\n \"name\": \"MigrateIdentityEvent\",\n \"type\": {\n \"kind\": \"struct\",\n \"fields\": [\n {\n \"name\": \"wallet_old\",\n \"type\": \"pubkey\"\n },\n {\n \"name\": \"wallet_new\",\n \"type\": \"pubkey\"\n },\n {\n \"name\": \"identity_old\",\n \"type\": \"pubkey\"\n },\n {\n \"name\": \"identity_new\",\n \"type\": \"pubkey\"\n }\n ]\n }\n }\n ]\n}","{\n \"address\": \"4F97jNoxQzT2qRbkWpW3ztC3Nz2TtKj3rnKG8ExgnrfV\",\n \"metadata\": {\n \"name\": \"entros_verifier\",\n \"version\": \"0.1.0\",\n \"spec\": \"0.1.0\",\n \"description\": \"ZK proof verification program for Entros Protocol\"\n },\n \"instructions\": [\n {\n \"name\": \"close_challenge\",\n \"docs\": [\n \"Close a used or expired challenge account to reclaim rent.\"\n ],\n \"discriminator\": [\n 29,\n 156,\n 109,\n 17,\n 41,\n 99,\n 71,\n 236\n ],\n \"accounts\": [\n {\n \"name\": \"challenger\",\n \"writable\": true,\n \"signer\": true\n },\n {\n \"name\": \"challenge\",\n \"writable\": true\n }\n ],\n \"args\": []\n },\n {\n \"name\": \"close_verification_result\",\n \"docs\": [\n \"Close a verification result account to reclaim rent.\"\n ],\n \"discriminator\": [\n 202,\n 203,\n 62,\n 127,\n 7,\n 157,\n 143,\n 12\n ],\n \"accounts\": [\n {\n \"name\": \"verifier\",\n \"writable\": true,\n \"signer\": true\n },\n {\n \"name\": \"verification_result\",\n \"writable\": true\n }\n ],\n \"args\": []\n },\n {\n \"name\": \"create_challenge\",\n \"docs\": [\n \"Create a verification challenge with a client-generated nonce.\"\n ],\n \"discriminator\": [\n 170,\n 244,\n 47,\n 1,\n 1,\n 15,\n 173,\n 239\n ],\n \"accounts\": [\n {\n \"name\": \"challenger\",\n \"writable\": true,\n \"signer\": true\n },\n {\n \"name\": \"challenge\",\n \"writable\": true,\n \"pda\": {\n \"seeds\": [\n {\n \"kind\": \"const\",\n \"value\": [\n 99,\n 104,\n 97,\n 108,\n 108,\n 101,\n 110,\n 103,\n 101\n ]\n },\n {\n \"kind\": \"account\",\n \"path\": \"challenger\"\n },\n {\n \"kind\": \"arg\",\n \"path\": \"nonce\"\n }\n ]\n }\n },\n {\n \"name\": \"system_program\",\n \"address\": \"11111111111111111111111111111111\"\n }\n ],\n \"args\": [\n {\n \"name\": \"nonce\",\n \"type\": {\n \"array\": [\n \"u8\",\n 32\n ]\n }\n }\n ]\n },\n {\n \"name\": \"verify_proof\",\n \"docs\": [\n \"Verify a proof against a challenge.\",\n \"Validates the challenge is unused and not expired, runs mock verification,\",\n \"and stores the result.\"\n ],\n \"discriminator\": [\n 217,\n 211,\n 191,\n 110,\n 144,\n 13,\n 186,\n 98\n ],\n \"accounts\": [\n {\n \"name\": \"verifier\",\n \"writable\": true,\n \"signer\": true\n },\n {\n \"name\": \"challenge\",\n \"writable\": true,\n \"pda\": {\n \"seeds\": [\n {\n \"kind\": \"const\",\n \"value\": [\n 99,\n 104,\n 97,\n 108,\n 108,\n 101,\n 110,\n 103,\n 101\n ]\n },\n {\n \"kind\": \"account\",\n \"path\": \"verifier\"\n },\n {\n \"kind\": \"arg\",\n \"path\": \"nonce\"\n }\n ]\n }\n },\n {\n \"name\": \"verification_result\",\n \"writable\": true,\n \"pda\": {\n \"seeds\": [\n {\n \"kind\": \"const\",\n \"value\": [\n 118,\n 101,\n 114,\n 105,\n 102,\n 105,\n 99,\n 97,\n 116,\n 105,\n 111,\n 110\n ]\n },\n {\n \"kind\": \"account\",\n \"path\": \"verifier\"\n },\n {\n \"kind\": \"arg\",\n \"path\": \"nonce\"\n }\n ]\n }\n },\n {\n \"name\": \"system_program\",\n \"address\": \"11111111111111111111111111111111\"\n }\n ],\n \"args\": [\n {\n \"name\": \"proof_bytes\",\n \"type\": \"bytes\"\n },\n {\n \"name\": \"public_inputs\",\n \"type\": {\n \"vec\": {\n \"array\": [\n \"u8\",\n 32\n ]\n }\n }\n },\n {\n \"name\": \"nonce\",\n \"type\": {\n \"array\": [\n \"u8\",\n 32\n ]\n }\n }\n ]\n }\n ],\n \"accounts\": [\n {\n \"name\": \"Challenge\",\n \"discriminator\": [\n 119,\n 250,\n 161,\n 121,\n 119,\n 81,\n 22,\n 208\n ]\n },\n {\n \"name\": \"VerificationResult\",\n \"discriminator\": [\n 104,\n 111,\n 80,\n 172,\n 219,\n 191,\n 162,\n 38\n ]\n }\n ],\n \"events\": [\n {\n \"name\": \"ChallengeCreated\",\n \"discriminator\": [\n 166,\n 178,\n 174,\n 178,\n 11,\n 172,\n 98,\n 243\n ]\n },\n {\n \"name\": \"VerificationComplete\",\n \"discriminator\": [\n 22,\n 74,\n 77,\n 232,\n 220,\n 46,\n 59,\n 120\n ]\n }\n ],\n \"errors\": [\n {\n \"code\": 6000,\n \"name\": \"InvalidProofFormat\",\n \"msg\": \"Invalid proof format\"\n },\n {\n \"code\": 6001,\n \"name\": \"ProofVerificationFailed\",\n \"msg\": \"Proof verification failed\"\n },\n {\n \"code\": 6002,\n \"name\": \"ChallengeExpired\",\n \"msg\": \"Challenge has expired\"\n },\n {\n \"code\": 6003,\n \"name\": \"ChallengeAlreadyUsed\",\n \"msg\": \"Challenge already used\"\n },\n {\n \"code\": 6004,\n \"name\": \"InvalidPublicInputs\",\n \"msg\": \"Invalid public inputs\"\n },\n {\n \"code\": 6005,\n \"name\": \"ChallengeNotUsed\",\n \"msg\": \"Challenge must be used before closing\"\n },\n {\n \"code\": 6006,\n \"name\": \"InvalidNonce\",\n \"msg\": \"Invalid nonce: must not be all zeros\"\n },\n {\n \"code\": 6007,\n \"name\": \"ArithmeticOverflow\",\n \"msg\": \"Arithmetic overflow\"\n }\n ],\n \"types\": [\n {\n \"name\": \"Challenge\",\n \"type\": {\n \"kind\": \"struct\",\n \"fields\": [\n {\n \"name\": \"challenger\",\n \"docs\": [\n \"The user who requested the challenge\"\n ],\n \"type\": \"pubkey\"\n },\n {\n \"name\": \"nonce\",\n \"docs\": [\n \"Random nonce for anti-replay\"\n ],\n \"type\": {\n \"array\": [\n \"u8\",\n 32\n ]\n }\n },\n {\n \"name\": \"created_at\",\n \"docs\": [\n \"Unix timestamp when challenge was created\"\n ],\n \"type\": \"i64\"\n },\n {\n \"name\": \"expires_at\",\n \"docs\": [\n \"Unix timestamp when challenge expires\"\n ],\n \"type\": \"i64\"\n },\n {\n \"name\": \"used\",\n \"docs\": [\n \"Whether this challenge has been consumed\"\n ],\n \"type\": \"bool\"\n },\n {\n \"name\": \"bump\",\n \"docs\": [\n \"PDA bump seed\"\n ],\n \"type\": \"u8\"\n }\n ]\n }\n },\n {\n \"name\": \"ChallengeCreated\",\n \"type\": {\n \"kind\": \"struct\",\n \"fields\": [\n {\n \"name\": \"challenger\",\n \"type\": \"pubkey\"\n },\n {\n \"name\": \"nonce\",\n \"type\": {\n \"array\": [\n \"u8\",\n 32\n ]\n }\n },\n {\n \"name\": \"expires_at\",\n \"type\": \"i64\"\n }\n ]\n }\n },\n {\n \"name\": \"VerificationComplete\",\n \"type\": {\n \"kind\": \"struct\",\n \"fields\": [\n {\n \"name\": \"verifier\",\n \"type\": \"pubkey\"\n },\n {\n \"name\": \"is_valid\",\n \"type\": \"bool\"\n },\n {\n \"name\": \"nonce\",\n \"type\": {\n \"array\": [\n \"u8\",\n 32\n ]\n }\n }\n ]\n }\n },\n {\n \"name\": \"VerificationResult\",\n \"type\": {\n \"kind\": \"struct\",\n \"fields\": [\n {\n \"name\": \"verifier\",\n \"docs\": [\n \"Who submitted the proof\"\n ],\n \"type\": \"pubkey\"\n },\n {\n \"name\": \"proof_hash\",\n \"docs\": [\n \"Hash of the proof bytes for audit trail\"\n ],\n \"type\": {\n \"array\": [\n \"u8\",\n 32\n ]\n }\n },\n {\n \"name\": \"verified_at\",\n \"docs\": [\n \"Unix timestamp of verification\"\n ],\n \"type\": \"i64\"\n },\n {\n \"name\": \"is_valid\",\n \"docs\": [\n \"Whether the proof was valid.\",\n \"Always true for persisted records — invalid proofs revert the transaction\",\n \"and never create a VerificationResult. Retained for account layout stability.\"\n ],\n \"type\": \"bool\"\n },\n {\n \"name\": \"challenge_nonce\",\n \"docs\": [\n \"The challenge nonce that was consumed\"\n ],\n \"type\": {\n \"array\": [\n \"u8\",\n 32\n ]\n }\n },\n {\n \"name\": \"bump\",\n \"docs\": [\n \"PDA bump seed\"\n ],\n \"type\": \"u8\"\n },\n {\n \"name\": \"commitment_new\",\n \"docs\": [\n \"New fingerprint commitment from public_inputs[0]. Read cross-program\",\n \"by entros-anchor::update_anchor to bind the proof to the identity update.\"\n ],\n \"type\": {\n \"array\": [\n \"u8\",\n 32\n ]\n }\n },\n {\n \"name\": \"commitment_prev\",\n \"docs\": [\n \"Previous fingerprint commitment from public_inputs[1]. Read cross-program\",\n \"by entros-anchor::update_anchor to bind to the identity's stored commitment.\"\n ],\n \"type\": {\n \"array\": [\n \"u8\",\n 32\n ]\n }\n },\n {\n \"name\": \"threshold\",\n \"docs\": [\n \"Hamming threshold from public_inputs[2]. Bounded at proof time to prevent\",\n \"attacker-chosen circuit parameters.\"\n ],\n \"type\": \"u16\"\n },\n {\n \"name\": \"min_distance\",\n \"docs\": [\n \"Hamming min_distance from public_inputs[3]. Bounded at proof time to\",\n \"prevent replay (Hamming=0) attacks via attacker-chosen min_distance=0.\"\n ],\n \"type\": \"u16\"\n }\n ]\n }\n }\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-lowercase-hex characters, wrong\n * length). Permissive about a leading `0x` because some integrations may\n * strip or preserve it inconsistently. Strict on case so a future validator\n * regression that emits uppercase hex surfaces immediately rather than\n * silently accepting drift from the wire-format contract (Rust `hex::encode`\n * is canonically lowercase).\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-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 (the on-chain check is currently log-only and\n * proceeds when no preceding Ed25519 ix is present).\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 *\n * Returns `null` if the receipt fails to decode — caller should fall back to\n * sending `mint_anchor` without an Ed25519 prefix. The on-chain check is\n * currently log-only, so the fallback still works on the deployed program;\n * once enforcement is enabled, missing receipts hard-fail and the SDK's\n * no-op fallback becomes a deliberate \"no-receipt\" path that `mint_anchor`\n * 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 are typed dynamically because the SDK's\n// peer dep on @coral-xyz/anchor + @solana/web3.js is loaded via dynamic\n// import (avoiding a hard dep for tree-shaking).\nimport type { Idl } from \"@coral-xyz/anchor\";\nimport type { SolanaProof } from \"../proof/types\";\nimport type { SignedReceiptDto, SubmissionResult } from \"./types\";\nimport { PROGRAM_IDS } from \"../config\";\nimport { sdkLog, sdkWarn } from \"../log\";\nimport { entrosAnchorIdl, entrosVerifierIdl } from \"../protocol/idl\";\nimport { buildEd25519ReceiptIx } from \"./receipt\";\n\n/**\n * Wait for a tx to confirm AND throw if the chain-side execution errored.\n * web3.js 1.x's `connection.confirmTransaction` resolves successfully even\n * when the tx reverted on chain (it only checks signature inclusion); the\n * caller MUST inspect `value.err`. Without this, on-chain Anchor errors\n * (CommitmentMismatch, MissingValidatorReceipt, ResetCooldownActive,\n * InsufficientFunds, etc.) are silently swallowed and `submitViaWallet`\n * returns a \"successful\" txSignature for\n * a tx that never mutated state — a credibility hit. The thrown message\n * preserves the JSON `InstructionError` shape so downstream regex parsing\n * can extract the `Custom` code.\n */\nasync function confirmAndCheck(\n connection: any,\n signature: string | undefined,\n): Promise<void> {\n if (!signature) {\n throw new Error(\"confirmAndCheck called without a transaction signature\");\n }\n const confirmation = await connection.confirmTransaction(signature, \"confirmed\");\n if (confirmation?.value?.err != null) {\n throw new Error(\n `Transaction failed on chain: ${JSON.stringify(confirmation.value.err)} (sig=${signature})`,\n );\n }\n}\n\n/**\n * Best-effort SAS attestation request. POSTs to the executor's `/attest`\n * endpoint with the wallet's public key, a server-issued challenge nonce,\n * 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 *\n * Wallet-only path: the executor's `/attest` endpoint requires nonce +\n * signature + message on every request (walletless tier no longer writes\n * to SAS). If any of those is unavailable on the client side — wallet\n * adapter has no `signMessage`, signing throws, or no server nonce was\n * issued during this verification — we skip the request entirely instead\n * of sending a doomed-to-400 call.\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 if (!serverNonce) {\n sdkLog(\"[Entros SDK] Skipping SAS attestation: no server-issued nonce\");\n return undefined;\n }\n if (!wallet?.signMessage) {\n sdkLog(\"[Entros SDK] Skipping SAS attestation: wallet does not support signMessage\");\n return undefined;\n }\n\n let signature: string;\n let message: string;\n try {\n const timestamp = Math.floor(Date.now() / 1000);\n message = `Entros-ATTEST:${walletAddress}:${timestamp}`;\n const messageBytes = new TextEncoder().encode(message);\n const sigBytes: Uint8Array = await wallet.signMessage(messageBytes);\n signature = Array.from(sigBytes)\n .map((b) => b.toString(16).padStart(2, \"0\"))\n .join(\"\");\n } catch {\n sdkWarn(\"[Entros SDK] Wallet signMessage failed, skipping SAS attestation\");\n return undefined;\n }\n\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> = {\n wallet_address: walletAddress,\n nonce: serverNonce,\n signature,\n message,\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. Consumed only on the first-verification\n * path: when present, the SDK prepends an `Ed25519Program::verify`\n * instruction so on-chain `mint_anchor` can confirm the commitment was\n * endorsed by the configured validator. Re-verification ignores the\n * field entirely — `update_anchor` enforces binding via the\n * 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 const verifierProgram: any = new anchor.Program(\n entrosVerifierIdl as Idl,\n provider,\n );\n const anchorProgram: any = new anchor.Program(\n entrosAnchorIdl as Idl,\n provider,\n );\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 confirmAndCheck(options.connection, txSig);\n } else {\n // First verification: mint anchor. Bundles an `Ed25519Program::verify`\n // instruction before `mint_anchor` when the validator returned a\n // signed receipt. The on-chain program inspects the preceding\n // instruction via the Instructions sysvar to confirm the validator\n // endorsed (wallet, commitment, validated_at) before allowing the\n // mint.\n //\n // The `instructions_sysvar` account is required by the on-chain\n // `MintAnchor` accounts struct unconditionally — it must be present\n // even when no receipt is bundled (the on-chain check is currently\n // log-only, but the Anchor framework itself requires every account\n // listed in the IDL to be supplied).\n const anchorProgram: any = new anchor.Program(\n entrosAnchorIdl as Idl,\n provider,\n );\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 // Decode the receipt up front so we can hard-fail if the validator\n // returned malformed bytes. Silently falling back to a no-receipt\n // mint when the caller expected a binding would mask validator bugs\n // and, once on-chain enforcement is enabled, would produce a\n // confusing on-chain reject after the user has already approved a\n // wallet signature. Fail-fast lets the caller surface a clear error\n // and retry once the validator is healthy.\n let ed25519Ix: import(\"@solana/web3.js\").TransactionInstruction | null = null;\n if (options.signedReceipt) {\n ed25519Ix = await buildEd25519ReceiptIx(options.signedReceipt);\n if (!ed25519Ix) {\n return {\n success: false,\n error:\n \"Validator returned a signed receipt that failed to decode (malformed hex or wrong byte length). Refusing to mint without a valid binding. The validator service may be misconfigured — check the validation-service logs.\",\n };\n }\n sdkLog(\n \"[Entros SDK] Bundling validator-signed mint receipt before mint_anchor\"\n );\n } else {\n // No receipt is the legitimate \"older validator\" path. The on-chain\n // check is currently log-only so the mint still succeeds; once\n // enforcement is enabled, this will turn into a hard reject and\n // operators must ensure the validator is configured for receipt\n // signing.\n sdkLog(\n \"[Entros SDK] No validator receipt available; minting without binding (on-chain check is log-only today)\"\n );\n }\n\n // Transaction shape:\n // [0] ComputeBudgetProgram.setComputeUnitLimit\n // [1] (optional) Ed25519Program::verify(receipt)\n // [2] mint_anchor(initial_commitment)\n //\n // Including an explicit compute-budget ix at index 0 prevents wallet\n // adapters that lazily inject one from inserting it between the\n // Ed25519 ix and `mint_anchor`. The on-chain receipt parser locates\n // the receipt at `current_instruction_index - 1`, so any ix between\n // the Ed25519 prefix and `mint_anchor` would silently break the\n // binding while the check is log-only or hard-fail the mint once\n // enforcement is enabled. 200K covers the mint_anchor compute cost;\n // the Ed25519 precompile runs in the runtime, not against the\n // program's CU budget.\n const tx = new Transaction();\n tx.add(ComputeBudgetProgram.setComputeUnitLimit({ units: 200_000 }));\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 confirmAndCheck(options.connection, txSig);\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 validation\n * pipeline invoked at the /attest step (same as mint and 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 anchorProgram: any = new anchor.Program(\n entrosAnchorIdl as Idl,\n provider,\n );\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 confirmAndCheck(options.connection, txSig);\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 type { Idl } from \"@coral-xyz/anchor\";\nimport { PROGRAM_IDS } from \"../config\";\nimport { sdkWarn } from \"../log\";\nimport { entrosAnchorIdl } from \"../protocol/idl\";\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 *\n * Uses the bundled `entros_anchor.json` IDL (copied verbatim from\n * `protocol-core/target/idl/`) instead of `Program.fetchIdl`, which\n * adds a 150-300ms RPC round-trip per call to fetch the IDL from chain.\n * Account decoding is identical; the only difference is that IDL changes\n * now require an SDK bump rather than a chain-side IDL upload — in\n * practice that's already true since on-chain Anchor changes need\n * matching SDK updates anyway.\n *\n * When the on-chain `entros_anchor` program changes, re-copy\n * `protocol-core/target/idl/entros_anchor.json` into `src/protocol/idl/`\n * and bump the SDK minor version.\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 coder = new anchor.BorshAccountsCoder(entrosAnchorIdl as 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 MOTION_FEATURE_COUNT,\n TOUCH_FEATURE_COUNT,\n} from \"./extraction/kinematic\";\nimport { fuseFeatures, fuseRawFeatures } from \"./extraction/statistics\";\nimport { yieldToMainThread } from \"./yield\";\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 analysis.\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 // The audio path is the dominant cost. Yield once it's done so the\n // verify-flow spinner gets a paint frame before motion/touch extraction\n // resumes the main-thread work.\n await yieldToMainThread();\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 await yieldToMainThread();\n\n const touchFeatures = extractTouchFeatures(data.touch);\n await yieldToMainThread();\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. Present only when the request\n * reached the validator with `commitment_new_hex` AND the validator\n * has a signing key configured. `undefined` indicates the SDK\n * should mint without an Ed25519 prefix; while the on-chain check\n * is log-only this is harmless, but once enforcement is enabled\n * 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 // Let React render the new stage label before we re-enter the heavy\n // synchronous extraction path. Without this, the host UI sets the\n // string but the main thread is captured by extractFeatures before\n // the spinner can repaint, and the user sees the previous stage's\n // label until extraction completes.\n await yieldToMainThread();\n const {\n raw: features,\n normalized: normalizedFeatures,\n f0Contour,\n accelMagnitude,\n } = await extractFeatures(sensorData);\n\n // Diagnostic: log feature vector composition. Block boundaries follow the\n // v2 layout, derived from the canonical per-modality counts so any future\n // modality bump propagates automatically (no hand-sync drift).\n const AUDIO_END = SPEAKER_FEATURE_COUNT;\n const MOTION_END = AUDIO_END + MOTION_FEATURE_COUNT;\n const TOUCH_END = MOTION_END + TOUCH_FEATURE_COUNT;\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..${AUDIO_END - 1}]: ${features.slice(0, AUDIO_END).filter((v) => v !== 0).length} non-zero. ` +\n `Motion/Mouse[${AUDIO_END}..${MOTION_END - 1}]: ${features.slice(AUDIO_END, MOTION_END).filter((v) => v !== 0).length} non-zero. ` +\n `Touch[${MOTION_END}..${TOUCH_END - 1}]: ${features.slice(MOTION_END, TOUCH_END).filter((v) => v !== 0).length} non-zero.`\n );\n\n // Compute the SimHash fingerprint and Poseidon TBH commitment BEFORE the\n // validation POST. The validator signs a (wallet, commitment, validated_at)\n // receipt that the SDK bundles before `mint_anchor` in the same atomic\n // transaction; for the validator to sign the right commitment, we must\n // transmit it in the request. SimHash + Poseidon together cost ~20ms —\n // 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 // Same rationale as the \"Extracting features...\" yield above — give\n // React a paint opportunity before we encode the audio buffer to base64\n // (~16k samples), which is the next synchronous chunk on the main thread.\n await yieldToMainThread();\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 verification. The\n // validator transcribes the audio and matches it against the\n // server-issued challenge phrase (which the executor looks up by\n // nonce). 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. The validator only signs when this field is present AND\n // its own signing key is configured; the SDK only consumes the\n // receipt on first-verification, so sending it on every\n // wallet-connected request is harmless on the re-verify path\n // (validator signs cheaply, executor passes through, SDK ignores\n // the field for `update_anchor`).\n const commitmentNewHex = bytesToHex(tbh.commitmentBytes);\n\n // Server-side transcription 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. Older\n // validator deploys omit the field entirely — the SDK proceeds\n // without a receipt and the on-chain log-only check writes \"no\n // preceding instruction\" to the tx logs. Once on-chain enforcement\n // is enabled, missing receipts will hard-fail mint_anchor; the\n // executor + validator deploys must therefore be brought up to\n // receipt-supporting versions before the 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 (err) {\n // Body wasn't JSON — typically an older validator returning an\n // empty 200, or a proxy mangling the response. Surface a warn\n // so operators can distinguish \"validator-too-old\" from a real\n // validator misconfiguration. Treat as no-receipt and proceed.\n const msg = err instanceof Error ? err.message : String(err);\n sdkWarn(\n `[Entros SDK] /validate-features returned 200 but body was not parseable JSON; proceeding without receipt: ${msg}`\n );\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 server-side checks entirely.\n // 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 // Block boundaries derived from extractor constants so they stay in\n // sync with the v2 layout if any modality count shifts.\n const motionStart = SPEAKER_FEATURE_COUNT;\n const touchStart = motionStart + MOTION_FEATURE_COUNT;\n const touchEnd = touchStart + TOUCH_FEATURE_COUNT;\n const audioNZ = features.slice(0, motionStart).filter((v) => v !== 0).length;\n const motionNZ = features.slice(motionStart, touchStart).filter((v) => v !== 0).length;\n const touchNZ = features.slice(touchStart, touchEnd).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. Re-verification\n // doesn't need the receipt — the binding is already enforced via\n // the VerificationResult PDA path that `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 // Capture constraints kept in lock-step with `sensor/audio.ts` —\n // the two entry points (standalone capture vs session-based\n // capture) must agree or the verify flow and direct-API\n // consumers diverge.\n echoCancellation: false,\n noiseSuppression: false,\n autoGainControl: false,\n // @ts-expect-error -- W3C Media Capture Extensions property; not\n // yet in lib.dom.d.ts as of TypeScript 6.0.\n voiceIsolation: true,\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). This client-side generator only fires when the executor is\n// unreachable; in that path the server has no record of the phrase and the\n// phrase verification step is skipped while other server-side checks 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 the phrase verification step —\n * other server-side checks 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, 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.\n *\n * Server-issued phrases are the only safe design here: if the client generated\n * the phrase and sent it to the server alongside the audio, an attacker would\n * submit their own phrase matching whatever content they captured. With server\n * issuance, the phrase is bound to the nonce and the 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","meydaModule","getMeyda","window","meydaModule","getMeyda","derivative","dx","dy","window"]}