@forgesworn/shamir-words 0.0.0-development → 1.0.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.
- package/LICENCE +21 -0
- package/README.md +121 -0
- package/package.json +5 -1
package/LICENCE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT Licence
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Forgesworn
|
|
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, sublicence, 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,121 @@
|
|
|
1
|
+
# shamir-words
|
|
2
|
+
|
|
3
|
+
**Split secrets into human-readable word shares that can be spoken, written down, or stored separately.**
|
|
4
|
+
|
|
5
|
+
Backing up cryptographic keys is hard. Raw byte shares are error-prone to transcribe and impossible to read over the phone. shamir-words combines [Shamir's Secret Sharing](https://en.wikipedia.org/wiki/Shamir%27s_secret_sharing) over GF(256) with [BIP-39](https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki) word encoding, so each share becomes a list of familiar English words — just like a Bitcoin seed phrase.
|
|
6
|
+
|
|
7
|
+
## Why shamir-words?
|
|
8
|
+
|
|
9
|
+
- **Human-readable shares** — each share is a BIP-39 word list, not a hex blob
|
|
10
|
+
- **Threshold recovery** — any _t_ of _n_ shares reconstruct the secret; fewer reveal nothing
|
|
11
|
+
- **Integrity checking** — SHA-256 checksum detects transcription errors before reconstruction
|
|
12
|
+
- **Minimal dependencies** — only `@noble/hashes` and `@scure/bip39` (audited cryptographic libraries)
|
|
13
|
+
- **TypeScript-first** — full type safety with exported interfaces and error classes
|
|
14
|
+
|
|
15
|
+
## Install
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm install @forgesworn/shamir-words
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Quick Start
|
|
22
|
+
|
|
23
|
+
```typescript
|
|
24
|
+
import {
|
|
25
|
+
splitSecret,
|
|
26
|
+
reconstructSecret,
|
|
27
|
+
shareToWords,
|
|
28
|
+
wordsToShare,
|
|
29
|
+
} from '@forgesworn/shamir-words';
|
|
30
|
+
|
|
31
|
+
// Your secret (e.g. a 32-byte private key)
|
|
32
|
+
const secret = new Uint8Array([
|
|
33
|
+
0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0xba, 0xbe,
|
|
34
|
+
0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
|
|
35
|
+
]);
|
|
36
|
+
|
|
37
|
+
// Split into 5 shares, any 3 can reconstruct
|
|
38
|
+
const shares = splitSecret(secret, 3, 5);
|
|
39
|
+
|
|
40
|
+
// Convert each share to speakable words
|
|
41
|
+
const wordShares = shares.map(shareToWords);
|
|
42
|
+
// e.g. ["abandon", "ability", "able", ...] — one word list per share
|
|
43
|
+
|
|
44
|
+
// Later: decode words back to shares and reconstruct
|
|
45
|
+
const decoded = wordShares.map(wordsToShare);
|
|
46
|
+
const recovered = reconstructSecret(decoded, 3);
|
|
47
|
+
// recovered === secret
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## API
|
|
51
|
+
|
|
52
|
+
### `splitSecret(secret, threshold, shares)`
|
|
53
|
+
|
|
54
|
+
Split a secret into Shamir shares over GF(256).
|
|
55
|
+
|
|
56
|
+
| Parameter | Type | Description |
|
|
57
|
+
|-----------|------|-------------|
|
|
58
|
+
| `secret` | `Uint8Array` | The secret to split (1-255 bytes) |
|
|
59
|
+
| `threshold` | `number` | Minimum shares needed to reconstruct (2-255) |
|
|
60
|
+
| `shares` | `number` | Total shares to create (threshold-255) |
|
|
61
|
+
|
|
62
|
+
Returns `ShamirShare[]`.
|
|
63
|
+
|
|
64
|
+
### `reconstructSecret(shares, threshold)`
|
|
65
|
+
|
|
66
|
+
Reconstruct a secret from shares using Lagrange interpolation.
|
|
67
|
+
|
|
68
|
+
| Parameter | Type | Description |
|
|
69
|
+
|-----------|------|-------------|
|
|
70
|
+
| `shares` | `ShamirShare[]` | At least `threshold` shares |
|
|
71
|
+
| `threshold` | `number` | The threshold used during splitting |
|
|
72
|
+
|
|
73
|
+
Returns `Uint8Array` — the original secret.
|
|
74
|
+
|
|
75
|
+
### `shareToWords(share)`
|
|
76
|
+
|
|
77
|
+
Encode a share as BIP-39 words. The word list embeds the share ID, threshold, data, and a SHA-256 checksum byte for integrity.
|
|
78
|
+
|
|
79
|
+
Returns `string[]`.
|
|
80
|
+
|
|
81
|
+
### `wordsToShare(words)`
|
|
82
|
+
|
|
83
|
+
Decode BIP-39 words back to a share. Verifies the checksum and rejects corrupted or tampered input.
|
|
84
|
+
|
|
85
|
+
Returns `ShamirShare`.
|
|
86
|
+
|
|
87
|
+
### Types
|
|
88
|
+
|
|
89
|
+
```typescript
|
|
90
|
+
interface ShamirShare {
|
|
91
|
+
id: number; // 1-255 (the x-coordinate)
|
|
92
|
+
threshold: number; // 2-255 (minimum shares for reconstruction)
|
|
93
|
+
data: Uint8Array; // evaluated polynomial bytes
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### Error Classes
|
|
98
|
+
|
|
99
|
+
- `ShamirError` — base class for all errors
|
|
100
|
+
- `ShamirValidationError` — invalid inputs (wrong types, out-of-range values)
|
|
101
|
+
- `ShamirCryptoError` — cryptographic failures (e.g. GF(256) zero inverse)
|
|
102
|
+
|
|
103
|
+
## Wire Format
|
|
104
|
+
|
|
105
|
+
Each word-encoded share packs bytes as:
|
|
106
|
+
|
|
107
|
+
```
|
|
108
|
+
[data_length, threshold, share_id, ...data, checksum]
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
The byte stream is split into 11-bit groups, each mapped to a BIP-39 word. The checksum is the first byte of SHA-256 over the preceding bytes.
|
|
112
|
+
|
|
113
|
+
## Limitations
|
|
114
|
+
|
|
115
|
+
- Secret size: 1-255 bytes (covers all standard key sizes up to 255 bytes)
|
|
116
|
+
- Share count: up to 255 (the GF(256) field size minus zero)
|
|
117
|
+
- Threshold: 2-255 (single-share schemes are just copying, not secret sharing)
|
|
118
|
+
|
|
119
|
+
## Licence
|
|
120
|
+
|
|
121
|
+
[MIT](LICENCE)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@forgesworn/shamir-words",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"description": "Shamir's Secret Sharing over GF(256) with BIP-39 word encoding for human-readable share exchange",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -33,11 +33,15 @@
|
|
|
33
33
|
"cryptography",
|
|
34
34
|
"key-splitting"
|
|
35
35
|
],
|
|
36
|
+
"publishConfig": {
|
|
37
|
+
"access": "public"
|
|
38
|
+
},
|
|
36
39
|
"sideEffects": false,
|
|
37
40
|
"license": "MIT",
|
|
38
41
|
"engines": {
|
|
39
42
|
"node": ">=18"
|
|
40
43
|
},
|
|
44
|
+
"homepage": "https://github.com/forgesworn/shamir-words",
|
|
41
45
|
"repository": {
|
|
42
46
|
"type": "git",
|
|
43
47
|
"url": "https://github.com/forgesworn/shamir-words.git"
|