@entros/pulse-sdk 3.3.1 → 3.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +21 -2
- package/dist/index.d.ts +21 -2
- package/dist/index.js +44 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +43 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +5 -2
package/dist/index.d.mts
CHANGED
|
@@ -695,6 +695,20 @@ interface BaselineWallet {
|
|
|
695
695
|
publicKey: PublicKey;
|
|
696
696
|
signMessage: (msg: Uint8Array) => Promise<Uint8Array>;
|
|
697
697
|
}
|
|
698
|
+
/**
|
|
699
|
+
* Thrown when a `signMessage` result fails to verify against the wallet's own
|
|
700
|
+
* public key — i.e. a different wallet signed than the one connected. The most
|
|
701
|
+
* common cause is a second wallet extension (e.g. Backpack) set as the browser
|
|
702
|
+
* default and intercepting the prompt while a different wallet (e.g. Phantom)
|
|
703
|
+
* is the one actually connected. Surfaced so callers can tell the user to sign
|
|
704
|
+
* with the connected wallet, rather than deriving a key bound to the wrong
|
|
705
|
+
* wallet — which would silently corrupt the encrypted baseline and later
|
|
706
|
+
* misreport as a stale baseline.
|
|
707
|
+
*/
|
|
708
|
+
declare class WalletSignatureMismatchError extends Error {
|
|
709
|
+
readonly expectedWallet: string;
|
|
710
|
+
constructor(expectedWallet: string);
|
|
711
|
+
}
|
|
698
712
|
/**
|
|
699
713
|
* Derive an AES-256 key from the wallet's deterministic signature over
|
|
700
714
|
* the domain-separated payload, via HKDF-SHA256.
|
|
@@ -816,11 +830,16 @@ declare function loadVerificationData(): Promise<StoredVerificationData | null>;
|
|
|
816
830
|
* can't `signMessage` (no method on the adapter, e.g., older Ledger
|
|
817
831
|
* firmware) OR the user cancelled the prompt OR the wallet erred. The
|
|
818
832
|
* `detail` field carries the specific cause when present.
|
|
833
|
+
* - `wallet-mismatch`: the `signMessage` signature did not verify against
|
|
834
|
+
* the connected wallet's public key — a different wallet signed the
|
|
835
|
+
* prompt (commonly another extension set as the browser default). NOT a
|
|
836
|
+
* stale baseline: the on-chain blob is intact. UX should ask the user to
|
|
837
|
+
* sign with the connected wallet and must NOT offer a destructive reset.
|
|
819
838
|
* - `stale-baseline`: blob predates a `reset_identity_state` cycle.
|
|
820
839
|
* Treat as terminal recovery failure; route to fresh-capture flow.
|
|
821
840
|
* - `unknown-error`: catch-all (RPC failure, malformed blob, etc.).
|
|
822
841
|
*/
|
|
823
|
-
type BaselineRecoveryReason = "no-on-chain-identity" | "no-encrypted-baseline" | "signing-unavailable" | "stale-baseline" | "unknown-error";
|
|
842
|
+
type BaselineRecoveryReason = "no-on-chain-identity" | "no-encrypted-baseline" | "signing-unavailable" | "wallet-mismatch" | "stale-baseline" | "unknown-error";
|
|
824
843
|
interface BaselineRecoveryResult {
|
|
825
844
|
recovered: boolean;
|
|
826
845
|
reason?: BaselineRecoveryReason;
|
|
@@ -951,4 +970,4 @@ declare function fetchChallenge(executorUrl: string, walletAddress: string, apiK
|
|
|
951
970
|
*/
|
|
952
971
|
declare function encodeAudioAsBase64(samples: Float32Array): string;
|
|
953
972
|
|
|
954
|
-
export { type AgentHumanOperator, type AudioCapture, type BaselineRecoveryReason, type BaselineRecoveryResult, type BaselineWallet, type CaptureOptions, type CaptureStage, type ChallengeResponse, type CircuitInput, DEFAULT_CAPTURE_MS, DEFAULT_MIN_DISTANCE, DEFAULT_THRESHOLD, ENCRYPTED_BASELINE_BLOB_BYTES, type EntrosAttestation, FINGERPRINT_BITS, type FeatureVector, type FusedFeatureVector, type IdentityState, type LissajousParams, MAX_CAPTURE_MS, MIN_AUDIO_SAMPLES, MIN_CAPTURE_MS, MIN_MOTION_SAMPLES, MIN_TOUCH_SAMPLES, MOTION_FEATURE_COUNT, type MotionSample, PROGRAM_IDS, type PackedFingerprint, type Point2D, type ProofResult, type PulseConfig, PulseSDK, PulseSession, SPEAKER_FEATURE_COUNT, type SensorData, type SolanaProof, type StageState, StaleEncryptedBaselineError, type StatsSummary, type StoredVerificationData, type SubmissionResult, type TBH, TOUCH_FEATURE_COUNT, type TemporalFingerprint, type TouchSample, type VerificationResult, attestAgentOperator, bigintToBytes32, bytes32ToBigint, bytesToFingerprint, clearBaselineKeyCache, computeCommitment, decryptBaselineBlob, deriveBaselineKey, deriveEncryptedBaselinePda, encodeAudioAsBase64, encryptBaselineBlob, extractAccelerationMagnitude, extractMotionFeatures, extractMouseDynamics, extractSpeakerFeatures, extractSpeakerFeaturesDetailed, extractTouchFeatures, fetchChallenge, fetchEncryptedBaseline, fetchIdentityState, fingerprintToBytes, fuseFeatures, fuseRawFeatures, generateLissajousPoints, generateLissajousSequence, generatePhrase, generatePhraseSequence, generateProof, generateSalt, generateSolanaProof, generateTBH, getAgentHumanOperator, getOrDeriveBaselineKey, hammingDistance, loadVerificationData, packBits, prepareCircuitInput, randomLissajousParams, recoverBaselineFromChain, serializeProof, simhash, storeVerificationData, submitResetViaWallet, submitViaRelayer, submitViaWallet, toBigEndian32, verifyEntrosAttestation };
|
|
973
|
+
export { type AgentHumanOperator, type AudioCapture, type BaselineRecoveryReason, type BaselineRecoveryResult, type BaselineWallet, type CaptureOptions, type CaptureStage, type ChallengeResponse, type CircuitInput, DEFAULT_CAPTURE_MS, DEFAULT_MIN_DISTANCE, DEFAULT_THRESHOLD, ENCRYPTED_BASELINE_BLOB_BYTES, type EntrosAttestation, FINGERPRINT_BITS, type FeatureVector, type FusedFeatureVector, type IdentityState, type LissajousParams, MAX_CAPTURE_MS, MIN_AUDIO_SAMPLES, MIN_CAPTURE_MS, MIN_MOTION_SAMPLES, MIN_TOUCH_SAMPLES, MOTION_FEATURE_COUNT, type MotionSample, PROGRAM_IDS, type PackedFingerprint, type Point2D, type ProofResult, type PulseConfig, PulseSDK, PulseSession, SPEAKER_FEATURE_COUNT, type SensorData, type SolanaProof, type StageState, StaleEncryptedBaselineError, type StatsSummary, type StoredVerificationData, type SubmissionResult, type TBH, TOUCH_FEATURE_COUNT, type TemporalFingerprint, type TouchSample, type VerificationResult, WalletSignatureMismatchError, attestAgentOperator, bigintToBytes32, bytes32ToBigint, bytesToFingerprint, clearBaselineKeyCache, computeCommitment, decryptBaselineBlob, deriveBaselineKey, deriveEncryptedBaselinePda, encodeAudioAsBase64, encryptBaselineBlob, extractAccelerationMagnitude, extractMotionFeatures, extractMouseDynamics, extractSpeakerFeatures, extractSpeakerFeaturesDetailed, extractTouchFeatures, fetchChallenge, fetchEncryptedBaseline, fetchIdentityState, fingerprintToBytes, fuseFeatures, fuseRawFeatures, generateLissajousPoints, generateLissajousSequence, generatePhrase, generatePhraseSequence, generateProof, generateSalt, generateSolanaProof, generateTBH, getAgentHumanOperator, getOrDeriveBaselineKey, hammingDistance, loadVerificationData, packBits, prepareCircuitInput, randomLissajousParams, recoverBaselineFromChain, serializeProof, simhash, storeVerificationData, submitResetViaWallet, submitViaRelayer, submitViaWallet, toBigEndian32, verifyEntrosAttestation };
|
package/dist/index.d.ts
CHANGED
|
@@ -695,6 +695,20 @@ interface BaselineWallet {
|
|
|
695
695
|
publicKey: PublicKey;
|
|
696
696
|
signMessage: (msg: Uint8Array) => Promise<Uint8Array>;
|
|
697
697
|
}
|
|
698
|
+
/**
|
|
699
|
+
* Thrown when a `signMessage` result fails to verify against the wallet's own
|
|
700
|
+
* public key — i.e. a different wallet signed than the one connected. The most
|
|
701
|
+
* common cause is a second wallet extension (e.g. Backpack) set as the browser
|
|
702
|
+
* default and intercepting the prompt while a different wallet (e.g. Phantom)
|
|
703
|
+
* is the one actually connected. Surfaced so callers can tell the user to sign
|
|
704
|
+
* with the connected wallet, rather than deriving a key bound to the wrong
|
|
705
|
+
* wallet — which would silently corrupt the encrypted baseline and later
|
|
706
|
+
* misreport as a stale baseline.
|
|
707
|
+
*/
|
|
708
|
+
declare class WalletSignatureMismatchError extends Error {
|
|
709
|
+
readonly expectedWallet: string;
|
|
710
|
+
constructor(expectedWallet: string);
|
|
711
|
+
}
|
|
698
712
|
/**
|
|
699
713
|
* Derive an AES-256 key from the wallet's deterministic signature over
|
|
700
714
|
* the domain-separated payload, via HKDF-SHA256.
|
|
@@ -816,11 +830,16 @@ declare function loadVerificationData(): Promise<StoredVerificationData | null>;
|
|
|
816
830
|
* can't `signMessage` (no method on the adapter, e.g., older Ledger
|
|
817
831
|
* firmware) OR the user cancelled the prompt OR the wallet erred. The
|
|
818
832
|
* `detail` field carries the specific cause when present.
|
|
833
|
+
* - `wallet-mismatch`: the `signMessage` signature did not verify against
|
|
834
|
+
* the connected wallet's public key — a different wallet signed the
|
|
835
|
+
* prompt (commonly another extension set as the browser default). NOT a
|
|
836
|
+
* stale baseline: the on-chain blob is intact. UX should ask the user to
|
|
837
|
+
* sign with the connected wallet and must NOT offer a destructive reset.
|
|
819
838
|
* - `stale-baseline`: blob predates a `reset_identity_state` cycle.
|
|
820
839
|
* Treat as terminal recovery failure; route to fresh-capture flow.
|
|
821
840
|
* - `unknown-error`: catch-all (RPC failure, malformed blob, etc.).
|
|
822
841
|
*/
|
|
823
|
-
type BaselineRecoveryReason = "no-on-chain-identity" | "no-encrypted-baseline" | "signing-unavailable" | "stale-baseline" | "unknown-error";
|
|
842
|
+
type BaselineRecoveryReason = "no-on-chain-identity" | "no-encrypted-baseline" | "signing-unavailable" | "wallet-mismatch" | "stale-baseline" | "unknown-error";
|
|
824
843
|
interface BaselineRecoveryResult {
|
|
825
844
|
recovered: boolean;
|
|
826
845
|
reason?: BaselineRecoveryReason;
|
|
@@ -951,4 +970,4 @@ declare function fetchChallenge(executorUrl: string, walletAddress: string, apiK
|
|
|
951
970
|
*/
|
|
952
971
|
declare function encodeAudioAsBase64(samples: Float32Array): string;
|
|
953
972
|
|
|
954
|
-
export { type AgentHumanOperator, type AudioCapture, type BaselineRecoveryReason, type BaselineRecoveryResult, type BaselineWallet, type CaptureOptions, type CaptureStage, type ChallengeResponse, type CircuitInput, DEFAULT_CAPTURE_MS, DEFAULT_MIN_DISTANCE, DEFAULT_THRESHOLD, ENCRYPTED_BASELINE_BLOB_BYTES, type EntrosAttestation, FINGERPRINT_BITS, type FeatureVector, type FusedFeatureVector, type IdentityState, type LissajousParams, MAX_CAPTURE_MS, MIN_AUDIO_SAMPLES, MIN_CAPTURE_MS, MIN_MOTION_SAMPLES, MIN_TOUCH_SAMPLES, MOTION_FEATURE_COUNT, type MotionSample, PROGRAM_IDS, type PackedFingerprint, type Point2D, type ProofResult, type PulseConfig, PulseSDK, PulseSession, SPEAKER_FEATURE_COUNT, type SensorData, type SolanaProof, type StageState, StaleEncryptedBaselineError, type StatsSummary, type StoredVerificationData, type SubmissionResult, type TBH, TOUCH_FEATURE_COUNT, type TemporalFingerprint, type TouchSample, type VerificationResult, attestAgentOperator, bigintToBytes32, bytes32ToBigint, bytesToFingerprint, clearBaselineKeyCache, computeCommitment, decryptBaselineBlob, deriveBaselineKey, deriveEncryptedBaselinePda, encodeAudioAsBase64, encryptBaselineBlob, extractAccelerationMagnitude, extractMotionFeatures, extractMouseDynamics, extractSpeakerFeatures, extractSpeakerFeaturesDetailed, extractTouchFeatures, fetchChallenge, fetchEncryptedBaseline, fetchIdentityState, fingerprintToBytes, fuseFeatures, fuseRawFeatures, generateLissajousPoints, generateLissajousSequence, generatePhrase, generatePhraseSequence, generateProof, generateSalt, generateSolanaProof, generateTBH, getAgentHumanOperator, getOrDeriveBaselineKey, hammingDistance, loadVerificationData, packBits, prepareCircuitInput, randomLissajousParams, recoverBaselineFromChain, serializeProof, simhash, storeVerificationData, submitResetViaWallet, submitViaRelayer, submitViaWallet, toBigEndian32, verifyEntrosAttestation };
|
|
973
|
+
export { type AgentHumanOperator, type AudioCapture, type BaselineRecoveryReason, type BaselineRecoveryResult, type BaselineWallet, type CaptureOptions, type CaptureStage, type ChallengeResponse, type CircuitInput, DEFAULT_CAPTURE_MS, DEFAULT_MIN_DISTANCE, DEFAULT_THRESHOLD, ENCRYPTED_BASELINE_BLOB_BYTES, type EntrosAttestation, FINGERPRINT_BITS, type FeatureVector, type FusedFeatureVector, type IdentityState, type LissajousParams, MAX_CAPTURE_MS, MIN_AUDIO_SAMPLES, MIN_CAPTURE_MS, MIN_MOTION_SAMPLES, MIN_TOUCH_SAMPLES, MOTION_FEATURE_COUNT, type MotionSample, PROGRAM_IDS, type PackedFingerprint, type Point2D, type ProofResult, type PulseConfig, PulseSDK, PulseSession, SPEAKER_FEATURE_COUNT, type SensorData, type SolanaProof, type StageState, StaleEncryptedBaselineError, type StatsSummary, type StoredVerificationData, type SubmissionResult, type TBH, TOUCH_FEATURE_COUNT, type TemporalFingerprint, type TouchSample, type VerificationResult, WalletSignatureMismatchError, attestAgentOperator, bigintToBytes32, bytes32ToBigint, bytesToFingerprint, clearBaselineKeyCache, computeCommitment, decryptBaselineBlob, deriveBaselineKey, deriveEncryptedBaselinePda, encodeAudioAsBase64, encryptBaselineBlob, extractAccelerationMagnitude, extractMotionFeatures, extractMouseDynamics, extractSpeakerFeatures, extractSpeakerFeaturesDetailed, extractTouchFeatures, fetchChallenge, fetchEncryptedBaseline, fetchIdentityState, fingerprintToBytes, fuseFeatures, fuseRawFeatures, generateLissajousPoints, generateLissajousSequence, generatePhrase, generatePhraseSequence, generateProof, generateSalt, generateSolanaProof, generateTBH, getAgentHumanOperator, getOrDeriveBaselineKey, hammingDistance, loadVerificationData, packBits, prepareCircuitInput, randomLissajousParams, recoverBaselineFromChain, serializeProof, simhash, storeVerificationData, submitResetViaWallet, submitViaRelayer, submitViaWallet, toBigEndian32, verifyEntrosAttestation };
|
package/dist/index.js
CHANGED
|
@@ -47,6 +47,7 @@ __export(index_exports, {
|
|
|
47
47
|
SPEAKER_FEATURE_COUNT: () => SPEAKER_FEATURE_COUNT,
|
|
48
48
|
StaleEncryptedBaselineError: () => StaleEncryptedBaselineError,
|
|
49
49
|
TOUCH_FEATURE_COUNT: () => TOUCH_FEATURE_COUNT,
|
|
50
|
+
WalletSignatureMismatchError: () => WalletSignatureMismatchError,
|
|
50
51
|
attestAgentOperator: () => attestAgentOperator,
|
|
51
52
|
bigintToBytes32: () => bigintToBytes32,
|
|
52
53
|
bytes32ToBigint: () => bytes32ToBigint,
|
|
@@ -4744,6 +4745,7 @@ async function buildEd25519ReceiptIx(receipt) {
|
|
|
4744
4745
|
}
|
|
4745
4746
|
|
|
4746
4747
|
// src/identity/baseline.ts
|
|
4748
|
+
var import_ed25519 = require("@noble/curves/ed25519");
|
|
4747
4749
|
var BLOB_VERSION = 1;
|
|
4748
4750
|
var ALGORITHM_AES_256_GCM = 1;
|
|
4749
4751
|
var ENCRYPTED_BASELINE_BLOB_BYTES = 96;
|
|
@@ -4803,17 +4805,40 @@ async function deriveEncryptedBaselinePda(walletPubkey) {
|
|
|
4803
4805
|
programId
|
|
4804
4806
|
);
|
|
4805
4807
|
}
|
|
4808
|
+
var WalletSignatureMismatchError = class extends Error {
|
|
4809
|
+
constructor(expectedWallet) {
|
|
4810
|
+
super(
|
|
4811
|
+
`signMessage did not verify against the connected wallet ${expectedWallet}. A different wallet likely signed the prompt \u2014 disable other wallet extensions or set your selected wallet as the default, then retry.`
|
|
4812
|
+
);
|
|
4813
|
+
this.name = "WalletSignatureMismatchError";
|
|
4814
|
+
this.expectedWallet = expectedWallet;
|
|
4815
|
+
}
|
|
4816
|
+
};
|
|
4806
4817
|
async function deriveBaselineKey(wallet) {
|
|
4807
4818
|
if (typeof wallet.signMessage !== "function") {
|
|
4808
4819
|
throw new Error("wallet does not support signMessage");
|
|
4809
4820
|
}
|
|
4810
4821
|
const message = buildDomainMessage(wallet.publicKey);
|
|
4811
|
-
const
|
|
4822
|
+
const messageBytes = new TextEncoder().encode(message);
|
|
4823
|
+
const signature = await wallet.signMessage(messageBytes);
|
|
4812
4824
|
if (!(signature instanceof Uint8Array) || signature.length !== 64) {
|
|
4813
4825
|
throw new Error(
|
|
4814
4826
|
`expected 64-byte Ed25519 signature, got ${signature?.length ?? "non-Uint8Array"}`
|
|
4815
4827
|
);
|
|
4816
4828
|
}
|
|
4829
|
+
let signatureValid;
|
|
4830
|
+
try {
|
|
4831
|
+
signatureValid = import_ed25519.ed25519.verify(
|
|
4832
|
+
signature,
|
|
4833
|
+
messageBytes,
|
|
4834
|
+
wallet.publicKey.toBytes()
|
|
4835
|
+
);
|
|
4836
|
+
} catch {
|
|
4837
|
+
signatureValid = false;
|
|
4838
|
+
}
|
|
4839
|
+
if (!signatureValid) {
|
|
4840
|
+
throw new WalletSignatureMismatchError(wallet.publicKey.toBase58());
|
|
4841
|
+
}
|
|
4817
4842
|
const ikm = await crypto.subtle.importKey(
|
|
4818
4843
|
"raw",
|
|
4819
4844
|
signature,
|
|
@@ -5669,6 +5694,13 @@ async function recoverBaselineFromChain(wallet, connection) {
|
|
|
5669
5694
|
key = await getOrDeriveBaselineKey(wallet);
|
|
5670
5695
|
} catch (err) {
|
|
5671
5696
|
const detail = err instanceof Error ? err.message : String(err);
|
|
5697
|
+
if (err instanceof WalletSignatureMismatchError) {
|
|
5698
|
+
return {
|
|
5699
|
+
recovered: false,
|
|
5700
|
+
reason: "wallet-mismatch",
|
|
5701
|
+
detail
|
|
5702
|
+
};
|
|
5703
|
+
}
|
|
5672
5704
|
return {
|
|
5673
5705
|
recovered: false,
|
|
5674
5706
|
reason: "signing-unavailable",
|
|
@@ -5948,6 +5980,7 @@ async function processSensorData(sensorData, config, wallet, connection, onProgr
|
|
|
5948
5980
|
} else {
|
|
5949
5981
|
isFirstVerification = !previousData;
|
|
5950
5982
|
}
|
|
5983
|
+
let walletMismatch = false;
|
|
5951
5984
|
if (!isFirstVerification && !previousData && wallet && connection) {
|
|
5952
5985
|
const baselineWallet = resolveBaselineWallet(wallet);
|
|
5953
5986
|
if (baselineWallet) {
|
|
@@ -5957,6 +5990,7 @@ async function processSensorData(sensorData, config, wallet, connection, onProgr
|
|
|
5957
5990
|
previousData = await loadVerificationData();
|
|
5958
5991
|
sdkLog("[Entros SDK] On-chain encrypted baseline recovered");
|
|
5959
5992
|
} else {
|
|
5993
|
+
walletMismatch = recovery.reason === "wallet-mismatch";
|
|
5960
5994
|
sdkLog(
|
|
5961
5995
|
`[Entros SDK] On-chain encrypted baseline recovery not available (${recovery.reason ?? "unknown"})`
|
|
5962
5996
|
);
|
|
@@ -5964,6 +5998,14 @@ async function processSensorData(sensorData, config, wallet, connection, onProgr
|
|
|
5964
5998
|
}
|
|
5965
5999
|
}
|
|
5966
6000
|
if (!isFirstVerification && !previousData) {
|
|
6001
|
+
if (walletMismatch) {
|
|
6002
|
+
return {
|
|
6003
|
+
success: false,
|
|
6004
|
+
commitment: tbh.commitmentBytes,
|
|
6005
|
+
isFirstVerification: false,
|
|
6006
|
+
error: "A different wallet signed than the one connected. Another wallet extension likely intercepted the signature prompt. Sign with your connected wallet, or disable other wallet extensions (or unset their default), then try again."
|
|
6007
|
+
};
|
|
6008
|
+
}
|
|
5967
6009
|
return {
|
|
5968
6010
|
success: false,
|
|
5969
6011
|
commitment: tbh.commitmentBytes,
|
|
@@ -7051,6 +7093,7 @@ async function fetchChallenge(executorUrl, walletAddress, apiKey) {
|
|
|
7051
7093
|
SPEAKER_FEATURE_COUNT,
|
|
7052
7094
|
StaleEncryptedBaselineError,
|
|
7053
7095
|
TOUCH_FEATURE_COUNT,
|
|
7096
|
+
WalletSignatureMismatchError,
|
|
7054
7097
|
attestAgentOperator,
|
|
7055
7098
|
bigintToBytes32,
|
|
7056
7099
|
bytes32ToBigint,
|