w3pk 0.9.2 → 0.9.3
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 +11 -5
- package/dist/index.d.mts +88 -1
- package/dist/index.d.ts +88 -1
- package/dist/index.js +30 -27
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +28 -25
- package/dist/index.mjs.map +1 -1
- package/docs/API_REFERENCE.md +90 -34
- package/docs/RECOVERY.md +138 -99
- package/package.json +1 -1
package/docs/API_REFERENCE.md
CHANGED
|
@@ -2308,11 +2308,23 @@ const hybridBackup = await w3pk.createBackupFile('hybrid', 'MySecurePassword123!
|
|
|
2308
2308
|
|
|
2309
2309
|
---
|
|
2310
2310
|
|
|
2311
|
-
|
|
2311
|
+
## Social Recovery API
|
|
2312
2312
|
|
|
2313
|
-
|
|
2313
|
+
Social recovery is handled by the `SocialRecoveryManager` class, which splits password-encrypted backup files into guardian shares using Shamir Secret Sharing.
|
|
2314
|
+
|
|
2315
|
+
### Import
|
|
2316
|
+
|
|
2317
|
+
```typescript
|
|
2318
|
+
import { SocialRecoveryManager } from 'w3pk';
|
|
2319
|
+
```
|
|
2320
|
+
|
|
2321
|
+
### `SocialRecoveryManager.setupSocialRecovery(backupFileJson: string, ethereumAddress: string, guardians: Guardian[], threshold: number): Promise<Guardian[]>`
|
|
2322
|
+
|
|
2323
|
+
Set up social recovery by splitting an encrypted backup file among guardians.
|
|
2314
2324
|
|
|
2315
2325
|
**Parameters:**
|
|
2326
|
+
- `backupFileJson: string` - Password-encrypted backup file JSON
|
|
2327
|
+
- `ethereumAddress: string` - Ethereum address for verification
|
|
2316
2328
|
- `guardians: Guardian[]`
|
|
2317
2329
|
```typescript
|
|
2318
2330
|
interface Guardian {
|
|
@@ -2323,15 +2335,27 @@ Set up social recovery with M-of-N guardian shares using Shamir Secret Sharing.
|
|
|
2323
2335
|
```
|
|
2324
2336
|
- `threshold: number` - Number of guardians required to recover (M in M-of-N)
|
|
2325
2337
|
|
|
2326
|
-
**Returns:** Array of guardians with encrypted
|
|
2338
|
+
**Returns:** Array of guardians with encrypted share fragments
|
|
2327
2339
|
|
|
2328
|
-
**Security:**
|
|
2340
|
+
**Security:**
|
|
2341
|
+
- Guardians receive fragments of an already-encrypted backup file
|
|
2342
|
+
- Password is never shared with guardians
|
|
2343
|
+
- Requires both threshold shares + password to recover
|
|
2329
2344
|
|
|
2330
2345
|
**Example:**
|
|
2331
2346
|
|
|
2332
2347
|
```typescript
|
|
2333
|
-
|
|
2334
|
-
|
|
2348
|
+
import { SocialRecoveryManager } from 'w3pk';
|
|
2349
|
+
|
|
2350
|
+
// Step 1: Create password-encrypted backup file
|
|
2351
|
+
const { blob } = await w3pk.createBackupFile('password', 'MySecurePassword123!');
|
|
2352
|
+
const backupFileJson = await blob.text();
|
|
2353
|
+
|
|
2354
|
+
// Step 2: Setup social recovery with 3-of-5 threshold
|
|
2355
|
+
const socialRecovery = new SocialRecoveryManager();
|
|
2356
|
+
const guardians = await socialRecovery.setupSocialRecovery(
|
|
2357
|
+
backupFileJson,
|
|
2358
|
+
w3pk.user.ethereumAddress,
|
|
2335
2359
|
[
|
|
2336
2360
|
{ name: 'Alice', email: 'alice@example.com' },
|
|
2337
2361
|
{ name: 'Bob', phone: '+1234567890' },
|
|
@@ -2340,19 +2364,19 @@ const guardians = await w3pk.setupSocialRecovery(
|
|
|
2340
2364
|
{ name: 'Eve', email: 'eve@example.com' }
|
|
2341
2365
|
],
|
|
2342
2366
|
3 // Need 3 guardians to recover
|
|
2343
|
-
)
|
|
2367
|
+
);
|
|
2344
2368
|
|
|
2345
|
-
console.log('Social recovery configured with', guardians.length, 'guardians')
|
|
2369
|
+
console.log('Social recovery configured with', guardians.length, 'guardians');
|
|
2346
2370
|
```
|
|
2347
2371
|
|
|
2348
2372
|
---
|
|
2349
2373
|
|
|
2350
|
-
### `generateGuardianInvite(
|
|
2374
|
+
### `SocialRecoveryManager.generateGuardianInvite(guardian: Guardian): Promise<GuardianInvite>`
|
|
2351
2375
|
|
|
2352
|
-
Generate invitation for a guardian with their
|
|
2376
|
+
Generate invitation for a guardian with their encrypted share fragment.
|
|
2353
2377
|
|
|
2354
2378
|
**Parameters:**
|
|
2355
|
-
- `
|
|
2379
|
+
- `guardian: Guardian` - Guardian object with share
|
|
2356
2380
|
|
|
2357
2381
|
**Returns:**
|
|
2358
2382
|
|
|
@@ -2360,57 +2384,89 @@ Generate invitation for a guardian with their recovery share.
|
|
|
2360
2384
|
interface GuardianInvite {
|
|
2361
2385
|
guardianId: string;
|
|
2362
2386
|
qrCode: string; // Data URL for QR code
|
|
2363
|
-
shareCode: string; //
|
|
2387
|
+
shareCode: string; // JSON string for manual entry
|
|
2364
2388
|
explainer: string; // Educational text for guardian
|
|
2365
|
-
link?: string; // Optional deep link
|
|
2366
2389
|
}
|
|
2367
2390
|
```
|
|
2368
2391
|
|
|
2369
2392
|
**Example:**
|
|
2370
2393
|
|
|
2371
2394
|
```typescript
|
|
2372
|
-
const
|
|
2395
|
+
const socialRecovery = new SocialRecoveryManager();
|
|
2396
|
+
|
|
2397
|
+
for (const guardian of guardians) {
|
|
2398
|
+
const invite = await socialRecovery.generateGuardianInvite(guardian);
|
|
2399
|
+
|
|
2400
|
+
// Show QR code to guardian
|
|
2401
|
+
console.log('QR code:', invite.qrCode);
|
|
2402
|
+
console.log('Share code:', invite.shareCode);
|
|
2403
|
+
console.log('Instructions:', invite.explainer);
|
|
2373
2404
|
|
|
2374
|
-
//
|
|
2375
|
-
|
|
2376
|
-
console.log('Or share this code:', invite.shareCode)
|
|
2377
|
-
console.log('Instructions:', invite.explainer)
|
|
2405
|
+
// Send via email, messaging app, etc.
|
|
2406
|
+
}
|
|
2378
2407
|
```
|
|
2379
2408
|
|
|
2380
2409
|
---
|
|
2381
2410
|
|
|
2382
|
-
### `recoverFromGuardians(shares: string[]): Promise<
|
|
2411
|
+
### `SocialRecoveryManager.recoverFromGuardians(shares: string[]): Promise<{ backupFileJson: string; ethereumAddress: string }>`
|
|
2383
2412
|
|
|
2384
|
-
|
|
2413
|
+
Reconstruct encrypted backup file from guardian shares.
|
|
2385
2414
|
|
|
2386
2415
|
**Parameters:**
|
|
2387
|
-
- `shares: string[]` - Array of share
|
|
2416
|
+
- `shares: string[]` - Array of share codes from guardians (JSON strings)
|
|
2388
2417
|
|
|
2389
2418
|
**Returns:**
|
|
2390
2419
|
|
|
2391
2420
|
```typescript
|
|
2392
|
-
|
|
2393
|
-
|
|
2394
|
-
ethereumAddress: string;
|
|
2421
|
+
{
|
|
2422
|
+
backupFileJson: string; // Reconstructed encrypted backup file
|
|
2423
|
+
ethereumAddress: string; // Ethereum address from backup
|
|
2395
2424
|
}
|
|
2396
2425
|
```
|
|
2397
2426
|
|
|
2398
2427
|
**Example:**
|
|
2399
2428
|
|
|
2400
2429
|
```typescript
|
|
2401
|
-
|
|
2430
|
+
import { SocialRecoveryManager } from 'w3pk';
|
|
2431
|
+
|
|
2432
|
+
const socialRecovery = new SocialRecoveryManager();
|
|
2433
|
+
|
|
2434
|
+
// Step 1: Collect shares from 3+ guardians
|
|
2402
2435
|
const shares = [
|
|
2403
|
-
|
|
2404
|
-
|
|
2405
|
-
|
|
2406
|
-
]
|
|
2436
|
+
aliceShareCode, // JSON string from Alice
|
|
2437
|
+
bobShareCode, // JSON string from Bob
|
|
2438
|
+
charlieShareCode // JSON string from Charlie
|
|
2439
|
+
];
|
|
2407
2440
|
|
|
2408
|
-
|
|
2409
|
-
|
|
2410
|
-
console.log('
|
|
2441
|
+
// Step 2: Reconstruct encrypted backup file
|
|
2442
|
+
const { backupFileJson, ethereumAddress } = await socialRecovery.recoverFromGuardians(shares);
|
|
2443
|
+
console.log('Backup file reconstructed for:', ethereumAddress);
|
|
2444
|
+
|
|
2445
|
+
// Step 3: Decrypt with password and register
|
|
2446
|
+
const password = 'MySecurePassword123!'; // Password set during setup
|
|
2447
|
+
await w3pk.registerWithBackupFile(backupFileJson, password, 'username');
|
|
2448
|
+
console.log('Wallet recovered and registered!');
|
|
2449
|
+
```
|
|
2450
|
+
|
|
2451
|
+
---
|
|
2411
2452
|
|
|
2412
|
-
|
|
2413
|
-
|
|
2453
|
+
### `SocialRecoveryManager.getSocialRecoveryConfig(): SocialRecoveryConfig | null`
|
|
2454
|
+
|
|
2455
|
+
Get current social recovery configuration from localStorage.
|
|
2456
|
+
|
|
2457
|
+
**Returns:** Social recovery configuration or null if not set up
|
|
2458
|
+
|
|
2459
|
+
**Example:**
|
|
2460
|
+
|
|
2461
|
+
```typescript
|
|
2462
|
+
const socialRecovery = new SocialRecoveryManager();
|
|
2463
|
+
const config = socialRecovery.getSocialRecoveryConfig();
|
|
2464
|
+
|
|
2465
|
+
if (config) {
|
|
2466
|
+
console.log('Threshold:', config.threshold);
|
|
2467
|
+
console.log('Total guardians:', config.totalGuardians);
|
|
2468
|
+
console.log('Guardians:', config.guardians);
|
|
2469
|
+
}
|
|
2414
2470
|
```
|
|
2415
2471
|
|
|
2416
2472
|
---
|
package/docs/RECOVERY.md
CHANGED
|
@@ -264,15 +264,25 @@ await sdk.importFromSync(syncData);
|
|
|
264
264
|
|
|
265
265
|
### **3. Social Recovery**
|
|
266
266
|
|
|
267
|
-
**Purpose**: Distribute encrypted
|
|
267
|
+
**Purpose**: Distribute encrypted backup file fragments among trusted guardians using Shamir Secret Sharing (M-of-N)
|
|
268
268
|
|
|
269
269
|
**Setup (3-of-5 example):**
|
|
270
270
|
```typescript
|
|
271
|
+
import { SocialRecoveryManager } from 'w3pk';
|
|
272
|
+
|
|
271
273
|
const sdk = createWeb3Passkey();
|
|
272
274
|
await sdk.login();
|
|
273
275
|
|
|
274
|
-
// Create encrypted backup
|
|
275
|
-
const
|
|
276
|
+
// Step 1: Create password-encrypted backup file
|
|
277
|
+
const password = 'MySecurePassword123!'; // User must remember this
|
|
278
|
+
const { blob } = await sdk.createBackupFile('password', password);
|
|
279
|
+
const backupFileJson = await blob.text();
|
|
280
|
+
|
|
281
|
+
// Step 2: Split backup file among guardians
|
|
282
|
+
const socialRecovery = new SocialRecoveryManager();
|
|
283
|
+
const guardians = await socialRecovery.setupSocialRecovery(
|
|
284
|
+
backupFileJson, // Encrypted backup file JSON
|
|
285
|
+
sdk.user.ethereumAddress,
|
|
276
286
|
[
|
|
277
287
|
{ name: 'Alice', email: 'alice@example.com' },
|
|
278
288
|
{ name: 'Bob', email: 'bob@example.com' },
|
|
@@ -280,84 +290,61 @@ const { guardianShares } = await sdk.setupSocialRecovery(
|
|
|
280
290
|
{ name: 'David', email: 'david@example.com' },
|
|
281
291
|
{ name: 'Eve', email: 'eve@example.com' },
|
|
282
292
|
],
|
|
283
|
-
3
|
|
284
|
-
'OptionalPassword' // encrypts backup before splitting
|
|
293
|
+
3 // threshold: need 3 shares to recover
|
|
285
294
|
);
|
|
286
295
|
|
|
287
|
-
// Generate invitation for each guardian
|
|
288
|
-
for (const
|
|
289
|
-
const
|
|
290
|
-
// Send
|
|
296
|
+
// Step 3: Generate invitation for each guardian
|
|
297
|
+
for (const guardian of guardians) {
|
|
298
|
+
const invite = await socialRecovery.generateGuardianInvite(guardian);
|
|
299
|
+
// Send invite.qrCode and invite.explainer to guardian
|
|
300
|
+
// Guardian stores their share safely (password manager, etc.)
|
|
291
301
|
}
|
|
292
302
|
```
|
|
293
303
|
|
|
294
|
-
**Recover Wallet
|
|
295
|
-
|
|
296
|
-
**Option 1: Recover and register new passkey (recommended for lost devices)**
|
|
304
|
+
**Recover Wallet:**
|
|
297
305
|
```typescript
|
|
306
|
+
import { SocialRecoveryManager } from 'w3pk';
|
|
307
|
+
|
|
298
308
|
const sdk = createWeb3Passkey();
|
|
309
|
+
const socialRecovery = new SocialRecoveryManager();
|
|
299
310
|
|
|
300
311
|
// Step 1: Collect shares from 3+ guardians
|
|
301
|
-
const shares = [
|
|
312
|
+
const shares = [aliceShareCode, bobShareCode, charlieShareCode];
|
|
302
313
|
|
|
303
|
-
// Step 2:
|
|
304
|
-
const {
|
|
305
|
-
shares,
|
|
306
|
-
'OptionalPassword' // password used during setupSocialRecovery (if any)
|
|
307
|
-
);
|
|
314
|
+
// Step 2: Reconstruct encrypted backup file from shares
|
|
315
|
+
const { backupFileJson, ethereumAddress } = await socialRecovery.recoverFromGuardians(shares);
|
|
308
316
|
|
|
309
|
-
// Step 3:
|
|
310
|
-
const
|
|
311
|
-
const manager = new BackupFileManager();
|
|
312
|
-
const { backupFile } = await manager.createPasswordBackup(
|
|
313
|
-
mnemonic,
|
|
314
|
-
ethereumAddress,
|
|
315
|
-
'NewPassword123!' // Choose a new password
|
|
316
|
-
);
|
|
317
|
+
// Step 3: Decrypt backup file with password
|
|
318
|
+
const password = prompt('Enter your backup password');
|
|
317
319
|
|
|
318
|
-
// Step 4: Register new passkey
|
|
319
|
-
|
|
320
|
-
await sdk.registerWithBackupFile(backupData, 'NewPassword123!', 'username');
|
|
320
|
+
// Step 4: Register new passkey with recovered backup file
|
|
321
|
+
await sdk.registerWithBackupFile(backupFileJson, password, 'username');
|
|
321
322
|
// Now logged in with new passkey, credentials stored locally ✅
|
|
322
323
|
```
|
|
323
324
|
|
|
324
|
-
**Option 2: Recover and import to existing passkey**
|
|
325
|
-
```typescript
|
|
326
|
-
const sdk = createWeb3Passkey();
|
|
327
|
-
|
|
328
|
-
// Step 1: Login with existing WebAuthn credential
|
|
329
|
-
await sdk.login();
|
|
330
|
-
|
|
331
|
-
// Step 2: Collect shares and recover mnemonic
|
|
332
|
-
const shares = [aliceShare, bobShare, charlieShare];
|
|
333
|
-
const { mnemonic } = await sdk.recoverFromGuardians(
|
|
334
|
-
shares,
|
|
335
|
-
'OptionalPassword'
|
|
336
|
-
);
|
|
337
|
-
|
|
338
|
-
// Step 3: Import mnemonic to current logged-in user
|
|
339
|
-
await sdk.importMnemonic(mnemonic);
|
|
340
|
-
// Credentials stored locally under current passkey ✅
|
|
341
|
-
```
|
|
342
|
-
|
|
343
325
|
**Encryption**:
|
|
344
|
-
1.
|
|
345
|
-
2. Serialize to JSON
|
|
346
|
-
3. Split using Shamir Secret Sharing (M-of-N)
|
|
347
|
-
4. Each guardian gets one
|
|
326
|
+
1. User creates password-encrypted BackupFile (AES-256-GCM)
|
|
327
|
+
2. Serialize BackupFile to JSON
|
|
328
|
+
3. Split JSON using Shamir Secret Sharing (M-of-N threshold)
|
|
329
|
+
4. Each guardian gets one encrypted fragment
|
|
330
|
+
5. Recovery requires: threshold shares + original password
|
|
348
331
|
|
|
349
332
|
**Use Case**: Forgot password, lost all devices, ultimate safety net
|
|
350
333
|
|
|
351
|
-
**Security**: No single guardian can recover wallet alone
|
|
334
|
+
**Security**: No single guardian can recover wallet alone. Guardians hold fragments of an already-encrypted backup file.
|
|
352
335
|
|
|
353
336
|
**Pros:**
|
|
354
337
|
- ✅ No single point of failure
|
|
338
|
+
- ✅ Double encryption: backup is encrypted, then fragments are distributed
|
|
339
|
+
- ✅ Guardians never see plaintext wallet data
|
|
340
|
+
- ✅ Password protection even after collecting shares
|
|
355
341
|
- ✅ Survives your own forgetfulness
|
|
356
342
|
- ✅ Survives any 2 guardians disappearing
|
|
357
343
|
- ✅ Highest security and redundancy
|
|
358
344
|
|
|
359
345
|
**Cons:**
|
|
360
346
|
- ⚠️ Requires trusted friends/family
|
|
347
|
+
- ⚠️ Must remember password (guardians don't have it)
|
|
361
348
|
- ⚠️ Setup complexity
|
|
362
349
|
- ⚠️ Recovery takes time (24-48 hours)
|
|
363
350
|
- ⚠️ Coordination required
|
|
@@ -365,9 +352,10 @@ await sdk.importMnemonic(mnemonic);
|
|
|
365
352
|
**Recovery scenarios:**
|
|
366
353
|
| Scenario | Can Recover? | How |
|
|
367
354
|
|----------|--------------|-----|
|
|
368
|
-
|
|
|
369
|
-
| Lost backup + lost passkey | ✅ Yes | Contact 3 guardians |
|
|
355
|
+
| Lost all devices | ✅ Yes | Contact 3 guardians → combine shares → enter password |
|
|
356
|
+
| Lost backup + lost passkey | ✅ Yes | Contact 3 guardians → reconstruct backup file → enter password |
|
|
370
357
|
| 2 guardians unavailable | ✅ Yes | Still have 3 others |
|
|
358
|
+
| Forgot password + have shares | ❌ No | Backup file is encrypted with password |
|
|
371
359
|
| All guardians lost shares | ❌ No | Need another recovery layer |
|
|
372
360
|
|
|
373
361
|
---
|
|
@@ -396,45 +384,81 @@ await sdk.importMnemonic(mnemonic);
|
|
|
396
384
|
### **Social Recovery Cryptography**
|
|
397
385
|
|
|
398
386
|
```typescript
|
|
399
|
-
Shamir Secret Sharing
|
|
387
|
+
Backup File-Based Shamir Secret Sharing:
|
|
400
388
|
|
|
401
389
|
Example: 3-of-5 scheme
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
-
|
|
405
|
-
-
|
|
390
|
+
|
|
391
|
+
Step 1: Create Encrypted Backup File
|
|
392
|
+
- User creates password-encrypted backup file
|
|
393
|
+
- Backup contains: { encryptedMnemonic, ethereumAddress, ... }
|
|
394
|
+
- Encryption: PBKDF2(password) → AES-256-GCM
|
|
395
|
+
- Result: BackupFile JSON (already encrypted)
|
|
396
|
+
|
|
397
|
+
Step 2: Split Backup File
|
|
398
|
+
- Serialize BackupFile to JSON string
|
|
399
|
+
- Convert JSON to bytes
|
|
400
|
+
- Split bytes using Shamir Secret Sharing (3-of-5)
|
|
401
|
+
- Result: 5 shares of encrypted data
|
|
402
|
+
|
|
403
|
+
Step 3: Distribute Shares
|
|
404
|
+
- Each guardian gets one share (hex-encoded fragment)
|
|
405
|
+
- Shares are fragments of the encrypted backup file
|
|
406
|
+
- Guardians never see the plaintext mnemonic
|
|
407
|
+
- Guardians don't have the password
|
|
408
|
+
|
|
409
|
+
Recovery Process:
|
|
410
|
+
- Collect 3+ shares from guardians
|
|
411
|
+
- Combine shares → reconstruct BackupFile JSON
|
|
412
|
+
- Decrypt with password → extract mnemonic
|
|
413
|
+
- Register new passkey or import to existing
|
|
406
414
|
|
|
407
415
|
Mathematical basis:
|
|
408
|
-
- Polynomial interpolation over finite field
|
|
416
|
+
- Polynomial interpolation over finite field GF(256)
|
|
409
417
|
- Degree = threshold - 1 (e.g., degree-2 polynomial for 3-of-5)
|
|
410
418
|
- Points on polynomial = shares
|
|
411
|
-
-
|
|
419
|
+
- Any 3 points → reconstruct polynomial → recover secret
|
|
420
|
+
- Any 2 points → mathematically impossible to recover
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
**Security Model:**
|
|
424
|
+
```
|
|
425
|
+
Double Encryption:
|
|
426
|
+
Layer 1: Backup file encrypted with password (AES-256-GCM)
|
|
427
|
+
Layer 2: Encrypted backup split into shares (Shamir)
|
|
428
|
+
|
|
429
|
+
Result:
|
|
430
|
+
- Guardians hold fragments of encrypted data
|
|
431
|
+
- Even with threshold shares, password still required
|
|
432
|
+
- No single guardian has access to wallet
|
|
433
|
+
- No collusion of guardians can bypass password
|
|
412
434
|
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
- Prevents share theft from coordinator
|
|
435
|
+
Attack Scenarios:
|
|
436
|
+
✅ Attacker steals 2 shares → Cannot reconstruct
|
|
437
|
+
✅ Attacker steals 3+ shares → Still needs password
|
|
438
|
+
✅ Attacker has password → Still needs threshold shares
|
|
439
|
+
❌ Attacker has password + threshold shares → Can recover
|
|
419
440
|
```
|
|
420
441
|
|
|
421
442
|
**Trust model:**
|
|
422
443
|
```
|
|
423
444
|
Coordinator (You):
|
|
445
|
+
- Must remember password (guardians don't have it)
|
|
424
446
|
- Cannot recover from less than threshold shares
|
|
425
|
-
- Can revoke/replace guardians
|
|
426
|
-
- Can
|
|
447
|
+
- Can revoke/replace guardians (requires new setup)
|
|
448
|
+
- Can verify guardian shares are distributed
|
|
427
449
|
|
|
428
450
|
Guardians:
|
|
429
|
-
-
|
|
430
|
-
- Cannot
|
|
451
|
+
- Hold encrypted fragments only
|
|
452
|
+
- Cannot decrypt without password
|
|
453
|
+
- Cannot recover alone (need threshold + password)
|
|
431
454
|
- Can verify share validity
|
|
432
|
-
- Can
|
|
455
|
+
- Can store share safely (it's already encrypted)
|
|
433
456
|
|
|
434
457
|
Attacker:
|
|
435
458
|
- Cannot recover with < threshold shares
|
|
436
|
-
- Cannot
|
|
437
|
-
- Must compromise guardians
|
|
459
|
+
- Cannot decrypt backup without password
|
|
460
|
+
- Must compromise both guardians AND password
|
|
461
|
+
- Mathematically secure (Shamir + AES-256-GCM)
|
|
438
462
|
```
|
|
439
463
|
|
|
440
464
|
---
|
|
@@ -485,24 +509,36 @@ await w3pk.importFromSync(backupData);
|
|
|
485
509
|
### Social Recovery
|
|
486
510
|
|
|
487
511
|
```typescript
|
|
488
|
-
|
|
489
|
-
const { guardianShares } = await w3pk.setupSocialRecovery(guardians, threshold, password);
|
|
512
|
+
import { SocialRecoveryManager } from 'w3pk';
|
|
490
513
|
|
|
491
|
-
//
|
|
492
|
-
const
|
|
514
|
+
// Setup - Create password-encrypted backup and split among guardians
|
|
515
|
+
const { blob } = await w3pk.createBackupFile('password', 'MyPassword123!');
|
|
516
|
+
const backupFileJson = await blob.text();
|
|
493
517
|
|
|
494
|
-
|
|
495
|
-
const
|
|
518
|
+
const socialRecovery = new SocialRecoveryManager();
|
|
519
|
+
const guardians = await socialRecovery.setupSocialRecovery(
|
|
520
|
+
backupFileJson,
|
|
521
|
+
w3pk.user.ethereumAddress,
|
|
522
|
+
[
|
|
523
|
+
{ name: 'Alice', email: 'alice@example.com' },
|
|
524
|
+
{ name: 'Bob', email: 'bob@example.com' },
|
|
525
|
+
{ name: 'Charlie', email: 'charlie@example.com' }
|
|
526
|
+
],
|
|
527
|
+
2 // threshold
|
|
528
|
+
);
|
|
496
529
|
|
|
497
|
-
//
|
|
498
|
-
const
|
|
499
|
-
const
|
|
500
|
-
|
|
501
|
-
|
|
530
|
+
// Generate invitations for guardians
|
|
531
|
+
for (const guardian of guardians) {
|
|
532
|
+
const invite = await socialRecovery.generateGuardianInvite(guardian);
|
|
533
|
+
// Send invite.qrCode and invite.shareCode to guardian
|
|
534
|
+
}
|
|
502
535
|
|
|
503
|
-
//
|
|
504
|
-
|
|
505
|
-
await
|
|
536
|
+
// Recover - Collect shares and reconstruct encrypted backup file
|
|
537
|
+
const shares = [aliceShareCode, bobShareCode]; // JSON strings from guardians
|
|
538
|
+
const { backupFileJson, ethereumAddress } = await socialRecovery.recoverFromGuardians(shares);
|
|
539
|
+
|
|
540
|
+
// Decrypt and register with password
|
|
541
|
+
await w3pk.registerWithBackupFile(backupFileJson, 'MyPassword123!', 'username');
|
|
506
542
|
```
|
|
507
543
|
|
|
508
544
|
---
|
|
@@ -705,17 +741,20 @@ Platform-specific:
|
|
|
705
741
|
3. Contact your guardians (need 3 of 5)
|
|
706
742
|
4. Each guardian provides their share:
|
|
707
743
|
- Scan QR code, OR
|
|
708
|
-
-
|
|
709
|
-
5. After
|
|
710
|
-
- System reconstructs backup file
|
|
711
|
-
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
-
|
|
715
|
-
-
|
|
744
|
+
- Paste share code manually (JSON format)
|
|
745
|
+
5. After collecting threshold shares (e.g., 3):
|
|
746
|
+
- System reconstructs encrypted backup file ✅
|
|
747
|
+
- Backup file is still encrypted
|
|
748
|
+
6. Enter your password:
|
|
749
|
+
- This is the password you set during social recovery setup
|
|
750
|
+
- Guardians DO NOT have this password
|
|
751
|
+
- System decrypts backup file → extracts mnemonic
|
|
752
|
+
7. Choose username and register:
|
|
753
|
+
- System creates new passkey on your device
|
|
754
|
+
- Wallet credentials stored locally ✅
|
|
716
755
|
|
|
717
756
|
Timeline: ~24-48 hours (depends on guardian availability)
|
|
718
|
-
|
|
757
|
+
Security: Requires both guardian shares AND your password
|
|
719
758
|
```
|
|
720
759
|
|
|
721
760
|
#### **Method 4: Manual Mnemonic Import**
|
|
@@ -764,7 +803,7 @@ A: You'll need to use another recovery method (passkey sync or social recovery).
|
|
|
764
803
|
A: Mathematically secure with Shamir's Secret Sharing. Any 2 guardians cannot recover (need 3 of 5).
|
|
765
804
|
|
|
766
805
|
**Q: Can guardians steal my wallet?**
|
|
767
|
-
A: No
|
|
806
|
+
A: No. Guardians hold encrypted fragments of an already-encrypted backup file. Even if they collude and combine all shares, they still need your password to decrypt the backup file. The password is never shared with guardians.
|
|
768
807
|
|
|
769
808
|
**Q: What happens if a guardian loses their share?**
|
|
770
809
|
A: No problem! You only need 3 out of 5. As long as 3 guardians have their shares, you can recover.
|
package/package.json
CHANGED