@bsv/wallet-toolbox
Version:
BRC100 conforming wallet, wallet storage and wallet signer components
213 lines • 7.69 kB
TypeScript
/**
* ShamirWalletManager
*
* A wallet manager that uses Shamir Secret Sharing for key recovery
* instead of password-derived keys and on-chain UMP tokens.
*
* Security improvements over CWIStyleWalletManager:
* - No password enumeration attacks possible (no password-derived keys)
* - No encrypted key material stored on-chain
* - Server only holds 1 share (cannot reconstruct alone)
* - Defense-in-depth with mouse entropy + CSPRNG for key generation
*
* Default configuration (2-of-3):
* - Share 1 (server): Stored on WAB server, released only after OTP verification
* - Shares 2..n (user): Application decides how to store (print, password manager, etc.)
*
* The threshold and total shares are configurable. WAB always stores exactly one share.
*/
import { PrivateKey, WalletInterface } from '@bsv/sdk';
import { PrivilegedKeyManager } from './sdk/PrivilegedKeyManager';
import { EntropyProgressCallback } from './entropy/EntropyCollector';
/**
* Result from creating a new Shamir-based wallet
*/
export interface CreateShamirWalletResult {
/**
* User shares to be stored by the application (excludes server share)
* For 2-of-3: returns 2 shares, server holds 1
* For 3-of-5: returns 4 shares, server holds 1
*/
userShares: string[];
/** Hash of the user's identity key (used for server lookup) */
userIdHash: string;
/** The generated private key (for immediate wallet use) */
privateKey: PrivateKey;
/** The threshold used (k shares needed to reconstruct) */
threshold: number;
/** Total number of shares generated */
totalShares: number;
}
/**
* Configuration for ShamirWalletManager
*/
export interface ShamirWalletManagerConfig {
/** WAB server URL */
wabServerUrl: string;
/** Auth method type for OTP verification (e.g., "TwilioPhone") */
authMethodType: string;
/** Function to build the underlying wallet from a private key */
walletBuilder: (privateKey: PrivateKey, privilegedKeyManager: PrivilegedKeyManager) => Promise<WalletInterface>;
/**
* Number of shares required to reconstruct the key (default: 2)
* Must be >= 2 and <= totalShares
*/
threshold?: number;
/**
* Total number of shares to generate (default: 3)
* WAB server stores 1, application receives (totalShares - 1)
*/
totalShares?: number;
}
/**
* Callback for handling user shares during wallet creation
*/
export type ShareStorageCallback = (shares: string[], threshold: number, totalShares: number) => Promise<boolean>;
export declare class ShamirWalletManager {
private config;
private wabClient;
private entropyCollector;
private privateKey?;
private underlying?;
private userIdHash?;
private readonly threshold;
private readonly totalShares;
constructor(config: ShamirWalletManagerConfig);
/**
* Get the configured threshold
*/
getThreshold(): number;
/**
* Get the configured total shares
*/
getTotalShares(): number;
/**
* Reset the entropy collector (e.g., if user wants to start over)
*/
resetEntropy(): void;
/**
* Add a mouse movement sample for entropy collection
* Call this from your UI's mousemove handler
*/
addMouseEntropy(x: number, y: number): import("./entropy/EntropyCollector").EntropyProgress | null;
/**
* Check if enough entropy has been collected
*/
hasEnoughEntropy(): boolean;
/**
* Get entropy collection progress
*/
getEntropyProgress(): import("./entropy/EntropyCollector").EntropyProgress;
/**
* Collect entropy from browser mouse movements
* Convenience method that sets up event listeners automatically
*/
collectEntropyFromBrowser(element?: EventTarget, onProgress?: EntropyProgressCallback): Promise<void>;
/**
* Generate a user ID hash from a private key
* This is used to identify the user on the WAB server without revealing the key
*/
private generateUserIdHash;
/**
* Create a new wallet with Shamir key split
*
* Flow:
* 1. Generate private key from entropy
* 2. Split into Shamir shares (threshold-of-totalShares)
* 3. Store first share on WAB server (requires OTP verification)
* 4. Return remaining shares for application to handle
*
* @param authPayload Auth method specific payload (e.g., { phoneNumber: "+1...", otp: "123456" })
* @param onUserSharesReady Callback when user shares are ready - return true to confirm saved
* @returns Result containing user shares (server share already stored)
*/
createNewWallet(authPayload: {
phoneNumber?: string;
email?: string;
otp: string;
}, onUserSharesReady: ShareStorageCallback): Promise<CreateShamirWalletResult>;
/**
* Start OTP verification for share retrieval
* Call this before recoverWithSharesBC
*/
startOTPVerification(payload: {
phoneNumber?: string;
email?: string;
}): Promise<void>;
/**
* Set the user ID hash for recovery operations
* This can be computed from Share A or C (both contain the same threshold/integrity)
*/
setUserIdHash(userIdHash: string): void;
/**
* Recover wallet using user shares plus the server share
* Requires OTP verification to retrieve the server share
*
* @param userShares Array of user-held shares (need threshold-1 shares)
* @param authPayload Contains OTP code and auth method data
*/
recoverWithServerShare(userShares: string[], authPayload: {
phoneNumber?: string;
email?: string;
otp: string;
}): Promise<PrivateKey>;
/**
* Recover wallet using only user-held shares (no server interaction)
* Requires at least threshold shares
*
* @param userShares Array of user-held shares (need at least threshold shares)
*/
recoverWithUserShares(userShares: string[]): Promise<PrivateKey>;
/**
* Extract threshold from a share (format: x.y.threshold.integrity)
*/
private getThresholdFromShare;
/**
* Build the underlying wallet after key recovery
*/
buildWallet(): Promise<WalletInterface>;
/**
* Get the underlying wallet (must call buildWallet first)
*/
getWallet(): WalletInterface;
/**
* Rotate keys - generate new key and update server share
* User must save new user shares
*
* @param authPayload Contains OTP code and auth method data
* @param onUserSharesReady Callback when new user shares are ready
*/
rotateKeys(authPayload: {
phoneNumber?: string;
email?: string;
otp: string;
}, onUserSharesReady: ShareStorageCallback): Promise<CreateShamirWalletResult>;
/**
* Validate Shamir share format
* Expected format: x.y.threshold.integrity (4 dot-separated parts)
*/
private validateShareFormat;
/**
* Check if the manager has a loaded private key
*/
hasPrivateKey(): boolean;
/**
* Get the user ID hash (for display or storage)
*/
getUserIdHash(): string | undefined;
/**
* Delete the user's account and stored share from the WAB server
* Requires OTP verification
*
* WARNING: This permanently deletes the server share.
* User must have enough remaining shares to meet the threshold for recovery.
*
* @param authPayload Contains OTP code and auth method data
*/
deleteAccount(authPayload: {
phoneNumber?: string;
email?: string;
otp: string;
}): Promise<void>;
}
//# sourceMappingURL=ShamirWalletManager.d.ts.map