@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 +16 -2
- package/dist/index.d.ts +16 -2
- package/dist/index.js +67 -7
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +64 -7
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/config.ts +2 -1
- package/src/extraction/kinematic.ts +28 -5
- package/src/extraction/mfcc.ts +11 -4
- package/src/extraction/statistics.ts +46 -0
- package/src/index.ts +2 -2
- package/src/proof/prover.ts +4 -2
- package/src/proof/types.ts +1 -0
- package/src/pulse.ts +1 -1
- package/test/integration.test.ts +3 -2
- package/test/serializer.test.ts +1 -0
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(
|
|
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(
|
|
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(
|
|
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,
|