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/dist/protocol/types.d.ts
CHANGED
|
@@ -1,12 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public protocol payload and verification types.
|
|
3
|
+
*
|
|
4
|
+
* These types describe the signed board records that move through manifest
|
|
5
|
+
* publication, DKG, ballot casting, decryption-share publication, and final
|
|
6
|
+
* tally verification.
|
|
7
|
+
*/
|
|
1
8
|
import type { EncodedPoint } from '../core/types.js';
|
|
2
9
|
import type { VerifiedDKGTranscript } from '../dkg/verification.js';
|
|
3
10
|
import type { DecryptionShare } from '../threshold/types.js';
|
|
4
11
|
import type { EncodedAuthPublicKey, EncodedTransportPrivateKey, EncodedTransportPublicKey } from '../transport/types.js';
|
|
5
|
-
/**
|
|
12
|
+
/**
|
|
13
|
+
* Canonical protocol payload type identifiers for the supported ceremony.
|
|
14
|
+
*/
|
|
6
15
|
export type ProtocolMessageType = 'manifest-publication' | 'registration' | 'manifest-acceptance' | 'phase-checkpoint' | 'pedersen-commitment' | 'encrypted-dual-share' | 'complaint' | 'complaint-resolution' | 'feldman-commitment' | 'key-derivation-confirmation' | 'ballot-submission' | 'ballot-close' | 'decryption-share' | 'tally-publication';
|
|
7
16
|
/** Complaint reasons recognized by the protocol layer. */
|
|
8
17
|
export type ComplaintReason = 'aes-gcm-failure' | 'malformed-plaintext' | 'pedersen-failure';
|
|
9
|
-
/**
|
|
18
|
+
/**
|
|
19
|
+
* Shared fields present on every unsigned protocol payload.
|
|
20
|
+
*
|
|
21
|
+
* These fields bind each payload to one manifest, session, participant, and
|
|
22
|
+
* protocol phase.
|
|
23
|
+
*/
|
|
10
24
|
export type BaseProtocolPayload = {
|
|
11
25
|
readonly protocolVersion: string;
|
|
12
26
|
readonly sessionId: string;
|
|
@@ -34,14 +48,23 @@ export type EncodedDisjunctiveBranch = {
|
|
|
34
48
|
export type EncodedDisjunctiveProof = {
|
|
35
49
|
readonly branches: readonly EncodedDisjunctiveBranch[];
|
|
36
50
|
};
|
|
37
|
-
/**
|
|
51
|
+
/**
|
|
52
|
+
* Registration payload carrying ceremony auth and transport keys.
|
|
53
|
+
*
|
|
54
|
+
* This is the public source of truth for the accepted roster.
|
|
55
|
+
*/
|
|
38
56
|
export type RegistrationPayload = BaseProtocolPayload & {
|
|
39
57
|
readonly messageType: 'registration';
|
|
40
58
|
readonly rosterHash: string;
|
|
41
59
|
readonly authPublicKey: EncodedAuthPublicKey;
|
|
42
60
|
readonly transportPublicKey: EncodedTransportPublicKey;
|
|
43
61
|
};
|
|
44
|
-
/**
|
|
62
|
+
/**
|
|
63
|
+
* Participant-signed manifest acceptance payload.
|
|
64
|
+
*
|
|
65
|
+
* This records acceptance of the frozen manifest and roster hash for one
|
|
66
|
+
* assigned participant index.
|
|
67
|
+
*/
|
|
45
68
|
export type ManifestAcceptancePayload = BaseProtocolPayload & {
|
|
46
69
|
readonly messageType: 'manifest-acceptance';
|
|
47
70
|
readonly rosterHash: string;
|
|
@@ -55,12 +78,21 @@ export type PhaseCheckpointPayload = BaseProtocolPayload & {
|
|
|
55
78
|
readonly checkpointTranscriptHash: string;
|
|
56
79
|
readonly qualifiedParticipantIndices: readonly number[];
|
|
57
80
|
};
|
|
58
|
-
/**
|
|
81
|
+
/**
|
|
82
|
+
* Broadcast payload carrying Pedersen coefficient commitments.
|
|
83
|
+
*
|
|
84
|
+
* This belongs to DKG phase 1.
|
|
85
|
+
*/
|
|
59
86
|
export type PedersenCommitmentPayload = BaseProtocolPayload & {
|
|
60
87
|
readonly messageType: 'pedersen-commitment';
|
|
61
88
|
readonly commitments: readonly string[];
|
|
62
89
|
};
|
|
63
|
-
/**
|
|
90
|
+
/**
|
|
91
|
+
* Encrypted share-envelope payload for the share-distribution step.
|
|
92
|
+
*
|
|
93
|
+
* This publishes the sender-ephemeral envelope metadata for one dealer to one
|
|
94
|
+
* recipient in DKG phase 1.
|
|
95
|
+
*/
|
|
64
96
|
export type EncryptedDualSharePayload = BaseProtocolPayload & {
|
|
65
97
|
readonly messageType: 'encrypted-dual-share';
|
|
66
98
|
readonly recipientIndex: number;
|
|
@@ -89,7 +121,11 @@ export type ComplaintResolutionPayload = BaseProtocolPayload & {
|
|
|
89
121
|
readonly suite: 'X25519';
|
|
90
122
|
readonly revealedEphemeralPrivateKey: EncodedTransportPrivateKey;
|
|
91
123
|
};
|
|
92
|
-
/**
|
|
124
|
+
/**
|
|
125
|
+
* Broadcast payload carrying Feldman commitments and coefficient proofs.
|
|
126
|
+
*
|
|
127
|
+
* This belongs to DKG phase 3.
|
|
128
|
+
*/
|
|
93
129
|
export type FeldmanCommitmentPayload = BaseProtocolPayload & {
|
|
94
130
|
readonly messageType: 'feldman-commitment';
|
|
95
131
|
readonly commitments: readonly string[];
|
|
@@ -107,19 +143,32 @@ export type KeyDerivationConfirmation = BaseProtocolPayload & {
|
|
|
107
143
|
readonly dkgTranscriptHash: string;
|
|
108
144
|
readonly publicKey: EncodedPoint;
|
|
109
145
|
};
|
|
110
|
-
/**
|
|
146
|
+
/**
|
|
147
|
+
* Signed manifest-publication payload anchoring the frozen manifest.
|
|
148
|
+
*
|
|
149
|
+
* This is the first public payload in the supported ceremony.
|
|
150
|
+
*/
|
|
111
151
|
export type ManifestPublicationPayload = BaseProtocolPayload & {
|
|
112
152
|
readonly messageType: 'manifest-publication';
|
|
113
153
|
readonly manifest: ElectionManifest;
|
|
114
154
|
};
|
|
115
|
-
/**
|
|
155
|
+
/**
|
|
156
|
+
* Signed additive ballot payload for one participant and one option slot.
|
|
157
|
+
*
|
|
158
|
+
* A complete voter ballot is represented as one such payload per option.
|
|
159
|
+
*/
|
|
116
160
|
export type BallotSubmissionPayload = BaseProtocolPayload & {
|
|
117
161
|
readonly messageType: 'ballot-submission';
|
|
118
162
|
readonly optionIndex: number;
|
|
119
163
|
readonly ciphertext: EncodedCiphertext;
|
|
120
164
|
readonly proof: EncodedDisjunctiveProof;
|
|
121
165
|
};
|
|
122
|
-
/**
|
|
166
|
+
/**
|
|
167
|
+
* Signed organizer payload that freezes which participants are counted.
|
|
168
|
+
*
|
|
169
|
+
* This is the cutoff record that determines the accepted ballot set used for
|
|
170
|
+
* tallying.
|
|
171
|
+
*/
|
|
123
172
|
export type BallotClosePayload = BaseProtocolPayload & {
|
|
124
173
|
readonly messageType: 'ballot-close';
|
|
125
174
|
readonly countedParticipantIndices: readonly number[];
|
|
@@ -136,7 +185,12 @@ export type DecryptionSharePayload = BaseProtocolPayload & {
|
|
|
136
185
|
readonly decryptionShare: EncodedPoint;
|
|
137
186
|
readonly proof: EncodedCompactProof;
|
|
138
187
|
};
|
|
139
|
-
/**
|
|
188
|
+
/**
|
|
189
|
+
* Signed tally-publication payload for the recovered additive tally.
|
|
190
|
+
*
|
|
191
|
+
* This is the optional published record checked against the verifier's own
|
|
192
|
+
* recomputed tally.
|
|
193
|
+
*/
|
|
140
194
|
export type TallyPublicationPayload = BaseProtocolPayload & {
|
|
141
195
|
readonly messageType: 'tally-publication';
|
|
142
196
|
readonly optionIndex: number;
|
|
@@ -145,18 +199,42 @@ export type TallyPublicationPayload = BaseProtocolPayload & {
|
|
|
145
199
|
readonly tally: string;
|
|
146
200
|
readonly decryptionParticipantIndices: readonly number[];
|
|
147
201
|
};
|
|
148
|
-
/**
|
|
202
|
+
/**
|
|
203
|
+
* Union of all unsigned protocol payload shapes that may appear on the board.
|
|
204
|
+
*/
|
|
149
205
|
export type ProtocolPayload = ManifestPublicationPayload | RegistrationPayload | ManifestAcceptancePayload | PhaseCheckpointPayload | PedersenCommitmentPayload | EncryptedDualSharePayload | ComplaintPayload | ComplaintResolutionPayload | FeldmanCommitmentPayload | KeyDerivationConfirmation | BallotSubmissionPayload | BallotClosePayload | DecryptionSharePayload | TallyPublicationPayload;
|
|
150
|
-
/**
|
|
206
|
+
/**
|
|
207
|
+
* Unsigned protocol payload paired with an authentication signature.
|
|
208
|
+
*
|
|
209
|
+
* This is the canonical board record shape accepted by the audit and
|
|
210
|
+
* verification layers.
|
|
211
|
+
*/
|
|
151
212
|
export type SignedPayload<TPayload extends ProtocolPayload = ProtocolPayload> = {
|
|
152
213
|
readonly payload: TPayload;
|
|
153
214
|
/** Raw Ed25519 signature bytes encoded as lowercase hex. */
|
|
154
215
|
readonly signature: string;
|
|
155
216
|
};
|
|
156
|
-
/**
|
|
217
|
+
/**
|
|
218
|
+
* Canonical election-manifest shape bound into protocol transcripts.
|
|
219
|
+
*
|
|
220
|
+
* The manifest is intentionally compact: it fixes the frozen roster hash,
|
|
221
|
+
* option list, and one explicit global score range, while participant count
|
|
222
|
+
* and threshold are derived later from the accepted registration roster.
|
|
223
|
+
*/
|
|
224
|
+
export type ScoreRange = {
|
|
225
|
+
readonly min: number;
|
|
226
|
+
readonly max: number;
|
|
227
|
+
};
|
|
228
|
+
/**
|
|
229
|
+
* Canonical election-manifest shape bound into protocol transcripts.
|
|
230
|
+
*
|
|
231
|
+
* The score range applies uniformly to every option slot in the supported
|
|
232
|
+
* workflow.
|
|
233
|
+
*/
|
|
157
234
|
export type ElectionManifest = {
|
|
158
235
|
readonly rosterHash: string;
|
|
159
236
|
readonly optionList: readonly string[];
|
|
237
|
+
readonly scoreRange: ScoreRange;
|
|
160
238
|
};
|
|
161
239
|
/**
|
|
162
240
|
* Input bundle for verifying typed ballot payloads.
|
|
@@ -169,7 +247,12 @@ type VerifyBallotSubmissionPayloadsInput = {
|
|
|
169
247
|
};
|
|
170
248
|
/** Input bundle for verifying typed ballot payloads across all options. */
|
|
171
249
|
export type VerifyBallotSubmissionPayloadsByOptionInput = VerifyBallotSubmissionPayloadsInput;
|
|
172
|
-
/**
|
|
250
|
+
/**
|
|
251
|
+
* Verified typed decryption-share payload.
|
|
252
|
+
*
|
|
253
|
+
* This pairs the original signed payload with the decoded low-level share used
|
|
254
|
+
* in final tally recomputation.
|
|
255
|
+
*/
|
|
173
256
|
export type VerifiedDecryptionSharePayload = {
|
|
174
257
|
readonly payload: SignedPayload<DecryptionSharePayload>;
|
|
175
258
|
readonly share: DecryptionShare;
|
|
@@ -192,7 +275,12 @@ export type VerifyDecryptionSharePayloadsByOptionInput = {
|
|
|
192
275
|
readonly manifest: ElectionManifest;
|
|
193
276
|
readonly sessionId: string;
|
|
194
277
|
};
|
|
195
|
-
/**
|
|
278
|
+
/**
|
|
279
|
+
* Input bundle for full ceremony verification across all published options.
|
|
280
|
+
*
|
|
281
|
+
* This is the top-level verifier input that an auditor or bulletin-board
|
|
282
|
+
* reader supplies when replaying a full ceremony.
|
|
283
|
+
*/
|
|
196
284
|
export type VerifyElectionCeremonyInput = {
|
|
197
285
|
readonly manifest: ElectionManifest;
|
|
198
286
|
readonly sessionId: string;
|
|
@@ -202,7 +290,12 @@ export type VerifyElectionCeremonyInput = {
|
|
|
202
290
|
readonly decryptionSharePayloads: readonly SignedPayload<DecryptionSharePayload>[];
|
|
203
291
|
readonly tallyPublications?: readonly SignedPayload<TallyPublicationPayload>[];
|
|
204
292
|
};
|
|
205
|
-
/**
|
|
293
|
+
/**
|
|
294
|
+
* Verified published tally for one option slot.
|
|
295
|
+
*
|
|
296
|
+
* The full ceremony verifier returns one of these per manifest option after
|
|
297
|
+
* replaying ballots, decryption shares, and optional tally publications.
|
|
298
|
+
*/
|
|
206
299
|
export type VerifiedPublishedOptionVotingResult = {
|
|
207
300
|
readonly optionIndex: number;
|
|
208
301
|
readonly ballots: import('./voting-ballot-aggregation.js').VerifiedOptionBallotAggregation;
|
|
@@ -1,12 +1,21 @@
|
|
|
1
1
|
import type { EncodedAuthPublicKey, EncodedTransportPublicKey } from '../transport/types.js';
|
|
2
2
|
import type { RegistrationPayload, SignedPayload } from './types.js';
|
|
3
|
-
/**
|
|
3
|
+
/**
|
|
4
|
+
* Roster entry used for deterministic roster hashing.
|
|
5
|
+
*
|
|
6
|
+
* This is the minimal frozen identity view derived from accepted registrations.
|
|
7
|
+
*/
|
|
4
8
|
export type RosterEntry = {
|
|
5
9
|
readonly participantIndex: number;
|
|
6
10
|
readonly authPublicKey: EncodedAuthPublicKey;
|
|
7
11
|
readonly transportPublicKey: EncodedTransportPublicKey;
|
|
8
12
|
};
|
|
9
|
-
/**
|
|
13
|
+
/**
|
|
14
|
+
* Verified protocol-signature result with the frozen registration roster.
|
|
15
|
+
*
|
|
16
|
+
* Downstream verifiers reuse this result instead of rebuilding the roster map
|
|
17
|
+
* for every phase.
|
|
18
|
+
*/
|
|
10
19
|
export type VerifiedProtocolSignatures = {
|
|
11
20
|
readonly participantCount: number;
|
|
12
21
|
readonly registrations: readonly SignedPayload<RegistrationPayload>[];
|
|
@@ -16,8 +25,7 @@ export type VerifiedProtocolSignatures = {
|
|
|
16
25
|
/**
|
|
17
26
|
* Hashes a deterministic roster view with SHA-256.
|
|
18
27
|
*
|
|
19
|
-
*
|
|
20
|
-
* @returns Lowercase hexadecimal roster hash.
|
|
28
|
+
* Manifest creation and registration verification both depend on this digest.
|
|
21
29
|
*/
|
|
22
30
|
export declare const hashRosterEntries: (rosterEntries: readonly RosterEntry[]) => Promise<string>;
|
|
23
31
|
/**
|
|
@@ -28,8 +36,7 @@ export declare const hashRosterEntries: (rosterEntries: readonly RosterEntry[])
|
|
|
28
36
|
* same registration payload. Every later payload is verified against the
|
|
29
37
|
* registered auth key for its participant index.
|
|
30
38
|
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
* @returns Verified registration roster and derived roster hash.
|
|
39
|
+
* This is the signature gate that stands between raw board data and every
|
|
40
|
+
* later semantic verifier.
|
|
34
41
|
*/
|
|
35
42
|
export declare const verifySignedProtocolPayloads: (signedPayloads: readonly SignedPayload[], participantCount?: number) => Promise<VerifiedProtocolSignatures>;
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Registration-roster hashing and signature verification for published
|
|
3
|
+
* protocol payloads.
|
|
4
|
+
*/
|
|
1
5
|
import { bytesToHex } from '../core/bytes.js';
|
|
2
6
|
import { InvalidPayloadError, assertValidParticipantIndex, sha256, utf8ToBytes, } from '../core/index.js';
|
|
3
7
|
import { importAuthPublicKey, verifyPayloadSignature } from '../transport/auth.js';
|
|
@@ -51,8 +55,7 @@ const canonicalizeRosterEntries = (rosterEntries) => {
|
|
|
51
55
|
/**
|
|
52
56
|
* Hashes a deterministic roster view with SHA-256.
|
|
53
57
|
*
|
|
54
|
-
*
|
|
55
|
-
* @returns Lowercase hexadecimal roster hash.
|
|
58
|
+
* Manifest creation and registration verification both depend on this digest.
|
|
56
59
|
*/
|
|
57
60
|
export const hashRosterEntries = async (rosterEntries) => bytesToHex(await sha256(utf8ToBytes(canonicalizeRosterEntries(rosterEntries))));
|
|
58
61
|
const assertUniqueParticipantIndices = (payloads, participantCount) => {
|
|
@@ -89,9 +92,8 @@ const registrationKey = (payload) => ({
|
|
|
89
92
|
* same registration payload. Every later payload is verified against the
|
|
90
93
|
* registered auth key for its participant index.
|
|
91
94
|
*
|
|
92
|
-
*
|
|
93
|
-
*
|
|
94
|
-
* @returns Verified registration roster and derived roster hash.
|
|
95
|
+
* This is the signature gate that stands between raw board data and every
|
|
96
|
+
* later semantic verifier.
|
|
95
97
|
*/
|
|
96
98
|
export const verifySignedProtocolPayloads = async (signedPayloads, participantCount) => {
|
|
97
99
|
const registrations = signedPayloads.filter((payload) => payload.payload.messageType === 'registration');
|
|
@@ -9,13 +9,21 @@ export type BallotTranscriptEntry = {
|
|
|
9
9
|
readonly ciphertext: ElGamalCiphertext;
|
|
10
10
|
readonly proof: DisjunctiveProof;
|
|
11
11
|
};
|
|
12
|
-
/**
|
|
12
|
+
/**
|
|
13
|
+
* Result of verifying and aggregating a ballot transcript.
|
|
14
|
+
*
|
|
15
|
+
* This is the bridge between ballot verification and threshold decryption.
|
|
16
|
+
*/
|
|
13
17
|
export type VerifiedBallotAggregation = {
|
|
14
18
|
readonly aggregate: VerifiedAggregateCiphertext;
|
|
15
19
|
readonly ballots: readonly BallotTranscriptEntry[];
|
|
16
20
|
readonly transcriptHash: string;
|
|
17
21
|
};
|
|
18
|
-
/**
|
|
22
|
+
/**
|
|
23
|
+
* Verified additive ballot aggregation for one manifest option slot.
|
|
24
|
+
*
|
|
25
|
+
* The full ceremony verifier works one option at a time at this stage.
|
|
26
|
+
*/
|
|
19
27
|
export type VerifiedOptionBallotAggregation = VerifiedBallotAggregation & {
|
|
20
28
|
readonly optionIndex: number;
|
|
21
29
|
};
|
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ballot transcript verification and additive aggregation helpers.
|
|
3
|
+
*
|
|
4
|
+
* This module turns verified ballot ciphertexts into per-option aggregates that
|
|
5
|
+
* the decryption and tally stages can consume.
|
|
6
|
+
*/
|
|
1
7
|
import { bytesToHex } from '../core/bytes.js';
|
|
2
8
|
import { InvalidPayloadError, RISTRETTO_GROUP, assertInSubgroup, sha256, utf8ToBytes, } from '../core/index.js';
|
|
3
9
|
import { encodePoint, RISTRETTO_ZERO } from '../core/ristretto.js';
|
|
@@ -4,10 +4,8 @@ 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
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* @param input Typed ballot verification input.
|
|
11
|
-
* @returns Ordered per-option additive ballot aggregations.
|
|
7
|
+
* This is the public entry point for applications that already have
|
|
8
|
+
* signature-checked ballot payloads and want the per-option verified
|
|
9
|
+
* ciphertext aggregates that feed threshold decryption.
|
|
12
10
|
*/
|
|
13
11
|
export declare const verifyBallotSubmissionPayloadsByOption: (input: VerifyBallotSubmissionPayloadsByOptionInput) => Promise<readonly VerifiedOptionBallotAggregation[]>;
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public ballot-verification entry point for the supported score-voting flow.
|
|
3
|
+
*/
|
|
1
4
|
import { InvalidPayloadError } from '../core/index.js';
|
|
2
5
|
import { auditSignedPayloads } from './board-audit.js';
|
|
3
6
|
import { verifyAndAggregateBallotsByOption, } from './voting-ballot-aggregation.js';
|
|
@@ -37,11 +40,9 @@ const verifyAuditedBallotSubmissionPayloadsByOption = async (input) => {
|
|
|
37
40
|
* Verifies typed ballot-submission payloads and recomputes one aggregate tally
|
|
38
41
|
* ciphertext per manifest option.
|
|
39
42
|
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
* @param input Typed ballot verification input.
|
|
44
|
-
* @returns Ordered per-option additive ballot aggregations.
|
|
43
|
+
* This is the public entry point for applications that already have
|
|
44
|
+
* signature-checked ballot payloads and want the per-option verified
|
|
45
|
+
* ciphertext aggregates that feed threshold decryption.
|
|
45
46
|
*/
|
|
46
47
|
export const verifyBallotSubmissionPayloadsByOption = async (input) => {
|
|
47
48
|
const context = await buildVotingManifestContext(input.manifest, input.sessionId);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ElGamalCiphertext } from '../elgamal/types.js';
|
|
2
2
|
import type { DLEQProof, DisjunctiveProof } from '../proofs/types.js';
|
|
3
|
-
import type { EncodedCiphertext, EncodedCompactProof, EncodedDisjunctiveProof } from './types.js';
|
|
3
|
+
import type { EncodedCiphertext, EncodedCompactProof, EncodedDisjunctiveProof, ScoreRange } from './types.js';
|
|
4
4
|
/**
|
|
5
5
|
* Encodes an additive ciphertext into fixed-width protocol hex.
|
|
6
6
|
*
|
|
@@ -47,6 +47,11 @@ export declare const encodeDisjunctiveProof: (proof: DisjunctiveProof) => Encode
|
|
|
47
47
|
*/
|
|
48
48
|
export declare const decodeDisjunctiveProof: (proof: EncodedDisjunctiveProof) => DisjunctiveProof;
|
|
49
49
|
/**
|
|
50
|
-
*
|
|
50
|
+
* Expands one inclusive contiguous score range into its allowed plaintext
|
|
51
|
+
* domain.
|
|
52
|
+
*
|
|
53
|
+
* Ballot builders and verifiers pass the resulting values into the
|
|
54
|
+
* disjunctive-proof layer so each encrypted score can be proven to belong to
|
|
55
|
+
* the manifest-declared domain.
|
|
51
56
|
*/
|
|
52
|
-
export declare const
|
|
57
|
+
export declare const scoreRangeDomain: (scoreRange: ScoreRange) => readonly bigint[];
|
|
@@ -1,4 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Encode and decode helpers that bridge low-level cryptographic objects and
|
|
3
|
+
* their published protocol payload representations.
|
|
4
|
+
*/
|
|
1
5
|
import { decodePoint, decodeScalar, encodeScalar } from '../core/ristretto.js';
|
|
6
|
+
import { validateSupportedScoreRange } from './score-range.js';
|
|
2
7
|
/**
|
|
3
8
|
* Encodes an additive ciphertext into fixed-width protocol hex.
|
|
4
9
|
*
|
|
@@ -62,6 +67,17 @@ export const decodeDisjunctiveProof = (proof) => ({
|
|
|
62
67
|
branches: proof.branches.map((branch) => decodeCompactProof(branch)),
|
|
63
68
|
});
|
|
64
69
|
/**
|
|
65
|
-
*
|
|
70
|
+
* Expands one inclusive contiguous score range into its allowed plaintext
|
|
71
|
+
* domain.
|
|
72
|
+
*
|
|
73
|
+
* Ballot builders and verifiers pass the resulting values into the
|
|
74
|
+
* disjunctive-proof layer so each encrypted score can be proven to belong to
|
|
75
|
+
* the manifest-declared domain.
|
|
66
76
|
*/
|
|
67
|
-
export const
|
|
77
|
+
export const scoreRangeDomain = (scoreRange) => {
|
|
78
|
+
validateSupportedScoreRange(scoreRange, {
|
|
79
|
+
min: 'Score range min',
|
|
80
|
+
max: 'Score range max',
|
|
81
|
+
});
|
|
82
|
+
return Object.freeze(Array.from({ length: scoreRange.max - scoreRange.min + 1 }, (_value, index) => BigInt(scoreRange.min + index)));
|
|
83
|
+
};
|
|
@@ -3,10 +3,8 @@ import type { VerifiedOptionDecryptionShares, VerifyDecryptionSharePayloadsByOpt
|
|
|
3
3
|
* Verifies typed decryption-share payloads against the DKG transcript-derived
|
|
4
4
|
* trustee keys and one locally recomputed aggregate ciphertext per option slot.
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* @param input Typed decryption-share verification input.
|
|
10
|
-
* @returns Verified decryption shares grouped by option.
|
|
6
|
+
* This is the public entry point for applications that have already accepted a
|
|
7
|
+
* DKG transcript and verified ballot aggregates and now need to validate the
|
|
8
|
+
* published threshold shares.
|
|
11
9
|
*/
|
|
12
10
|
export declare const verifyDecryptionSharePayloadsByOption: (input: VerifyDecryptionSharePayloadsByOptionInput) => Promise<readonly VerifiedOptionDecryptionShares[]>;
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public decryption-share verification entry point for the supported voting
|
|
3
|
+
* workflow.
|
|
4
|
+
*/
|
|
1
5
|
import { InvalidPayloadError, RISTRETTO_GROUP, assertInSubgroupOrIdentity, } from '../core/index.js';
|
|
2
6
|
import { deriveTranscriptVerificationKey } from '../dkg/verification.js';
|
|
3
7
|
import { verifyDLEQProof } from '../proofs/dleq.js';
|
|
@@ -92,11 +96,9 @@ const verifyAuditedDecryptionSharePayloadsByOption = async (input) => {
|
|
|
92
96
|
* Verifies typed decryption-share payloads against the DKG transcript-derived
|
|
93
97
|
* trustee keys and one locally recomputed aggregate ciphertext per option slot.
|
|
94
98
|
*
|
|
95
|
-
*
|
|
96
|
-
*
|
|
97
|
-
*
|
|
98
|
-
* @param input Typed decryption-share verification input.
|
|
99
|
-
* @returns Verified decryption shares grouped by option.
|
|
99
|
+
* This is the public entry point for applications that have already accepted a
|
|
100
|
+
* DKG transcript and verified ballot aggregates and now need to validate the
|
|
101
|
+
* published threshold shares.
|
|
100
102
|
*/
|
|
101
103
|
export const verifyDecryptionSharePayloadsByOption = async (input) => {
|
|
102
104
|
const context = await buildVotingManifestContext(input.manifest, input.sessionId);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ProofContext } from '../proofs/types.js';
|
|
2
|
-
import type { DecryptionSharePayload, ElectionManifest,
|
|
2
|
+
import type { DecryptionSharePayload, ElectionManifest, RegistrationPayload, ProtocolPayload, SignedPayload, OptionAggregateInput } from './types.js';
|
|
3
3
|
export declare const BALLOT_SUBMISSION_PHASE = 5;
|
|
4
4
|
export declare const BALLOT_CLOSE_PHASE = 6;
|
|
5
5
|
export declare const DECRYPTION_SHARE_PHASE = 7;
|
|
@@ -10,6 +10,7 @@ type VotingManifestContext = {
|
|
|
10
10
|
readonly optionCount: number;
|
|
11
11
|
readonly protocolVersion: string;
|
|
12
12
|
readonly scoreDomainValues: readonly bigint[];
|
|
13
|
+
readonly scoreRangeMax: bigint;
|
|
13
14
|
readonly sessionId: string;
|
|
14
15
|
};
|
|
15
16
|
export declare const assertPhase: (payload: ProtocolPayload, expectedPhase: number, label: string) => void;
|
|
@@ -1,8 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared voting-workflow validation and context helpers.
|
|
3
|
+
*
|
|
4
|
+
* Ballot verification, decryption-share verification, tally verification, and
|
|
5
|
+
* the full ceremony verifier all reuse this layer.
|
|
6
|
+
*/
|
|
1
7
|
import { assertPositiveParticipantIndex, InvalidPayloadError, RISTRETTO_GROUP, } from '../core/index.js';
|
|
2
8
|
import { importAuthPublicKey, verifyPayloadSignature } from '../transport/auth.js';
|
|
3
9
|
import { hashElectionManifest, assertSupportedProtocolVersion, SHIPPED_PROTOCOL_VERSION, validateElectionManifest, } from './manifest.js';
|
|
4
10
|
import { signedProtocolPayloadBytes } from './payloads.js';
|
|
5
|
-
import {
|
|
11
|
+
import { scoreRangeDomain } from './voting-codecs.js';
|
|
6
12
|
export const BALLOT_SUBMISSION_PHASE = 5;
|
|
7
13
|
export const BALLOT_CLOSE_PHASE = 6;
|
|
8
14
|
export const DECRYPTION_SHARE_PHASE = 7;
|
|
@@ -47,7 +53,8 @@ export const buildVotingManifestContext = async (manifest, sessionId) => {
|
|
|
47
53
|
manifestHash: await hashElectionManifest(validatedManifest),
|
|
48
54
|
optionCount: validatedManifest.optionList.length,
|
|
49
55
|
protocolVersion: SHIPPED_PROTOCOL_VERSION,
|
|
50
|
-
scoreDomainValues:
|
|
56
|
+
scoreDomainValues: scoreRangeDomain(validatedManifest.scoreRange),
|
|
57
|
+
scoreRangeMax: BigInt(validatedManifest.scoreRange.max),
|
|
51
58
|
sessionId,
|
|
52
59
|
};
|
|
53
60
|
};
|
|
@@ -1,17 +1,31 @@
|
|
|
1
1
|
import { type VerifiedDKGTranscript } from '../dkg/verification.js';
|
|
2
2
|
import { type BoardAudit } from './board-audit.js';
|
|
3
3
|
import type { BallotClosePayload, BallotSubmissionPayload, DecryptionSharePayload, ElectionManifest, VerifyElectionCeremonyInput, VerifiedPublishedOptionVotingResult, TallyPublicationPayload } from './types.js';
|
|
4
|
-
/**
|
|
4
|
+
/**
|
|
5
|
+
* Stable high-level failure codes for full ceremony verification.
|
|
6
|
+
*
|
|
7
|
+
* Applications can key off these codes instead of parsing free-form error
|
|
8
|
+
* strings.
|
|
9
|
+
*/
|
|
5
10
|
export type ElectionVerificationErrorCode = 'MANIFEST_INVALID' | 'BOARD_INVALID' | 'DKG_INVALID' | 'SIGNATURE_INVALID' | 'BALLOT_INVALID' | 'DECRYPTION_INVALID' | 'TALLY_INVALID';
|
|
6
|
-
/**
|
|
11
|
+
/**
|
|
12
|
+
* Named verification stage used by the high-level ceremony verifier.
|
|
13
|
+
*/
|
|
7
14
|
export type ElectionVerificationStage = 'manifest' | 'board' | 'dkg' | 'signatures' | 'ballots' | 'decryption' | 'tally';
|
|
8
|
-
/**
|
|
15
|
+
/**
|
|
16
|
+
* Stable structured failure result returned by the non-throwing verifier.
|
|
17
|
+
*/
|
|
9
18
|
export type ElectionVerificationFailure = {
|
|
10
19
|
readonly code: ElectionVerificationErrorCode;
|
|
11
20
|
readonly stage: ElectionVerificationStage;
|
|
12
21
|
readonly reason: string;
|
|
13
22
|
};
|
|
14
|
-
/**
|
|
23
|
+
/**
|
|
24
|
+
* Detailed successful output from full ceremony verification.
|
|
25
|
+
*
|
|
26
|
+
* This bundles the derived DKG material, accepted ballot set, per-option
|
|
27
|
+
* tallies, and deterministic board-audit output.
|
|
28
|
+
*/
|
|
15
29
|
export type VerifiedElectionCeremony = {
|
|
16
30
|
readonly manifest: ElectionManifest;
|
|
17
31
|
readonly manifestHash: string;
|
|
@@ -38,7 +52,11 @@ export type VerifiedElectionCeremony = {
|
|
|
38
52
|
readonly dkg: VerifiedDKGTranscript;
|
|
39
53
|
readonly options: readonly VerifiedPublishedOptionVotingResult[];
|
|
40
54
|
};
|
|
41
|
-
/**
|
|
55
|
+
/**
|
|
56
|
+
* Non-throwing result shape for full ceremony verification.
|
|
57
|
+
*
|
|
58
|
+
* Most application integrations should prefer this over exceptions.
|
|
59
|
+
*/
|
|
42
60
|
export type ElectionVerificationResult = {
|
|
43
61
|
readonly ok: true;
|
|
44
62
|
readonly verified: VerifiedElectionCeremony;
|
|
@@ -51,36 +69,15 @@ export type ElectionVerificationResult = {
|
|
|
51
69
|
* DKG verification, ballot verification, decryption-share verification, and
|
|
52
70
|
* per-option tally checks.
|
|
53
71
|
*
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
* @example
|
|
58
|
-
* ```ts
|
|
59
|
-
* const verified = await verifyElectionCeremony(bundle);
|
|
60
|
-
*
|
|
61
|
-
* console.log(verified.boardAudit.overall.fingerprint);
|
|
62
|
-
* console.log(verified.countedParticipantIndices);
|
|
63
|
-
* console.log(verified.perOptionTallies);
|
|
64
|
-
* ```
|
|
72
|
+
* This is the main verifier entry point for callers that want failures to
|
|
73
|
+
* abort immediately.
|
|
65
74
|
*/
|
|
66
75
|
export declare const verifyElectionCeremony: (input: VerifyElectionCeremonyInput) => Promise<VerifiedElectionCeremony>;
|
|
67
76
|
/**
|
|
68
77
|
* Runs the full ceremony verifier and returns a structured success-or-failure
|
|
69
78
|
* result without throwing.
|
|
70
79
|
*
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
*
|
|
74
|
-
* @example
|
|
75
|
-
* ```ts
|
|
76
|
-
* const result = await tryVerifyElectionCeremony(bundle);
|
|
77
|
-
*
|
|
78
|
-
* if (!result.ok) {
|
|
79
|
-
* console.error(result.error.stage, result.error.code, result.error.reason);
|
|
80
|
-
* return;
|
|
81
|
-
* }
|
|
82
|
-
*
|
|
83
|
-
* console.log(result.verified.qualifiedParticipantIndices);
|
|
84
|
-
* ```
|
|
80
|
+
* This is the preferred integration point for applications that want stable
|
|
81
|
+
* failure stages and codes instead of exception handling.
|
|
85
82
|
*/
|
|
86
83
|
export declare const tryVerifyElectionCeremony: (input: VerifyElectionCeremonyInput) => Promise<ElectionVerificationResult>;
|