threshold-elgamal 2.0.0 → 2.1.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 +9 -3
- package/dist/dkg/verification.d.ts +9 -2
- package/dist/dkg/verification.js +9 -2
- package/dist/protocol/types.d.ts +4 -3
- package/dist/protocol/voting-ballots.d.ts +4 -3
- package/dist/protocol/voting-ballots.js +4 -3
- package/dist/protocol/voting-decryption.d.ts +2 -1
- package/dist/protocol/voting-decryption.js +2 -1
- package/dist/protocol/voting-verification.d.ts +2 -2
- package/dist/protocol/voting-verification.js +4 -6
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -94,7 +94,7 @@ The cryptographic threshold is derived internally from the accepted registration
|
|
|
94
94
|
|
|
95
95
|
There is no supported `n-of-n` mode and no supported public `k-of-n` configuration.
|
|
96
96
|
|
|
97
|
-
Transcript verification requires key-derivation
|
|
97
|
+
Transcript verification requires `key-derivation-confirmation` payloads from every qualified participant. In the current design those unanimous confirmations are part of verifier soundness: the library does not implement a public post-Feldman complaint/reconstruction phase, so the DKG verifier is participant-confirmed rather than fully public-data-only. Lowering confirmation acceptance to threshold-many is out of scope unless that missing public consistency machinery is added.
|
|
98
98
|
|
|
99
99
|
See [Honest-majority voting flow](https://tenemo.github.io/threshold-elgamal/guides/three-participant-voting-flow/) for the full phase-by-phase transcript.
|
|
100
100
|
|
|
@@ -130,7 +130,7 @@ const rosterHash = await hashRosterEntries([
|
|
|
130
130
|
const manifest = createElectionManifest({
|
|
131
131
|
rosterHash,
|
|
132
132
|
optionList: ["Option A", "Option B"],
|
|
133
|
-
scoreRange: { min:
|
|
133
|
+
scoreRange: { min: 0, max: 5 },
|
|
134
134
|
});
|
|
135
135
|
|
|
136
136
|
const manifestHash = await hashElectionManifest(manifest);
|
|
@@ -145,6 +145,10 @@ console.log(majorityThreshold(3)); // 2
|
|
|
145
145
|
console.log(sessionId.length); // 64
|
|
146
146
|
```
|
|
147
147
|
|
|
148
|
+
The example uses `0..5` only as one concrete score range. The supported rule is
|
|
149
|
+
one manifest-declared contiguous range with non-negative bounds and
|
|
150
|
+
`scoreRange.max <= 100`.
|
|
151
|
+
|
|
148
152
|
If your application consumes a complete public board, start with [Verifying a public board](https://tenemo.github.io/threshold-elgamal/guides/verifying-a-public-board/) and then move directly to the verifier entry point:
|
|
149
153
|
|
|
150
154
|
```typescript
|
|
@@ -158,7 +162,7 @@ const bundle: VerifyElectionCeremonyInput = {
|
|
|
158
162
|
sessionId,
|
|
159
163
|
dkgTranscript,
|
|
160
164
|
ballotPayloads,
|
|
161
|
-
ballotClosePayload,
|
|
165
|
+
ballotClosePayloads: [ballotClosePayload],
|
|
162
166
|
decryptionSharePayloads,
|
|
163
167
|
tallyPublications,
|
|
164
168
|
};
|
|
@@ -173,6 +177,8 @@ if (!result.ok) {
|
|
|
173
177
|
}
|
|
174
178
|
```
|
|
175
179
|
|
|
180
|
+
Pass the full published `ballot-close` slot in `ballotClosePayloads`, even when the normal case is one organizer payload. The verifier audits that slot, collapses only exact retransmissions, and requires exactly one accepted close record.
|
|
181
|
+
|
|
176
182
|
The root package exposes the builders and lower-level helpers required for the documented ceremony, including:
|
|
177
183
|
|
|
178
184
|
- manifest publication
|
|
@@ -78,9 +78,16 @@ export declare const deriveJointPublicKey: (feldmanCommitments: readonly {
|
|
|
78
78
|
/**
|
|
79
79
|
* Verifies a DKG transcript, its signatures, Feldman extraction proofs, the
|
|
80
80
|
* exact claimed threshold degree, accepted complaint outcomes, the DKG
|
|
81
|
-
* transcript hash,
|
|
81
|
+
* transcript hash, the announced joint public key, and unanimous qualified
|
|
82
|
+
* participant key confirmations.
|
|
82
83
|
*
|
|
83
84
|
* This is the DKG-specific verifier that the full ceremony verifier delegates
|
|
84
|
-
* to before it touches ballots or tally material.
|
|
85
|
+
* to before it touches ballots or tally material. It consumes a public signed
|
|
86
|
+
* transcript plus `key-derivation-confirmation` payloads from every qualified
|
|
87
|
+
* participant. It does not implement a public post-Feldman
|
|
88
|
+
* complaint/reconstruction phase, so it is a participant-confirmed transcript
|
|
89
|
+
* verifier rather than a fully public-data-only GJKR verifier. Lowering this
|
|
90
|
+
* requirement to threshold-many confirmations is out of scope unless that
|
|
91
|
+
* missing public consistency machinery is added.
|
|
85
92
|
*/
|
|
86
93
|
export declare const verifyDKGTranscript: (input: VerifyDKGTranscriptInput) => Promise<VerifiedDKGTranscript>;
|
package/dist/dkg/verification.js
CHANGED
|
@@ -659,10 +659,17 @@ const verifyCheckpointedDKGTranscript = async (input, setup) => {
|
|
|
659
659
|
/**
|
|
660
660
|
* Verifies a DKG transcript, its signatures, Feldman extraction proofs, the
|
|
661
661
|
* exact claimed threshold degree, accepted complaint outcomes, the DKG
|
|
662
|
-
* transcript hash,
|
|
662
|
+
* transcript hash, the announced joint public key, and unanimous qualified
|
|
663
|
+
* participant key confirmations.
|
|
663
664
|
*
|
|
664
665
|
* This is the DKG-specific verifier that the full ceremony verifier delegates
|
|
665
|
-
* to before it touches ballots or tally material.
|
|
666
|
+
* to before it touches ballots or tally material. It consumes a public signed
|
|
667
|
+
* transcript plus `key-derivation-confirmation` payloads from every qualified
|
|
668
|
+
* participant. It does not implement a public post-Feldman
|
|
669
|
+
* complaint/reconstruction phase, so it is a participant-confirmed transcript
|
|
670
|
+
* verifier rather than a fully public-data-only GJKR verifier. Lowering this
|
|
671
|
+
* requirement to threshold-many confirmations is out of scope unless that
|
|
672
|
+
* missing public consistency machinery is added.
|
|
666
673
|
*/
|
|
667
674
|
export const verifyDKGTranscript = async (input) => {
|
|
668
675
|
const auditedTranscript = await auditSignedPayloads(input.transcript);
|
package/dist/protocol/types.d.ts
CHANGED
|
@@ -136,7 +136,7 @@ export type FeldmanCommitmentPayload = BaseProtocolPayload & {
|
|
|
136
136
|
}[];
|
|
137
137
|
};
|
|
138
138
|
/**
|
|
139
|
-
* Final
|
|
139
|
+
* Final participant confirmation payload for the derived joint key.
|
|
140
140
|
*/
|
|
141
141
|
export type KeyDerivationConfirmation = BaseProtocolPayload & {
|
|
142
142
|
readonly messageType: 'key-derivation-confirmation';
|
|
@@ -279,14 +279,15 @@ export type VerifyDecryptionSharePayloadsByOptionInput = {
|
|
|
279
279
|
* Input bundle for full ceremony verification across all published options.
|
|
280
280
|
*
|
|
281
281
|
* This is the top-level verifier input that an auditor or bulletin-board
|
|
282
|
-
* reader supplies when replaying a full ceremony
|
|
282
|
+
* reader supplies when replaying a full ceremony from the published board,
|
|
283
|
+
* including the full ballot-close slot instead of a preselected close record.
|
|
283
284
|
*/
|
|
284
285
|
export type VerifyElectionCeremonyInput = {
|
|
285
286
|
readonly manifest: ElectionManifest;
|
|
286
287
|
readonly sessionId: string;
|
|
287
288
|
readonly dkgTranscript: readonly SignedPayload[];
|
|
288
289
|
readonly ballotPayloads: readonly SignedPayload<BallotSubmissionPayload>[];
|
|
289
|
-
readonly
|
|
290
|
+
readonly ballotClosePayloads: readonly SignedPayload<BallotClosePayload>[];
|
|
290
291
|
readonly decryptionSharePayloads: readonly SignedPayload<DecryptionSharePayload>[];
|
|
291
292
|
readonly tallyPublications?: readonly SignedPayload<TallyPublicationPayload>[];
|
|
292
293
|
};
|
|
@@ -4,8 +4,9 @@ import { type VerifiedOptionBallotAggregation } from './voting-ballot-aggregatio
|
|
|
4
4
|
* Verifies typed ballot-submission payloads and recomputes one aggregate tally
|
|
5
5
|
* ciphertext per manifest option.
|
|
6
6
|
*
|
|
7
|
-
* This is the public entry point for applications that already
|
|
8
|
-
*
|
|
9
|
-
*
|
|
7
|
+
* This is the public entry point for applications that already collected
|
|
8
|
+
* signed ballot payloads and want the per-option verified ciphertext
|
|
9
|
+
* aggregates that feed threshold decryption. The helper re-audits the signed
|
|
10
|
+
* payloads before it decodes and aggregates them.
|
|
10
11
|
*/
|
|
11
12
|
export declare const verifyBallotSubmissionPayloadsByOption: (input: VerifyBallotSubmissionPayloadsByOptionInput) => Promise<readonly VerifiedOptionBallotAggregation[]>;
|
|
@@ -40,9 +40,10 @@ const verifyAuditedBallotSubmissionPayloadsByOption = async (input) => {
|
|
|
40
40
|
* Verifies typed ballot-submission payloads and recomputes one aggregate tally
|
|
41
41
|
* ciphertext per manifest option.
|
|
42
42
|
*
|
|
43
|
-
* This is the public entry point for applications that already
|
|
44
|
-
*
|
|
45
|
-
*
|
|
43
|
+
* This is the public entry point for applications that already collected
|
|
44
|
+
* signed ballot payloads and want the per-option verified ciphertext
|
|
45
|
+
* aggregates that feed threshold decryption. The helper re-audits the signed
|
|
46
|
+
* payloads before it decodes and aggregates them.
|
|
46
47
|
*/
|
|
47
48
|
export const verifyBallotSubmissionPayloadsByOption = async (input) => {
|
|
48
49
|
const context = await buildVotingManifestContext(input.manifest, input.sessionId);
|
|
@@ -5,6 +5,7 @@ import type { VerifiedOptionDecryptionShares, VerifyDecryptionSharePayloadsByOpt
|
|
|
5
5
|
*
|
|
6
6
|
* This is the public entry point for applications that have already accepted a
|
|
7
7
|
* DKG transcript and verified ballot aggregates and now need to validate the
|
|
8
|
-
* published threshold shares.
|
|
8
|
+
* published threshold shares. The helper re-audits the signed share payloads
|
|
9
|
+
* before it groups and verifies them.
|
|
9
10
|
*/
|
|
10
11
|
export declare const verifyDecryptionSharePayloadsByOption: (input: VerifyDecryptionSharePayloadsByOptionInput) => Promise<readonly VerifiedOptionDecryptionShares[]>;
|
|
@@ -98,7 +98,8 @@ const verifyAuditedDecryptionSharePayloadsByOption = async (input) => {
|
|
|
98
98
|
*
|
|
99
99
|
* This is the public entry point for applications that have already accepted a
|
|
100
100
|
* DKG transcript and verified ballot aggregates and now need to validate the
|
|
101
|
-
* published threshold shares.
|
|
101
|
+
* published threshold shares. The helper re-audits the signed share payloads
|
|
102
|
+
* before it groups and verifies them.
|
|
102
103
|
*/
|
|
103
104
|
export const verifyDecryptionSharePayloadsByOption = async (input) => {
|
|
104
105
|
const context = await buildVotingManifestContext(input.manifest, input.sessionId);
|
|
@@ -66,8 +66,8 @@ export type ElectionVerificationResult = {
|
|
|
66
66
|
};
|
|
67
67
|
/**
|
|
68
68
|
* Replays the published ceremony from manifest to tally, including board audit,
|
|
69
|
-
* DKG verification, ballot
|
|
70
|
-
* per-option tally checks.
|
|
69
|
+
* DKG verification, full ballot-close-slot audit, ballot verification,
|
|
70
|
+
* decryption-share verification, and per-option tally checks.
|
|
71
71
|
*
|
|
72
72
|
* This is the main verifier entry point for callers that want failures to
|
|
73
73
|
* abort immediately.
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* This module is the shortest path for auditors and bulletin-board readers who
|
|
5
5
|
* want one call that replays manifest validation, board audit, DKG, ballots,
|
|
6
|
-
* decryption shares, and tally checks.
|
|
6
|
+
* the full ballot-close slot, decryption shares, and tally checks.
|
|
7
7
|
*/
|
|
8
8
|
import { InvalidPayloadError } from '../core/index.js';
|
|
9
9
|
import { decodeScalar } from '../core/ristretto.js';
|
|
@@ -127,8 +127,8 @@ const verifyBallotClosePayload = (input) => {
|
|
|
127
127
|
};
|
|
128
128
|
/**
|
|
129
129
|
* Replays the published ceremony from manifest to tally, including board audit,
|
|
130
|
-
* DKG verification, ballot
|
|
131
|
-
* per-option tally checks.
|
|
130
|
+
* DKG verification, full ballot-close-slot audit, ballot verification,
|
|
131
|
+
* decryption-share verification, and per-option tally checks.
|
|
132
132
|
*
|
|
133
133
|
* This is the main verifier entry point for callers that want failures to
|
|
134
134
|
* abort immediately.
|
|
@@ -150,9 +150,7 @@ export const verifyElectionCeremony = async (input) => {
|
|
|
150
150
|
try {
|
|
151
151
|
dkgAudit = await auditSignedPayloads(input.dkgTranscript);
|
|
152
152
|
ballotAudit = await auditSignedPayloads(input.ballotPayloads);
|
|
153
|
-
ballotCloseAudit = await auditSignedPayloads(
|
|
154
|
-
input.ballotClosePayload,
|
|
155
|
-
]);
|
|
153
|
+
ballotCloseAudit = await auditSignedPayloads(input.ballotClosePayloads);
|
|
156
154
|
decryptionAudit = await auditSignedPayloads(input.decryptionSharePayloads);
|
|
157
155
|
tallyAudit =
|
|
158
156
|
input.tallyPublications === undefined ||
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "threshold-elgamal",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"description": "A browser-native TypeScript ElGamal library for Ristretto255-based research prototypes, shipping additive ElGamal, threshold decryption, protocol helpers, board auditing, transport primitives, and log-driven DKG state machines.",
|
|
5
5
|
"author": "Piotr Piech <piotr@piech.dev>",
|
|
6
6
|
"license": "MPL-2.0",
|