@digitaldefiance/ecies-lib 4.17.10 → 4.19.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.
Files changed (62) hide show
  1. package/README.md +3 -2
  2. package/package.json +2 -2
  3. package/src/lib/voting/threshold/ceremony-coordinator.d.ts +152 -0
  4. package/src/lib/voting/threshold/ceremony-coordinator.d.ts.map +1 -0
  5. package/src/lib/voting/threshold/ceremony-coordinator.js +316 -0
  6. package/src/lib/voting/threshold/ceremony-coordinator.js.map +1 -0
  7. package/src/lib/voting/threshold/decryption-combiner.d.ts.map +1 -1
  8. package/src/lib/voting/threshold/decryption-combiner.js +3 -3
  9. package/src/lib/voting/threshold/decryption-combiner.js.map +1 -1
  10. package/src/lib/voting/threshold/guardian-registry.d.ts +1 -1
  11. package/src/lib/voting/threshold/guardian-registry.d.ts.map +1 -1
  12. package/src/lib/voting/threshold/index.d.ts +11 -0
  13. package/src/lib/voting/threshold/index.d.ts.map +1 -1
  14. package/src/lib/voting/threshold/index.js +32 -1
  15. package/src/lib/voting/threshold/index.js.map +1 -1
  16. package/src/lib/voting/threshold/interfaces/partial-decryption.d.ts +2 -2
  17. package/src/lib/voting/threshold/interfaces/partial-decryption.d.ts.map +1 -1
  18. package/src/lib/voting/threshold/interval-scheduler.d.ts +123 -0
  19. package/src/lib/voting/threshold/interval-scheduler.d.ts.map +1 -0
  20. package/src/lib/voting/threshold/interval-scheduler.js +281 -0
  21. package/src/lib/voting/threshold/interval-scheduler.js.map +1 -0
  22. package/src/lib/voting/threshold/partial-decryption-service.d.ts.map +1 -1
  23. package/src/lib/voting/threshold/partial-decryption-service.js +16 -15
  24. package/src/lib/voting/threshold/partial-decryption-service.js.map +1 -1
  25. package/src/lib/voting/threshold/public-tally-feed.d.ts +100 -0
  26. package/src/lib/voting/threshold/public-tally-feed.d.ts.map +1 -0
  27. package/src/lib/voting/threshold/public-tally-feed.js +202 -0
  28. package/src/lib/voting/threshold/public-tally-feed.js.map +1 -0
  29. package/src/lib/voting/threshold/tally-verifier.d.ts +85 -0
  30. package/src/lib/voting/threshold/tally-verifier.d.ts.map +1 -0
  31. package/src/lib/voting/threshold/tally-verifier.js +169 -0
  32. package/src/lib/voting/threshold/tally-verifier.js.map +1 -0
  33. package/src/lib/voting/threshold/threshold-audit-log.d.ts +71 -0
  34. package/src/lib/voting/threshold/threshold-audit-log.d.ts.map +1 -0
  35. package/src/lib/voting/threshold/threshold-audit-log.js +243 -0
  36. package/src/lib/voting/threshold/threshold-audit-log.js.map +1 -0
  37. package/src/lib/voting/threshold/threshold-county-aggregator.d.ts +81 -0
  38. package/src/lib/voting/threshold/threshold-county-aggregator.d.ts.map +1 -0
  39. package/src/lib/voting/threshold/threshold-county-aggregator.js +154 -0
  40. package/src/lib/voting/threshold/threshold-county-aggregator.js.map +1 -0
  41. package/src/lib/voting/threshold/threshold-key-generator.d.ts.map +1 -1
  42. package/src/lib/voting/threshold/threshold-key-generator.js.map +1 -1
  43. package/src/lib/voting/threshold/threshold-national-aggregator.d.ts +95 -0
  44. package/src/lib/voting/threshold/threshold-national-aggregator.d.ts.map +1 -0
  45. package/src/lib/voting/threshold/threshold-national-aggregator.js +210 -0
  46. package/src/lib/voting/threshold/threshold-national-aggregator.js.map +1 -0
  47. package/src/lib/voting/threshold/threshold-poll-factory.d.ts +88 -0
  48. package/src/lib/voting/threshold/threshold-poll-factory.d.ts.map +1 -0
  49. package/src/lib/voting/threshold/threshold-poll-factory.js +156 -0
  50. package/src/lib/voting/threshold/threshold-poll-factory.js.map +1 -0
  51. package/src/lib/voting/threshold/threshold-poll.d.ts +76 -0
  52. package/src/lib/voting/threshold/threshold-poll.d.ts.map +1 -0
  53. package/src/lib/voting/threshold/threshold-poll.js +144 -0
  54. package/src/lib/voting/threshold/threshold-poll.js.map +1 -0
  55. package/src/lib/voting/threshold/threshold-precinct-aggregator.d.ts +86 -0
  56. package/src/lib/voting/threshold/threshold-precinct-aggregator.d.ts.map +1 -0
  57. package/src/lib/voting/threshold/threshold-precinct-aggregator.js +156 -0
  58. package/src/lib/voting/threshold/threshold-precinct-aggregator.js.map +1 -0
  59. package/src/lib/voting/threshold/threshold-state-aggregator.d.ts +85 -0
  60. package/src/lib/voting/threshold/threshold-state-aggregator.d.ts.map +1 -0
  61. package/src/lib/voting/threshold/threshold-state-aggregator.js +164 -0
  62. package/src/lib/voting/threshold/threshold-state-aggregator.js.map +1 -0
@@ -0,0 +1,144 @@
1
+ "use strict";
2
+ /**
3
+ * Threshold Poll
4
+ *
5
+ * Extends the standard Poll with threshold decryption support,
6
+ * integrating IntervalScheduler, CeremonyCoordinator, and PublicTallyFeed.
7
+ * Uses the same encryption (Paillier) and vote encoding as standard polls.
8
+ *
9
+ * @module voting/threshold
10
+ */
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.ThresholdPoll = void 0;
13
+ const poll_core_1 = require("../poll-core");
14
+ const ceremony_coordinator_1 = require("./ceremony-coordinator");
15
+ const interval_scheduler_1 = require("./interval-scheduler");
16
+ const public_tally_feed_1 = require("./public-tally-feed");
17
+ /**
18
+ * A poll with threshold decryption support.
19
+ *
20
+ * Wraps a standard Poll and adds:
21
+ * - Interval scheduling for periodic decryption ceremonies
22
+ * - Ceremony coordination for collecting Guardian partial decryptions
23
+ * - Public tally feed for broadcasting verified interval tallies
24
+ *
25
+ * Uses the same encryption and vote encoding as standard polls,
26
+ * ensuring full compatibility with existing vote encoders and talliers.
27
+ *
28
+ * @example
29
+ * ```typescript
30
+ * const poll = new ThresholdPoll(
31
+ * id, choices, method, authority, publicKey, thresholdConfig,
32
+ * );
33
+ *
34
+ * // Cast votes (same as standard poll)
35
+ * poll.vote(voter, encryptedVote);
36
+ *
37
+ * // Start interval scheduling
38
+ * poll.intervalScheduler.start(poll.id);
39
+ *
40
+ * // Close triggers final ceremony
41
+ * poll.close();
42
+ * ```
43
+ */
44
+ class ThresholdPoll {
45
+ _innerPoll;
46
+ _thresholdConfig;
47
+ _intervalConfig;
48
+ _intervalScheduler;
49
+ _ceremonyCoordinator;
50
+ _tallyFeed;
51
+ constructor(id, choices, method, authority, publicKey, config) {
52
+ // Create the inner standard poll (same encryption and vote encoding)
53
+ this._innerPoll = new poll_core_1.Poll(id, choices, method, authority, publicKey);
54
+ this._thresholdConfig = config.thresholdConfig;
55
+ this._intervalConfig = config.intervalConfig;
56
+ // Create interval scheduler and configure for this poll
57
+ this._intervalScheduler = new interval_scheduler_1.IntervalScheduler();
58
+ this._intervalScheduler.configure(id, config.intervalConfig);
59
+ // Create ceremony coordinator if key pair is provided
60
+ if (config.keyPair) {
61
+ this._ceremonyCoordinator = new ceremony_coordinator_1.CeremonyCoordinator(config.keyPair.publicKey, config.keyPair.verificationKeys, config.keyPair.theta, config.thresholdConfig, config.intervalConfig.ceremonyTimeoutMs);
62
+ }
63
+ else {
64
+ // Create a coordinator with the authority's public key
65
+ // (verification keys and theta will need to be set later when key pair is generated)
66
+ this._ceremonyCoordinator = new ceremony_coordinator_1.CeremonyCoordinator(publicKey, [], 0n, config.thresholdConfig, config.intervalConfig.ceremonyTimeoutMs);
67
+ }
68
+ // Create public tally feed
69
+ this._tallyFeed = new public_tally_feed_1.PublicTallyFeed();
70
+ }
71
+ // --- IThresholdPoll properties ---
72
+ get thresholdConfig() {
73
+ return this._thresholdConfig;
74
+ }
75
+ get intervalConfig() {
76
+ return this._intervalConfig;
77
+ }
78
+ get intervalScheduler() {
79
+ return this._intervalScheduler;
80
+ }
81
+ get ceremonyCoordinator() {
82
+ return this._ceremonyCoordinator;
83
+ }
84
+ get tallyFeed() {
85
+ return this._tallyFeed;
86
+ }
87
+ get isThresholdEnabled() {
88
+ return true;
89
+ }
90
+ // --- IPoll delegation ---
91
+ get id() {
92
+ return this._innerPoll.id;
93
+ }
94
+ get choices() {
95
+ return this._innerPoll.choices;
96
+ }
97
+ get method() {
98
+ return this._innerPoll.method;
99
+ }
100
+ get isClosed() {
101
+ return this._innerPoll.isClosed;
102
+ }
103
+ get voterCount() {
104
+ return this._innerPoll.voterCount;
105
+ }
106
+ get createdAt() {
107
+ return this._innerPoll.createdAt;
108
+ }
109
+ get closedAt() {
110
+ return this._innerPoll.closedAt;
111
+ }
112
+ get auditLog() {
113
+ return this._innerPoll.auditLog;
114
+ }
115
+ getEncryptedVotes() {
116
+ return this._innerPoll.getEncryptedVotes();
117
+ }
118
+ vote(voter, encryptedVote) {
119
+ const receipt = this._innerPoll.vote(voter, encryptedVote);
120
+ // Notify the interval scheduler of the new vote
121
+ try {
122
+ this._intervalScheduler.notifyVote(this.id);
123
+ }
124
+ catch {
125
+ // Scheduler may not be started yet; ignore
126
+ }
127
+ return receipt;
128
+ }
129
+ verifyReceipt(voter, receipt) {
130
+ return this._innerPoll.verifyReceipt(voter, receipt);
131
+ }
132
+ close() {
133
+ this._innerPoll.close();
134
+ // Trigger final decryption ceremony
135
+ try {
136
+ this._intervalScheduler.triggerFinal(this.id);
137
+ }
138
+ catch {
139
+ // Scheduler may not be configured; ignore
140
+ }
141
+ }
142
+ }
143
+ exports.ThresholdPoll = ThresholdPoll;
144
+ //# sourceMappingURL=threshold-poll.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"threshold-poll.js","sourceRoot":"","sources":["../../../../../../../packages/digitaldefiance-ecies-lib/src/lib/voting/threshold/threshold-poll.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,86 @@
1
+ /**
2
+ * Threshold Precinct Aggregator
3
+ *
4
+ * Extends the standard PrecinctAggregator with threshold decryption support,
5
+ * enabling interval decryption at the precinct level. Uses the same
6
+ * homomorphic aggregation as the base class but adds the ability to
7
+ * perform threshold decryption ceremonies via a CeremonyCoordinator.
8
+ *
9
+ * @module voting/threshold
10
+ */
11
+ import type { PublicKey } from 'paillier-bigint';
12
+ import type { PlatformID } from '../../../interfaces/platform-id';
13
+ import { PrecinctAggregator } from '../hierarchical-aggregator';
14
+ import type { ICheckpointManager } from '../interfaces/checkpoint-manager';
15
+ import type { JurisdictionConfig } from '../interfaces/jurisdiction-config';
16
+ import type { IVoteLogger } from '../interfaces/vote-logger';
17
+ import type { Poll } from '../poll-core';
18
+ import type { ICeremonyCoordinator } from './interfaces/ceremony-coordinator';
19
+ import type { IntervalTally } from './interfaces/interval-tally';
20
+ import type { IPublicTallyFeed } from './interfaces/public-tally-feed';
21
+ import type { IThresholdAggregator } from './interfaces/threshold-aggregator';
22
+ import type { ThresholdKeyConfig } from './interfaces/threshold-key-config';
23
+ /**
24
+ * Precinct-level aggregator with threshold decryption support.
25
+ *
26
+ * Inherits all standard precinct aggregation behavior (vote collection,
27
+ * homomorphic tallying, optional persistence) and adds the ability to
28
+ * perform interval decryptions via a CeremonyCoordinator.
29
+ *
30
+ * @example
31
+ * ```typescript
32
+ * const aggregator = new ThresholdPrecinctAggregator(
33
+ * poll, config, publicKey, thresholdConfig, tallyFeed,
34
+ * );
35
+ *
36
+ * // Cast votes as usual
37
+ * await aggregator.vote(voter, encryptedVote);
38
+ *
39
+ * // Perform interval decryption
40
+ * const tally = await aggregator.performIntervalDecryption(coordinator, 1);
41
+ * ```
42
+ */
43
+ export declare class ThresholdPrecinctAggregator<TID extends PlatformID = Uint8Array> extends PrecinctAggregator<TID> implements IThresholdAggregator<TID> {
44
+ private readonly _publicKey;
45
+ private readonly _thresholdConfig;
46
+ private readonly _tallyFeed?;
47
+ private readonly _intervalTallies;
48
+ private readonly _choices;
49
+ private readonly _pollId;
50
+ private _parentAggregator?;
51
+ constructor(poll: Poll<TID>, config: JurisdictionConfig<TID>, publicKey: PublicKey, thresholdConfig: ThresholdKeyConfig, tallyFeed?: IPublicTallyFeed<TID>, logger?: IVoteLogger<TID>, checkpointMgr?: ICheckpointManager<TID>);
52
+ /**
53
+ * Set the parent aggregator for result propagation.
54
+ */
55
+ setParent(parent: IThresholdAggregator<TID>): void;
56
+ /**
57
+ * Get the encrypted aggregate tally for this precinct.
58
+ *
59
+ * Uses the same homomorphic aggregation as the base PrecinctAggregator.
60
+ */
61
+ getEncryptedTally(): bigint[];
62
+ /**
63
+ * Perform an interval decryption at the precinct level.
64
+ *
65
+ * Starts a ceremony via the coordinator, waits for it to complete,
66
+ * and publishes the result to the tally feed.
67
+ *
68
+ * @param ceremonyCoordinator - The coordinator managing the ceremony
69
+ * @param intervalNumber - The interval number for this decryption
70
+ * @returns The decrypted interval tally
71
+ */
72
+ performIntervalDecryption(ceremonyCoordinator: ICeremonyCoordinator<TID>, intervalNumber: number): Promise<IntervalTally<TID>>;
73
+ /**
74
+ * Propagate an interval tally result to the parent aggregator.
75
+ */
76
+ propagateToParent(tally: IntervalTally<TID>): void;
77
+ /**
78
+ * Get all interval tallies produced by this aggregator.
79
+ */
80
+ getIntervalTallies(): readonly IntervalTally<TID>[];
81
+ /**
82
+ * Build an IntervalTally from decryption results.
83
+ */
84
+ private buildIntervalTally;
85
+ }
86
+ //# sourceMappingURL=threshold-precinct-aggregator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"threshold-precinct-aggregator.d.ts","sourceRoot":"","sources":["../../../../../../../packages/digitaldefiance-ecies-lib/src/lib/voting/threshold/threshold-precinct-aggregator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iCAAiC,CAAC;AAClE,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAChE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,kCAAkC,CAAC;AAC3E,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,mCAAmC,CAAC;AAC5E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAC7D,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AAEzC,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,mCAAmC,CAAC;AAC9E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AACjE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAC;AACvE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,mCAAmC,CAAC;AAC9E,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,mCAAmC,CAAC;AAE5E;;;;;;;;;;;;;;;;;;;GAmBG;AACH,qBAAa,2BAA2B,CAAC,GAAG,SAAS,UAAU,GAAG,UAAU,CAC1E,SAAQ,kBAAkB,CAAC,GAAG,CAC9B,YAAW,oBAAoB,CAAC,GAAG,CAAC;IAEpC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAY;IACvC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAqB;IACtD,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAwB;IACpD,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAA4B;IAC7D,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAoB;IAC7C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAM;IAC9B,OAAO,CAAC,iBAAiB,CAAC,CAA4B;gBAGpD,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC,EACf,MAAM,EAAE,kBAAkB,CAAC,GAAG,CAAC,EAC/B,SAAS,EAAE,SAAS,EACpB,eAAe,EAAE,kBAAkB,EACnC,SAAS,CAAC,EAAE,gBAAgB,CAAC,GAAG,CAAC,EACjC,MAAM,CAAC,EAAE,WAAW,CAAC,GAAG,CAAC,EACzB,aAAa,CAAC,EAAE,kBAAkB,CAAC,GAAG,CAAC;IAUzC;;OAEG;IACH,SAAS,CAAC,MAAM,EAAE,oBAAoB,CAAC,GAAG,CAAC,GAAG,IAAI;IAIlD;;;;OAIG;IACH,iBAAiB,IAAI,MAAM,EAAE;IAK7B;;;;;;;;;OASG;IACG,yBAAyB,CAC7B,mBAAmB,EAAE,oBAAoB,CAAC,GAAG,CAAC,EAC9C,cAAc,EAAE,MAAM,GACrB,OAAO,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC;IA+D9B;;OAEG;IACH,iBAAiB,CAAC,KAAK,EAAE,aAAa,CAAC,GAAG,CAAC,GAAG,IAAI;IAMlD;;OAEG;IACH,kBAAkB,IAAI,SAAS,aAAa,CAAC,GAAG,CAAC,EAAE;IAInD;;OAEG;IACH,OAAO,CAAC,kBAAkB;CA8B3B"}
@@ -0,0 +1,156 @@
1
+ "use strict";
2
+ /**
3
+ * Threshold Precinct Aggregator
4
+ *
5
+ * Extends the standard PrecinctAggregator with threshold decryption support,
6
+ * enabling interval decryption at the precinct level. Uses the same
7
+ * homomorphic aggregation as the base class but adds the ability to
8
+ * perform threshold decryption ceremonies via a CeremonyCoordinator.
9
+ *
10
+ * @module voting/threshold
11
+ */
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ exports.ThresholdPrecinctAggregator = void 0;
14
+ const hierarchical_aggregator_1 = require("../hierarchical-aggregator");
15
+ const ceremony_status_1 = require("./enumerations/ceremony-status");
16
+ /**
17
+ * Precinct-level aggregator with threshold decryption support.
18
+ *
19
+ * Inherits all standard precinct aggregation behavior (vote collection,
20
+ * homomorphic tallying, optional persistence) and adds the ability to
21
+ * perform interval decryptions via a CeremonyCoordinator.
22
+ *
23
+ * @example
24
+ * ```typescript
25
+ * const aggregator = new ThresholdPrecinctAggregator(
26
+ * poll, config, publicKey, thresholdConfig, tallyFeed,
27
+ * );
28
+ *
29
+ * // Cast votes as usual
30
+ * await aggregator.vote(voter, encryptedVote);
31
+ *
32
+ * // Perform interval decryption
33
+ * const tally = await aggregator.performIntervalDecryption(coordinator, 1);
34
+ * ```
35
+ */
36
+ class ThresholdPrecinctAggregator extends hierarchical_aggregator_1.PrecinctAggregator {
37
+ _publicKey;
38
+ _thresholdConfig;
39
+ _tallyFeed;
40
+ _intervalTallies = [];
41
+ _choices;
42
+ _pollId;
43
+ _parentAggregator;
44
+ constructor(poll, config, publicKey, thresholdConfig, tallyFeed, logger, checkpointMgr) {
45
+ super(poll, config, logger, checkpointMgr);
46
+ this._publicKey = publicKey;
47
+ this._thresholdConfig = thresholdConfig;
48
+ this._tallyFeed = tallyFeed;
49
+ this._choices = poll.choices;
50
+ this._pollId = poll.id;
51
+ }
52
+ /**
53
+ * Set the parent aggregator for result propagation.
54
+ */
55
+ setParent(parent) {
56
+ this._parentAggregator = parent;
57
+ }
58
+ /**
59
+ * Get the encrypted aggregate tally for this precinct.
60
+ *
61
+ * Uses the same homomorphic aggregation as the base PrecinctAggregator.
62
+ */
63
+ getEncryptedTally() {
64
+ const tally = this.getTally();
65
+ return [...tally.encryptedTallies];
66
+ }
67
+ /**
68
+ * Perform an interval decryption at the precinct level.
69
+ *
70
+ * Starts a ceremony via the coordinator, waits for it to complete,
71
+ * and publishes the result to the tally feed.
72
+ *
73
+ * @param ceremonyCoordinator - The coordinator managing the ceremony
74
+ * @param intervalNumber - The interval number for this decryption
75
+ * @returns The decrypted interval tally
76
+ */
77
+ async performIntervalDecryption(ceremonyCoordinator, intervalNumber) {
78
+ const encryptedTally = this.getEncryptedTally();
79
+ // Start a ceremony for this interval
80
+ const ceremony = ceremonyCoordinator.startCeremony(this._pollId, intervalNumber, encryptedTally);
81
+ // Wait for the ceremony to complete (partials submitted externally)
82
+ return new Promise((resolve, reject) => {
83
+ // Check if already completed (synchronous submission case)
84
+ const current = ceremonyCoordinator.getCeremony(ceremony.id);
85
+ if (current &&
86
+ current.status === ceremony_status_1.CeremonyStatus.Completed &&
87
+ current.result) {
88
+ const intervalTally = this.buildIntervalTally(current.result.tallies, current.result.combinedProof, current.result.participatingGuardians, intervalNumber);
89
+ this._intervalTallies.push(intervalTally);
90
+ if (this._tallyFeed) {
91
+ this._tallyFeed.publish(intervalTally);
92
+ }
93
+ resolve(intervalTally);
94
+ return;
95
+ }
96
+ // Subscribe to completion
97
+ ceremonyCoordinator.onCeremonyComplete((completedCeremony) => {
98
+ if (completedCeremony.id !== ceremony.id)
99
+ return;
100
+ if (completedCeremony.status === ceremony_status_1.CeremonyStatus.Completed &&
101
+ completedCeremony.result) {
102
+ const intervalTally = this.buildIntervalTally(completedCeremony.result.tallies, completedCeremony.result.combinedProof, completedCeremony.result.participatingGuardians, intervalNumber);
103
+ this._intervalTallies.push(intervalTally);
104
+ if (this._tallyFeed) {
105
+ this._tallyFeed.publish(intervalTally);
106
+ }
107
+ resolve(intervalTally);
108
+ }
109
+ else {
110
+ reject(new Error(`Ceremony ${ceremony.id} failed with status: ${completedCeremony.status}`));
111
+ }
112
+ });
113
+ });
114
+ }
115
+ /**
116
+ * Propagate an interval tally result to the parent aggregator.
117
+ */
118
+ propagateToParent(tally) {
119
+ if (this._parentAggregator) {
120
+ this._parentAggregator.propagateToParent(tally);
121
+ }
122
+ }
123
+ /**
124
+ * Get all interval tallies produced by this aggregator.
125
+ */
126
+ getIntervalTallies() {
127
+ return this._intervalTallies;
128
+ }
129
+ /**
130
+ * Build an IntervalTally from decryption results.
131
+ */
132
+ buildIntervalTally(tallies, proof, participatingGuardians, intervalNumber) {
133
+ const baseTally = this.getTally();
134
+ const cumulativeVoteCount = baseTally.voterCount;
135
+ // Compute vote count for this interval
136
+ const previousCumulative = this._intervalTallies.length > 0
137
+ ? this._intervalTallies[this._intervalTallies.length - 1]
138
+ .cumulativeVoteCount
139
+ : 0;
140
+ const voteCount = cumulativeVoteCount - previousCumulative;
141
+ return {
142
+ pollId: this._pollId,
143
+ intervalNumber,
144
+ tallies: tallies,
145
+ choices: this._choices,
146
+ voteCount,
147
+ cumulativeVoteCount,
148
+ proof,
149
+ participatingGuardians,
150
+ timestamp: Date.now(),
151
+ isFinal: false,
152
+ };
153
+ }
154
+ }
155
+ exports.ThresholdPrecinctAggregator = ThresholdPrecinctAggregator;
156
+ //# sourceMappingURL=threshold-precinct-aggregator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"threshold-precinct-aggregator.js","sourceRoot":"","sources":["../../../../../../../packages/digitaldefiance-ecies-lib/src/lib/voting/threshold/threshold-precinct-aggregator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,85 @@
1
+ /**
2
+ * Threshold State Aggregator
3
+ *
4
+ * Extends the standard StateAggregator with threshold decryption support.
5
+ * Enforces that threshold decryption is required at this level when any
6
+ * child jurisdiction uses threshold decryption (Requirement 10.6).
7
+ *
8
+ * @module voting/threshold
9
+ */
10
+ import type { PublicKey } from 'paillier-bigint';
11
+ import type { PlatformID } from '../../../interfaces/platform-id';
12
+ import { StateAggregator } from '../hierarchical-aggregator';
13
+ import type { JurisdictionConfig } from '../interfaces/jurisdiction-config';
14
+ import type { ICeremonyCoordinator } from './interfaces/ceremony-coordinator';
15
+ import type { IntervalTally } from './interfaces/interval-tally';
16
+ import type { IPublicTallyFeed } from './interfaces/public-tally-feed';
17
+ import type { IThresholdAggregator } from './interfaces/threshold-aggregator';
18
+ import type { ThresholdKeyConfig } from './interfaces/threshold-key-config';
19
+ /**
20
+ * State-level aggregator with threshold decryption support.
21
+ *
22
+ * Combines county tallies using homomorphic addition (inherited) and
23
+ * enforces that threshold decryption is required at this level when
24
+ * child jurisdictions use threshold decryption.
25
+ *
26
+ * @example
27
+ * ```typescript
28
+ * const state = new ThresholdStateAggregator(
29
+ * config, publicKey, thresholdConfig, choices, pollId, tallyFeed,
30
+ * );
31
+ *
32
+ * // Add county tallies
33
+ * state.addCountyTally(countyTally);
34
+ *
35
+ * // Perform interval decryption (enforced at state level)
36
+ * const tally = await state.performIntervalDecryption(coordinator, 1);
37
+ * ```
38
+ */
39
+ export declare class ThresholdStateAggregator<TID extends PlatformID = Uint8Array> extends StateAggregator<TID> implements IThresholdAggregator<TID> {
40
+ private readonly _thresholdConfig;
41
+ private readonly _tallyFeed?;
42
+ private readonly _intervalTallies;
43
+ private readonly _choices;
44
+ private readonly _pollId;
45
+ private _parentAggregator?;
46
+ private readonly _childIntervalTallies;
47
+ private _thresholdRequired;
48
+ constructor(config: JurisdictionConfig<TID>, publicKey: PublicKey, thresholdConfig: ThresholdKeyConfig, choices: readonly string[], pollId: TID, tallyFeed?: IPublicTallyFeed<TID>);
49
+ /**
50
+ * Set the parent aggregator for result propagation.
51
+ */
52
+ setParent(parent: IThresholdAggregator<TID>): void;
53
+ /**
54
+ * Whether threshold decryption is enforced at this level.
55
+ * Per Requirement 10.6, if a child jurisdiction uses threshold
56
+ * decryption, all higher levels must also use it.
57
+ */
58
+ get thresholdRequired(): boolean;
59
+ set thresholdRequired(value: boolean);
60
+ /**
61
+ * Get the encrypted aggregate tally for this state.
62
+ */
63
+ getEncryptedTally(): bigint[];
64
+ /**
65
+ * Perform an interval decryption at the state level.
66
+ *
67
+ * Enforces that threshold decryption is required at this level
68
+ * before proceeding with the ceremony.
69
+ */
70
+ performIntervalDecryption(ceremonyCoordinator: ICeremonyCoordinator<TID>, intervalNumber: number): Promise<IntervalTally<TID>>;
71
+ /**
72
+ * Propagate an interval tally result from a child (county) aggregator.
73
+ */
74
+ propagateToParent(tally: IntervalTally<TID>): void;
75
+ /**
76
+ * Get all interval tallies produced by this aggregator.
77
+ */
78
+ getIntervalTallies(): readonly IntervalTally<TID>[];
79
+ /**
80
+ * Get child interval tallies received for a specific interval.
81
+ */
82
+ getChildIntervalTallies(intervalNumber: number): readonly IntervalTally<TID>[];
83
+ private buildIntervalTally;
84
+ }
85
+ //# sourceMappingURL=threshold-state-aggregator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"threshold-state-aggregator.d.ts","sourceRoot":"","sources":["../../../../../../../packages/digitaldefiance-ecies-lib/src/lib/voting/threshold/threshold-state-aggregator.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iCAAiC,CAAC;AAClE,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAC7D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,mCAAmC,CAAC;AAE5E,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,mCAAmC,CAAC;AAC9E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AACjE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAC;AACvE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,mCAAmC,CAAC;AAC9E,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,mCAAmC,CAAC;AAE5E;;;;;;;;;;;;;;;;;;;GAmBG;AACH,qBAAa,wBAAwB,CAAC,GAAG,SAAS,UAAU,GAAG,UAAU,CACvE,SAAQ,eAAe,CAAC,GAAG,CAC3B,YAAW,oBAAoB,CAAC,GAAG,CAAC;IAEpC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAqB;IACtD,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAwB;IACpD,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAA4B;IAC7D,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAoB;IAC7C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAM;IAC9B,OAAO,CAAC,iBAAiB,CAAC,CAA4B;IACtD,OAAO,CAAC,QAAQ,CAAC,qBAAqB,CAC1B;IACZ,OAAO,CAAC,kBAAkB,CAAQ;gBAGhC,MAAM,EAAE,kBAAkB,CAAC,GAAG,CAAC,EAC/B,SAAS,EAAE,SAAS,EACpB,eAAe,EAAE,kBAAkB,EACnC,OAAO,EAAE,SAAS,MAAM,EAAE,EAC1B,MAAM,EAAE,GAAG,EACX,SAAS,CAAC,EAAE,gBAAgB,CAAC,GAAG,CAAC;IASnC;;OAEG;IACH,SAAS,CAAC,MAAM,EAAE,oBAAoB,CAAC,GAAG,CAAC,GAAG,IAAI;IAIlD;;;;OAIG;IACH,IAAI,iBAAiB,IAAI,OAAO,CAE/B;IAED,IAAI,iBAAiB,CAAC,KAAK,EAAE,OAAO,EAEnC;IAED;;OAEG;IACH,iBAAiB,IAAI,MAAM,EAAE;IAK7B;;;;;OAKG;IACG,yBAAyB,CAC7B,mBAAmB,EAAE,oBAAoB,CAAC,GAAG,CAAC,EAC9C,cAAc,EAAE,MAAM,GACrB,OAAO,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC;IA+D9B;;OAEG;IACH,iBAAiB,CAAC,KAAK,EAAE,aAAa,CAAC,GAAG,CAAC,GAAG,IAAI;IAUlD;;OAEG;IACH,kBAAkB,IAAI,SAAS,aAAa,CAAC,GAAG,CAAC,EAAE;IAInD;;OAEG;IACH,uBAAuB,CACrB,cAAc,EAAE,MAAM,GACrB,SAAS,aAAa,CAAC,GAAG,CAAC,EAAE;IAIhC,OAAO,CAAC,kBAAkB;CA6B3B"}
@@ -0,0 +1,164 @@
1
+ "use strict";
2
+ /**
3
+ * Threshold State Aggregator
4
+ *
5
+ * Extends the standard StateAggregator with threshold decryption support.
6
+ * Enforces that threshold decryption is required at this level when any
7
+ * child jurisdiction uses threshold decryption (Requirement 10.6).
8
+ *
9
+ * @module voting/threshold
10
+ */
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.ThresholdStateAggregator = void 0;
13
+ const hierarchical_aggregator_1 = require("../hierarchical-aggregator");
14
+ const ceremony_status_1 = require("./enumerations/ceremony-status");
15
+ /**
16
+ * State-level aggregator with threshold decryption support.
17
+ *
18
+ * Combines county tallies using homomorphic addition (inherited) and
19
+ * enforces that threshold decryption is required at this level when
20
+ * child jurisdictions use threshold decryption.
21
+ *
22
+ * @example
23
+ * ```typescript
24
+ * const state = new ThresholdStateAggregator(
25
+ * config, publicKey, thresholdConfig, choices, pollId, tallyFeed,
26
+ * );
27
+ *
28
+ * // Add county tallies
29
+ * state.addCountyTally(countyTally);
30
+ *
31
+ * // Perform interval decryption (enforced at state level)
32
+ * const tally = await state.performIntervalDecryption(coordinator, 1);
33
+ * ```
34
+ */
35
+ class ThresholdStateAggregator extends hierarchical_aggregator_1.StateAggregator {
36
+ _thresholdConfig;
37
+ _tallyFeed;
38
+ _intervalTallies = [];
39
+ _choices;
40
+ _pollId;
41
+ _parentAggregator;
42
+ _childIntervalTallies = new Map();
43
+ _thresholdRequired = true;
44
+ constructor(config, publicKey, thresholdConfig, choices, pollId, tallyFeed) {
45
+ super(config, publicKey);
46
+ this._thresholdConfig = thresholdConfig;
47
+ this._tallyFeed = tallyFeed;
48
+ this._choices = choices;
49
+ this._pollId = pollId;
50
+ }
51
+ /**
52
+ * Set the parent aggregator for result propagation.
53
+ */
54
+ setParent(parent) {
55
+ this._parentAggregator = parent;
56
+ }
57
+ /**
58
+ * Whether threshold decryption is enforced at this level.
59
+ * Per Requirement 10.6, if a child jurisdiction uses threshold
60
+ * decryption, all higher levels must also use it.
61
+ */
62
+ get thresholdRequired() {
63
+ return this._thresholdRequired;
64
+ }
65
+ set thresholdRequired(value) {
66
+ this._thresholdRequired = value;
67
+ }
68
+ /**
69
+ * Get the encrypted aggregate tally for this state.
70
+ */
71
+ getEncryptedTally() {
72
+ const tally = this.getTally();
73
+ return [...tally.encryptedTallies];
74
+ }
75
+ /**
76
+ * Perform an interval decryption at the state level.
77
+ *
78
+ * Enforces that threshold decryption is required at this level
79
+ * before proceeding with the ceremony.
80
+ */
81
+ async performIntervalDecryption(ceremonyCoordinator, intervalNumber) {
82
+ if (!this._thresholdRequired) {
83
+ throw new Error('Threshold decryption is not enabled at the state level');
84
+ }
85
+ const encryptedTally = this.getEncryptedTally();
86
+ const ceremony = ceremonyCoordinator.startCeremony(this._pollId, intervalNumber, encryptedTally);
87
+ return new Promise((resolve, reject) => {
88
+ const current = ceremonyCoordinator.getCeremony(ceremony.id);
89
+ if (current &&
90
+ current.status === ceremony_status_1.CeremonyStatus.Completed &&
91
+ current.result) {
92
+ const intervalTally = this.buildIntervalTally(current.result.tallies, current.result.combinedProof, current.result.participatingGuardians, intervalNumber);
93
+ this._intervalTallies.push(intervalTally);
94
+ if (this._tallyFeed) {
95
+ this._tallyFeed.publish(intervalTally);
96
+ }
97
+ resolve(intervalTally);
98
+ return;
99
+ }
100
+ ceremonyCoordinator.onCeremonyComplete((completedCeremony) => {
101
+ if (completedCeremony.id !== ceremony.id)
102
+ return;
103
+ if (completedCeremony.status === ceremony_status_1.CeremonyStatus.Completed &&
104
+ completedCeremony.result) {
105
+ const intervalTally = this.buildIntervalTally(completedCeremony.result.tallies, completedCeremony.result.combinedProof, completedCeremony.result.participatingGuardians, intervalNumber);
106
+ this._intervalTallies.push(intervalTally);
107
+ if (this._tallyFeed) {
108
+ this._tallyFeed.publish(intervalTally);
109
+ }
110
+ resolve(intervalTally);
111
+ }
112
+ else {
113
+ reject(new Error(`Ceremony ${ceremony.id} failed with status: ${completedCeremony.status}`));
114
+ }
115
+ });
116
+ });
117
+ }
118
+ /**
119
+ * Propagate an interval tally result from a child (county) aggregator.
120
+ */
121
+ propagateToParent(tally) {
122
+ const existing = this._childIntervalTallies.get(tally.intervalNumber) ?? [];
123
+ existing.push(tally);
124
+ this._childIntervalTallies.set(tally.intervalNumber, existing);
125
+ if (this._parentAggregator) {
126
+ this._parentAggregator.propagateToParent(tally);
127
+ }
128
+ }
129
+ /**
130
+ * Get all interval tallies produced by this aggregator.
131
+ */
132
+ getIntervalTallies() {
133
+ return this._intervalTallies;
134
+ }
135
+ /**
136
+ * Get child interval tallies received for a specific interval.
137
+ */
138
+ getChildIntervalTallies(intervalNumber) {
139
+ return this._childIntervalTallies.get(intervalNumber) ?? [];
140
+ }
141
+ buildIntervalTally(tallies, proof, participatingGuardians, intervalNumber) {
142
+ const baseTally = this.getTally();
143
+ const cumulativeVoteCount = baseTally.voterCount;
144
+ const previousCumulative = this._intervalTallies.length > 0
145
+ ? this._intervalTallies[this._intervalTallies.length - 1]
146
+ .cumulativeVoteCount
147
+ : 0;
148
+ const voteCount = cumulativeVoteCount - previousCumulative;
149
+ return {
150
+ pollId: this._pollId,
151
+ intervalNumber,
152
+ tallies: tallies,
153
+ choices: this._choices,
154
+ voteCount,
155
+ cumulativeVoteCount,
156
+ proof,
157
+ participatingGuardians,
158
+ timestamp: Date.now(),
159
+ isFinal: false,
160
+ };
161
+ }
162
+ }
163
+ exports.ThresholdStateAggregator = ThresholdStateAggregator;
164
+ //# sourceMappingURL=threshold-state-aggregator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"threshold-state-aggregator.js","sourceRoot":"","sources":["../../../../../../../packages/digitaldefiance-ecies-lib/src/lib/voting/threshold/threshold-state-aggregator.ts"],"names":[],"mappings":"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"}