@bcts/shamir 1.0.0-alpha.9 → 1.0.0-beta.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/LICENSE +3 -2
- package/dist/index.cjs +103 -66
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +34 -78
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +34 -78
- package/dist/index.d.mts.map +1 -1
- package/dist/index.iife.js +125 -89
- package/dist/index.iife.js.map +1 -1
- package/dist/index.mjs +88 -44
- package/dist/index.mjs.map +1 -1
- package/package.json +16 -17
- package/src/error.ts +30 -0
- package/src/hazmat.ts +40 -28
- package/src/index.ts +6 -14
- package/src/interpolate.ts +6 -0
- package/src/shamir.ts +6 -0
package/package.json
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bcts/shamir",
|
|
3
|
-
"version": "1.0.0-
|
|
3
|
+
"version": "1.0.0-beta.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Blockchain Commons Shamir Secret Sharing for TypeScript",
|
|
6
6
|
"license": "BSD-2-Clause-Patent",
|
|
7
|
-
"author": "
|
|
8
|
-
"homepage": "https://
|
|
7
|
+
"author": "Parity Technologies <admin@parity.io> (https://parity.io)",
|
|
8
|
+
"homepage": "https://bcts.dev",
|
|
9
9
|
"repository": {
|
|
10
10
|
"type": "git",
|
|
11
|
-
"url": "https://github.com/
|
|
11
|
+
"url": "https://github.com/paritytech/bcts",
|
|
12
12
|
"directory": "packages/shamir"
|
|
13
13
|
},
|
|
14
14
|
"bugs": {
|
|
15
|
-
"url": "https://github.com/
|
|
15
|
+
"url": "https://github.com/paritytech/bcts/issues"
|
|
16
16
|
},
|
|
17
17
|
"main": "dist/index.cjs",
|
|
18
18
|
"module": "dist/index.mjs",
|
|
@@ -33,11 +33,10 @@
|
|
|
33
33
|
],
|
|
34
34
|
"scripts": {
|
|
35
35
|
"build": "tsdown",
|
|
36
|
-
"dev": "tsdown --watch",
|
|
37
36
|
"test": "vitest run",
|
|
38
37
|
"test:watch": "vitest",
|
|
39
|
-
"lint": "eslint 'src/**/*.ts'",
|
|
40
|
-
"lint:fix": "eslint 'src/**/*.ts' --fix",
|
|
38
|
+
"lint": "eslint 'src/**/*.ts' 'tests/**/*.ts'",
|
|
39
|
+
"lint:fix": "eslint 'src/**/*.ts' 'tests/**/*.ts' --fix",
|
|
41
40
|
"typecheck": "tsc --noEmit",
|
|
42
41
|
"clean": "rm -rf dist",
|
|
43
42
|
"docs": "typedoc",
|
|
@@ -56,19 +55,19 @@
|
|
|
56
55
|
"node": ">=18.0.0"
|
|
57
56
|
},
|
|
58
57
|
"dependencies": {
|
|
59
|
-
"@bcts/crypto": "^1.0.0-
|
|
60
|
-
"@bcts/rand": "^1.0.0-
|
|
58
|
+
"@bcts/crypto": "^1.0.0-beta.0",
|
|
59
|
+
"@bcts/rand": "^1.0.0-beta.0"
|
|
61
60
|
},
|
|
62
61
|
"devDependencies": {
|
|
63
62
|
"@bcts/eslint": "^0.1.0",
|
|
64
63
|
"@bcts/tsconfig": "^0.1.0",
|
|
65
|
-
"@eslint/js": "^
|
|
66
|
-
"@types/node": "^
|
|
67
|
-
"eslint": "^
|
|
64
|
+
"@eslint/js": "^10.0.1",
|
|
65
|
+
"@types/node": "^25.6.0",
|
|
66
|
+
"eslint": "^10.2.1",
|
|
68
67
|
"ts-node": "^10.9.2",
|
|
69
|
-
"tsdown": "^0.
|
|
70
|
-
"typedoc": "^0.28.
|
|
71
|
-
"typescript": "^
|
|
72
|
-
"vitest": "^
|
|
68
|
+
"tsdown": "^0.21.0",
|
|
69
|
+
"typedoc": "^0.28.19",
|
|
70
|
+
"typescript": "^6.0.3",
|
|
71
|
+
"vitest": "^4.1.5"
|
|
73
72
|
}
|
|
74
73
|
}
|
package/src/error.ts
CHANGED
|
@@ -1,11 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright © 2023-2026 Blockchain Commons, LLC
|
|
3
|
+
* Copyright © 2025-2026 Parity Technologies
|
|
4
|
+
*
|
|
5
|
+
*/
|
|
6
|
+
|
|
1
7
|
// Ported from bc-shamir-rust/src/error.rs
|
|
2
8
|
|
|
3
9
|
/**
|
|
4
10
|
* Error types for Shamir secret sharing operations.
|
|
11
|
+
*
|
|
12
|
+
* Each variant mirrors a corresponding `Error::*` enum in
|
|
13
|
+
* `bc-shamir-rust/src/error.rs` with the same trigger conditions and the
|
|
14
|
+
* same default `Display` strings.
|
|
15
|
+
*
|
|
16
|
+
* Note on `InterpolationFailure`: this variant is **reserved but
|
|
17
|
+
* unreachable** in both the Rust and TypeScript implementations.
|
|
18
|
+
* `interpolate()` in `interpolate.ts` never actually returns / throws an
|
|
19
|
+
* interpolation failure today — the Lagrange-basis math always succeeds
|
|
20
|
+
* for any well-formed input. The variant is kept for forward
|
|
21
|
+
* compatibility (e.g. should a future revision add input validation that
|
|
22
|
+
* could reject pathological cases) and to keep the TS error type a 1:1
|
|
23
|
+
* mirror of Rust's `Error` enum.
|
|
5
24
|
*/
|
|
6
25
|
export enum ShamirErrorType {
|
|
7
26
|
SecretTooLong = "SecretTooLong",
|
|
8
27
|
TooManyShares = "TooManyShares",
|
|
28
|
+
/**
|
|
29
|
+
* Reserved / unreachable in both Rust and TS today. See enum doc above.
|
|
30
|
+
*/
|
|
9
31
|
InterpolationFailure = "InterpolationFailure",
|
|
10
32
|
ChecksumFailure = "ChecksumFailure",
|
|
11
33
|
SecretTooShort = "SecretTooShort",
|
|
@@ -48,4 +70,12 @@ export class ShamirError extends Error {
|
|
|
48
70
|
}
|
|
49
71
|
}
|
|
50
72
|
|
|
73
|
+
/**
|
|
74
|
+
* Mirrors Rust's `Result<T, Error>` for API parity.
|
|
75
|
+
*
|
|
76
|
+
* The TypeScript port surfaces failures by throwing `ShamirError`
|
|
77
|
+
* instances rather than returning a sum type, so this alias is a no-op
|
|
78
|
+
* (`ShamirResult<T>` ≡ `T`). It is kept so signatures published in
|
|
79
|
+
* `@bcts/shamir` remain visually parallel to their Rust counterparts.
|
|
80
|
+
*/
|
|
51
81
|
export type ShamirResult<T> = T;
|
package/src/hazmat.ts
CHANGED
|
@@ -1,8 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright © 2023-2026 Blockchain Commons, LLC
|
|
3
|
+
* Copyright © 2025-2026 Parity Technologies
|
|
4
|
+
*
|
|
5
|
+
*/
|
|
6
|
+
|
|
1
7
|
// Ported from bc-shamir-rust/src/hazmat.rs
|
|
2
|
-
// GF(2^8) bitsliced polynomial operations for Shamir secret sharing
|
|
8
|
+
// GF(2^8) bitsliced polynomial operations for Shamir secret sharing.
|
|
9
|
+
//
|
|
10
|
+
// **Defensive arity guards.** Each helper here checks its array-length
|
|
11
|
+
// preconditions (`r.length === 8`, `x.length >= 32`, …) and throws a
|
|
12
|
+
// plain `Error` on violation. These guards mirror Rust's slice-indexing
|
|
13
|
+
// `panic!` semantics — they signal an internal *contract violation*
|
|
14
|
+
// (programmer error), not an end-user input error, and are deliberately
|
|
15
|
+
// **not** elevated to `ShamirError`: that type carries variants for
|
|
16
|
+
// recoverable, user-facing failures of the public `splitSecret` /
|
|
17
|
+
// `recoverSecret` APIs, and has no variant matching "wrong array arity".
|
|
18
|
+
// The public Shamir API never triggers these guards in normal use.
|
|
3
19
|
|
|
4
20
|
import { memzero } from "@bcts/crypto";
|
|
5
21
|
|
|
22
|
+
/**
|
|
23
|
+
* Internal contract guard. Mirrors a Rust `assert!(condition, message)`
|
|
24
|
+
* panic on the boundary between hazmat helpers — kept as a bare `Error`
|
|
25
|
+
* so it cannot be confused with a `ShamirError` from the public API.
|
|
26
|
+
*/
|
|
27
|
+
function assertContract(condition: boolean, message: string): void {
|
|
28
|
+
if (!condition) {
|
|
29
|
+
throw new Error(message);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
6
33
|
/**
|
|
7
34
|
* Convert an array of bytes into a bitsliced representation.
|
|
8
35
|
* Takes the first 32 bytes from x and produces 8 u32 values.
|
|
@@ -11,12 +38,8 @@ import { memzero } from "@bcts/crypto";
|
|
|
11
38
|
* @param x - Input array of at least 32 bytes
|
|
12
39
|
*/
|
|
13
40
|
export function bitslice(r: Uint32Array, x: Uint8Array): void {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
}
|
|
17
|
-
if (r.length !== 8) {
|
|
18
|
-
throw new Error("bitslice: output must have 8 elements");
|
|
19
|
-
}
|
|
41
|
+
assertContract(x.length >= 32, "bitslice: input must be at least 32 bytes");
|
|
42
|
+
assertContract(r.length === 8, "bitslice: output must have 8 elements");
|
|
20
43
|
|
|
21
44
|
memzero(r);
|
|
22
45
|
|
|
@@ -36,12 +59,8 @@ export function bitslice(r: Uint32Array, x: Uint8Array): void {
|
|
|
36
59
|
* @param x - Input array of 8 u32 values (bitsliced representation)
|
|
37
60
|
*/
|
|
38
61
|
export function unbitslice(r: Uint8Array, x: Uint32Array): void {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
}
|
|
42
|
-
if (x.length !== 8) {
|
|
43
|
-
throw new Error("unbitslice: input must have 8 elements");
|
|
44
|
-
}
|
|
62
|
+
assertContract(r.length >= 32, "unbitslice: output must be at least 32 bytes");
|
|
63
|
+
assertContract(x.length === 8, "unbitslice: input must have 8 elements");
|
|
45
64
|
|
|
46
65
|
memzero(r.subarray(0, 32));
|
|
47
66
|
|
|
@@ -61,9 +80,7 @@ export function unbitslice(r: Uint8Array, x: Uint32Array): void {
|
|
|
61
80
|
* @param x - Byte value to set in all positions
|
|
62
81
|
*/
|
|
63
82
|
export function bitsliceSetall(r: Uint32Array, x: number): void {
|
|
64
|
-
|
|
65
|
-
throw new Error("bitsliceSetall: output must have 8 elements");
|
|
66
|
-
}
|
|
83
|
+
assertContract(r.length === 8, "bitsliceSetall: output must have 8 elements");
|
|
67
84
|
|
|
68
85
|
for (let idx = 0; idx < 8; idx++) {
|
|
69
86
|
// JavaScript needs special handling for the arithmetic right shift
|
|
@@ -83,9 +100,7 @@ export function bitsliceSetall(r: Uint32Array, x: number): void {
|
|
|
83
100
|
* @param x - Second operand
|
|
84
101
|
*/
|
|
85
102
|
export function gf256Add(r: Uint32Array, x: Uint32Array): void {
|
|
86
|
-
|
|
87
|
-
throw new Error("gf256Add: arrays must have 8 elements");
|
|
88
|
-
}
|
|
103
|
+
assertContract(r.length === 8 && x.length === 8, "gf256Add: arrays must have 8 elements");
|
|
89
104
|
|
|
90
105
|
for (let i = 0; i < 8; i++) {
|
|
91
106
|
r[i] ^= x[i];
|
|
@@ -103,9 +118,10 @@ export function gf256Add(r: Uint32Array, x: Uint32Array): void {
|
|
|
103
118
|
* @param b - Second operand (must NOT overlap with r)
|
|
104
119
|
*/
|
|
105
120
|
export function gf256Mul(r: Uint32Array, a: Uint32Array, b: Uint32Array): void {
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
121
|
+
assertContract(
|
|
122
|
+
r.length === 8 && a.length === 8 && b.length === 8,
|
|
123
|
+
"gf256Mul: arrays must have 8 elements",
|
|
124
|
+
);
|
|
109
125
|
|
|
110
126
|
// Russian Peasant multiplication on two bitsliced polynomials
|
|
111
127
|
const a2 = new Uint32Array(a);
|
|
@@ -212,9 +228,7 @@ export function gf256Mul(r: Uint32Array, a: Uint32Array, b: Uint32Array): void {
|
|
|
212
228
|
* @param x - Value to square
|
|
213
229
|
*/
|
|
214
230
|
export function gf256Square(r: Uint32Array, x: Uint32Array): void {
|
|
215
|
-
|
|
216
|
-
throw new Error("gf256Square: arrays must have 8 elements");
|
|
217
|
-
}
|
|
231
|
+
assertContract(r.length === 8 && x.length === 8, "gf256Square: arrays must have 8 elements");
|
|
218
232
|
|
|
219
233
|
// Use the Freshman's Dream rule to square the polynomial
|
|
220
234
|
// Assignments are done from 7 downto 0, because this allows
|
|
@@ -259,9 +273,7 @@ export function gf256Square(r: Uint32Array, x: Uint32Array): void {
|
|
|
259
273
|
* @param x - Value to invert (will be modified)
|
|
260
274
|
*/
|
|
261
275
|
export function gf256Inv(r: Uint32Array, x: Uint32Array): void {
|
|
262
|
-
|
|
263
|
-
throw new Error("gf256Inv: arrays must have 8 elements");
|
|
264
|
-
}
|
|
276
|
+
assertContract(r.length === 8 && x.length === 8, "gf256Inv: arrays must have 8 elements");
|
|
265
277
|
|
|
266
278
|
const y = new Uint32Array(8);
|
|
267
279
|
const z = new Uint32Array(8);
|
package/src/index.ts
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright © 2023-2026 Blockchain Commons, LLC
|
|
3
|
+
* Copyright © 2025-2026 Parity Technologies
|
|
4
|
+
*
|
|
5
|
+
*/
|
|
6
|
+
|
|
1
7
|
// Blockchain Commons Shamir Secret Sharing
|
|
2
8
|
// Ported from bc-shamir-rust
|
|
3
9
|
//
|
|
@@ -29,17 +35,3 @@ export { ShamirError, ShamirErrorType, type ShamirResult } from "./error.js";
|
|
|
29
35
|
|
|
30
36
|
// Main functions
|
|
31
37
|
export { splitSecret, recoverSecret } from "./shamir.js";
|
|
32
|
-
|
|
33
|
-
// Low-level operations (hazmat)
|
|
34
|
-
export {
|
|
35
|
-
bitslice,
|
|
36
|
-
unbitslice,
|
|
37
|
-
bitsliceSetall,
|
|
38
|
-
gf256Add,
|
|
39
|
-
gf256Mul,
|
|
40
|
-
gf256Square,
|
|
41
|
-
gf256Inv,
|
|
42
|
-
} from "./hazmat.js";
|
|
43
|
-
|
|
44
|
-
// Interpolation
|
|
45
|
-
export { interpolate } from "./interpolate.js";
|
package/src/interpolate.ts
CHANGED