threshold-elgamal 1.0.9 → 2.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/README.md +33 -35
- package/dist/core/bigint.d.ts +2 -1
- package/dist/core/bigint.js +6 -1
- package/dist/core/bytes.js +4 -0
- package/dist/core/crypto.js +5 -0
- package/dist/core/errors.d.ts +50 -11
- package/dist/core/errors.js +50 -11
- package/dist/core/groups.d.ts +6 -1
- package/dist/core/groups.js +13 -2
- package/dist/core/index.d.ts +4 -0
- package/dist/core/index.js +4 -0
- package/dist/core/public.d.ts +13 -0
- package/dist/core/public.js +12 -0
- package/dist/core/random.js +4 -0
- package/dist/core/ristretto.d.ts +7 -0
- package/dist/core/ristretto.js +7 -0
- package/dist/core/types.d.ts +14 -6
- package/dist/core/validation.d.ts +45 -12
- package/dist/core/validation.js +52 -12
- package/dist/dkg/pedersen-share-codec.d.ts +12 -2
- package/dist/dkg/pedersen-share-codec.js +19 -2
- package/dist/dkg/public.d.ts +12 -0
- package/dist/dkg/public.js +11 -0
- package/dist/dkg/verification.d.ts +33 -14
- package/dist/dkg/verification.js +16 -12
- package/dist/elgamal/additive.d.ts +15 -3
- package/dist/elgamal/additive.js +27 -23
- package/dist/elgamal/bsgs.js +7 -0
- package/dist/elgamal/public.d.ts +11 -0
- package/dist/elgamal/public.js +10 -0
- package/dist/elgamal/types.d.ts +6 -0
- package/dist/index.d.ts +27 -25
- package/dist/index.js +20 -19
- package/dist/proofs/disjunctive.d.ts +11 -16
- package/dist/proofs/disjunctive.js +12 -17
- package/dist/proofs/dleq.d.ts +17 -13
- package/dist/proofs/dleq.js +11 -12
- package/dist/proofs/helpers.d.ts +1 -1
- package/dist/proofs/helpers.js +5 -4
- package/dist/proofs/nonces.js +6 -0
- package/dist/proofs/public.d.ts +12 -0
- package/dist/proofs/public.js +11 -0
- package/dist/proofs/schnorr.d.ts +10 -11
- package/dist/proofs/schnorr.js +10 -11
- package/dist/proofs/types.d.ts +30 -5
- package/dist/protocol/board-audit.d.ts +8 -3
- package/dist/protocol/board-audit.js +8 -2
- package/dist/protocol/builders.d.ts +77 -13
- package/dist/protocol/builders.js +83 -13
- package/dist/protocol/canonical-json.js +4 -0
- package/dist/protocol/manifest.d.ts +32 -15
- package/dist/protocol/manifest.js +65 -18
- package/dist/protocol/ordering.js +6 -0
- package/dist/protocol/payloads.d.ts +3 -3
- package/dist/protocol/payloads.js +7 -3
- package/dist/protocol/public.d.ts +17 -0
- package/dist/protocol/public.js +16 -0
- package/dist/protocol/score-range.d.ts +6 -0
- package/dist/protocol/score-range.js +24 -0
- package/dist/protocol/transcript.js +4 -0
- package/dist/protocol/types.d.ts +110 -17
- package/dist/protocol/verification.d.ts +14 -7
- package/dist/protocol/verification.js +7 -5
- package/dist/protocol/voting-ballot-aggregation.d.ts +10 -2
- package/dist/protocol/voting-ballot-aggregation.js +6 -0
- package/dist/protocol/voting-ballots.d.ts +3 -5
- package/dist/protocol/voting-ballots.js +6 -5
- package/dist/protocol/voting-codecs.d.ts +8 -3
- package/dist/protocol/voting-codecs.js +18 -2
- package/dist/protocol/voting-decryption.d.ts +3 -5
- package/dist/protocol/voting-decryption.js +7 -5
- package/dist/protocol/voting-shared.d.ts +2 -1
- package/dist/protocol/voting-shared.js +9 -2
- package/dist/protocol/voting-verification.d.ts +27 -30
- package/dist/protocol/voting-verification.js +13 -26
- package/dist/serialize/encoding.js +4 -0
- package/dist/threshold/decrypt.d.ts +13 -5
- package/dist/threshold/decrypt.js +20 -5
- package/dist/threshold/public.d.ts +11 -0
- package/dist/threshold/public.js +10 -0
- package/dist/threshold/types.d.ts +23 -4
- package/dist/transport/auth.d.ts +10 -16
- package/dist/transport/auth.js +16 -16
- package/dist/transport/complaints.d.ts +2 -4
- package/dist/transport/complaints.js +8 -4
- package/dist/transport/envelopes.d.ts +5 -7
- package/dist/transport/envelopes.js +9 -7
- package/dist/transport/key-agreement.d.ts +15 -23
- package/dist/transport/key-agreement.js +21 -23
- package/dist/transport/types.d.ts +16 -2
- package/dist/vss/feldman.d.ts +11 -1
- package/dist/vss/feldman.js +11 -1
- package/dist/vss/pedersen.d.ts +13 -0
- package/dist/vss/pedersen.js +13 -0
- package/dist/vss/public.d.ts +10 -0
- package/dist/vss/public.js +9 -0
- package/dist/vss/types.d.ts +4 -0
- package/package.json +43 -14
package/README.md
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
# threshold-elgamal
|
|
2
2
|
|
|
3
|
-
[](https://www.npmjs.com/package/threshold-elgamal)
|
|
4
|
-
[](https://www.npmjs.com/package/threshold-elgamal)
|
|
3
|
+
[](https://www.npmjs.com/package/threshold-elgamal) [](https://www.npmjs.com/package/threshold-elgamal)
|
|
5
4
|
|
|
6
5
|
---
|
|
7
6
|
|
|
@@ -11,15 +10,15 @@
|
|
|
11
10
|
|
|
12
11
|
---
|
|
13
12
|
|
|
14
|
-
[](https://nodejs.org/)
|
|
15
13
|
[](LICENSE)
|
|
16
14
|
|
|
17
|
-
`threshold-elgamal` is a browser-native TypeScript library for verifiable score-voting research prototypes.
|
|
15
|
+
`threshold-elgamal` is a browser-native TypeScript library for verifiable score-voting research prototypes. It focuses on one workflow:
|
|
18
16
|
|
|
19
17
|
- additive ElGamal on `ristretto255`
|
|
20
18
|
- honest-majority GJKR DKG
|
|
21
|
-
-
|
|
22
|
-
-
|
|
19
|
+
- one explicit global contiguous score range per ceremony
|
|
20
|
+
- manifest `scoreRange.max` capped at `100` to keep proofs and tally recovery tractable
|
|
21
|
+
- one public manifest shape: `rosterHash`, `optionList`, and `scoreRange`
|
|
23
22
|
- organizer-signed `ballot-close` before decryption
|
|
24
23
|
- full local recomputation and full ceremony verification from the public board
|
|
25
24
|
|
|
@@ -37,45 +36,40 @@ npm install threshold-elgamal
|
|
|
37
36
|
|
|
38
37
|
- Use ESM imports such as `import { createElectionManifest } from 'threshold-elgamal'`.
|
|
39
38
|
- Browsers need native `bigint` together with Web Crypto.
|
|
40
|
-
- Node
|
|
39
|
+
- Node must satisfy the package `engines.node` requirement and expose `globalThis.crypto`.
|
|
41
40
|
- Authentication signatures require Web Crypto `Ed25519`.
|
|
42
41
|
- Transport share exchange requires Web Crypto `X25519`.
|
|
43
42
|
|
|
44
|
-
See [Runtime and compatibility](https://tenemo.github.io/threshold-elgamal/guides/runtime-and-compatibility/) for
|
|
45
|
-
|
|
46
|
-
## Start here
|
|
47
|
-
|
|
48
|
-
- [Verifying a public board](https://tenemo.github.io/threshold-elgamal/guides/verifying-a-public-board/): start here for `tryVerifyElectionCeremony(...)` and `verifyElectionCeremony(...)`.
|
|
49
|
-
- [Browser and worker usage](https://tenemo.github.io/threshold-elgamal/guides/browser-and-worker-usage/): start here for key generation, manifest setup, and encrypted transport envelopes.
|
|
50
|
-
- [Published payload examples](https://tenemo.github.io/threshold-elgamal/guides/published-payload-examples/): start here if you need concrete JSON, posting, or persistence patterns.
|
|
51
|
-
- [Honest-majority voting flow](https://tenemo.github.io/threshold-elgamal/guides/three-participant-voting-flow/): read this for the supported phase-by-phase transcript story.
|
|
43
|
+
See [Runtime and compatibility](https://tenemo.github.io/threshold-elgamal/guides/runtime-and-compatibility/) for environment requirements.
|
|
52
44
|
|
|
53
45
|
## Documentation
|
|
54
46
|
|
|
55
|
-
-
|
|
56
|
-
-
|
|
57
|
-
-
|
|
47
|
+
- Homepage: [tenemo.github.io/threshold-elgamal](https://tenemo.github.io/threshold-elgamal/)
|
|
48
|
+
- Getting started: [tenemo.github.io/threshold-elgamal/guides/getting-started](https://tenemo.github.io/threshold-elgamal/guides/getting-started/)
|
|
49
|
+
- Runtime and compatibility: [tenemo.github.io/threshold-elgamal/guides/runtime-and-compatibility](https://tenemo.github.io/threshold-elgamal/guides/runtime-and-compatibility/)
|
|
58
50
|
- Browser and worker usage: [tenemo.github.io/threshold-elgamal/guides/browser-and-worker-usage](https://tenemo.github.io/threshold-elgamal/guides/browser-and-worker-usage/)
|
|
59
|
-
- Published payload examples: [tenemo.github.io/threshold-elgamal/guides/published-payload-examples](https://tenemo.github.io/threshold-elgamal/guides/published-payload-examples/)
|
|
60
51
|
- Honest-majority voting flow: [tenemo.github.io/threshold-elgamal/guides/three-participant-voting-flow](https://tenemo.github.io/threshold-elgamal/guides/three-participant-voting-flow/)
|
|
61
|
-
-
|
|
52
|
+
- Published payload examples: [tenemo.github.io/threshold-elgamal/guides/published-payload-examples](https://tenemo.github.io/threshold-elgamal/guides/published-payload-examples/)
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
- Verifying a public board: [tenemo.github.io/threshold-elgamal/guides/verifying-a-public-board](https://tenemo.github.io/threshold-elgamal/guides/verifying-a-public-board/)
|
|
62
57
|
- Security boundary: [tenemo.github.io/threshold-elgamal/guides/security-and-non-goals](https://tenemo.github.io/threshold-elgamal/guides/security-and-non-goals/)
|
|
63
58
|
- Production voting safety review: [tenemo.github.io/threshold-elgamal/guides/production-voting-safety-review](https://tenemo.github.io/threshold-elgamal/guides/production-voting-safety-review/)
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
64
62
|
- API docs: [tenemo.github.io/threshold-elgamal/api](https://tenemo.github.io/threshold-elgamal/api/)
|
|
65
63
|
|
|
66
64
|
## Browser support
|
|
67
65
|
|
|
68
|
-
The
|
|
66
|
+
The cryptographic browser path is fixed:
|
|
69
67
|
|
|
70
68
|
- `Ed25519` for protocol payload signatures
|
|
71
69
|
- `X25519` for encrypted share transport
|
|
72
70
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
- Chrome and Edge `137+`
|
|
76
|
-
- Firefox `130+`
|
|
77
|
-
- Safari `18.4+`
|
|
78
|
-
- iOS and iPadOS browsers on the Safari `18.4+` WebKit generation
|
|
71
|
+
- Use modern browsers that expose Web Crypto `Ed25519`, Web Crypto `X25519`, and native `bigint`
|
|
72
|
+
- Validate your target environments with `pnpm exec tsx ./tools/ci/verify-browser-compat.ts` before deployment
|
|
79
73
|
|
|
80
74
|
Older browsers, stale embedded webviews, and runtimes without Web Crypto `X25519` support are not supported.
|
|
81
75
|
|
|
@@ -84,10 +78,10 @@ Older browsers, stale embedded webviews, and runtimes without Web Crypto `X25519
|
|
|
84
78
|
The supported boardroom flow is:
|
|
85
79
|
|
|
86
80
|
1. Freeze the roster in the application and hash it with `hashRosterEntries(...)`.
|
|
87
|
-
2. Build the
|
|
81
|
+
2. Build the manifest with `createElectionManifest({ rosterHash, optionList, scoreRange })`.
|
|
88
82
|
3. Publish the manifest, registrations, and manifest acceptances.
|
|
89
83
|
4. Run the honest-majority GJKR transcript.
|
|
90
|
-
5. Post ballot payloads for complete
|
|
84
|
+
5. Post ballot payloads for complete scores inside the manifest-declared range.
|
|
91
85
|
6. Post one organizer-signed `ballot-close` payload that freezes which complete ballots are counted.
|
|
92
86
|
7. Post threshold decryption shares and tally publications for the close-selected ballot set.
|
|
93
87
|
8. Verify the whole ceremony with `verifyElectionCeremony(...)`.
|
|
@@ -136,6 +130,7 @@ const rosterHash = await hashRosterEntries([
|
|
|
136
130
|
const manifest = createElectionManifest({
|
|
137
131
|
rosterHash,
|
|
138
132
|
optionList: ["Option A", "Option B"],
|
|
133
|
+
scoreRange: { min: 1, max: 10 },
|
|
139
134
|
});
|
|
140
135
|
|
|
141
136
|
const manifestHash = await hashElectionManifest(manifest);
|
|
@@ -178,7 +173,7 @@ if (!result.ok) {
|
|
|
178
173
|
}
|
|
179
174
|
```
|
|
180
175
|
|
|
181
|
-
The root package
|
|
176
|
+
The root package exposes the builders and lower-level helpers required for the documented ceremony, including:
|
|
182
177
|
|
|
183
178
|
- manifest publication
|
|
184
179
|
- registration
|
|
@@ -193,14 +188,17 @@ The root package also exposes builders for the signed protocol payloads used acr
|
|
|
193
188
|
- decryption shares
|
|
194
189
|
- tally publication
|
|
195
190
|
|
|
196
|
-
|
|
191
|
+
The reveal path also works from the root package:
|
|
197
192
|
|
|
198
193
|
- prepare the accepted aggregate with `prepareAggregateForDecryption(...)`
|
|
199
194
|
- compute each partial share with `createDecryptionShare(...)`
|
|
200
|
-
- prove
|
|
195
|
+
- prove it with `createDLEQProof(...)`
|
|
196
|
+
- publish it with `createDecryptionSharePayload(...)`
|
|
201
197
|
|
|
202
198
|
After collecting a threshold subset, recover the tally with `combineDecryptionShares(...)` against the prepared aggregate ciphertext.
|
|
203
199
|
|
|
200
|
+
The grouped public submodules remain available when you prefer narrower imports by subsystem, but the supported full ceremony does not require them.
|
|
201
|
+
|
|
204
202
|
For concrete posted JSON shapes, use [Published payload examples](https://tenemo.github.io/threshold-elgamal/guides/published-payload-examples/).
|
|
205
203
|
|
|
206
204
|
## Security boundary
|
|
@@ -210,7 +208,7 @@ The library is designed for an honest-origin, honest-client, static-adversary se
|
|
|
210
208
|
What it tries to enforce:
|
|
211
209
|
|
|
212
210
|
- additive-only tallying on `ristretto255`
|
|
213
|
-
-
|
|
211
|
+
- one explicit global contiguous manifest score range
|
|
214
212
|
- grouped per-option ballot verification
|
|
215
213
|
- mandatory local aggregate recomputation before decryption
|
|
216
214
|
- organizer-visible and auditable ballot cutoff through `ballot-close`
|
|
@@ -224,9 +222,9 @@ What it does not claim:
|
|
|
224
222
|
- constant-time JavaScript `bigint` execution
|
|
225
223
|
- production readiness
|
|
226
224
|
|
|
227
|
-
`ballot-close` is an auditable administrative cutoff, not a fairness proof about board arrival order. The library proves
|
|
225
|
+
`ballot-close` is an auditable administrative cutoff, not a fairness proof about board arrival order. The library proves which ballots count, not whether the organizer waited long enough before closing.
|
|
228
226
|
|
|
229
|
-
For a production-threat-model verdict that maps these boundaries to the
|
|
227
|
+
For a production-threat-model verdict that maps these boundaries to the verifier and tests, read the [production voting safety review](https://tenemo.github.io/threshold-elgamal/guides/production-voting-safety-review/).
|
|
230
228
|
|
|
231
229
|
## Development
|
|
232
230
|
|
package/dist/core/bigint.d.ts
CHANGED
|
@@ -7,7 +7,8 @@ export declare const mod: (value: bigint, modulus: bigint) => bigint;
|
|
|
7
7
|
/**
|
|
8
8
|
* Reduces a value into the range `0..q-1`.
|
|
9
9
|
*
|
|
10
|
-
* @throws {@link InvalidScalarError
|
|
10
|
+
* @throws {@link threshold-elgamal/core!InvalidScalarError | InvalidScalarError}
|
|
11
|
+
* When `q` is not positive.
|
|
11
12
|
*/
|
|
12
13
|
export declare const modQ: (value: bigint, q: bigint) => bigint;
|
|
13
14
|
/**
|
package/dist/core/bigint.js
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Finite-field arithmetic helpers shared by proofs, verifiable secret sharing,
|
|
3
|
+
* threshold reconstruction, and transcript verification.
|
|
4
|
+
*/
|
|
1
5
|
import { InvalidScalarError } from './errors.js';
|
|
2
6
|
const assertPositiveModulus = (modulus) => {
|
|
3
7
|
if (modulus <= 0n) {
|
|
@@ -66,7 +70,8 @@ const modP = (value, p) => mod(value, p);
|
|
|
66
70
|
/**
|
|
67
71
|
* Reduces a value into the range `0..q-1`.
|
|
68
72
|
*
|
|
69
|
-
* @throws {@link InvalidScalarError
|
|
73
|
+
* @throws {@link threshold-elgamal/core!InvalidScalarError | InvalidScalarError}
|
|
74
|
+
* When `q` is not positive.
|
|
70
75
|
*/
|
|
71
76
|
export const modQ = (value, q) => mod(value, q);
|
|
72
77
|
/**
|
package/dist/core/bytes.js
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Byte, hex, and buffer-shape conversion helpers used by hashing,
|
|
3
|
+
* serialization, signatures, and transport code throughout the package.
|
|
4
|
+
*/
|
|
1
5
|
import { InvalidPayloadError } from './errors.js';
|
|
2
6
|
const hexPattern = /^[0-9a-f]+$/i;
|
|
3
7
|
const defaultHexErrorMessage = 'Hex input must be a non-empty even-length hexadecimal string';
|
package/dist/core/crypto.js
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runtime crypto helpers that normalize Web Crypto access for hashing,
|
|
3
|
+
* HKDF-based key derivation, and UTF-8 encoding across browser and Node
|
|
4
|
+
* runtimes.
|
|
5
|
+
*/
|
|
1
6
|
import { toBufferSource } from './bytes.js';
|
|
2
7
|
import { InvalidScalarError, UnsupportedSuiteError } from './errors.js';
|
|
3
8
|
const textEncoder = new TextEncoder();
|
package/dist/core/errors.d.ts
CHANGED
|
@@ -1,37 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared error taxonomy for the package.
|
|
3
|
+
*
|
|
4
|
+
* Public helpers throw these errors when callers violate mathematical,
|
|
5
|
+
* encoding, transcript, or workflow invariants.
|
|
6
|
+
*/
|
|
1
7
|
declare class ThresholdElGamalError extends Error {
|
|
2
8
|
constructor(message: string);
|
|
3
9
|
}
|
|
4
|
-
/**
|
|
10
|
+
/**
|
|
11
|
+
* Raised when a scalar value falls outside the expected field or subgroup
|
|
12
|
+
* domain for the current operation.
|
|
13
|
+
*/
|
|
5
14
|
export declare class InvalidScalarError extends ThresholdElGamalError {
|
|
6
15
|
}
|
|
7
|
-
/**
|
|
16
|
+
/**
|
|
17
|
+
* Raised when a point or public key is not a canonical member of the selected
|
|
18
|
+
* cryptographic group.
|
|
19
|
+
*/
|
|
8
20
|
export declare class InvalidGroupElementError extends ThresholdElGamalError {
|
|
9
21
|
}
|
|
10
|
-
/**
|
|
22
|
+
/**
|
|
23
|
+
* Raised when a participant index falls outside the supported `1..n`
|
|
24
|
+
* numbering scheme used across the protocol.
|
|
25
|
+
*/
|
|
11
26
|
export declare class IndexOutOfRangeError extends ThresholdElGamalError {
|
|
12
27
|
}
|
|
13
|
-
/**
|
|
28
|
+
/**
|
|
29
|
+
* Raised when a payload, transcript field, manifest field, or serialized value
|
|
30
|
+
* does not satisfy the package's canonical encoding rules.
|
|
31
|
+
*/
|
|
14
32
|
export declare class InvalidPayloadError extends ThresholdElGamalError {
|
|
15
33
|
}
|
|
16
|
-
/**
|
|
34
|
+
/**
|
|
35
|
+
* Raised when a Schnorr, DLEQ, or disjunctive proof transcript fails
|
|
36
|
+
* structural checks or cryptographic verification.
|
|
37
|
+
*/
|
|
17
38
|
export declare class InvalidProofError extends ThresholdElGamalError {
|
|
18
39
|
}
|
|
19
|
-
/**
|
|
40
|
+
/**
|
|
41
|
+
* Raised when the requested suite or required runtime capability is unavailable
|
|
42
|
+
* in the current environment.
|
|
43
|
+
*/
|
|
20
44
|
export declare class UnsupportedSuiteError extends ThresholdElGamalError {
|
|
21
45
|
}
|
|
22
|
-
/**
|
|
46
|
+
/**
|
|
47
|
+
* Raised when an additive plaintext falls outside the explicitly bounded domain
|
|
48
|
+
* that the current workflow promised to support.
|
|
49
|
+
*/
|
|
23
50
|
export declare class PlaintextDomainError extends ThresholdElGamalError {
|
|
24
51
|
}
|
|
25
|
-
/**
|
|
52
|
+
/**
|
|
53
|
+
* Raised when a serialized share, decrypted share envelope, or reconstructed
|
|
54
|
+
* share set fails threshold-specific validation.
|
|
55
|
+
*/
|
|
26
56
|
export declare class InvalidShareError extends ThresholdElGamalError {
|
|
27
57
|
}
|
|
28
|
-
/**
|
|
58
|
+
/**
|
|
59
|
+
* Raised when a published payload claims to belong to a protocol phase that
|
|
60
|
+
* does not match the supported ceremony state machine.
|
|
61
|
+
*/
|
|
29
62
|
export declare class PhaseViolationError extends ThresholdElGamalError {
|
|
30
63
|
}
|
|
31
|
-
/**
|
|
64
|
+
/**
|
|
65
|
+
* Raised when threshold parameters or participant counts violate the supported
|
|
66
|
+
* `1 <= k <= n` relationship or the package's honest-majority policy.
|
|
67
|
+
*/
|
|
32
68
|
export declare class ThresholdViolationError extends ThresholdElGamalError {
|
|
33
69
|
}
|
|
34
|
-
/**
|
|
70
|
+
/**
|
|
71
|
+
* Raised when transcript hashes, manifest hashes, or other canonical digest
|
|
72
|
+
* commitments do not match the values claimed by published payloads.
|
|
73
|
+
*/
|
|
35
74
|
export declare class TranscriptMismatchError extends ThresholdElGamalError {
|
|
36
75
|
}
|
|
37
76
|
export {};
|
package/dist/core/errors.js
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared error taxonomy for the package.
|
|
3
|
+
*
|
|
4
|
+
* Public helpers throw these errors when callers violate mathematical,
|
|
5
|
+
* encoding, transcript, or workflow invariants.
|
|
6
|
+
*/
|
|
1
7
|
class ThresholdElGamalError extends Error {
|
|
2
8
|
constructor(message) {
|
|
3
9
|
super(message);
|
|
@@ -5,36 +11,69 @@ class ThresholdElGamalError extends Error {
|
|
|
5
11
|
Object.setPrototypeOf(this, new.target.prototype);
|
|
6
12
|
}
|
|
7
13
|
}
|
|
8
|
-
/**
|
|
14
|
+
/**
|
|
15
|
+
* Raised when a scalar value falls outside the expected field or subgroup
|
|
16
|
+
* domain for the current operation.
|
|
17
|
+
*/
|
|
9
18
|
export class InvalidScalarError extends ThresholdElGamalError {
|
|
10
19
|
}
|
|
11
|
-
/**
|
|
20
|
+
/**
|
|
21
|
+
* Raised when a point or public key is not a canonical member of the selected
|
|
22
|
+
* cryptographic group.
|
|
23
|
+
*/
|
|
12
24
|
export class InvalidGroupElementError extends ThresholdElGamalError {
|
|
13
25
|
}
|
|
14
|
-
/**
|
|
26
|
+
/**
|
|
27
|
+
* Raised when a participant index falls outside the supported `1..n`
|
|
28
|
+
* numbering scheme used across the protocol.
|
|
29
|
+
*/
|
|
15
30
|
export class IndexOutOfRangeError extends ThresholdElGamalError {
|
|
16
31
|
}
|
|
17
|
-
/**
|
|
32
|
+
/**
|
|
33
|
+
* Raised when a payload, transcript field, manifest field, or serialized value
|
|
34
|
+
* does not satisfy the package's canonical encoding rules.
|
|
35
|
+
*/
|
|
18
36
|
export class InvalidPayloadError extends ThresholdElGamalError {
|
|
19
37
|
}
|
|
20
|
-
/**
|
|
38
|
+
/**
|
|
39
|
+
* Raised when a Schnorr, DLEQ, or disjunctive proof transcript fails
|
|
40
|
+
* structural checks or cryptographic verification.
|
|
41
|
+
*/
|
|
21
42
|
export class InvalidProofError extends ThresholdElGamalError {
|
|
22
43
|
}
|
|
23
|
-
/**
|
|
44
|
+
/**
|
|
45
|
+
* Raised when the requested suite or required runtime capability is unavailable
|
|
46
|
+
* in the current environment.
|
|
47
|
+
*/
|
|
24
48
|
export class UnsupportedSuiteError extends ThresholdElGamalError {
|
|
25
49
|
}
|
|
26
|
-
/**
|
|
50
|
+
/**
|
|
51
|
+
* Raised when an additive plaintext falls outside the explicitly bounded domain
|
|
52
|
+
* that the current workflow promised to support.
|
|
53
|
+
*/
|
|
27
54
|
export class PlaintextDomainError extends ThresholdElGamalError {
|
|
28
55
|
}
|
|
29
|
-
/**
|
|
56
|
+
/**
|
|
57
|
+
* Raised when a serialized share, decrypted share envelope, or reconstructed
|
|
58
|
+
* share set fails threshold-specific validation.
|
|
59
|
+
*/
|
|
30
60
|
export class InvalidShareError extends ThresholdElGamalError {
|
|
31
61
|
}
|
|
32
|
-
/**
|
|
62
|
+
/**
|
|
63
|
+
* Raised when a published payload claims to belong to a protocol phase that
|
|
64
|
+
* does not match the supported ceremony state machine.
|
|
65
|
+
*/
|
|
33
66
|
export class PhaseViolationError extends ThresholdElGamalError {
|
|
34
67
|
}
|
|
35
|
-
/**
|
|
68
|
+
/**
|
|
69
|
+
* Raised when threshold parameters or participant counts violate the supported
|
|
70
|
+
* `1 <= k <= n` relationship or the package's honest-majority policy.
|
|
71
|
+
*/
|
|
36
72
|
export class ThresholdViolationError extends ThresholdElGamalError {
|
|
37
73
|
}
|
|
38
|
-
/**
|
|
74
|
+
/**
|
|
75
|
+
* Raised when transcript hashes, manifest hashes, or other canonical digest
|
|
76
|
+
* commitments do not match the values claimed by published payloads.
|
|
77
|
+
*/
|
|
39
78
|
export class TranscriptMismatchError extends ThresholdElGamalError {
|
|
40
79
|
}
|
package/dist/core/groups.d.ts
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
import type { CryptoGroup } from './types.js';
|
|
2
|
-
/**
|
|
2
|
+
/**
|
|
3
|
+
* Immutable definition of the built-in `ristretto255` tally group.
|
|
4
|
+
*
|
|
5
|
+
* Every public cryptographic workflow in this package ultimately routes
|
|
6
|
+
* through this suite definition.
|
|
7
|
+
*/
|
|
3
8
|
export declare const RISTRETTO_GROUP: CryptoGroup;
|
|
4
9
|
export declare const assertCanonicalRistrettoGroup: (group: CryptoGroup, label?: string) => void;
|
package/dist/core/groups.js
CHANGED
|
@@ -1,6 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Built-in group definitions and suite guard rails.
|
|
3
|
+
*
|
|
4
|
+
* The public API is intentionally tied to one canonical suite,
|
|
5
|
+
* `ristretto255`, and this module makes that choice explicit.
|
|
6
|
+
*/
|
|
1
7
|
import { UnsupportedSuiteError } from './errors.js';
|
|
2
8
|
import { derivePedersenGenerator, RISTRETTO_BYTE_LENGTH } from './ristretto.js';
|
|
3
|
-
/**
|
|
9
|
+
/**
|
|
10
|
+
* Immutable definition of the built-in `ristretto255` tally group.
|
|
11
|
+
*
|
|
12
|
+
* Every public cryptographic workflow in this package ultimately routes
|
|
13
|
+
* through this suite definition.
|
|
14
|
+
*/
|
|
4
15
|
export const RISTRETTO_GROUP = Object.freeze({
|
|
5
16
|
name: 'ristretto255',
|
|
6
17
|
byteLength: RISTRETTO_BYTE_LENGTH,
|
|
@@ -20,6 +31,6 @@ const sameCanonicalRistrettoGroup = (group) => group.name === RISTRETTO_GROUP.na
|
|
|
20
31
|
export const assertCanonicalRistrettoGroup = (group, label = 'Group') => {
|
|
21
32
|
const normalizedLabel = label.length > 0 ? `${label[0].toLowerCase()}${label.slice(1)}` : label;
|
|
22
33
|
if (!sameCanonicalRistrettoGroup(group)) {
|
|
23
|
-
throw new UnsupportedSuiteError(`${normalizedLabel} must match the
|
|
34
|
+
throw new UnsupportedSuiteError(`${normalizedLabel} must match the canonical ristretto255 group definition`);
|
|
24
35
|
}
|
|
25
36
|
};
|
package/dist/core/index.d.ts
CHANGED
package/dist/core/index.js
CHANGED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Low-level core helpers for arithmetic, error handling, and group constants.
|
|
3
|
+
*
|
|
4
|
+
* Use this module when you need primitives that sit below the voting workflow
|
|
5
|
+
* surface exposed by the root package.
|
|
6
|
+
*
|
|
7
|
+
* @module threshold-elgamal/core
|
|
8
|
+
* @packageDocumentation
|
|
9
|
+
*/
|
|
10
|
+
export { IndexOutOfRangeError, InvalidGroupElementError, InvalidPayloadError, InvalidProofError, InvalidScalarError, InvalidShareError, PhaseViolationError, PlaintextDomainError, ThresholdViolationError, TranscriptMismatchError, UnsupportedSuiteError, } from './errors.js';
|
|
11
|
+
export { modQ } from './bigint.js';
|
|
12
|
+
export { RISTRETTO_GROUP } from './groups.js';
|
|
13
|
+
export type { EncodedPoint } from './types.js';
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Low-level core helpers for arithmetic, error handling, and group constants.
|
|
3
|
+
*
|
|
4
|
+
* Use this module when you need primitives that sit below the voting workflow
|
|
5
|
+
* surface exposed by the root package.
|
|
6
|
+
*
|
|
7
|
+
* @module threshold-elgamal/core
|
|
8
|
+
* @packageDocumentation
|
|
9
|
+
*/
|
|
10
|
+
export { IndexOutOfRangeError, InvalidGroupElementError, InvalidPayloadError, InvalidProofError, InvalidScalarError, InvalidShareError, PhaseViolationError, PlaintextDomainError, ThresholdViolationError, TranscriptMismatchError, UnsupportedSuiteError, } from './errors.js';
|
|
11
|
+
export { modQ } from './bigint.js';
|
|
12
|
+
export { RISTRETTO_GROUP } from './groups.js';
|
package/dist/core/random.js
CHANGED
package/dist/core/ristretto.d.ts
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Low-level Ristretto255 point and scalar operations.
|
|
3
|
+
*
|
|
4
|
+
* Higher-level modules such as additive ElGamal, proofs, VSS, and threshold
|
|
5
|
+
* reconstruction build on these wrappers instead of calling the curve library
|
|
6
|
+
* directly.
|
|
7
|
+
*/
|
|
1
8
|
import { ristretto255 } from '@noble/curves/ed25519.js';
|
|
2
9
|
import type { EncodedPoint } from './types.js';
|
|
3
10
|
type InternalPoint = InstanceType<typeof ristretto255.Point>;
|
package/dist/core/ristretto.js
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Low-level Ristretto255 point and scalar operations.
|
|
3
|
+
*
|
|
4
|
+
* Higher-level modules such as additive ElGamal, proofs, VSS, and threshold
|
|
5
|
+
* reconstruction build on these wrappers instead of calling the curve library
|
|
6
|
+
* directly.
|
|
7
|
+
*/
|
|
1
8
|
import { ristretto255, ristretto255_hasher } from '@noble/curves/ed25519.js';
|
|
2
9
|
import { sha512 } from '@noble/hashes/sha2.js';
|
|
3
10
|
import { bytesToBigInt, bytesToBigIntLE, bytesToHex, hexToBytes, } from './bytes.js';
|
package/dist/core/types.d.ts
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Foundational nominal and suite types shared across the package.
|
|
3
|
+
*/
|
|
1
4
|
/**
|
|
2
5
|
* Nominal typing helper used to distinguish compatible runtime values in the
|
|
3
6
|
* type system.
|
|
@@ -5,13 +8,18 @@
|
|
|
5
8
|
export type Brand<T, TBrand extends string> = T & {
|
|
6
9
|
readonly __brand: TBrand;
|
|
7
10
|
};
|
|
8
|
-
/** @internal Canonical name for the
|
|
11
|
+
/** @internal Canonical name for the built-in Ristretto255 suite. */
|
|
9
12
|
export type GroupName = 'ristretto255';
|
|
10
|
-
/** @internal Accepted helper input identifiers for the
|
|
13
|
+
/** @internal Accepted helper input identifiers for the built-in Ristretto suite. */
|
|
11
14
|
export type GroupIdentifier = GroupName;
|
|
12
|
-
/**
|
|
15
|
+
/**
|
|
16
|
+
* Canonical 32-byte Ristretto point encoding exposed at the public boundary.
|
|
17
|
+
*
|
|
18
|
+
* Public helpers use this branded string type to distinguish encoded points
|
|
19
|
+
* from ordinary hex strings.
|
|
20
|
+
*/
|
|
13
21
|
export type EncodedPoint = Brand<string, 'EncodedPoint'>;
|
|
14
|
-
/** @internal Immutable
|
|
22
|
+
/** @internal Immutable group definition for the built-in suite. */
|
|
15
23
|
export type CryptoGroup = {
|
|
16
24
|
/** Canonical suite name. */
|
|
17
25
|
readonly name: GroupName;
|
|
@@ -29,7 +37,7 @@ export type CryptoGroup = {
|
|
|
29
37
|
readonly securityEstimate: number;
|
|
30
38
|
};
|
|
31
39
|
/**
|
|
32
|
-
* Random byte source injected into sampling helpers for deterministic
|
|
33
|
-
* or custom runtime integration.
|
|
40
|
+
* Random byte source injected into sampling helpers for deterministic tests,
|
|
41
|
+
* reproducible vectors, or custom runtime integration.
|
|
34
42
|
*/
|
|
35
43
|
export type RandomBytesSource = (length: number) => Uint8Array;
|
|
@@ -1,6 +1,16 @@
|
|
|
1
|
-
/**
|
|
1
|
+
/**
|
|
2
|
+
* Returns `true` when the value is a canonical non-identity Ristretto point.
|
|
3
|
+
*
|
|
4
|
+
* This is the predicate used for public keys and most commitment elements.
|
|
5
|
+
*/
|
|
2
6
|
export declare const isInSubgroup: (value: string) => boolean;
|
|
3
|
-
/**
|
|
7
|
+
/**
|
|
8
|
+
* Returns `true` when the value is a canonical Ristretto point, including the
|
|
9
|
+
* identity element.
|
|
10
|
+
*
|
|
11
|
+
* This variant is used for ciphertext components and transcript values that
|
|
12
|
+
* are allowed to land on the identity.
|
|
13
|
+
*/
|
|
4
14
|
export declare const isInSubgroupOrIdentity: (value: string) => boolean;
|
|
5
15
|
/**
|
|
6
16
|
* Validates that a scalar belongs to `Z_q`.
|
|
@@ -30,25 +40,48 @@ export declare const assertPlaintextAdditive: (value: bigint, bound: bigint, q:
|
|
|
30
40
|
*/
|
|
31
41
|
export declare const assertThreshold: (threshold: number, participantCount: number) => void;
|
|
32
42
|
/**
|
|
33
|
-
* Derives the
|
|
43
|
+
* Derives the supported honest-majority threshold `ceil(n / 2)`.
|
|
34
44
|
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
45
|
+
* This is the threshold policy used by the package's DKG and full voting flow.
|
|
46
|
+
* Callers do not choose a custom `k`; the verifier derives it from the
|
|
47
|
+
* accepted registration roster.
|
|
38
48
|
*/
|
|
39
49
|
export declare const majorityThreshold: (participantCount: number) => number;
|
|
40
50
|
/**
|
|
41
|
-
* Validates that the supplied threshold matches the
|
|
51
|
+
* Validates that the supplied threshold matches the library's GJKR
|
|
42
52
|
* honest-majority policy.
|
|
43
53
|
*/
|
|
44
54
|
export declare const assertMajorityThreshold: (threshold: number, participantCount: number) => number;
|
|
45
|
-
/**
|
|
55
|
+
/**
|
|
56
|
+
* Validates a 1-based participant index without assuming a fixed participant
|
|
57
|
+
* count.
|
|
58
|
+
*
|
|
59
|
+
* The package consistently numbers trustees and voters from `1`.
|
|
60
|
+
*/
|
|
46
61
|
export declare const assertPositiveParticipantIndex: (index: number) => void;
|
|
47
|
-
/**
|
|
62
|
+
/**
|
|
63
|
+
* Validates a 1-based participant index against a fixed participant count.
|
|
64
|
+
*
|
|
65
|
+
* This is the usual check for published payloads that already sit inside a
|
|
66
|
+
* frozen roster.
|
|
67
|
+
*/
|
|
48
68
|
export declare const assertValidParticipantIndex: (index: number, participantCount: number) => void;
|
|
49
|
-
/**
|
|
69
|
+
/**
|
|
70
|
+
* Validates that a value is a canonical non-identity Ristretto point.
|
|
71
|
+
*
|
|
72
|
+
* This is the assertion form of {@link isInSubgroup}.
|
|
73
|
+
*/
|
|
50
74
|
export declare const assertInSubgroup: (value: string) => void;
|
|
51
|
-
/**
|
|
75
|
+
/**
|
|
76
|
+
* Validates that a value is a canonical Ristretto point, including identity.
|
|
77
|
+
*
|
|
78
|
+
* This is the assertion form of {@link isInSubgroupOrIdentity}.
|
|
79
|
+
*/
|
|
52
80
|
export declare const assertInSubgroupOrIdentity: (value: string) => void;
|
|
53
|
-
/**
|
|
81
|
+
/**
|
|
82
|
+
* Validates a public key as a canonical non-identity Ristretto point.
|
|
83
|
+
*
|
|
84
|
+
* Public keys, verification keys, and commitment generators all route through
|
|
85
|
+
* this helper.
|
|
86
|
+
*/
|
|
54
87
|
export declare const assertValidPublicKey: (value: string) => void;
|