@iam-protocol/pulse-sdk 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.mts CHANGED
@@ -1,5 +1,6 @@
1
1
  declare const FINGERPRINT_BITS = 256;
2
2
  declare const DEFAULT_THRESHOLD = 30;
3
+ declare const DEFAULT_MIN_DISTANCE = 3;
3
4
  declare const MIN_CAPTURE_MS = 2000;
4
5
  declare const MAX_CAPTURE_MS = 60000;
5
6
  declare const DEFAULT_CAPTURE_MS = 7000;
@@ -222,6 +223,18 @@ declare function variance(values: number[], mu?: number): number;
222
223
  declare function skewness(values: number[]): number;
223
224
  declare function kurtosis(values: number[]): number;
224
225
  declare function condense(values: number[]): StatsSummary;
226
+ /**
227
+ * Shannon entropy over histogram bins. Measures information density.
228
+ * Real human data has moderate entropy (varied but structured).
229
+ * Synthetic data is either too uniform (high entropy) or too structured (low entropy).
230
+ */
231
+ declare function entropy(values: number[], bins?: number): number;
232
+ /**
233
+ * Autocorrelation at a given lag. Detects periodic synthetic patterns.
234
+ * Real human data has low autocorrelation at most lags (chaotic/noisy).
235
+ * Synthetic data often has high autocorrelation (periodic/smooth).
236
+ */
237
+ declare function autocorrelation(values: number[], lag?: number): number;
225
238
  declare function fuseFeatures(audio: number[], motion: number[], touch: number[]): number[];
226
239
 
227
240
  /** Serialized proof ready for on-chain submission */
@@ -246,6 +259,7 @@ interface CircuitInput {
246
259
  commitment_new: string;
247
260
  commitment_prev: string;
248
261
  threshold: string;
262
+ min_distance: string;
249
263
  }
250
264
  /** Proof generation result */
251
265
  interface ProofResult {
@@ -269,7 +283,7 @@ declare function serializeProof(proof: RawProof, publicSignals: string[]): Solan
269
283
  /**
270
284
  * Prepare circuit input from current and previous TBH data.
271
285
  */
272
- declare function prepareCircuitInput(current: TBH, previous: TBH, threshold?: number): CircuitInput;
286
+ declare function prepareCircuitInput(current: TBH, previous: TBH, threshold?: number, minDistance?: number): CircuitInput;
273
287
  /**
274
288
  * Generate a Groth16 proof for the Hamming distance circuit.
275
289
  *
@@ -373,4 +387,4 @@ declare function randomLissajousParams(): LissajousParams;
373
387
  */
374
388
  declare function generateLissajousPoints(params: LissajousParams): Point2D[];
375
389
 
376
- export { type AudioCapture, type CaptureOptions, type CaptureStage, type CircuitInput, DEFAULT_CAPTURE_MS, DEFAULT_THRESHOLD, FINGERPRINT_BITS, type FeatureVector, type FusedFeatureVector, type IdentityState, type LissajousParams, MAX_CAPTURE_MS, MIN_CAPTURE_MS, type MotionSample, PROGRAM_IDS, type PackedFingerprint, type Point2D, type ProofResult, type PulseConfig, PulseSDK, PulseSession, type SensorData, type SolanaProof, type StageState, type StatsSummary, type StoredVerificationData, type SubmissionResult, type TBH, type TemporalFingerprint, type TouchSample, type VerificationResult, bigintToBytes32, computeCommitment, condense, fetchIdentityState, fuseFeatures, generateLissajousPoints, generatePhrase, generateProof, generateSalt, generateSolanaProof, generateTBH, hammingDistance, kurtosis, loadVerificationData, mean, packBits, prepareCircuitInput, randomLissajousParams, serializeProof, simhash, skewness, storeVerificationData, submitViaRelayer, submitViaWallet, toBigEndian32, variance };
390
+ export { type AudioCapture, type CaptureOptions, type CaptureStage, type CircuitInput, DEFAULT_CAPTURE_MS, DEFAULT_MIN_DISTANCE, DEFAULT_THRESHOLD, FINGERPRINT_BITS, type FeatureVector, type FusedFeatureVector, type IdentityState, type LissajousParams, MAX_CAPTURE_MS, MIN_CAPTURE_MS, type MotionSample, PROGRAM_IDS, type PackedFingerprint, type Point2D, type ProofResult, type PulseConfig, PulseSDK, PulseSession, type SensorData, type SolanaProof, type StageState, type StatsSummary, type StoredVerificationData, type SubmissionResult, type TBH, type TemporalFingerprint, type TouchSample, type VerificationResult, autocorrelation, bigintToBytes32, computeCommitment, condense, entropy, fetchIdentityState, fuseFeatures, generateLissajousPoints, generatePhrase, generateProof, generateSalt, generateSolanaProof, generateTBH, hammingDistance, kurtosis, loadVerificationData, mean, packBits, prepareCircuitInput, randomLissajousParams, serializeProof, simhash, skewness, storeVerificationData, submitViaRelayer, submitViaWallet, toBigEndian32, variance };
package/dist/index.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  declare const FINGERPRINT_BITS = 256;
2
2
  declare const DEFAULT_THRESHOLD = 30;
3
+ declare const DEFAULT_MIN_DISTANCE = 3;
3
4
  declare const MIN_CAPTURE_MS = 2000;
4
5
  declare const MAX_CAPTURE_MS = 60000;
5
6
  declare const DEFAULT_CAPTURE_MS = 7000;
@@ -222,6 +223,18 @@ declare function variance(values: number[], mu?: number): number;
222
223
  declare function skewness(values: number[]): number;
223
224
  declare function kurtosis(values: number[]): number;
224
225
  declare function condense(values: number[]): StatsSummary;
226
+ /**
227
+ * Shannon entropy over histogram bins. Measures information density.
228
+ * Real human data has moderate entropy (varied but structured).
229
+ * Synthetic data is either too uniform (high entropy) or too structured (low entropy).
230
+ */
231
+ declare function entropy(values: number[], bins?: number): number;
232
+ /**
233
+ * Autocorrelation at a given lag. Detects periodic synthetic patterns.
234
+ * Real human data has low autocorrelation at most lags (chaotic/noisy).
235
+ * Synthetic data often has high autocorrelation (periodic/smooth).
236
+ */
237
+ declare function autocorrelation(values: number[], lag?: number): number;
225
238
  declare function fuseFeatures(audio: number[], motion: number[], touch: number[]): number[];
226
239
 
227
240
  /** Serialized proof ready for on-chain submission */
@@ -246,6 +259,7 @@ interface CircuitInput {
246
259
  commitment_new: string;
247
260
  commitment_prev: string;
248
261
  threshold: string;
262
+ min_distance: string;
249
263
  }
250
264
  /** Proof generation result */
251
265
  interface ProofResult {
@@ -269,7 +283,7 @@ declare function serializeProof(proof: RawProof, publicSignals: string[]): Solan
269
283
  /**
270
284
  * Prepare circuit input from current and previous TBH data.
271
285
  */
272
- declare function prepareCircuitInput(current: TBH, previous: TBH, threshold?: number): CircuitInput;
286
+ declare function prepareCircuitInput(current: TBH, previous: TBH, threshold?: number, minDistance?: number): CircuitInput;
273
287
  /**
274
288
  * Generate a Groth16 proof for the Hamming distance circuit.
275
289
  *
@@ -373,4 +387,4 @@ declare function randomLissajousParams(): LissajousParams;
373
387
  */
374
388
  declare function generateLissajousPoints(params: LissajousParams): Point2D[];
375
389
 
376
- export { type AudioCapture, type CaptureOptions, type CaptureStage, type CircuitInput, DEFAULT_CAPTURE_MS, DEFAULT_THRESHOLD, FINGERPRINT_BITS, type FeatureVector, type FusedFeatureVector, type IdentityState, type LissajousParams, MAX_CAPTURE_MS, MIN_CAPTURE_MS, type MotionSample, PROGRAM_IDS, type PackedFingerprint, type Point2D, type ProofResult, type PulseConfig, PulseSDK, PulseSession, type SensorData, type SolanaProof, type StageState, type StatsSummary, type StoredVerificationData, type SubmissionResult, type TBH, type TemporalFingerprint, type TouchSample, type VerificationResult, bigintToBytes32, computeCommitment, condense, fetchIdentityState, fuseFeatures, generateLissajousPoints, generatePhrase, generateProof, generateSalt, generateSolanaProof, generateTBH, hammingDistance, kurtosis, loadVerificationData, mean, packBits, prepareCircuitInput, randomLissajousParams, serializeProof, simhash, skewness, storeVerificationData, submitViaRelayer, submitViaWallet, toBigEndian32, variance };
390
+ export { type AudioCapture, type CaptureOptions, type CaptureStage, type CircuitInput, DEFAULT_CAPTURE_MS, DEFAULT_MIN_DISTANCE, DEFAULT_THRESHOLD, FINGERPRINT_BITS, type FeatureVector, type FusedFeatureVector, type IdentityState, type LissajousParams, MAX_CAPTURE_MS, MIN_CAPTURE_MS, type MotionSample, PROGRAM_IDS, type PackedFingerprint, type Point2D, type ProofResult, type PulseConfig, PulseSDK, PulseSession, type SensorData, type SolanaProof, type StageState, type StatsSummary, type StoredVerificationData, type SubmissionResult, type TBH, type TemporalFingerprint, type TouchSample, type VerificationResult, autocorrelation, bigintToBytes32, computeCommitment, condense, entropy, fetchIdentityState, fuseFeatures, generateLissajousPoints, generatePhrase, generateProof, generateSalt, generateSolanaProof, generateTBH, hammingDistance, kurtosis, loadVerificationData, mean, packBits, prepareCircuitInput, randomLissajousParams, serializeProof, simhash, skewness, storeVerificationData, submitViaRelayer, submitViaWallet, toBigEndian32, variance };
package/dist/index.js CHANGED
@@ -12978,6 +12978,7 @@ var init_esm4 = __esm({
12978
12978
  var index_exports = {};
12979
12979
  __export(index_exports, {
12980
12980
  DEFAULT_CAPTURE_MS: () => DEFAULT_CAPTURE_MS,
12981
+ DEFAULT_MIN_DISTANCE: () => DEFAULT_MIN_DISTANCE,
12981
12982
  DEFAULT_THRESHOLD: () => DEFAULT_THRESHOLD,
12982
12983
  FINGERPRINT_BITS: () => FINGERPRINT_BITS,
12983
12984
  MAX_CAPTURE_MS: () => MAX_CAPTURE_MS,
@@ -12985,9 +12986,11 @@ __export(index_exports, {
12985
12986
  PROGRAM_IDS: () => PROGRAM_IDS,
12986
12987
  PulseSDK: () => PulseSDK,
12987
12988
  PulseSession: () => PulseSession,
12989
+ autocorrelation: () => autocorrelation,
12988
12990
  bigintToBytes32: () => bigintToBytes32,
12989
12991
  computeCommitment: () => computeCommitment,
12990
12992
  condense: () => condense,
12993
+ entropy: () => entropy,
12991
12994
  fetchIdentityState: () => fetchIdentityState,
12992
12995
  fuseFeatures: () => fuseFeatures,
12993
12996
  generateLissajousPoints: () => generateLissajousPoints,
@@ -13023,6 +13026,7 @@ var BN254_SCALAR_FIELD = BigInt(
13023
13026
  );
13024
13027
  var FINGERPRINT_BITS = 256;
13025
13028
  var DEFAULT_THRESHOLD = 30;
13029
+ var DEFAULT_MIN_DISTANCE = 3;
13026
13030
  var PROOF_A_SIZE = 64;
13027
13031
  var PROOF_B_SIZE = 128;
13028
13032
  var PROOF_C_SIZE = 64;
@@ -13262,6 +13266,37 @@ function condense(values) {
13262
13266
  kurtosis: kurtosis(values)
13263
13267
  };
13264
13268
  }
13269
+ function entropy(values, bins = 16) {
13270
+ if (values.length < 2) return 0;
13271
+ const min = Math.min(...values);
13272
+ const max = Math.max(...values);
13273
+ if (min === max) return 0;
13274
+ const counts = new Array(bins).fill(0);
13275
+ const range = max - min;
13276
+ for (const v of values) {
13277
+ const idx = Math.min(Math.floor((v - min) / range * bins), bins - 1);
13278
+ counts[idx]++;
13279
+ }
13280
+ let h = 0;
13281
+ for (const c of counts) {
13282
+ if (c > 0) {
13283
+ const p = c / values.length;
13284
+ h -= p * Math.log2(p);
13285
+ }
13286
+ }
13287
+ return h;
13288
+ }
13289
+ function autocorrelation(values, lag = 1) {
13290
+ if (values.length <= lag) return 0;
13291
+ const m = mean(values);
13292
+ const v = variance(values, m);
13293
+ if (v === 0) return 0;
13294
+ let sum = 0;
13295
+ for (let i = 0; i < values.length - lag; i++) {
13296
+ sum += (values[i] - m) * (values[i + lag] - m);
13297
+ }
13298
+ return sum / ((values.length - lag) * v);
13299
+ }
13265
13300
  function fuseFeatures(audio, motion, touch) {
13266
13301
  return [...audio, ...motion, ...touch];
13267
13302
  }
@@ -13276,10 +13311,10 @@ function extractMFCC(audio) {
13276
13311
  try {
13277
13312
  Meyda = require("meyda");
13278
13313
  } catch {
13279
- return new Array(NUM_MFCC * 3 * 4).fill(0);
13314
+ return new Array(NUM_MFCC * 3 * 4 + NUM_MFCC).fill(0);
13280
13315
  }
13281
13316
  const numFrames = Math.floor((samples.length - FRAME_SIZE) / HOP_SIZE) + 1;
13282
- if (numFrames < 3) return new Array(NUM_MFCC * 3 * 4).fill(0);
13317
+ if (numFrames < 3) return new Array(NUM_MFCC * 3 * 4 + NUM_MFCC).fill(0);
13283
13318
  const mfccFrames = [];
13284
13319
  for (let i = 0; i < numFrames; i++) {
13285
13320
  const start = i * HOP_SIZE;
@@ -13314,6 +13349,10 @@ function extractMFCC(audio) {
13314
13349
  const stats = condense(dd);
13315
13350
  features.push(stats.mean, stats.variance, stats.skewness, stats.kurtosis);
13316
13351
  }
13352
+ for (let c = 0; c < NUM_MFCC; c++) {
13353
+ const raw = mfccFrames.map((f) => f[c] ?? 0);
13354
+ features.push(entropy(raw));
13355
+ }
13317
13356
  return features;
13318
13357
  }
13319
13358
  function computeDeltas(frames) {
@@ -13328,7 +13367,7 @@ function computeDeltas(frames) {
13328
13367
 
13329
13368
  // src/extraction/kinematic.ts
13330
13369
  function extractMotionFeatures(samples) {
13331
- if (samples.length < 5) return new Array(48).fill(0);
13370
+ if (samples.length < 5) return new Array(54).fill(0);
13332
13371
  const axes = {
13333
13372
  ax: samples.map((s) => s.ax),
13334
13373
  ay: samples.map((s) => s.ay),
@@ -13354,10 +13393,19 @@ function extractMotionFeatures(samples) {
13354
13393
  jounceStats.kurtosis
13355
13394
  );
13356
13395
  }
13396
+ for (const values of Object.values(axes)) {
13397
+ const jerk = derivative(values);
13398
+ const windowSize = Math.max(5, Math.floor(jerk.length / 4));
13399
+ const windowVariances = [];
13400
+ for (let i = 0; i <= jerk.length - windowSize; i += windowSize) {
13401
+ windowVariances.push(variance(jerk.slice(i, i + windowSize)));
13402
+ }
13403
+ features.push(windowVariances.length >= 2 ? variance(windowVariances) : 0);
13404
+ }
13357
13405
  return features;
13358
13406
  }
13359
13407
  function extractTouchFeatures(samples) {
13360
- if (samples.length < 5) return new Array(32).fill(0);
13408
+ if (samples.length < 5) return new Array(36).fill(0);
13361
13409
  const x = samples.map((s) => s.x);
13362
13410
  const y = samples.map((s) => s.y);
13363
13411
  const pressure = samples.map((s) => s.pressure);
@@ -13377,6 +13425,14 @@ function extractTouchFeatures(samples) {
13377
13425
  const jerkY = derivative(accY);
13378
13426
  features.push(...Object.values(condense(jerkX)));
13379
13427
  features.push(...Object.values(condense(jerkY)));
13428
+ for (const values of [vx, vy, pressure, area]) {
13429
+ const windowSize = Math.max(5, Math.floor(values.length / 4));
13430
+ const windowVariances = [];
13431
+ for (let i = 0; i <= values.length - windowSize; i += windowSize) {
13432
+ windowVariances.push(variance(values.slice(i, i + windowSize)));
13433
+ }
13434
+ features.push(windowVariances.length >= 2 ? variance(windowVariances) : 0);
13435
+ }
13380
13436
  return features;
13381
13437
  }
13382
13438
  function derivative(values) {
@@ -13558,7 +13614,7 @@ async function getSnarkjs() {
13558
13614
  }
13559
13615
  return snarkjsModule;
13560
13616
  }
13561
- function prepareCircuitInput(current, previous, threshold = DEFAULT_THRESHOLD) {
13617
+ function prepareCircuitInput(current, previous, threshold = DEFAULT_THRESHOLD, minDistance = DEFAULT_MIN_DISTANCE) {
13562
13618
  return {
13563
13619
  ft_new: current.fingerprint,
13564
13620
  ft_prev: previous.fingerprint,
@@ -13566,7 +13622,8 @@ function prepareCircuitInput(current, previous, threshold = DEFAULT_THRESHOLD) {
13566
13622
  salt_prev: previous.salt.toString(),
13567
13623
  commitment_new: current.commitment.toString(),
13568
13624
  commitment_prev: previous.commitment.toString(),
13569
- threshold: threshold.toString()
13625
+ threshold: threshold.toString(),
13626
+ min_distance: minDistance.toString()
13570
13627
  };
13571
13628
  }
13572
13629
  async function generateProof(input, wasmPath, zkeyPath) {
@@ -13784,7 +13841,7 @@ var inMemoryStore = null;
13784
13841
 
13785
13842
  // src/pulse.ts
13786
13843
  function extractFeatures(data) {
13787
- const audioFeatures = data.audio ? extractMFCC(data.audio) : new Array(156).fill(0);
13844
+ const audioFeatures = data.audio ? extractMFCC(data.audio) : new Array(169).fill(0);
13788
13845
  const motionFeatures = extractMotionFeatures(data.motion);
13789
13846
  const touchFeatures = extractTouchFeatures(data.touch);
13790
13847
  return fuseFeatures(audioFeatures, motionFeatures, touchFeatures);
@@ -14167,6 +14224,7 @@ function generateLissajousPoints(params) {
14167
14224
  // Annotate the CommonJS export names for ESM import in node:
14168
14225
  0 && (module.exports = {
14169
14226
  DEFAULT_CAPTURE_MS,
14227
+ DEFAULT_MIN_DISTANCE,
14170
14228
  DEFAULT_THRESHOLD,
14171
14229
  FINGERPRINT_BITS,
14172
14230
  MAX_CAPTURE_MS,
@@ -14174,9 +14232,11 @@ function generateLissajousPoints(params) {
14174
14232
  PROGRAM_IDS,
14175
14233
  PulseSDK,
14176
14234
  PulseSession,
14235
+ autocorrelation,
14177
14236
  bigintToBytes32,
14178
14237
  computeCommitment,
14179
14238
  condense,
14239
+ entropy,
14180
14240
  fetchIdentityState,
14181
14241
  fuseFeatures,
14182
14242
  generateLissajousPoints,