An open API service indexing awesome lists of open source software.

https://github.com/vault12/capacitor-shamir

Native Shamir Secret Sharing. Securely split & restore secrets on iOS, Android, and Web with a single Capacitor plugin.
https://github.com/vault12/capacitor-shamir

android capacitor capacitor-android capacitor-ios capacitor-plugin ionic-framework ios secret-management shamir shamir-algorithm shamir-secret-sharing

Last synced: 12 months ago
JSON representation

Native Shamir Secret Sharing. Securely split & restore secrets on iOS, Android, and Web with a single Capacitor plugin.

Awesome Lists containing this project

README

          

# capacitor-shamir


Capacitor Shamir


A powerful Capacitor plugin for secure secret sharing using Shamir's Secret Sharing algorithm


NPM Release
Build Status
Coverage
Dual License: MIT OR Apache-2.0
PRs Welcome
Downloads

---

## ๐ŸŽฏ What is Shamir's Secret Sharing?

[Shamir's Secret Sharing](https://en.wikipedia.org/wiki/Shamir%27s_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](#finite-field-implementation), 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](https://vault12.com)** - a mobile app that provides secure, decentralized backup and recovery for crypto seed phrases and other sensitive data using Shamir's Secret Sharing.

## ๐Ÿ“ฆ Installation

```bash
npm install capacitor-shamir
npx cap sync
```

### Platform Quirks

#### Requirements
This plugin requires **Capacitor 7 or higher**.

#### Web
The web implementation uses [IndexedDB](https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API) for file operations and includes all necessary polyfills.

## ๐Ÿš€ Quick Start

```typescript
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 data
- `shardsBase64` - for generated shards in memory
- `shardsPath` / `shardsPaths` - for file-based operations
- `dstPath` - for file restoration

> [!IMPORTANT]
> Use `progress` only for UI updates, not to detect completion. A job is done when `!!dataBase64` (or other result property), not when `progress === 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(...)`](#generateshards)
* [`restoreFromShards(...)`](#restorefromshards)
* [`restoreShard(...)`](#restoreshard)
* [`generateFileShards(...)`](#generatefileshards)
* [`generateShardsToFiles(...)`](#generateshardstofiles)
* [`restoreFromFileShards(...)`](#restorefromfileshards)
* [`restoreFromFileShardsToData(...)`](#restorefromfileshardstodata)
* [`restoreFileShard(...)`](#restorefileshard)
* [Interfaces](#interfaces)

### generateShards(...)

```typescript
generateShards(options: { totalShards: number; threshold: number; inputDataBase64: string; }, callback: (data?: { progress: number; shardsBase64?: string[] | undefined; } | undefined, error?: Error | undefined) => void) => Promise
```

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(...)

```typescript
restoreFromShards(options: { inputShardsBase64: string[]; }, callback: (data?: { progress: number; dataBase64?: string | undefined; } | undefined, error?: Error | undefined) => void) => Promise
```

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(...)

```typescript
restoreShard(options: { shardIndex: number; inputShardsBase64: string[]; }, callback: (data?: { progress: number; dataBase64?: string | undefined; } | undefined, error?: Error | undefined) => void) => Promise
```

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(...)

```typescript
generateFileShards(options: { totalShards: number; threshold: number; srcPath: string; dstPathRoot: string; }, callback: (data?: { progress: number; shardsPaths?: string[] | undefined; } | undefined, error?: Error | undefined) => void) => Promise
```

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(...)

```typescript
generateShardsToFiles(options: { totalShards: number; threshold: number; inputDataBase64: string; dstPathRoot: string; }, callback: (data?: { progress: number; shardsPaths?: string[] | undefined; } | undefined, error?: Error | undefined) => void) => Promise
```

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(...)

```typescript
restoreFromFileShards(options: { shardsPaths: string[]; dstPath: string; }, callback: (data?: { progress: number; dstPath?: string | undefined; } | undefined, error?: Error | undefined) => void) => Promise
```

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(...)

```typescript
restoreFromFileShardsToData(options: { shardsPaths: string[]; }, callback: (data?: { progress: number; dataBase64?: string | undefined; } | undefined, error?: Error | undefined) => void) => Promise
```

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(...)

```typescript
restoreFileShard(options: { shardIndex: number; shardsPaths: string[]; dstPathRoot: string; }, callback: (data?: { progress: number; shardPath?: string | undefined; } | undefined, error?: Error | undefined) => void) => Promise
```

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](https://github.com/simbo1905/shamir), which is licensed under the Apache License 2.0.

See the [LICENSE](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

```bash
# 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](CONTRIBUTING.md) for details.

### Development Setup

```bash
# 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](https://github.com/vault12/capacitor-shamir/releases) for detailed changelog.

## ๐Ÿ™ Acknowledgments

- Web implementation includes code derived from [simbo1905/shamir](https://github.com/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](https://web.archive.org/web/20180131040703/http://www.cs.utsa.edu/~wagner/laws/FFM.html)
- Built for [Capacitor](https://capacitorjs.com/) framework
- Implements [Shamir's Secret Sharing](https://en.wikipedia.org/wiki/Shamir%27s_secret_sharing) algorithm

## ๐Ÿ“ž Support

- ๐Ÿ› [Issue Tracker](https://github.com/vault12/capacitor-shamir/issues)

---


Made with โค๏ธ by the Vault12 Team