capacitor-shamir
v1.0.4
Published
Provides Shamir's Secret Sharing (SSS) functionality for secure splitting and recovering secrets natively on iOS, Android, and Web.
Readme
capacitor-shamir
🎯 What is Shamir's Secret Sharing?
Shamir's Secret Sharing is a cryptographic algorithm that divides a secret into multiple parts (shards), where a minimum threshold of shards is required to reconstruct the original secret. This ensures that:
- No single shard reveals any information about the secret
- Any threshold number of shards can reconstruct the secret
- Security through distribution - store shards separately for maximum security
Security
Shamir's Secret Sharing provides information-theoretic security, which means the algorithm is mathematically proven to be unbreakable regardless of computational power. Key security advantages:
- Quantum Resistance: Security relies on mathematical impossibility rather than computational complexity, remaining secure against quantum computers
- No Key Management: There is no single master key to rotate or protect; instead, security hinges on distributing and safeguarding the individual shares
- Mathematical Foundation: Based on polynomial interpolation over finite fields, where reconstructing the secret without sufficient shards is mathematically impossible, not just computationally difficult
✨ Features
- Secure Secret Splitting: Split sensitive data into encrypted shards using Shamir's Secret Sharing
- Cross-Platform: Native support for iOS, Android, and Web
- Flexible Storage: Memory-based and filesystem-based operations
- Progress Tracking: Real-time progress callbacks for all operations
- Performance Optimized: Efficient handling of large files and data
- Recovery Options: Restore complete secrets or individual shards
🏆 Real-World Usage
This plugin is actively used in production by Vault12 Guard - a mobile app that provides secure, decentralized backup and recovery for crypto seed phrases and other sensitive data using Shamir's Secret Sharing.
📦 Installation
npm install capacitor-shamir
npx cap syncPlatform Quirks
Requirements
This plugin requires Capacitor 7 or higher.
Web
The web implementation uses IndexedDB for file operations and includes all necessary polyfills.
🚀 Quick Start
import { Shamir } from 'capacitor-shamir';
// Split a secret into 5 shards, requiring 3 to reconstruct
const secret = btoa("My secret data");
await Shamir.generateShards({
totalShards: 5,
threshold: 3,
inputDataBase64: secret
}, (data, error) => {
if (error) {
console.error('Error:', error);
return;
}
if (data?.shardsBase64) {
console.log('Secret split into shards:', data.shardsBase64);
} else {
console.log('Progress:', data?.progress + '%');
}
});API Reference
Overview
This plugin provides both memory-based and file-based API methods for:
- Splitting secret data into cryptographic shards
- Restoring secret data from cryptographic shards
- Recovering individual N-th shard from a set of cryptographic shards
Key Implementation Details
Progress Reporting
All methods use callback-based progress reporting to provide real-time updates during operations.
Job Completion
A job is complete when the callback's data object contains a result property with a truthy value:
dataBase64- for restored secret datashardsBase64- for generated shards in memoryshardsPath/shardsPaths- for file-based operationsdstPath- for file restoration
[!IMPORTANT] Use
progressonly for UI updates, not to detect completion. A job is done when!!dataBase64(or other result property), not whenprogress === 100.
Data Format
Since Capacitor doesn't support blob data transfer, all data exchange uses Base64-encoded strings.
Methods
| Category | Methods | Description |
|----------|---------|-------------|
| Memory Operations | generateShards, restoreFromShards, restoreShard | Work with Base64 data in memory |
| File Operations | generateFileShards, restoreFromFileShards, restoreFileShard | Direct file-to-file operations |
| Hybrid Operations | generateShardsToFiles, restoreFromFileShardsToData | Convert between memory and file formats |
generateShards(...)restoreFromShards(...)restoreShard(...)generateFileShards(...)generateShardsToFiles(...)restoreFromFileShards(...)restoreFromFileShardsToData(...)restoreFileShard(...)- Interfaces
generateShards(...)
generateShards(options: { totalShards: number; threshold: number; inputDataBase64: string; }, callback: (data?: { progress: number; shardsBase64?: string[] | undefined; } | undefined, error?: Error | undefined) => void) => Promise<void>Splits secret data (Base64) into encrypted shards in memory.
| Param | Type | Description |
| -------------- | ------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------- |
| options | { totalShards: number; threshold: number; inputDataBase64: string; } | totalShards (≤255), threshold (≥2, ≤255), and inputDataBase64 (Base64-encoded secret) |
| callback | (data?: { progress: number; shardsBase64?: string[]; }, error?: Error) => void | Reports progress and returns shards as Base64 strings |
restoreFromShards(...)
restoreFromShards(options: { inputShardsBase64: string[]; }, callback: (data?: { progress: number; dataBase64?: string | undefined; } | undefined, error?: Error | undefined) => void) => Promise<void>Restores secret data from encrypted shards (all in memory, Base64).
| Param | Type | Description |
| -------------- | --------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------ |
| options | { inputShardsBase64: string[]; } | inputShardsBase64: array of Base64-encoded shards |
| callback | (data?: { progress: number; dataBase64?: string; }, error?: Error) => void | Reports progress and returns restored secret as Base64 |
restoreShard(...)
restoreShard(options: { shardIndex: number; inputShardsBase64: string[]; }, callback: (data?: { progress: number; dataBase64?: string | undefined; } | undefined, error?: Error | undefined) => void) => Promise<void>Restores a specific shard from a set of encrypted shards (all in memory, Base64).
| Param | Type | Description |
| -------------- | --------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------- |
| options | { shardIndex: number; inputShardsBase64: string[]; } | shardIndex (>0, ≤255) and inputShardsBase64 |
| callback | (data?: { progress: number; dataBase64?: string; }, error?: Error) => void | Reports progress and returns the requested shard as Base64 |
generateFileShards(...)
generateFileShards(options: { totalShards: number; threshold: number; srcPath: string; dstPathRoot: string; }, callback: (data?: { progress: number; shardsPaths?: string[] | undefined; } | undefined, error?: Error | undefined) => void) => Promise<void>Splits a file into encrypted shard files.
| Param | Type | Description |
| -------------- | ------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------- |
| options | { totalShards: number; threshold: number; srcPath: string; dstPathRoot: string; } | totalShards (≤255), threshold (≥2, ≤255), srcPath (input file), dstPathRoot (output directory) |
| callback | (data?: { progress: number; shardsPaths?: string[]; }, error?: Error) => void | Reports progress and returns paths to shard files |
generateShardsToFiles(...)
generateShardsToFiles(options: { totalShards: number; threshold: number; inputDataBase64: string; dstPathRoot: string; }, callback: (data?: { progress: number; shardsPaths?: string[] | undefined; } | undefined, error?: Error | undefined) => void) => Promise<void>Splits secret data (Base64) into encrypted shard files.
| Param | Type | Description |
| -------------- | ------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------- |
| options | { totalShards: number; threshold: number; inputDataBase64: string; dstPathRoot: string; } | totalShards (≤255), threshold (≥2, ≤255), inputDataBase64, dstPathRoot (output directory) |
| callback | (data?: { progress: number; shardsPaths?: string[]; }, error?: Error) => void | Reports progress and returns paths to shard files |
restoreFromFileShards(...)
restoreFromFileShards(options: { shardsPaths: string[]; dstPath: string; }, callback: (data?: { progress: number; dstPath?: string | undefined; } | undefined, error?: Error | undefined) => void) => Promise<void>Restores a file from encrypted shard files.
| Param | Type | Description |
| -------------- | ------------------------------------------------------------------------------------------------------------ | ------------------------------------------------- |
| options | { shardsPaths: string[]; dstPath: string; } | shardsPaths (input files), dstPath (output file) |
| callback | (data?: { progress: number; dstPath?: string; }, error?: Error) => void | Reports progress and returns the output file path |
restoreFromFileShardsToData(...)
restoreFromFileShardsToData(options: { shardsPaths: string[]; }, callback: (data?: { progress: number; dataBase64?: string | undefined; } | undefined, error?: Error | undefined) => void) => Promise<void>Restores secret data (Base64) from encrypted shard files.
| Param | Type | Description |
| -------------- | --------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------ |
| options | { shardsPaths: string[]; } | shardsPaths (input files) |
| callback | (data?: { progress: number; dataBase64?: string; }, error?: Error) => void | Reports progress and returns restored secret as Base64 |
restoreFileShard(...)
restoreFileShard(options: { shardIndex: number; shardsPaths: string[]; dstPathRoot: string; }, callback: (data?: { progress: number; shardPath?: string | undefined; } | undefined, error?: Error | undefined) => void) => Promise<void>Restores a specific shard file from a set of encrypted shard files.
| Param | Type | Description |
| -------------- | -------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------- |
| options | { shardIndex: number; shardsPaths: string[]; dstPathRoot: string; } | shardIndex (>0, ≤255), shardsPaths (input files), dstPathRoot (output directory) |
| callback | (data?: { progress: number; shardPath?: string; }, error?: Error) => void | Reports progress and returns the path to the restored shard file |
Interfaces
Error
| Prop | Type |
| ------------- | ------------------- |
| name | string |
| message | string |
| stack | string |
License
This project is dual-licensed under MIT OR Apache-2.0. You may choose to use this project under the terms of either license.
This dual licensing approach is necessary because the web implementation includes code derived from simbo1905/shamir, which is licensed under the Apache License 2.0.
See the LICENSE file for the full legal text.
🛠️ Troubleshooting
Common Issues
Large File Performance
- For files > 10MB, consider using file-based operations instead of memory-based
- Monitor progress callbacks to provide user feedback during long operations
Base64 Encoding
- Remember to encode/decode data properly when working with binary content
Platform Differences
- File paths vary between platforms - use absolute paths when possible
- iOS sandbox restrictions may limit file access locations
🧪 Testing
# Run unit tests
npm run test
# Run platform-specific test cases
npm run verify:ios
npm run verify:android📱 Platform Support
| Platform | Version | Status | |----------|---------|--------| | iOS | 14.0+ | ✅ Fully supported | | Android | API 23+ | ✅ Fully supported | | Web | Modern browsers | ✅ Fully supported |
🤝 Contributing
We welcome contributions! Please see our Contributing Guide for details.
Development Setup
# Clone the repository
git clone https://github.com/vault12/capacitor-shamir.git
cd capacitor-shamir
# Install dependencies
npm install
# Build the plugin
npm run build
# Run tests
npm test📝 Changelog
See Releases for detailed changelog.
🙏 Acknowledgments
- Web implementation includes code derived from simbo1905/shamir under the Apache License 2.0
- Finite field mathematics implementation based on The Laws of Cryptography: The Finite Field GF(28) by Neal R. Wagner
- Built for Capacitor framework
- Implements Shamir's Secret Sharing algorithm
