@le-space/p2pass 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 (46) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +258 -0
  3. package/dist/backup/registry-backup.d.ts +26 -0
  4. package/dist/backup/registry-backup.js +51 -0
  5. package/dist/identity/identity-service.d.ts +116 -0
  6. package/dist/identity/identity-service.js +524 -0
  7. package/dist/identity/mode-detector.d.ts +29 -0
  8. package/dist/identity/mode-detector.js +124 -0
  9. package/dist/identity/signing-preference.d.ts +30 -0
  10. package/dist/identity/signing-preference.js +55 -0
  11. package/dist/index.d.ts +15 -0
  12. package/dist/index.js +91 -0
  13. package/dist/p2p/setup.d.ts +48 -0
  14. package/dist/p2p/setup.js +283 -0
  15. package/dist/recovery/ipns-key.d.ts +41 -0
  16. package/dist/recovery/ipns-key.js +127 -0
  17. package/dist/recovery/manifest.d.ts +106 -0
  18. package/dist/recovery/manifest.js +243 -0
  19. package/dist/registry/device-registry.d.ts +122 -0
  20. package/dist/registry/device-registry.js +275 -0
  21. package/dist/registry/index.d.ts +3 -0
  22. package/dist/registry/index.js +46 -0
  23. package/dist/registry/manager.d.ts +76 -0
  24. package/dist/registry/manager.js +376 -0
  25. package/dist/registry/pairing-protocol.d.ts +61 -0
  26. package/dist/registry/pairing-protocol.js +653 -0
  27. package/dist/ucan/storacha-auth.d.ts +45 -0
  28. package/dist/ucan/storacha-auth.js +164 -0
  29. package/dist/ui/StorachaFab.svelte +134 -0
  30. package/dist/ui/StorachaFab.svelte.d.ts +23 -0
  31. package/dist/ui/StorachaIntegration.svelte +2467 -0
  32. package/dist/ui/StorachaIntegration.svelte.d.ts +23 -0
  33. package/dist/ui/fonts/dm-mono-400.ttf +0 -0
  34. package/dist/ui/fonts/dm-mono-500.ttf +0 -0
  35. package/dist/ui/fonts/dm-sans-400.ttf +0 -0
  36. package/dist/ui/fonts/dm-sans-500.ttf +0 -0
  37. package/dist/ui/fonts/dm-sans-600.ttf +0 -0
  38. package/dist/ui/fonts/dm-sans-700.ttf +0 -0
  39. package/dist/ui/fonts/epilogue-400.ttf +0 -0
  40. package/dist/ui/fonts/epilogue-500.ttf +0 -0
  41. package/dist/ui/fonts/epilogue-600.ttf +0 -0
  42. package/dist/ui/fonts/epilogue-700.ttf +0 -0
  43. package/dist/ui/fonts/storacha-fonts.css +152 -0
  44. package/dist/ui/storacha-backup.d.ts +44 -0
  45. package/dist/ui/storacha-backup.js +218 -0
  46. package/package.json +112 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Sabysachi Patra & Nico Krause
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,258 @@
1
+ # P2Pass (`@le-space/p2pass`)
2
+
3
+ [![Tests](https://github.com/asabya/p2p-passkeys/actions/workflows/tests.yml/badge.svg)](https://github.com/asabya/p2p-passkeys/actions/workflows/tests.yml)
4
+
5
+ Standalone Svelte component for passkey-based DID identities replicating p2p between devices and [Storacha](https://storacha.network) decentralized backup. Published on npm as **`@le-space/p2pass`** (Le Space).
6
+
7
+ Drop in `<StorachaFab />` and get:
8
+
9
+ - WebAuthn passkey authentication (hardware Ed25519, P-256, or worker Ed25519 fallback)
10
+ - UCAN delegation-based Storacha access
11
+ - OrbitDB backup/restore with progress tracking
12
+ - P2P device linking via libp2p with copy/paste peer info
13
+ - Multi-device registry with automatic device detection
14
+ - Floating action button with Storacha branding
15
+
16
+ ## Install
17
+
18
+ ```bash
19
+ npm install @le-space/p2pass
20
+ ```
21
+
22
+ ## Usage
23
+
24
+ ```svelte
25
+ <script>
26
+ import { StorachaFab } from '@le-space/p2pass';
27
+ </script>
28
+
29
+ <StorachaFab {orbitdb} {libp2p} onAuthenticate={handleAuthenticate} />
30
+ ```
31
+
32
+ The component handles everything internally:
33
+
34
+ 1. Click the floating Storacha button (bottom-right)
35
+ 2. Choose a **signing mode** (hardware Ed25519 with P-256 fallback, hardware P-256 only, or worker Ed25519), then **Authenticate with Passkey** → biometric prompt → DID created
36
+ 3. Two tabs appear: **P2P Passkeys** (device linking) and **Storacha** (backup/restore); P2P Passkeys is the default
37
+ 4. Paste a UCAN delegation → connected to Storacha → backup/restore enabled
38
+ 5. P2P Passkeys tab shows connection status, peer info, and linked devices
39
+
40
+ ## Worker Ed25519 Passkey Flow
41
+
42
+ Worker mode (`preferWorkerMode={true}`) uses WebAuthn purely for user verification and PRF seed extraction — the actual signing key is an Ed25519 keypair generated in a web worker, encrypted with the PRF-derived key.
43
+
44
+ ### First Visit (Registration)
45
+
46
+ ```
47
+ User clicks "Authenticate with Passkey"
48
+
49
+ ├─ navigator.credentials.create()
50
+ │ ├─ Biometric prompt (Face ID / Touch ID / PIN)
51
+ │ ├─ Creates discoverable credential (resident key)
52
+ │ └─ PRF extension: eval({ first: deterministicSalt })
53
+
54
+ ├─ Extract PRF seed from credential response
55
+ │ └─ Deterministic 32-byte seed derived from biometric + salt
56
+
57
+ ├─ Initialize Ed25519 keystore with PRF seed
58
+ │ └─ PRF seed used as AES-GCM encryption key for the keystore
59
+
60
+ ├─ Generate Ed25519 keypair in web worker
61
+ │ ├─ Random Ed25519 keypair created
62
+ │ ├─ DID derived: did:key:z6Mk...
63
+ │ └─ Archive exported (private key material)
64
+
65
+ ├─ Encrypt archive with PRF-derived AES key
66
+ │ └─ { ciphertext, iv } stored as hex strings
67
+
68
+ ├─ Derive IPNS keypair from PRF seed (for recovery)
69
+ │ └─ Deterministic Ed25519 key for IPNS manifest publishing
70
+
71
+ └─ Store credentials
72
+ ├─ Encrypted archive → localStorage (bootstrap cache)
73
+ ├─ Keypair + archive → OrbitDB registry (when available)
74
+ └─ WebAuthn credential metadata → localStorage (for re-auth)
75
+ ```
76
+
77
+ ### Return Visit (Restoration)
78
+
79
+ ```
80
+ User clicks "Authenticate with Passkey"
81
+
82
+ ├─ Find cached archive in localStorage
83
+ │ └─ { did, ciphertext, iv, publicKeyHex }
84
+
85
+ ├─ Load stored WebAuthn credential metadata
86
+
87
+ ├─ navigator.credentials.get()
88
+ │ ├─ Biometric prompt (same passkey as registration)
89
+ │ └─ PRF extension: eval({ first: sameSalt })
90
+
91
+ ├─ Extract PRF seed → same seed as registration
92
+
93
+ ├─ Decrypt archive with PRF seed → same Ed25519 keypair
94
+
95
+ └─ Same DID restored: did:key:z6Mk...
96
+ ```
97
+
98
+ ### Recovery (New Device / Cleared Storage)
99
+
100
+ ```
101
+ User clicks "Recover Identity"
102
+
103
+ ├─ navigator.credentials.get() (discoverable credential)
104
+ │ ├─ Biometric prompt — passkey synced via iCloud/Google/etc.
105
+ │ └─ PRF extension → same PRF seed
106
+
107
+ ├─ Derive IPNS keypair from PRF seed
108
+
109
+ ├─ Resolve IPNS manifest via w3name
110
+ │ └─ Manifest contains: { ownerDid, archiveCID, delegation, registryAddress }
111
+
112
+ ├─ Fetch encrypted archive from IPFS gateway (no auth needed)
113
+ │ └─ GET https://{archiveCID}.ipfs.w3s.link/ → { ciphertext, iv }
114
+
115
+ ├─ Decrypt archive with PRF seed → Ed25519 keypair restored
116
+
117
+ ├─ Connect to Storacha using delegation from manifest
118
+
119
+ └─ Same DID restored on new device
120
+ ```
121
+
122
+ ### Key Insight
123
+
124
+ The WebAuthn credential never signs anything — it's only used for:
125
+
126
+ 1. **User verification** (biometric gate)
127
+ 2. **PRF seed extraction** (deterministic secret derived from biometric + salt)
128
+
129
+ The PRF seed is the root of all derived keys:
130
+
131
+ - **Ed25519 DID keypair** — encrypted with PRF-derived AES key
132
+ - **IPNS recovery key** — deterministically derived from PRF seed
133
+ - **Keystore encryption** — PRF seed used as AES-GCM key
134
+
135
+ This means the same passkey on any device (via passkey sync) produces the same PRF seed, which unlocks the same DID identity.
136
+
137
+ ### Signing Modes
138
+
139
+ | Mode | Security | Key Storage | Biometric |
140
+ | ---------------- | -------- | ----------------------------------- | ------------- |
141
+ | Hardware Ed25519 | Highest | TPM/Secure Enclave | Per signature |
142
+ | Hardware P-256 | High | TPM/Secure Enclave | Per signature |
143
+ | Worker Ed25519 | Medium | Web worker + encrypted localStorage | On init only |
144
+
145
+ **Worker Ed25519** matches typical OrbitDB multi-device flows (signing key in a worker). **Hardware** modes keep private keys in the authenticator; hardware Ed25519 lists Ed25519 first and may obtain **P-256** if the device does not support hardware Ed25519. Pick the mode in the panel before authenticating, or set `signingPreference="worker"` / `preferWorkerMode` on the component.
146
+
147
+ ## Props
148
+
149
+ When using `StorachaFab` or `StorachaIntegration` directly:
150
+
151
+ | Prop | Type | Default | Description |
152
+ | ------------------- | -------- | --------------- | ---------------------------------------------------------------------------------------- |
153
+ | `orbitdb` | object | `null` | OrbitDB instance (for backup/restore) |
154
+ | `database` | object | `null` | Database instance to backup |
155
+ | `isInitialized` | boolean | `false` | Whether OrbitDB is ready |
156
+ | `entryCount` | number | `0` | Database entry count |
157
+ | `databaseName` | string | `'restored-db'` | Name for restored database |
158
+ | `onRestore` | function | `() => {}` | Called when restore completes |
159
+ | `onBackup` | function | `() => {}` | Called when backup completes |
160
+ | `onAuthenticate` | function | `() => {}` | Called after passkey auth (receives signingMode) |
161
+ | `libp2p` | object | `null` | libp2p instance for P2P connectivity |
162
+ | `signingPreference` | `string` | `null` | `'hardware-ed25519'`, `'hardware-p256'`, or `'worker'` — overrides the in-panel selector |
163
+ | `preferWorkerMode` | boolean | `false` | Deprecated; same as `signingPreference="worker"` |
164
+
165
+ ## Components
166
+
167
+ ### `StorachaFab`
168
+
169
+ Floating action button (bottom-right) with the Storacha rooster logo. Opens the integration panel as an overlay. Self-contained — no Tailwind or external CSS required.
170
+
171
+ ### `StorachaIntegration`
172
+
173
+ The panel component itself. Can be embedded inline instead of as a floating panel.
174
+
175
+ ## Programmatic API
176
+
177
+ ```js
178
+ import {
179
+ IdentityService,
180
+ createStorachaClient,
181
+ parseDelegation,
182
+ setupP2PStack,
183
+ createLibp2pInstance,
184
+ cleanupP2PStack,
185
+ } from '@le-space/p2pass';
186
+
187
+ // Create identity (worker mode for P2P)
188
+ const identity = new IdentityService();
189
+ const { mode, did, algorithm } = await identity.initialize(undefined, { preferWorkerMode: true });
190
+
191
+ // Get UCAN principal
192
+ const principal = await identity.getPrincipal();
193
+
194
+ // Connect to Storacha
195
+ const delegation = await parseDelegation(delegationBase64);
196
+ const client = await createStorachaClient(principal, delegation);
197
+
198
+ // Start P2P stack
199
+ const libp2p = await createLibp2pInstance();
200
+ // After auth, upgrade to full stack with OrbitDB:
201
+ const stack = await setupP2PStack(credential);
202
+ ```
203
+
204
+ ## Development
205
+
206
+ ```bash
207
+ npm run dev:example # Run example app
208
+ npm test # Run unit tests
209
+ npm run package # Build library
210
+ ```
211
+
212
+ ### End-to-end tests
213
+
214
+ Playwright drives the **example app** in Chromium with virtual WebAuthn. Tests live in `e2e/` (for example `link-devices.spec.js` for multi-device pairing).
215
+
216
+ **Run:**
217
+
218
+ ```bash
219
+ npm run test:e2e # headless; starts relay + Vite automatically
220
+ npm run test:e2e:ui # Playwright UI mode (debugging)
221
+ ```
222
+
223
+ `playwright.config.js` starts **`scripts/e2e-with-relay.mjs`**, which:
224
+
225
+ 1. Launches **orbitdb-relay-pinner** (local libp2p relay).
226
+ 2. Fetches WebSocket bootstrap multiaddrs from the relay’s HTTP API and passes them to Vite as **`VITE_BOOTSTRAP_PEERS`** so browsers can connect.
227
+ 3. Runs **`svelte-package`** and the **example Vite dev server** on port **5173**.
228
+
229
+ First-time setup may require browser binaries:
230
+
231
+ ```bash
232
+ npx playwright install chromium
233
+ ```
234
+
235
+ **Reuse a running dev server** (you must still provide a relay and matching `VITE_BOOTSTRAP_PEERS` yourself if you skip the script):
236
+
237
+ ```bash
238
+ PW_REUSE_SERVER=1 npm run test:e2e
239
+ ```
240
+
241
+ Failed runs write HTML reports, screenshots, traces, and video under `test-results/` (see Playwright output for paths).
242
+
243
+ **Signing mode in e2e:** set `E2E_SIGNING_MODE` to `worker`, `hardware-ed25519`, or `hardware-p256` (default in helpers is `worker`). CI runs the link-devices spec **three times** (matrix), one per mode.
244
+
245
+ ```bash
246
+ E2E_SIGNING_MODE=hardware-ed25519 npm run test:e2e
247
+ ```
248
+
249
+ ## Dependencies
250
+
251
+ - [`@le-space/orbitdb-identity-provider-webauthn-did`](https://github.com/Le-Space/orbitdb-identity-provider-webauthn-did) — WebAuthn crypto primitives
252
+ - [`@storacha/client`](https://github.com/storacha/w3up) — Storacha storage client
253
+ - [`orbitdb-storacha-bridge`](https://github.com/nicobao/orbitdb-storacha-bridge) — OrbitDB backup/restore
254
+ - Forked `@le-space/ucanto-*` packages for WebAuthn Ed25519/P-256 UCAN support
255
+
256
+ ## License
257
+
258
+ MIT
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Backup registry DB to Storacha via bridge.
3
+ * @param {Object} bridge - Initialized OrbitDBStorachaBridge instance
4
+ * @param {Object} orbitdb - OrbitDB instance
5
+ * @param {Object} registryDb - Registry database to backup
6
+ * @returns {Promise<{success: boolean, blocksUploaded?: number, blocksTotal?: number, error?: string}>}
7
+ */
8
+ export function backupRegistryDb(bridge: Object, orbitdb: Object, registryDb: Object): Promise<{
9
+ success: boolean;
10
+ blocksUploaded?: number;
11
+ blocksTotal?: number;
12
+ error?: string;
13
+ }>;
14
+ /**
15
+ * Restore registry from Storacha backup.
16
+ * @param {Object} bridge - Initialized OrbitDBStorachaBridge instance
17
+ * @param {Object} orbitdb - OrbitDB instance
18
+ * @param {Object} [options]
19
+ * @returns {Promise<{success: boolean, database?: Object, entriesRecovered?: number, error?: string}>}
20
+ */
21
+ export function restoreRegistryDb(bridge: Object, orbitdb: Object, options?: Object): Promise<{
22
+ success: boolean;
23
+ database?: Object;
24
+ entriesRecovered?: number;
25
+ error?: string;
26
+ }>;
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Backup registry DB to Storacha via bridge.
3
+ * @param {Object} bridge - Initialized OrbitDBStorachaBridge instance
4
+ * @param {Object} orbitdb - OrbitDB instance
5
+ * @param {Object} registryDb - Registry database to backup
6
+ * @returns {Promise<{success: boolean, blocksUploaded?: number, blocksTotal?: number, error?: string}>}
7
+ */
8
+ export async function backupRegistryDb(bridge, orbitdb, registryDb) {
9
+ try {
10
+ const result = await bridge.backup(orbitdb, registryDb.address);
11
+ return {
12
+ success: true,
13
+ blocksUploaded: result.blocksUploaded,
14
+ blocksTotal: result.blocksTotal,
15
+ };
16
+ } catch (err) {
17
+ return {
18
+ success: false,
19
+ error: err.message,
20
+ };
21
+ }
22
+ }
23
+
24
+ /**
25
+ * Restore registry from Storacha backup.
26
+ * @param {Object} bridge - Initialized OrbitDBStorachaBridge instance
27
+ * @param {Object} orbitdb - OrbitDB instance
28
+ * @param {Object} [options]
29
+ * @returns {Promise<{success: boolean, database?: Object, entriesRecovered?: number, error?: string}>}
30
+ */
31
+ export async function restoreRegistryDb(bridge, orbitdb, options = {}) {
32
+ try {
33
+ const result = await bridge.restoreFromSpace(orbitdb, {
34
+ timeout: 120000,
35
+ preferredDatabaseName: 'multi-device-registry',
36
+ restartAfterRestore: true,
37
+ verifyIntegrity: true,
38
+ ...options,
39
+ });
40
+ return {
41
+ success: true,
42
+ database: result.database,
43
+ entriesRecovered: result.entriesRecovered,
44
+ };
45
+ } catch (err) {
46
+ return {
47
+ success: false,
48
+ error: err.message,
49
+ };
50
+ }
51
+ }
@@ -0,0 +1,116 @@
1
+ /**
2
+ * Best-effort: this origin likely already has passkey / identity material (no WebAuthn prompt).
3
+ * Uses the same signals as restore paths — false negatives are OK (same handlers still apply).
4
+ *
5
+ * @returns {boolean}
6
+ */
7
+ export function hasLocalPasskeyHint(): boolean;
8
+ export class IdentityService {
9
+ /**
10
+ * Bind an OrbitDB registry database for credential storage.
11
+ * If pending credentials exist from a prior initialize() call, flushes them.
12
+ *
13
+ * @param {Object} db - OrbitDB KeyValue database (from openDeviceRegistry)
14
+ */
15
+ setRegistry(db: Object): Promise<void>;
16
+ /**
17
+ * Get the bound registry DB (or null).
18
+ * @returns {Object|null}
19
+ */
20
+ getRegistry(): Object | null;
21
+ /**
22
+ * Initialize identity — auto-detect hardware vs worker mode.
23
+ * If existing credentials found, restores them (may prompt biometric for worker PRF).
24
+ * If no credentials, creates new passkey.
25
+ *
26
+ * @param {'platform'|'cross-platform'} [authenticatorType]
27
+ * @param {{ preferWorkerMode?: boolean, signingPreference?: import('./signing-preference.js').SigningPreference }} [options]
28
+ * @returns {Promise<{ mode: string, did: string, algorithm: string }>}
29
+ */
30
+ initialize(authenticatorType?: "platform" | "cross-platform", options?: {
31
+ preferWorkerMode?: boolean;
32
+ signingPreference?: import("./signing-preference.js").SigningPreference;
33
+ }): Promise<{
34
+ mode: string;
35
+ did: string;
36
+ algorithm: string;
37
+ }>;
38
+ /**
39
+ * Force create a new identity (discards existing).
40
+ * @param {'platform'|'cross-platform'} [authenticatorType]
41
+ * @param {{ preferWorkerMode?: boolean, signingPreference?: import('./signing-preference.js').SigningPreference }} [options]
42
+ * @returns {Promise<{ mode: string, did: string, algorithm: string }>}
43
+ */
44
+ createNewIdentity(authenticatorType?: "platform" | "cross-platform", options?: {
45
+ preferWorkerMode?: boolean;
46
+ signingPreference?: import("./signing-preference.js").SigningPreference;
47
+ }): Promise<{
48
+ mode: string;
49
+ did: string;
50
+ algorithm: string;
51
+ }>;
52
+ /**
53
+ * Recovery entry point — uses discoverable credentials to derive IPNS key.
54
+ * Does NOT restore the DID — caller must resolve manifest and restore registry first.
55
+ * @returns {Promise<{ prfSeed: Uint8Array, ipnsKeyPair: Object, rawCredentialId: Uint8Array }>}
56
+ */
57
+ initializeFromRecovery(): Promise<{
58
+ prfSeed: Uint8Array;
59
+ ipnsKeyPair: Object;
60
+ rawCredentialId: Uint8Array;
61
+ }>;
62
+ /**
63
+ * Restore DID from an encrypted archive entry (from registry DB after recovery).
64
+ * Uses the PRF seed stored during initializeFromRecovery().
65
+ * @param {Object} archiveEntry - { ciphertext: string (hex), iv: string (hex) }
66
+ * @param {string} did - The owner DID from the manifest
67
+ * @returns {Promise<void>}
68
+ */
69
+ restoreFromManifest(archiveEntry: Object, did: string): Promise<void>;
70
+ /**
71
+ * Get current signing mode info.
72
+ * @returns {{ mode: string|null, did: string|null, algorithm: string|null, secure: boolean }}
73
+ */
74
+ getSigningMode(): {
75
+ mode: string | null;
76
+ did: string | null;
77
+ algorithm: string | null;
78
+ secure: boolean;
79
+ };
80
+ /**
81
+ * Get a UCAN-compatible principal/signer.
82
+ * For hardware mode: returns varsig signer via toUcantoSigner()
83
+ * For worker mode: returns Ed25519 principal from archive
84
+ *
85
+ * @returns {Promise<any>} UCAN signer
86
+ */
87
+ getPrincipal(): Promise<any>;
88
+ /**
89
+ * @returns {boolean}
90
+ */
91
+ isInitialized(): boolean;
92
+ /**
93
+ * Get the derived IPNS keypair (available after initialize or recovery).
94
+ * @returns {{ privateKey: Object, publicKey: Object }|null}
95
+ */
96
+ getIPNSKeyPair(): {
97
+ privateKey: Object;
98
+ publicKey: Object;
99
+ } | null;
100
+ /**
101
+ * Get the stored PRF seed (available after initialize or recovery).
102
+ * @returns {Uint8Array|null}
103
+ */
104
+ getPrfSeed(): Uint8Array | null;
105
+ /**
106
+ * Get the encrypted archive data (ciphertext + iv as hex strings) for the current identity.
107
+ * Used by manifest publishing to upload the archive to IPFS for auth-free recovery.
108
+ *
109
+ * @returns {Promise<{ ciphertext: string, iv: string }|null>}
110
+ */
111
+ getEncryptedArchiveData(): Promise<{
112
+ ciphertext: string;
113
+ iv: string;
114
+ } | null>;
115
+ #private;
116
+ }