react-native-wallet-keystore 0.1.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.
Files changed (39) hide show
  1. package/LICENSE +20 -0
  2. package/README.md +376 -0
  3. package/WalletKeystore.podspec +29 -0
  4. package/android/build.gradle +62 -0
  5. package/android/src/main/AndroidManifest.xml +2 -0
  6. package/android/src/main/java/com/walletkeystore/Secp256k1.kt +158 -0
  7. package/android/src/main/java/com/walletkeystore/WalletKeystoreCrypto.kt +233 -0
  8. package/android/src/main/java/com/walletkeystore/WalletKeystoreModule.kt +627 -0
  9. package/android/src/main/java/com/walletkeystore/WalletKeystorePackage.kt +31 -0
  10. package/ios/WalletKeystore.h +5 -0
  11. package/ios/WalletKeystore.mm +895 -0
  12. package/lib/module/NativeWalletKeystore.js +15 -0
  13. package/lib/module/NativeWalletKeystore.js.map +1 -0
  14. package/lib/module/errors.js +57 -0
  15. package/lib/module/errors.js.map +1 -0
  16. package/lib/module/index.js +9 -0
  17. package/lib/module/index.js.map +1 -0
  18. package/lib/module/keystore.js +220 -0
  19. package/lib/module/keystore.js.map +1 -0
  20. package/lib/module/package.json +1 -0
  21. package/lib/module/viem.js +65 -0
  22. package/lib/module/viem.js.map +1 -0
  23. package/lib/typescript/package.json +1 -0
  24. package/lib/typescript/src/NativeWalletKeystore.d.ts +26 -0
  25. package/lib/typescript/src/NativeWalletKeystore.d.ts.map +1 -0
  26. package/lib/typescript/src/errors.d.ts +29 -0
  27. package/lib/typescript/src/errors.d.ts.map +1 -0
  28. package/lib/typescript/src/index.d.ts +3 -0
  29. package/lib/typescript/src/index.d.ts.map +1 -0
  30. package/lib/typescript/src/keystore.d.ts +100 -0
  31. package/lib/typescript/src/keystore.d.ts.map +1 -0
  32. package/lib/typescript/src/viem.d.ts +24 -0
  33. package/lib/typescript/src/viem.d.ts.map +1 -0
  34. package/package.json +210 -0
  35. package/src/NativeWalletKeystore.ts +43 -0
  36. package/src/errors.ts +94 -0
  37. package/src/index.tsx +6 -0
  38. package/src/keystore.ts +317 -0
  39. package/src/viem.ts +99 -0
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+
3
+ import { TurboModuleRegistry } from 'react-native';
4
+
5
+ /**
6
+ * Codegen contract.
7
+ *
8
+ * Everything crossing the bridge is a plain `string` on purpose: codegen
9
+ * supports a narrow set of types, and string-literal unions are handled
10
+ * inconsistently across React Native versions. The typed surface lives in
11
+ * `keystore.ts`, which narrows these values.
12
+ */
13
+
14
+ export default TurboModuleRegistry.getEnforcing('WalletKeystore');
15
+ //# sourceMappingURL=NativeWalletKeystore.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["TurboModuleRegistry","getEnforcing"],"sourceRoot":"../../src","sources":["NativeWalletKeystore.ts"],"mappings":";;AAAA,SAASA,mBAAmB,QAA0B,cAAc;;AAEpE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAiCA,eAAeA,mBAAmB,CAACC,YAAY,CAAO,gBAAgB,CAAC","ignoreList":[]}
@@ -0,0 +1,57 @@
1
+ "use strict";
2
+
3
+ /**
4
+ * Stable, cross-platform error codes.
5
+ *
6
+ * The distinctions are load-bearing: `USER_CANCELED` means re-prompt,
7
+ * `NOT_ENROLLED` means send the user to Settings, and `KEY_INVALIDATED` means
8
+ * the secret is gone and recovery must start. Collapsing them makes callers
9
+ * guess.
10
+ */
11
+ const CODES = ['NOT_AVAILABLE', 'NOT_ENROLLED', 'USER_CANCELED', 'USER_FALLBACK', 'LOCKOUT', 'LOCKOUT_PERMANENT', 'SYSTEM_CANCEL', 'KEY_NOT_FOUND', 'KEY_ALREADY_EXISTS', 'KEY_INVALIDATED', 'STORAGE_ERROR', 'INVALID_KEY', 'UNKNOWN'];
12
+ const KNOWN_CODES = new Set(CODES);
13
+ export class KeystoreError extends Error {
14
+ /** The raw native code, kept even when `code` has fallen back to `UNKNOWN`. */
15
+
16
+ constructor(code, message, options) {
17
+ super(message);
18
+ this.name = 'KeystoreError';
19
+ this.code = code;
20
+ this.nativeCode = options?.nativeCode;
21
+ if (options && 'cause' in options) {
22
+ // Assigned rather than passed to super() to support pre-ES2022 targets.
23
+ this.cause = options.cause;
24
+ }
25
+
26
+ // Without this, extending a built-in breaks `instanceof` once compiled to
27
+ // ES5 — silently, and only for consumers.
28
+ Object.setPrototypeOf(this, KeystoreError.prototype);
29
+ const capture = Error.captureStackTrace;
30
+ if (typeof capture === 'function') {
31
+ capture(this, KeystoreError);
32
+ }
33
+ }
34
+ }
35
+ function isKeystoreErrorCode(value) {
36
+ return typeof value === 'string' && KNOWN_CODES.has(value);
37
+ }
38
+
39
+ /**
40
+ * Normalizes any rejection into a `KeystoreError`.
41
+ *
42
+ * React Native surfaces `reject(code, message)` as an `Error` carrying `code`,
43
+ * but a JS-side failure can produce any shape at all, so everything degrades to
44
+ * `UNKNOWN` rather than throwing while building the error.
45
+ */
46
+ export function toKeystoreError(value) {
47
+ if (value instanceof KeystoreError) {
48
+ return value;
49
+ }
50
+ const raw = value?.code;
51
+ const message = value?.message ?? 'The keystore operation failed.';
52
+ return new KeystoreError(isKeystoreErrorCode(raw) ? raw : 'UNKNOWN', typeof message === 'string' ? message : String(message), {
53
+ nativeCode: typeof raw === 'string' ? raw : undefined,
54
+ cause: value
55
+ });
56
+ }
57
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["CODES","KNOWN_CODES","Set","KeystoreError","Error","constructor","code","message","options","name","nativeCode","cause","Object","setPrototypeOf","prototype","capture","captureStackTrace","isKeystoreErrorCode","value","has","toKeystoreError","raw","String","undefined"],"sourceRoot":"../../src","sources":["errors.ts"],"mappings":";;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAMA,KAAK,GAAG,CACZ,eAAe,EACf,cAAc,EACd,eAAe,EACf,eAAe,EACf,SAAS,EACT,mBAAmB,EACnB,eAAe,EACf,eAAe,EACf,oBAAoB,EACpB,iBAAiB,EACjB,eAAe,EACf,aAAa,EACb,SAAS,CACD;AAIV,MAAMC,WAAgC,GAAG,IAAIC,GAAG,CAACF,KAAK,CAAC;AAEvD,OAAO,MAAMG,aAAa,SAASC,KAAK,CAAC;EAGvC;;EAGAC,WAAWA,CACTC,IAAuB,EACvBC,OAAe,EACfC,OAAkD,EAClD;IACA,KAAK,CAACD,OAAO,CAAC;IACd,IAAI,CAACE,IAAI,GAAG,eAAe;IAC3B,IAAI,CAACH,IAAI,GAAGA,IAAI;IAChB,IAAI,CAACI,UAAU,GAAGF,OAAO,EAAEE,UAAU;IAErC,IAAIF,OAAO,IAAI,OAAO,IAAIA,OAAO,EAAE;MACjC;MACC,IAAI,CAAyBG,KAAK,GAAGH,OAAO,CAACG,KAAK;IACrD;;IAEA;IACA;IACAC,MAAM,CAACC,cAAc,CAAC,IAAI,EAAEV,aAAa,CAACW,SAAS,CAAC;IAEpD,MAAMC,OAAO,GACXX,KAAK,CAGLY,iBAAiB;IACnB,IAAI,OAAOD,OAAO,KAAK,UAAU,EAAE;MACjCA,OAAO,CAAC,IAAI,EAAEZ,aAAa,CAAC;IAC9B;EACF;AACF;AAEA,SAASc,mBAAmBA,CAACC,KAAc,EAA8B;EACvE,OAAO,OAAOA,KAAK,KAAK,QAAQ,IAAIjB,WAAW,CAACkB,GAAG,CAACD,KAAK,CAAC;AAC5D;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASE,eAAeA,CAACF,KAAc,EAAiB;EAC7D,IAAIA,KAAK,YAAYf,aAAa,EAAE;IAClC,OAAOe,KAAK;EACd;EAEA,MAAMG,GAAG,GAAIH,KAAK,EAA4CZ,IAAI;EAClE,MAAMC,OAAO,GACVW,KAAK,EAA+CX,OAAO,IAC5D,gCAAgC;EAElC,OAAO,IAAIJ,aAAa,CACtBc,mBAAmB,CAACI,GAAG,CAAC,GAAGA,GAAG,GAAG,SAAS,EAC1C,OAAOd,OAAO,KAAK,QAAQ,GAAGA,OAAO,GAAGe,MAAM,CAACf,OAAO,CAAC,EACvD;IACEG,UAAU,EAAE,OAAOW,GAAG,KAAK,QAAQ,GAAGA,GAAG,GAAGE,SAAS;IACrDZ,KAAK,EAAEO;EACT,CACF,CAAC;AACH","ignoreList":[]}
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+
3
+ export * from "./keystore.js";
4
+ export { KeystoreError } from "./errors.js";
5
+
6
+ // The viem adapter is intentionally not re-exported. It ships as the
7
+ // `react-native-wallet-keystore/viem` subpath with viem as an optional peer, so
8
+ // importing the core API never requires viem to be installed.
9
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["KeystoreError"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":";;AAAA,cAAc,eAAY;AAC1B,SAASA,aAAa,QAAgC,aAAU;;AAEhE;AACA;AACA","ignoreList":[]}
@@ -0,0 +1,220 @@
1
+ "use strict";
2
+
3
+ import NativeWalletKeystore from "./NativeWalletKeystore.js";
4
+ import { KeystoreError, toKeystoreError } from "./errors.js";
5
+
6
+ /**
7
+ * Android reports which biometric *hardware* exists, not which modality is
8
+ * enrolled, so it returns `'biometric'` when more than one is present.
9
+ */
10
+
11
+ /**
12
+ * Whether the wrapping key is destroyed when biometric enrollment changes.
13
+ *
14
+ * Orthogonal to {@link AuthPolicy} on purpose: `'biometricOnly'` must never
15
+ * imply invalidation, or a user adding a fingerprint silently destroys their
16
+ * wallet. Opting in is explicit.
17
+ */
18
+
19
+ export const DEFAULT_AUTH_POLICY = 'biometricOrPasscode';
20
+ export const DEFAULT_INVALIDATION_POLICY = 'never';
21
+
22
+ /** Uncompressed SEC1 public key: `0x04` followed by 64 bytes. */
23
+
24
+ /** 65-byte Ethereum signature: `r || s || v`, with `v` 27 or 28. */
25
+
26
+ const BIOMETRY_TYPES = new Set(['faceId', 'touchId', 'opticId', 'fingerprint', 'face', 'iris', 'biometric', 'none']);
27
+ const HEX_PATTERN = /^(?:[0-9a-fA-F]{2})+$/;
28
+ const HEX_32_BYTES = /^(?:0x)?[0-9a-fA-F]{64}$/;
29
+ function strip0x(value) {
30
+ return value.startsWith('0x') || value.startsWith('0X') ? value.slice(2) : value;
31
+ }
32
+ function prefix0x(value) {
33
+ return value.startsWith('0x') ? value : `0x${value}`;
34
+ }
35
+ function assertKeyId(keyId) {
36
+ if (typeof keyId !== 'string' || keyId.trim() === '') {
37
+ throw new KeystoreError('UNKNOWN', 'A non-empty `keyId` is required.');
38
+ }
39
+ }
40
+ function assertReason(reason, action) {
41
+ // iOS raises on an empty localizedReason rather than failing gracefully, so
42
+ // this is checked before the bridge to keep both platforms consistent.
43
+ if (typeof reason !== 'string' || reason.trim() === '') {
44
+ throw new KeystoreError('UNKNOWN', `A non-empty \`reason\` is required to ${action}.`);
45
+ }
46
+ }
47
+
48
+ /**
49
+ * Which biometric modality the hardware supports, whether or not anything is
50
+ * enrolled. Resolves `'none'` when there is no hardware; never rejects.
51
+ *
52
+ * Enrollment state comes from {@link authenticate} via `NOT_ENROLLED`.
53
+ */
54
+ export async function getBiometryType() {
55
+ const type = await NativeWalletKeystore.getBiometryType();
56
+ // A native layer newer than this JS could return a modality we don't know.
57
+ return BIOMETRY_TYPES.has(type) ? type : 'biometric';
58
+ }
59
+
60
+ /**
61
+ * Prompts for device-owner authentication.
62
+ *
63
+ * A UX gate, not a security boundary — the boolean can be faked by a
64
+ * compromised bundle. Use {@link signDigest} where it actually matters.
65
+ *
66
+ * Never resolves `false`; every failure rejects.
67
+ *
68
+ * @throws {KeystoreError}
69
+ */
70
+ export async function authenticate(reason, policy = DEFAULT_AUTH_POLICY) {
71
+ try {
72
+ assertReason(reason, 'authenticate');
73
+ return await NativeWalletKeystore.authenticate(reason, policy);
74
+ } catch (error) {
75
+ throw toKeystoreError(error);
76
+ }
77
+ }
78
+
79
+ /**
80
+ * Stores a secret encrypted under a hardware-bound wrapping key.
81
+ *
82
+ * @throws {KeystoreError} `KEY_ALREADY_EXISTS` if `keyId` is taken; overwriting
83
+ * is always deliberate.
84
+ */
85
+ export async function storeSecret(keyId, secretHex, options = {}) {
86
+ try {
87
+ assertKeyId(keyId);
88
+ if (typeof secretHex !== 'string' || !HEX_PATTERN.test(secretHex)) {
89
+ throw new KeystoreError('UNKNOWN', '`secretHex` must be a non-empty, even-length hex string.');
90
+ }
91
+ await NativeWalletKeystore.storeSecret(keyId, secretHex, options.policy ?? DEFAULT_AUTH_POLICY, options.invalidation ?? DEFAULT_INVALIDATION_POLICY);
92
+ } catch (error) {
93
+ throw toKeystoreError(error);
94
+ }
95
+ }
96
+
97
+ /**
98
+ * Authenticates and returns the stored secret as hex.
99
+ *
100
+ * The prompt is raised by the keystore as a precondition of using the wrapping
101
+ * key, so it cannot be bypassed from JS.
102
+ *
103
+ * @throws {KeystoreError} `KEY_NOT_FOUND`, `KEY_INVALIDATED`, or any auth code.
104
+ */
105
+ export async function getSecret(keyId, reason) {
106
+ try {
107
+ assertKeyId(keyId);
108
+ assertReason(reason, 'read a secret');
109
+ return await NativeWalletKeystore.getSecret(keyId, reason);
110
+ } catch (error) {
111
+ throw toKeystoreError(error);
112
+ }
113
+ }
114
+
115
+ /** Whether a secret is stored under `keyId`. Does not authenticate. */
116
+ export async function hasSecret(keyId) {
117
+ try {
118
+ assertKeyId(keyId);
119
+ return await NativeWalletKeystore.hasSecret(keyId);
120
+ } catch (error) {
121
+ throw toKeystoreError(error);
122
+ }
123
+ }
124
+
125
+ /** Removes the secret and its wrapping key. Idempotent. */
126
+ export async function deleteSecret(keyId) {
127
+ try {
128
+ assertKeyId(keyId);
129
+ await NativeWalletKeystore.deleteSecret(keyId);
130
+ } catch (error) {
131
+ throw toKeystoreError(error);
132
+ }
133
+ }
134
+
135
+ /**
136
+ * Generates a secp256k1 keypair in hardware-wrapped storage.
137
+ *
138
+ * Entropy comes from the platform CSPRNG, never from JavaScript, and the
139
+ * private key never crosses the bridge.
140
+ *
141
+ * @returns The uncompressed public key.
142
+ */
143
+ export async function generateKey(keyId, options = {}) {
144
+ try {
145
+ assertKeyId(keyId);
146
+ return prefix0x(await NativeWalletKeystore.generateKey(keyId, options.policy ?? DEFAULT_AUTH_POLICY, options.invalidation ?? DEFAULT_INVALIDATION_POLICY));
147
+ } catch (error) {
148
+ throw toKeystoreError(error);
149
+ }
150
+ }
151
+
152
+ /**
153
+ * Imports an existing secp256k1 private key.
154
+ *
155
+ * @throws {KeystoreError} `INVALID_KEY` unless the key is in [1, n-1]. Keys
156
+ * outside that range are rejected rather than clamped.
157
+ */
158
+ export async function importPrivateKey(keyId, privateKeyHex, options = {}) {
159
+ try {
160
+ assertKeyId(keyId);
161
+ if (typeof privateKeyHex !== 'string' || !HEX_32_BYTES.test(privateKeyHex)) {
162
+ throw new KeystoreError('INVALID_KEY', 'A private key must be exactly 32 bytes of hex.');
163
+ }
164
+
165
+ // The range check stays native, where the curve order is already at hand.
166
+ return prefix0x(await NativeWalletKeystore.importPrivateKey(keyId, strip0x(privateKeyHex), options.policy ?? DEFAULT_AUTH_POLICY, options.invalidation ?? DEFAULT_INVALIDATION_POLICY));
167
+ } catch (error) {
168
+ throw toKeystoreError(error);
169
+ }
170
+ }
171
+
172
+ /** The uncompressed public key. Does not authenticate. */
173
+ export async function getPublicKey(keyId) {
174
+ try {
175
+ assertKeyId(keyId);
176
+ return prefix0x(await NativeWalletKeystore.getPublicKey(keyId));
177
+ } catch (error) {
178
+ throw toKeystoreError(error);
179
+ }
180
+ }
181
+
182
+ /**
183
+ * Authenticates, then signs a 32-byte digest.
184
+ *
185
+ * Only a digest crosses the boundary — never a message or a transaction.
186
+ * Keccak and EIP-191/712/155 encoding stay in JS, which keeps this module
187
+ * curve-specific but chain-agnostic.
188
+ *
189
+ * @returns 65 bytes, `r || s || v`, low-s normalized per EIP-2 with `v` of
190
+ * 27/28 — byte-identical to viem.
191
+ */
192
+ export async function signDigest(keyId, digestHex, reason) {
193
+ try {
194
+ assertKeyId(keyId);
195
+ if (typeof digestHex !== 'string' || !HEX_32_BYTES.test(digestHex)) {
196
+ throw new KeystoreError('INVALID_KEY', 'A digest must be exactly 32 bytes of hex. Hash the message in JS first.');
197
+ }
198
+ assertReason(reason, 'sign');
199
+ return prefix0x(await NativeWalletKeystore.signDigest(keyId, strip0x(digestHex), reason));
200
+ } catch (error) {
201
+ throw toKeystoreError(error);
202
+ }
203
+ }
204
+
205
+ /**
206
+ * Authenticates, then returns the raw private key.
207
+ *
208
+ * For user-initiated backup only. The result lands in the JS heap where it
209
+ * cannot be zeroed, so prefer {@link signDigest} for everyday use.
210
+ */
211
+ export async function exportPrivateKey(keyId, reason) {
212
+ try {
213
+ assertKeyId(keyId);
214
+ assertReason(reason, 'export a private key');
215
+ return prefix0x(await NativeWalletKeystore.exportPrivateKey(keyId, reason));
216
+ } catch (error) {
217
+ throw toKeystoreError(error);
218
+ }
219
+ }
220
+ //# sourceMappingURL=keystore.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["NativeWalletKeystore","KeystoreError","toKeystoreError","DEFAULT_AUTH_POLICY","DEFAULT_INVALIDATION_POLICY","BIOMETRY_TYPES","Set","HEX_PATTERN","HEX_32_BYTES","strip0x","value","startsWith","slice","prefix0x","assertKeyId","keyId","trim","assertReason","reason","action","getBiometryType","type","has","authenticate","policy","error","storeSecret","secretHex","options","test","invalidation","getSecret","hasSecret","deleteSecret","generateKey","importPrivateKey","privateKeyHex","getPublicKey","signDigest","digestHex","exportPrivateKey"],"sourceRoot":"../../src","sources":["keystore.ts"],"mappings":";;AAAA,OAAOA,oBAAoB,MAAM,2BAAwB;AACzD,SAASC,aAAa,EAAEC,eAAe,QAAQ,aAAU;;AAEzD;AACA;AACA;AACA;;AAaA;AACA;AACA;AACA;AACA;AACA;AACA;;AAGA,OAAO,MAAMC,mBAA+B,GAAG,qBAAqB;AACpE,OAAO,MAAMC,2BAA+C,GAAG,OAAO;;AAEtE;;AAGA;;AAQA,MAAMC,cAAmC,GAAG,IAAIC,GAAG,CAAe,CAChE,QAAQ,EACR,SAAS,EACT,SAAS,EACT,aAAa,EACb,MAAM,EACN,MAAM,EACN,WAAW,EACX,MAAM,CACP,CAAC;AAEF,MAAMC,WAAW,GAAG,uBAAuB;AAC3C,MAAMC,YAAY,GAAG,0BAA0B;AAE/C,SAASC,OAAOA,CAACC,KAAa,EAAU;EACtC,OAAOA,KAAK,CAACC,UAAU,CAAC,IAAI,CAAC,IAAID,KAAK,CAACC,UAAU,CAAC,IAAI,CAAC,GACnDD,KAAK,CAACE,KAAK,CAAC,CAAC,CAAC,GACdF,KAAK;AACX;AAEA,SAASG,QAAQA,CAACH,KAAa,EAAiB;EAC9C,OAAQA,KAAK,CAACC,UAAU,CAAC,IAAI,CAAC,GAAGD,KAAK,GAAG,KAAKA,KAAK,EAAE;AACvD;AAEA,SAASI,WAAWA,CAACC,KAAa,EAAQ;EACxC,IAAI,OAAOA,KAAK,KAAK,QAAQ,IAAIA,KAAK,CAACC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE;IACpD,MAAM,IAAIf,aAAa,CAAC,SAAS,EAAE,kCAAkC,CAAC;EACxE;AACF;AAEA,SAASgB,YAAYA,CAACC,MAAc,EAAEC,MAAc,EAAQ;EAC1D;EACA;EACA,IAAI,OAAOD,MAAM,KAAK,QAAQ,IAAIA,MAAM,CAACF,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE;IACtD,MAAM,IAAIf,aAAa,CACrB,SAAS,EACT,yCAAyCkB,MAAM,GACjD,CAAC;EACH;AACF;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,eAAeC,eAAeA,CAAA,EAA0B;EAC7D,MAAMC,IAAI,GAAG,MAAMrB,oBAAoB,CAACoB,eAAe,CAAC,CAAC;EACzD;EACA,OAAQf,cAAc,CAACiB,GAAG,CAACD,IAAI,CAAC,GAAGA,IAAI,GAAG,WAAW;AACvD;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,eAAeE,YAAYA,CAChCL,MAAc,EACdM,MAAkB,GAAGrB,mBAAmB,EACtB;EAClB,IAAI;IACFc,YAAY,CAACC,MAAM,EAAE,cAAc,CAAC;IACpC,OAAO,MAAMlB,oBAAoB,CAACuB,YAAY,CAACL,MAAM,EAAEM,MAAM,CAAC;EAChE,CAAC,CAAC,OAAOC,KAAK,EAAE;IACd,MAAMvB,eAAe,CAACuB,KAAK,CAAC;EAC9B;AACF;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,eAAeC,WAAWA,CAC/BX,KAAa,EACbY,SAAiB,EACjBC,OAAmB,GAAG,CAAC,CAAC,EACT;EACf,IAAI;IACFd,WAAW,CAACC,KAAK,CAAC;IAElB,IAAI,OAAOY,SAAS,KAAK,QAAQ,IAAI,CAACpB,WAAW,CAACsB,IAAI,CAACF,SAAS,CAAC,EAAE;MACjE,MAAM,IAAI1B,aAAa,CACrB,SAAS,EACT,0DACF,CAAC;IACH;IAEA,MAAMD,oBAAoB,CAAC0B,WAAW,CACpCX,KAAK,EACLY,SAAS,EACTC,OAAO,CAACJ,MAAM,IAAIrB,mBAAmB,EACrCyB,OAAO,CAACE,YAAY,IAAI1B,2BAC1B,CAAC;EACH,CAAC,CAAC,OAAOqB,KAAK,EAAE;IACd,MAAMvB,eAAe,CAACuB,KAAK,CAAC;EAC9B;AACF;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,eAAeM,SAASA,CAC7BhB,KAAa,EACbG,MAAc,EACG;EACjB,IAAI;IACFJ,WAAW,CAACC,KAAK,CAAC;IAClBE,YAAY,CAACC,MAAM,EAAE,eAAe,CAAC;IACrC,OAAO,MAAMlB,oBAAoB,CAAC+B,SAAS,CAAChB,KAAK,EAAEG,MAAM,CAAC;EAC5D,CAAC,CAAC,OAAOO,KAAK,EAAE;IACd,MAAMvB,eAAe,CAACuB,KAAK,CAAC;EAC9B;AACF;;AAEA;AACA,OAAO,eAAeO,SAASA,CAACjB,KAAa,EAAoB;EAC/D,IAAI;IACFD,WAAW,CAACC,KAAK,CAAC;IAClB,OAAO,MAAMf,oBAAoB,CAACgC,SAAS,CAACjB,KAAK,CAAC;EACpD,CAAC,CAAC,OAAOU,KAAK,EAAE;IACd,MAAMvB,eAAe,CAACuB,KAAK,CAAC;EAC9B;AACF;;AAEA;AACA,OAAO,eAAeQ,YAAYA,CAAClB,KAAa,EAAiB;EAC/D,IAAI;IACFD,WAAW,CAACC,KAAK,CAAC;IAClB,MAAMf,oBAAoB,CAACiC,YAAY,CAAClB,KAAK,CAAC;EAChD,CAAC,CAAC,OAAOU,KAAK,EAAE;IACd,MAAMvB,eAAe,CAACuB,KAAK,CAAC;EAC9B;AACF;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,eAAeS,WAAWA,CAC/BnB,KAAa,EACba,OAAmB,GAAG,CAAC,CAAC,EACD;EACvB,IAAI;IACFd,WAAW,CAACC,KAAK,CAAC;IAClB,OAAOF,QAAQ,CACb,MAAMb,oBAAoB,CAACkC,WAAW,CACpCnB,KAAK,EACLa,OAAO,CAACJ,MAAM,IAAIrB,mBAAmB,EACrCyB,OAAO,CAACE,YAAY,IAAI1B,2BAC1B,CACF,CAAC;EACH,CAAC,CAAC,OAAOqB,KAAK,EAAE;IACd,MAAMvB,eAAe,CAACuB,KAAK,CAAC;EAC9B;AACF;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,eAAeU,gBAAgBA,CACpCpB,KAAa,EACbqB,aAAqB,EACrBR,OAAmB,GAAG,CAAC,CAAC,EACD;EACvB,IAAI;IACFd,WAAW,CAACC,KAAK,CAAC;IAElB,IACE,OAAOqB,aAAa,KAAK,QAAQ,IACjC,CAAC5B,YAAY,CAACqB,IAAI,CAACO,aAAa,CAAC,EACjC;MACA,MAAM,IAAInC,aAAa,CACrB,aAAa,EACb,gDACF,CAAC;IACH;;IAEA;IACA,OAAOY,QAAQ,CACb,MAAMb,oBAAoB,CAACmC,gBAAgB,CACzCpB,KAAK,EACLN,OAAO,CAAC2B,aAAa,CAAC,EACtBR,OAAO,CAACJ,MAAM,IAAIrB,mBAAmB,EACrCyB,OAAO,CAACE,YAAY,IAAI1B,2BAC1B,CACF,CAAC;EACH,CAAC,CAAC,OAAOqB,KAAK,EAAE;IACd,MAAMvB,eAAe,CAACuB,KAAK,CAAC;EAC9B;AACF;;AAEA;AACA,OAAO,eAAeY,YAAYA,CAACtB,KAAa,EAAyB;EACvE,IAAI;IACFD,WAAW,CAACC,KAAK,CAAC;IAClB,OAAOF,QAAQ,CAAC,MAAMb,oBAAoB,CAACqC,YAAY,CAACtB,KAAK,CAAC,CAAC;EACjE,CAAC,CAAC,OAAOU,KAAK,EAAE;IACd,MAAMvB,eAAe,CAACuB,KAAK,CAAC;EAC9B;AACF;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,eAAea,UAAUA,CAC9BvB,KAAa,EACbwB,SAAiB,EACjBrB,MAAc,EACS;EACvB,IAAI;IACFJ,WAAW,CAACC,KAAK,CAAC;IAElB,IAAI,OAAOwB,SAAS,KAAK,QAAQ,IAAI,CAAC/B,YAAY,CAACqB,IAAI,CAACU,SAAS,CAAC,EAAE;MAClE,MAAM,IAAItC,aAAa,CACrB,aAAa,EACb,yEACF,CAAC;IACH;IAEAgB,YAAY,CAACC,MAAM,EAAE,MAAM,CAAC;IAE5B,OAAOL,QAAQ,CACb,MAAMb,oBAAoB,CAACsC,UAAU,CAACvB,KAAK,EAAEN,OAAO,CAAC8B,SAAS,CAAC,EAAErB,MAAM,CACzE,CAAC;EACH,CAAC,CAAC,OAAOO,KAAK,EAAE;IACd,MAAMvB,eAAe,CAACuB,KAAK,CAAC;EAC9B;AACF;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,eAAee,gBAAgBA,CACpCzB,KAAa,EACbG,MAAc,EACG;EACjB,IAAI;IACFJ,WAAW,CAACC,KAAK,CAAC;IAClBE,YAAY,CAACC,MAAM,EAAE,sBAAsB,CAAC;IAC5C,OAAOL,QAAQ,CAAC,MAAMb,oBAAoB,CAACwC,gBAAgB,CAACzB,KAAK,EAAEG,MAAM,CAAC,CAAC;EAC7E,CAAC,CAAC,OAAOO,KAAK,EAAE;IACd,MAAMvB,eAAe,CAACuB,KAAK,CAAC;EAC9B;AACF","ignoreList":[]}
@@ -0,0 +1 @@
1
+ {"type":"module"}
@@ -0,0 +1,65 @@
1
+ "use strict";
2
+
3
+ import { hashMessage, hashTypedData, keccak256, serializeTransaction } from 'viem';
4
+ import { publicKeyToAddress, toAccount } from 'viem/accounts';
5
+ import { getPublicKey, signDigest } from "./keystore.js";
6
+ const DEFAULT_REASON = 'Sign with your wallet key';
7
+
8
+ /**
9
+ * Adapts a hardware-wrapped key into a viem {@link LocalAccount}.
10
+ *
11
+ * Every path hashes in JS and sends only a 32-byte digest to native, leaving
12
+ * EIP-191, EIP-712 and transaction serialization to viem.
13
+ *
14
+ * ```ts
15
+ * const account = await toKeystoreAccount('wallet-1');
16
+ * const client = createWalletClient({ account, chain: mainnet, transport: http() });
17
+ * await client.sendTransaction({ to: '0x…', value: 1n });
18
+ * ```
19
+ *
20
+ * Each signature raises its own authentication prompt, so batching several will
21
+ * prompt several times.
22
+ */
23
+ export async function toKeystoreAccount(keyId, options = {}) {
24
+ const reason = options.reason ?? DEFAULT_REASON;
25
+ const publicKey = options.publicKey ?? (await getPublicKey(keyId));
26
+
27
+ // Derived here rather than natively: the address is a pure function of the
28
+ // public key, and keccak has no business in the native layer.
29
+ const address = publicKeyToAddress(publicKey);
30
+ const sign = digest => signDigest(keyId, digest, reason);
31
+ const account = toAccount({
32
+ address,
33
+ async sign({
34
+ hash
35
+ }) {
36
+ return sign(hash);
37
+ },
38
+ async signMessage({
39
+ message
40
+ }) {
41
+ return sign(hashMessage(message));
42
+ },
43
+ async signTypedData(typedData) {
44
+ return sign(hashTypedData(typedData));
45
+ },
46
+ async signTransaction(transaction, args) {
47
+ const serializer = args?.serializer ?? serializeTransaction;
48
+
49
+ // Sign the hash of the unsigned serialization, then re-serialize with the
50
+ // signature attached; viem's serializer owns the EIP-155 and typed-tx
51
+ // rules for every transaction type.
52
+ const unsigned = await serializer(transaction);
53
+ const signature = await sign(keccak256(unsigned));
54
+ return await serializer(transaction, {
55
+ r: `0x${signature.slice(2, 66)}`,
56
+ s: `0x${signature.slice(66, 130)}`,
57
+ v: BigInt(parseInt(signature.slice(130, 132), 16))
58
+ });
59
+ }
60
+ });
61
+
62
+ // toAccount's return type is a union; this pins it to the local branch.
63
+ return account;
64
+ }
65
+ //# sourceMappingURL=viem.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["hashMessage","hashTypedData","keccak256","serializeTransaction","publicKeyToAddress","toAccount","getPublicKey","signDigest","DEFAULT_REASON","toKeystoreAccount","keyId","options","reason","publicKey","address","sign","digest","account","hash","signMessage","message","signTypedData","typedData","signTransaction","transaction","args","serializer","unsigned","signature","r","slice","s","v","BigInt","parseInt"],"sourceRoot":"../../src","sources":["viem.ts"],"mappings":";;AAAA,SACEA,WAAW,EACXC,aAAa,EACbC,SAAS,EACTC,oBAAoB,QAQf,MAAM;AACb,SAASC,kBAAkB,EAAEC,SAAS,QAAQ,eAAe;AAE7D,SAASC,YAAY,EAAEC,UAAU,QAAQ,eAAY;AASrD,MAAMC,cAAc,GAAG,2BAA2B;;AAElD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,eAAeC,iBAAiBA,CACrCC,KAAa,EACbC,OAA+B,GAAG,CAAC,CAAC,EACb;EACvB,MAAMC,MAAM,GAAGD,OAAO,CAACC,MAAM,IAAIJ,cAAc;EAC/C,MAAMK,SAAS,GAAGF,OAAO,CAACE,SAAS,KAAK,MAAMP,YAAY,CAACI,KAAK,CAAC,CAAC;;EAElE;EACA;EACA,MAAMI,OAAO,GAAGV,kBAAkB,CAACS,SAAS,CAAC;EAE7C,MAAME,IAAI,GAAIC,MAAW,IACvBT,UAAU,CAACG,KAAK,EAAEM,MAAM,EAAEJ,MAAM,CAAiB;EAEnD,MAAMK,OAAO,GAAGZ,SAAS,CAAC;IACxBS,OAAO;IAEP,MAAMC,IAAIA,CAAC;MAAEG;IAAoB,CAAC,EAAE;MAClC,OAAOH,IAAI,CAACG,IAAI,CAAC;IACnB,CAAC;IAED,MAAMC,WAAWA,CAAC;MAAEC;IAAsC,CAAC,EAAE;MAC3D,OAAOL,IAAI,CAACf,WAAW,CAACoB,OAAO,CAAC,CAAC;IACnC,CAAC;IAED,MAAMC,aAAaA,CAGjBC,SAAsD,EAAE;MACxD,OAAOP,IAAI,CAACd,aAAa,CAACqB,SAAgC,CAAC,CAAC;IAC9D,CAAC;IAED,MAAMC,eAAeA,CACnBC,WAAoC,EACpCC,IAGC,EACD;MACA,MAAMC,UAAU,GAAGD,IAAI,EAAEC,UAAU,IAAIvB,oBAAoB;;MAE3D;MACA;MACA;MACA,MAAMwB,QAAQ,GAAI,MAAMD,UAAU,CAACF,WAAW,CAAS;MACvD,MAAMI,SAAS,GAAG,MAAMb,IAAI,CAACb,SAAS,CAACyB,QAAQ,CAAC,CAAC;MAEjD,OAAQ,MAAMD,UAAU,CAACF,WAAW,EAAE;QACpCK,CAAC,EAAE,KAAKD,SAAS,CAACE,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAS;QACvCC,CAAC,EAAE,KAAKH,SAAS,CAACE,KAAK,CAAC,EAAE,EAAE,GAAG,CAAC,EAAS;QACzCE,CAAC,EAAEC,MAAM,CAACC,QAAQ,CAACN,SAAS,CAACE,KAAK,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,EAAE,CAAC;MACnD,CAAC,CAAC;IACJ;EACF,CAAC,CAAC;;EAEF;EACA,OAAOb,OAAO;AAChB","ignoreList":[]}
@@ -0,0 +1 @@
1
+ {"type":"module"}
@@ -0,0 +1,26 @@
1
+ import { type TurboModule } from 'react-native';
2
+ /**
3
+ * Codegen contract.
4
+ *
5
+ * Everything crossing the bridge is a plain `string` on purpose: codegen
6
+ * supports a narrow set of types, and string-literal unions are handled
7
+ * inconsistently across React Native versions. The typed surface lives in
8
+ * `keystore.ts`, which narrows these values.
9
+ */
10
+ export interface Spec extends TurboModule {
11
+ getBiometryType(): Promise<string>;
12
+ authenticate(reason: string, policy: string): Promise<boolean>;
13
+ storeSecret(keyId: string, secretHex: string, policy: string, invalidation: string): Promise<void>;
14
+ getSecret(keyId: string, reason: string): Promise<string>;
15
+ hasSecret(keyId: string): Promise<boolean>;
16
+ deleteSecret(keyId: string): Promise<void>;
17
+ generateKey(keyId: string, policy: string, invalidation: string): Promise<string>;
18
+ importPrivateKey(keyId: string, privateKeyHex: string, policy: string, invalidation: string): Promise<string>;
19
+ getPublicKey(keyId: string): Promise<string>;
20
+ /** Returns 65 bytes of hex: `r || s || v`, low-s normalized, `v` of 27/28. */
21
+ signDigest(keyId: string, digestHex: string, reason: string): Promise<string>;
22
+ exportPrivateKey(keyId: string, reason: string): Promise<string>;
23
+ }
24
+ declare const _default: Spec;
25
+ export default _default;
26
+ //# sourceMappingURL=NativeWalletKeystore.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NativeWalletKeystore.d.ts","sourceRoot":"","sources":["../../../src/NativeWalletKeystore.ts"],"names":[],"mappings":"AAAA,OAAO,EAAuB,KAAK,WAAW,EAAE,MAAM,cAAc,CAAC;AAErE;;;;;;;GAOG;AACH,MAAM,WAAW,IAAK,SAAQ,WAAW;IACvC,eAAe,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;IACnC,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAE/D,WAAW,CACT,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,IAAI,CAAC,CAAC;IACjB,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC1D,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC3C,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAE3C,WAAW,CACT,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,MAAM,CAAC,CAAC;IACnB,gBAAgB,CACd,KAAK,EAAE,MAAM,EACb,aAAa,EAAE,MAAM,EACrB,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,MAAM,CAAC,CAAC;IACnB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAE7C,8EAA8E;IAC9E,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC9E,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;CAClE;;AAED,wBAAwE"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Stable, cross-platform error codes.
3
+ *
4
+ * The distinctions are load-bearing: `USER_CANCELED` means re-prompt,
5
+ * `NOT_ENROLLED` means send the user to Settings, and `KEY_INVALIDATED` means
6
+ * the secret is gone and recovery must start. Collapsing them makes callers
7
+ * guess.
8
+ */
9
+ declare const CODES: readonly ["NOT_AVAILABLE", "NOT_ENROLLED", "USER_CANCELED", "USER_FALLBACK", "LOCKOUT", "LOCKOUT_PERMANENT", "SYSTEM_CANCEL", "KEY_NOT_FOUND", "KEY_ALREADY_EXISTS", "KEY_INVALIDATED", "STORAGE_ERROR", "INVALID_KEY", "UNKNOWN"];
10
+ export type KeystoreErrorCode = (typeof CODES)[number];
11
+ export declare class KeystoreError extends Error {
12
+ readonly code: KeystoreErrorCode;
13
+ /** The raw native code, kept even when `code` has fallen back to `UNKNOWN`. */
14
+ readonly nativeCode?: string;
15
+ constructor(code: KeystoreErrorCode, message: string, options?: {
16
+ nativeCode?: string;
17
+ cause?: unknown;
18
+ });
19
+ }
20
+ /**
21
+ * Normalizes any rejection into a `KeystoreError`.
22
+ *
23
+ * React Native surfaces `reject(code, message)` as an `Error` carrying `code`,
24
+ * but a JS-side failure can produce any shape at all, so everything degrades to
25
+ * `UNKNOWN` rather than throwing while building the error.
26
+ */
27
+ export declare function toKeystoreError(value: unknown): KeystoreError;
28
+ export {};
29
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../../src/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,QAAA,MAAM,KAAK,oOAcD,CAAC;AAEX,MAAM,MAAM,iBAAiB,GAAG,CAAC,OAAO,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC;AAIvD,qBAAa,aAAc,SAAQ,KAAK;IACtC,QAAQ,CAAC,IAAI,EAAE,iBAAiB,CAAC;IAEjC,+EAA+E;IAC/E,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;gBAG3B,IAAI,EAAE,iBAAiB,EACvB,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE;QAAE,UAAU,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE;CAyBrD;AAMD;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,aAAa,CAkB7D"}
@@ -0,0 +1,3 @@
1
+ export * from './keystore.js';
2
+ export { KeystoreError, type KeystoreErrorCode } from './errors.js';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.tsx"],"names":[],"mappings":"AAAA,cAAc,eAAY,CAAC;AAC3B,OAAO,EAAE,aAAa,EAAE,KAAK,iBAAiB,EAAE,MAAM,aAAU,CAAC"}
@@ -0,0 +1,100 @@
1
+ /**
2
+ * Android reports which biometric *hardware* exists, not which modality is
3
+ * enrolled, so it returns `'biometric'` when more than one is present.
4
+ */
5
+ export type BiometryType = 'faceId' | 'touchId' | 'opticId' | 'fingerprint' | 'face' | 'iris' | 'biometric' | 'none';
6
+ export type AuthPolicy = 'biometricOnly' | 'biometricOrPasscode';
7
+ /**
8
+ * Whether the wrapping key is destroyed when biometric enrollment changes.
9
+ *
10
+ * Orthogonal to {@link AuthPolicy} on purpose: `'biometricOnly'` must never
11
+ * imply invalidation, or a user adding a fingerprint silently destroys their
12
+ * wallet. Opting in is explicit.
13
+ */
14
+ export type InvalidationPolicy = 'onEnrollmentChange' | 'never';
15
+ export declare const DEFAULT_AUTH_POLICY: AuthPolicy;
16
+ export declare const DEFAULT_INVALIDATION_POLICY: InvalidationPolicy;
17
+ /** Uncompressed SEC1 public key: `0x04` followed by 64 bytes. */
18
+ export type PublicKeyHex = `0x${string}`;
19
+ /** 65-byte Ethereum signature: `r || s || v`, with `v` 27 or 28. */
20
+ export type SignatureHex = `0x${string}`;
21
+ type KeyOptions = {
22
+ policy?: AuthPolicy;
23
+ invalidation?: InvalidationPolicy;
24
+ };
25
+ /**
26
+ * Which biometric modality the hardware supports, whether or not anything is
27
+ * enrolled. Resolves `'none'` when there is no hardware; never rejects.
28
+ *
29
+ * Enrollment state comes from {@link authenticate} via `NOT_ENROLLED`.
30
+ */
31
+ export declare function getBiometryType(): Promise<BiometryType>;
32
+ /**
33
+ * Prompts for device-owner authentication.
34
+ *
35
+ * A UX gate, not a security boundary — the boolean can be faked by a
36
+ * compromised bundle. Use {@link signDigest} where it actually matters.
37
+ *
38
+ * Never resolves `false`; every failure rejects.
39
+ *
40
+ * @throws {KeystoreError}
41
+ */
42
+ export declare function authenticate(reason: string, policy?: AuthPolicy): Promise<boolean>;
43
+ /**
44
+ * Stores a secret encrypted under a hardware-bound wrapping key.
45
+ *
46
+ * @throws {KeystoreError} `KEY_ALREADY_EXISTS` if `keyId` is taken; overwriting
47
+ * is always deliberate.
48
+ */
49
+ export declare function storeSecret(keyId: string, secretHex: string, options?: KeyOptions): Promise<void>;
50
+ /**
51
+ * Authenticates and returns the stored secret as hex.
52
+ *
53
+ * The prompt is raised by the keystore as a precondition of using the wrapping
54
+ * key, so it cannot be bypassed from JS.
55
+ *
56
+ * @throws {KeystoreError} `KEY_NOT_FOUND`, `KEY_INVALIDATED`, or any auth code.
57
+ */
58
+ export declare function getSecret(keyId: string, reason: string): Promise<string>;
59
+ /** Whether a secret is stored under `keyId`. Does not authenticate. */
60
+ export declare function hasSecret(keyId: string): Promise<boolean>;
61
+ /** Removes the secret and its wrapping key. Idempotent. */
62
+ export declare function deleteSecret(keyId: string): Promise<void>;
63
+ /**
64
+ * Generates a secp256k1 keypair in hardware-wrapped storage.
65
+ *
66
+ * Entropy comes from the platform CSPRNG, never from JavaScript, and the
67
+ * private key never crosses the bridge.
68
+ *
69
+ * @returns The uncompressed public key.
70
+ */
71
+ export declare function generateKey(keyId: string, options?: KeyOptions): Promise<PublicKeyHex>;
72
+ /**
73
+ * Imports an existing secp256k1 private key.
74
+ *
75
+ * @throws {KeystoreError} `INVALID_KEY` unless the key is in [1, n-1]. Keys
76
+ * outside that range are rejected rather than clamped.
77
+ */
78
+ export declare function importPrivateKey(keyId: string, privateKeyHex: string, options?: KeyOptions): Promise<PublicKeyHex>;
79
+ /** The uncompressed public key. Does not authenticate. */
80
+ export declare function getPublicKey(keyId: string): Promise<PublicKeyHex>;
81
+ /**
82
+ * Authenticates, then signs a 32-byte digest.
83
+ *
84
+ * Only a digest crosses the boundary — never a message or a transaction.
85
+ * Keccak and EIP-191/712/155 encoding stay in JS, which keeps this module
86
+ * curve-specific but chain-agnostic.
87
+ *
88
+ * @returns 65 bytes, `r || s || v`, low-s normalized per EIP-2 with `v` of
89
+ * 27/28 — byte-identical to viem.
90
+ */
91
+ export declare function signDigest(keyId: string, digestHex: string, reason: string): Promise<SignatureHex>;
92
+ /**
93
+ * Authenticates, then returns the raw private key.
94
+ *
95
+ * For user-initiated backup only. The result lands in the JS heap where it
96
+ * cannot be zeroed, so prefer {@link signDigest} for everyday use.
97
+ */
98
+ export declare function exportPrivateKey(keyId: string, reason: string): Promise<string>;
99
+ export {};
100
+ //# sourceMappingURL=keystore.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"keystore.d.ts","sourceRoot":"","sources":["../../../src/keystore.ts"],"names":[],"mappings":"AAGA;;;GAGG;AACH,MAAM,MAAM,YAAY,GACpB,QAAQ,GACR,SAAS,GACT,SAAS,GACT,aAAa,GACb,MAAM,GACN,MAAM,GACN,WAAW,GACX,MAAM,CAAC;AAEX,MAAM,MAAM,UAAU,GAAG,eAAe,GAAG,qBAAqB,CAAC;AAEjE;;;;;;GAMG;AACH,MAAM,MAAM,kBAAkB,GAAG,oBAAoB,GAAG,OAAO,CAAC;AAEhE,eAAO,MAAM,mBAAmB,EAAE,UAAkC,CAAC;AACrE,eAAO,MAAM,2BAA2B,EAAE,kBAA4B,CAAC;AAEvE,iEAAiE;AACjE,MAAM,MAAM,YAAY,GAAG,KAAK,MAAM,EAAE,CAAC;AAEzC,oEAAoE;AACpE,MAAM,MAAM,YAAY,GAAG,KAAK,MAAM,EAAE,CAAC;AAEzC,KAAK,UAAU,GAAG;IAChB,MAAM,CAAC,EAAE,UAAU,CAAC;IACpB,YAAY,CAAC,EAAE,kBAAkB,CAAC;CACnC,CAAC;AA2CF;;;;;GAKG;AACH,wBAAsB,eAAe,IAAI,OAAO,CAAC,YAAY,CAAC,CAI7D;AAED;;;;;;;;;GASG;AACH,wBAAsB,YAAY,CAChC,MAAM,EAAE,MAAM,EACd,MAAM,GAAE,UAAgC,GACvC,OAAO,CAAC,OAAO,CAAC,CAOlB;AAED;;;;;GAKG;AACH,wBAAsB,WAAW,CAC/B,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,MAAM,EACjB,OAAO,GAAE,UAAe,GACvB,OAAO,CAAC,IAAI,CAAC,CAoBf;AAED;;;;;;;GAOG;AACH,wBAAsB,SAAS,CAC7B,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,MAAM,CAAC,CAQjB;AAED,uEAAuE;AACvE,wBAAsB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAO/D;AAED,2DAA2D;AAC3D,wBAAsB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAO/D;AAED;;;;;;;GAOG;AACH,wBAAsB,WAAW,CAC/B,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,UAAe,GACvB,OAAO,CAAC,YAAY,CAAC,CAavB;AAED;;;;;GAKG;AACH,wBAAsB,gBAAgB,CACpC,KAAK,EAAE,MAAM,EACb,aAAa,EAAE,MAAM,EACrB,OAAO,GAAE,UAAe,GACvB,OAAO,CAAC,YAAY,CAAC,CA0BvB;AAED,0DAA0D;AAC1D,wBAAsB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAOvE;AAED;;;;;;;;;GASG;AACH,wBAAsB,UAAU,CAC9B,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,YAAY,CAAC,CAmBvB;AAED;;;;;GAKG;AACH,wBAAsB,gBAAgB,CACpC,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,MAAM,CAAC,CAQjB"}
@@ -0,0 +1,24 @@
1
+ import { type Hex, type LocalAccount } from 'viem';
2
+ export type KeystoreAccountOptions = {
3
+ /** Shown in the authentication prompt. */
4
+ reason?: string;
5
+ /** Skips a native round-trip. Must belong to `keyId`. */
6
+ publicKey?: Hex;
7
+ };
8
+ /**
9
+ * Adapts a hardware-wrapped key into a viem {@link LocalAccount}.
10
+ *
11
+ * Every path hashes in JS and sends only a 32-byte digest to native, leaving
12
+ * EIP-191, EIP-712 and transaction serialization to viem.
13
+ *
14
+ * ```ts
15
+ * const account = await toKeystoreAccount('wallet-1');
16
+ * const client = createWalletClient({ account, chain: mainnet, transport: http() });
17
+ * await client.sendTransaction({ to: '0x…', value: 1n });
18
+ * ```
19
+ *
20
+ * Each signature raises its own authentication prompt, so batching several will
21
+ * prompt several times.
22
+ */
23
+ export declare function toKeystoreAccount(keyId: string, options?: KeystoreAccountOptions): Promise<LocalAccount>;
24
+ //# sourceMappingURL=viem.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"viem.d.ts","sourceRoot":"","sources":["../../../src/viem.ts"],"names":[],"mappings":"AAAA,OAAO,EAKL,KAAK,GAAG,EACR,KAAK,YAAY,EAMlB,MAAM,MAAM,CAAC;AAKd,MAAM,MAAM,sBAAsB,GAAG;IACnC,0CAA0C;IAC1C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,yDAAyD;IACzD,SAAS,CAAC,EAAE,GAAG,CAAC;CACjB,CAAC;AAIF;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,iBAAiB,CACrC,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,sBAA2B,GACnC,OAAO,CAAC,YAAY,CAAC,CAsDvB"}