@iam-protocol/pulse-sdk 0.2.0 → 0.2.2
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/README.md +3 -0
- package/dist/index.d.mts +17 -2
- package/dist/index.d.ts +17 -2
- package/dist/index.js +65 -4
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +63 -4
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/challenge/lissajous.ts +29 -0
- package/src/challenge/phrase.ts +34 -1
- package/src/index.ts +2 -2
- package/src/pulse.ts +2 -1
- package/src/sensor/audio.ts +9 -1
- package/src/sensor/types.ts +2 -0
package/README.md
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
# @iam-protocol/pulse-sdk
|
|
2
2
|
|
|
3
|
+
[](https://www.npmjs.com/package/@iam-protocol/pulse-sdk)
|
|
4
|
+
[](https://www.npmjs.com/package/@iam-protocol/pulse-sdk)
|
|
5
|
+
|
|
3
6
|
Client-side SDK for the IAM Protocol. Captures behavioral biometrics (voice, motion, touch), generates a Temporal-Biometric Hash, produces a Groth16 zero-knowledge proof, and submits it for on-chain verification on Solana.
|
|
4
7
|
|
|
5
8
|
## Install
|
package/dist/index.d.mts
CHANGED
|
@@ -51,6 +51,8 @@ interface CaptureOptions {
|
|
|
51
51
|
minDurationMs?: number;
|
|
52
52
|
/** Maximum capture duration in ms. Auto-stops if signal hasn't fired. Default: 60000 */
|
|
53
53
|
maxDurationMs?: number;
|
|
54
|
+
/** Called with RMS audio level (0-1) on each buffer during audio capture (~4x per second). */
|
|
55
|
+
onAudioLevel?: (rms: number) => void;
|
|
54
56
|
}
|
|
55
57
|
/** Stage of a capture session */
|
|
56
58
|
type CaptureStage = "audio" | "motion" | "touch";
|
|
@@ -119,7 +121,7 @@ declare class PulseSession {
|
|
|
119
121
|
private motionData;
|
|
120
122
|
private touchData;
|
|
121
123
|
constructor(config: ResolvedConfig, touchElement?: HTMLElement);
|
|
122
|
-
startAudio(): Promise<void>;
|
|
124
|
+
startAudio(onAudioLevel?: (rms: number) => void): Promise<void>;
|
|
123
125
|
stopAudio(): Promise<AudioCapture | null>;
|
|
124
126
|
skipAudio(): void;
|
|
125
127
|
startMotion(): Promise<void>;
|
|
@@ -360,6 +362,11 @@ declare function loadVerificationData(): StoredVerificationData | null;
|
|
|
360
362
|
* Each phrase is 5-6 syllable pairs, forming nonsensical but speakable words.
|
|
361
363
|
*/
|
|
362
364
|
declare function generatePhrase(wordCount?: number): string;
|
|
365
|
+
/**
|
|
366
|
+
* Generate a sequence of phrases for dynamic mid-session switching.
|
|
367
|
+
* Each phrase uses a different syllable subset to prevent pre-computation.
|
|
368
|
+
*/
|
|
369
|
+
declare function generatePhraseSequence(count?: number, wordCount?: number): string[];
|
|
363
370
|
|
|
364
371
|
/**
|
|
365
372
|
* Generate Lissajous curve points for the touch tracing challenge.
|
|
@@ -386,5 +393,13 @@ declare function randomLissajousParams(): LissajousParams;
|
|
|
386
393
|
* Generate Lissajous curve points normalized to [0, 1] range.
|
|
387
394
|
*/
|
|
388
395
|
declare function generateLissajousPoints(params: LissajousParams): Point2D[];
|
|
396
|
+
/**
|
|
397
|
+
* Generate a sequence of Lissajous curves for dynamic mid-session switching.
|
|
398
|
+
* Each curve uses different parameters, preventing pre-computation.
|
|
399
|
+
*/
|
|
400
|
+
declare function generateLissajousSequence(count?: number): {
|
|
401
|
+
params: LissajousParams;
|
|
402
|
+
points: Point2D[];
|
|
403
|
+
}[];
|
|
389
404
|
|
|
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 };
|
|
405
|
+
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, generateLissajousSequence, generatePhrase, generatePhraseSequence, 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
|
@@ -51,6 +51,8 @@ interface CaptureOptions {
|
|
|
51
51
|
minDurationMs?: number;
|
|
52
52
|
/** Maximum capture duration in ms. Auto-stops if signal hasn't fired. Default: 60000 */
|
|
53
53
|
maxDurationMs?: number;
|
|
54
|
+
/** Called with RMS audio level (0-1) on each buffer during audio capture (~4x per second). */
|
|
55
|
+
onAudioLevel?: (rms: number) => void;
|
|
54
56
|
}
|
|
55
57
|
/** Stage of a capture session */
|
|
56
58
|
type CaptureStage = "audio" | "motion" | "touch";
|
|
@@ -119,7 +121,7 @@ declare class PulseSession {
|
|
|
119
121
|
private motionData;
|
|
120
122
|
private touchData;
|
|
121
123
|
constructor(config: ResolvedConfig, touchElement?: HTMLElement);
|
|
122
|
-
startAudio(): Promise<void>;
|
|
124
|
+
startAudio(onAudioLevel?: (rms: number) => void): Promise<void>;
|
|
123
125
|
stopAudio(): Promise<AudioCapture | null>;
|
|
124
126
|
skipAudio(): void;
|
|
125
127
|
startMotion(): Promise<void>;
|
|
@@ -360,6 +362,11 @@ declare function loadVerificationData(): StoredVerificationData | null;
|
|
|
360
362
|
* Each phrase is 5-6 syllable pairs, forming nonsensical but speakable words.
|
|
361
363
|
*/
|
|
362
364
|
declare function generatePhrase(wordCount?: number): string;
|
|
365
|
+
/**
|
|
366
|
+
* Generate a sequence of phrases for dynamic mid-session switching.
|
|
367
|
+
* Each phrase uses a different syllable subset to prevent pre-computation.
|
|
368
|
+
*/
|
|
369
|
+
declare function generatePhraseSequence(count?: number, wordCount?: number): string[];
|
|
363
370
|
|
|
364
371
|
/**
|
|
365
372
|
* Generate Lissajous curve points for the touch tracing challenge.
|
|
@@ -386,5 +393,13 @@ declare function randomLissajousParams(): LissajousParams;
|
|
|
386
393
|
* Generate Lissajous curve points normalized to [0, 1] range.
|
|
387
394
|
*/
|
|
388
395
|
declare function generateLissajousPoints(params: LissajousParams): Point2D[];
|
|
396
|
+
/**
|
|
397
|
+
* Generate a sequence of Lissajous curves for dynamic mid-session switching.
|
|
398
|
+
* Each curve uses different parameters, preventing pre-computation.
|
|
399
|
+
*/
|
|
400
|
+
declare function generateLissajousSequence(count?: number): {
|
|
401
|
+
params: LissajousParams;
|
|
402
|
+
points: Point2D[];
|
|
403
|
+
}[];
|
|
389
404
|
|
|
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 };
|
|
405
|
+
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, generateLissajousSequence, generatePhrase, generatePhraseSequence, generateProof, generateSalt, generateSolanaProof, generateTBH, hammingDistance, kurtosis, loadVerificationData, mean, packBits, prepareCircuitInput, randomLissajousParams, serializeProof, simhash, skewness, storeVerificationData, submitViaRelayer, submitViaWallet, toBigEndian32, variance };
|
package/dist/index.js
CHANGED
|
@@ -12994,7 +12994,9 @@ __export(index_exports, {
|
|
|
12994
12994
|
fetchIdentityState: () => fetchIdentityState,
|
|
12995
12995
|
fuseFeatures: () => fuseFeatures,
|
|
12996
12996
|
generateLissajousPoints: () => generateLissajousPoints,
|
|
12997
|
+
generateLissajousSequence: () => generateLissajousSequence,
|
|
12997
12998
|
generatePhrase: () => generatePhrase,
|
|
12999
|
+
generatePhraseSequence: () => generatePhraseSequence,
|
|
12998
13000
|
generateProof: () => generateProof,
|
|
12999
13001
|
generateSalt: () => generateSalt,
|
|
13000
13002
|
generateSolanaProof: () => generateSolanaProof,
|
|
@@ -13047,7 +13049,8 @@ async function captureAudio(options = {}) {
|
|
|
13047
13049
|
const {
|
|
13048
13050
|
signal,
|
|
13049
13051
|
minDurationMs = MIN_CAPTURE_MS,
|
|
13050
|
-
maxDurationMs = MAX_CAPTURE_MS
|
|
13052
|
+
maxDurationMs = MAX_CAPTURE_MS,
|
|
13053
|
+
onAudioLevel
|
|
13051
13054
|
} = options;
|
|
13052
13055
|
const stream = await navigator.mediaDevices.getUserMedia({
|
|
13053
13056
|
audio: {
|
|
@@ -13067,7 +13070,13 @@ async function captureAudio(options = {}) {
|
|
|
13067
13070
|
const bufferSize = 4096;
|
|
13068
13071
|
const processor = ctx.createScriptProcessor(bufferSize, 1, 1);
|
|
13069
13072
|
processor.onaudioprocess = (e2) => {
|
|
13070
|
-
|
|
13073
|
+
const data = e2.inputBuffer.getChannelData(0);
|
|
13074
|
+
chunks.push(new Float32Array(data));
|
|
13075
|
+
if (onAudioLevel) {
|
|
13076
|
+
let sum = 0;
|
|
13077
|
+
for (let i = 0; i < data.length; i++) sum += data[i] * data[i];
|
|
13078
|
+
onAudioLevel(Math.sqrt(sum / data.length));
|
|
13079
|
+
}
|
|
13071
13080
|
};
|
|
13072
13081
|
source.connect(processor);
|
|
13073
13082
|
processor.connect(ctx.destination);
|
|
@@ -13937,13 +13946,14 @@ var PulseSession = class {
|
|
|
13937
13946
|
this.touchElement = touchElement;
|
|
13938
13947
|
}
|
|
13939
13948
|
// --- Audio ---
|
|
13940
|
-
async startAudio() {
|
|
13949
|
+
async startAudio(onAudioLevel) {
|
|
13941
13950
|
if (this.audioStageState !== "idle")
|
|
13942
13951
|
throw new Error("Audio capture already started");
|
|
13943
13952
|
this.audioStageState = "capturing";
|
|
13944
13953
|
this.audioController = new AbortController();
|
|
13945
13954
|
this.audioPromise = captureAudio({
|
|
13946
|
-
signal: this.audioController.signal
|
|
13955
|
+
signal: this.audioController.signal,
|
|
13956
|
+
onAudioLevel
|
|
13947
13957
|
}).catch(() => null);
|
|
13948
13958
|
}
|
|
13949
13959
|
async stopAudio() {
|
|
@@ -14191,6 +14201,28 @@ function generatePhrase(wordCount = 5) {
|
|
|
14191
14201
|
}
|
|
14192
14202
|
return words.join(" ");
|
|
14193
14203
|
}
|
|
14204
|
+
function generatePhraseSequence(count = 3, wordCount = 4) {
|
|
14205
|
+
const subsetSize = Math.floor(SYLLABLES.length / count);
|
|
14206
|
+
const phrases = [];
|
|
14207
|
+
for (let p = 0; p < count; p++) {
|
|
14208
|
+
const start = p * subsetSize % SYLLABLES.length;
|
|
14209
|
+
const subset = [
|
|
14210
|
+
...SYLLABLES.slice(start, start + subsetSize),
|
|
14211
|
+
...SYLLABLES.slice(0, Math.max(0, start + subsetSize - SYLLABLES.length))
|
|
14212
|
+
];
|
|
14213
|
+
const words = [];
|
|
14214
|
+
for (let w = 0; w < wordCount; w++) {
|
|
14215
|
+
const syllableCount = 2 + Math.floor(Math.random() * 2);
|
|
14216
|
+
let word = "";
|
|
14217
|
+
for (let s = 0; s < syllableCount; s++) {
|
|
14218
|
+
word += subset[Math.floor(Math.random() * subset.length)];
|
|
14219
|
+
}
|
|
14220
|
+
words.push(word);
|
|
14221
|
+
}
|
|
14222
|
+
phrases.push(words.join(" "));
|
|
14223
|
+
}
|
|
14224
|
+
return phrases;
|
|
14225
|
+
}
|
|
14194
14226
|
|
|
14195
14227
|
// src/challenge/lissajous.ts
|
|
14196
14228
|
function randomLissajousParams() {
|
|
@@ -14221,6 +14253,33 @@ function generateLissajousPoints(params) {
|
|
|
14221
14253
|
}
|
|
14222
14254
|
return result;
|
|
14223
14255
|
}
|
|
14256
|
+
function generateLissajousSequence(count = 2) {
|
|
14257
|
+
const allRatios = [
|
|
14258
|
+
[1, 2],
|
|
14259
|
+
[2, 3],
|
|
14260
|
+
[3, 4],
|
|
14261
|
+
[3, 5],
|
|
14262
|
+
[4, 5],
|
|
14263
|
+
[1, 3],
|
|
14264
|
+
[2, 5],
|
|
14265
|
+
[5, 6],
|
|
14266
|
+
[3, 7],
|
|
14267
|
+
[4, 7]
|
|
14268
|
+
];
|
|
14269
|
+
const shuffled = [...allRatios].sort(() => Math.random() - 0.5);
|
|
14270
|
+
const sequence = [];
|
|
14271
|
+
for (let i = 0; i < count; i++) {
|
|
14272
|
+
const pair = shuffled[i % shuffled.length];
|
|
14273
|
+
const params = {
|
|
14274
|
+
a: pair[0],
|
|
14275
|
+
b: pair[1],
|
|
14276
|
+
delta: Math.PI * (0.1 + Math.random() * 0.8),
|
|
14277
|
+
points: 200
|
|
14278
|
+
};
|
|
14279
|
+
sequence.push({ params, points: generateLissajousPoints(params) });
|
|
14280
|
+
}
|
|
14281
|
+
return sequence;
|
|
14282
|
+
}
|
|
14224
14283
|
// Annotate the CommonJS export names for ESM import in node:
|
|
14225
14284
|
0 && (module.exports = {
|
|
14226
14285
|
DEFAULT_CAPTURE_MS,
|
|
@@ -14240,7 +14299,9 @@ function generateLissajousPoints(params) {
|
|
|
14240
14299
|
fetchIdentityState,
|
|
14241
14300
|
fuseFeatures,
|
|
14242
14301
|
generateLissajousPoints,
|
|
14302
|
+
generateLissajousSequence,
|
|
14243
14303
|
generatePhrase,
|
|
14304
|
+
generatePhraseSequence,
|
|
14244
14305
|
generateProof,
|
|
14245
14306
|
generateSalt,
|
|
14246
14307
|
generateSolanaProof,
|