@digitaldefiance/node-ecies-lib 4.8.2 → 4.10.6
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/package.json +10 -5
- package/src/constants.d.ts.map +1 -1
- package/src/constants.js +31 -25
- package/src/constants.js.map +1 -1
- package/src/interfaces/index.d.ts +1 -2
- package/src/interfaces/index.d.ts.map +1 -1
- package/src/interfaces/index.js +6 -3
- package/src/interfaces/index.js.map +1 -1
- package/src/interfaces/member.d.ts +30 -12
- package/src/interfaces/member.d.ts.map +1 -1
- package/src/interfaces/platform-buffer.d.ts +9 -0
- package/src/interfaces/platform-buffer.d.ts.map +1 -0
- package/src/interfaces/platform-buffer.js +3 -0
- package/src/interfaces/platform-buffer.js.map +1 -0
- package/src/interfaces/platform-id.d.ts +2 -2
- package/src/interfaces/platform-id.d.ts.map +1 -1
- package/src/lib/id-providers/buffer-provider.d.ts +54 -0
- package/src/lib/id-providers/buffer-provider.d.ts.map +1 -0
- package/src/lib/id-providers/buffer-provider.js +93 -0
- package/src/lib/id-providers/buffer-provider.js.map +1 -0
- package/src/lib/index.d.ts +1 -0
- package/src/lib/index.d.ts.map +1 -1
- package/src/lib/index.js +1 -0
- package/src/lib/index.js.map +1 -1
- package/src/lib/voting/audit.d.ts +39 -48
- package/src/lib/voting/audit.d.ts.map +1 -1
- package/src/lib/voting/audit.js +103 -111
- package/src/lib/voting/audit.js.map +1 -1
- package/src/lib/voting/bulletin-board.d.ts +47 -81
- package/src/lib/voting/bulletin-board.d.ts.map +1 -1
- package/src/lib/voting/bulletin-board.js +95 -231
- package/src/lib/voting/bulletin-board.js.map +1 -1
- package/src/lib/voting/encoder.d.ts +7 -16
- package/src/lib/voting/encoder.d.ts.map +1 -1
- package/src/lib/voting/encoder.js +11 -107
- package/src/lib/voting/encoder.js.map +1 -1
- package/src/lib/voting/enumerations/index.d.ts +6 -0
- package/src/lib/voting/enumerations/index.d.ts.map +1 -0
- package/src/lib/voting/enumerations/index.js +14 -0
- package/src/lib/voting/enumerations/index.js.map +1 -0
- package/src/lib/voting/event-logger.d.ts +13 -74
- package/src/lib/voting/event-logger.d.ts.map +1 -1
- package/src/lib/voting/event-logger.js +19 -140
- package/src/lib/voting/event-logger.js.map +1 -1
- package/src/lib/voting/examples.d.ts +112 -0
- package/src/lib/voting/examples.d.ts.map +1 -0
- package/src/lib/voting/examples.js +386 -0
- package/src/lib/voting/examples.js.map +1 -0
- package/src/lib/voting/factory.d.ts +38 -9
- package/src/lib/voting/factory.d.ts.map +1 -1
- package/src/lib/voting/factory.js +42 -8
- package/src/lib/voting/factory.js.map +1 -1
- package/src/lib/voting/hierarchical-aggregator.d.ts +44 -0
- package/src/lib/voting/hierarchical-aggregator.d.ts.map +1 -0
- package/src/lib/voting/hierarchical-aggregator.js +56 -0
- package/src/lib/voting/hierarchical-aggregator.js.map +1 -0
- package/src/lib/voting/index.d.ts +43 -7
- package/src/lib/voting/index.d.ts.map +1 -1
- package/src/lib/voting/index.js +53 -10
- package/src/lib/voting/index.js.map +1 -1
- package/src/lib/voting/interfaces/aggregated-tally.d.ts +10 -0
- package/src/lib/voting/interfaces/aggregated-tally.d.ts.map +1 -0
- package/src/lib/voting/interfaces/aggregated-tally.js +3 -0
- package/src/lib/voting/interfaces/aggregated-tally.js.map +1 -0
- package/src/lib/voting/interfaces/audit-entry.d.ts +10 -0
- package/src/lib/voting/interfaces/audit-entry.d.ts.map +1 -0
- package/src/lib/voting/interfaces/audit-entry.js +3 -0
- package/src/lib/voting/interfaces/audit-entry.js.map +1 -0
- package/src/lib/voting/interfaces/audit-log.d.ts +10 -0
- package/src/lib/voting/interfaces/audit-log.d.ts.map +1 -0
- package/src/lib/voting/interfaces/audit-log.js +3 -0
- package/src/lib/voting/interfaces/audit-log.js.map +1 -0
- package/src/lib/voting/interfaces/bulletin-board-entry.d.ts +10 -0
- package/src/lib/voting/interfaces/bulletin-board-entry.d.ts.map +1 -0
- package/src/lib/voting/interfaces/bulletin-board-entry.js +3 -0
- package/src/lib/voting/interfaces/bulletin-board-entry.js.map +1 -0
- package/src/lib/voting/interfaces/bulletin-board.d.ts +10 -0
- package/src/lib/voting/interfaces/bulletin-board.d.ts.map +1 -0
- package/src/lib/voting/interfaces/bulletin-board.js +3 -0
- package/src/lib/voting/interfaces/bulletin-board.js.map +1 -0
- package/src/lib/voting/interfaces/checkpoint-manager-extended.d.ts +10 -0
- package/src/lib/voting/interfaces/checkpoint-manager-extended.d.ts.map +1 -0
- package/src/lib/voting/interfaces/checkpoint-manager-extended.js +3 -0
- package/src/lib/voting/interfaces/checkpoint-manager-extended.js.map +1 -0
- package/src/lib/voting/interfaces/checkpoint-manager.d.ts +9 -0
- package/src/lib/voting/interfaces/checkpoint-manager.d.ts.map +1 -0
- package/src/lib/voting/interfaces/checkpoint-manager.js +3 -0
- package/src/lib/voting/interfaces/checkpoint-manager.js.map +1 -0
- package/src/lib/voting/interfaces/checkpoint-metadata.d.ts +8 -0
- package/src/lib/voting/interfaces/checkpoint-metadata.d.ts.map +1 -0
- package/src/lib/voting/interfaces/checkpoint-metadata.js +3 -0
- package/src/lib/voting/interfaces/checkpoint-metadata.js.map +1 -0
- package/src/lib/voting/interfaces/ecies-service-with-voting.d.ts +8 -0
- package/src/lib/voting/interfaces/ecies-service-with-voting.d.ts.map +1 -0
- package/src/lib/voting/interfaces/ecies-service-with-voting.js +3 -0
- package/src/lib/voting/interfaces/ecies-service-with-voting.js.map +1 -0
- package/src/lib/voting/interfaces/encrypted-vote.d.ts +10 -0
- package/src/lib/voting/interfaces/encrypted-vote.d.ts.map +1 -0
- package/src/lib/voting/interfaces/encrypted-vote.js +3 -0
- package/src/lib/voting/interfaces/encrypted-vote.js.map +1 -0
- package/src/lib/voting/interfaces/event-log-entry.d.ts +10 -0
- package/src/lib/voting/interfaces/event-log-entry.d.ts.map +1 -0
- package/src/lib/voting/interfaces/event-log-entry.js +3 -0
- package/src/lib/voting/interfaces/event-log-entry.js.map +1 -0
- package/src/lib/voting/interfaces/event-logger.d.ts +10 -0
- package/src/lib/voting/interfaces/event-logger.d.ts.map +1 -0
- package/src/lib/voting/interfaces/event-logger.js +3 -0
- package/src/lib/voting/interfaces/event-logger.js.map +1 -0
- package/src/lib/voting/interfaces/index.d.ts +37 -0
- package/src/lib/voting/interfaces/index.d.ts.map +1 -0
- package/src/lib/voting/interfaces/index.js +9 -0
- package/src/lib/voting/interfaces/index.js.map +1 -0
- package/src/lib/voting/interfaces/jurisdiction-config.d.ts +10 -0
- package/src/lib/voting/interfaces/jurisdiction-config.d.ts.map +1 -0
- package/src/lib/voting/interfaces/jurisdiction-config.js +3 -0
- package/src/lib/voting/interfaces/jurisdiction-config.js.map +1 -0
- package/src/lib/voting/interfaces/plaintext-vote.d.ts +10 -0
- package/src/lib/voting/interfaces/plaintext-vote.d.ts.map +1 -0
- package/src/lib/voting/interfaces/plaintext-vote.js +3 -0
- package/src/lib/voting/interfaces/plaintext-vote.js.map +1 -0
- package/src/lib/voting/interfaces/poll-configuration.d.ts +8 -0
- package/src/lib/voting/interfaces/poll-configuration.d.ts.map +1 -0
- package/src/lib/voting/interfaces/poll-configuration.js +3 -0
- package/src/lib/voting/interfaces/poll-configuration.js.map +1 -0
- package/src/lib/voting/interfaces/poll-results.d.ts +8 -0
- package/src/lib/voting/interfaces/poll-results.d.ts.map +1 -0
- package/src/lib/voting/interfaces/poll-results.js +3 -0
- package/src/lib/voting/interfaces/poll-results.js.map +1 -0
- package/src/lib/voting/interfaces/poll-tallier.d.ts +10 -0
- package/src/lib/voting/interfaces/poll-tallier.d.ts.map +1 -0
- package/src/lib/voting/interfaces/poll-tallier.js +3 -0
- package/src/lib/voting/interfaces/poll-tallier.js.map +1 -0
- package/src/lib/voting/interfaces/poll.d.ts +10 -0
- package/src/lib/voting/interfaces/poll.d.ts.map +1 -0
- package/src/lib/voting/interfaces/poll.js +3 -0
- package/src/lib/voting/interfaces/poll.js.map +1 -0
- package/src/lib/voting/interfaces/round-result.d.ts +8 -0
- package/src/lib/voting/interfaces/round-result.d.ts.map +1 -0
- package/src/lib/voting/interfaces/round-result.js +3 -0
- package/src/lib/voting/interfaces/round-result.js.map +1 -0
- package/src/lib/voting/interfaces/state-snapshot.d.ts +15 -0
- package/src/lib/voting/interfaces/state-snapshot.d.ts.map +1 -0
- package/src/lib/voting/interfaces/state-snapshot.js +3 -0
- package/src/lib/voting/interfaces/state-snapshot.js.map +1 -0
- package/src/lib/voting/interfaces/supermajority-config.d.ts +8 -0
- package/src/lib/voting/interfaces/supermajority-config.d.ts.map +1 -0
- package/src/lib/voting/interfaces/supermajority-config.js +3 -0
- package/src/lib/voting/interfaces/supermajority-config.js.map +1 -0
- package/src/lib/voting/interfaces/tally-proof.d.ts +10 -0
- package/src/lib/voting/interfaces/tally-proof.d.ts.map +1 -0
- package/src/lib/voting/interfaces/tally-proof.js +3 -0
- package/src/lib/voting/interfaces/tally-proof.js.map +1 -0
- package/src/lib/voting/interfaces/vote-encoder.d.ts +10 -0
- package/src/lib/voting/interfaces/vote-encoder.d.ts.map +1 -0
- package/src/lib/voting/interfaces/vote-encoder.js +3 -0
- package/src/lib/voting/interfaces/vote-encoder.js.map +1 -0
- package/src/lib/voting/interfaces/vote-logger-extended.d.ts +10 -0
- package/src/lib/voting/interfaces/vote-logger-extended.d.ts.map +1 -0
- package/src/lib/voting/interfaces/vote-logger-extended.js +3 -0
- package/src/lib/voting/interfaces/vote-logger-extended.js.map +1 -0
- package/src/lib/voting/interfaces/vote-logger.d.ts +9 -0
- package/src/lib/voting/interfaces/vote-logger.d.ts.map +1 -0
- package/src/lib/voting/interfaces/vote-logger.js +3 -0
- package/src/lib/voting/interfaces/vote-logger.js.map +1 -0
- package/src/lib/voting/interfaces/voting-consts.d.ts +9 -0
- package/src/lib/voting/interfaces/voting-consts.d.ts.map +1 -0
- package/src/lib/voting/interfaces/voting-consts.js +3 -0
- package/src/lib/voting/interfaces/voting-consts.js.map +1 -0
- package/src/lib/voting/interfaces/voting-key-derivation-options.d.ts +7 -0
- package/src/lib/voting/interfaces/voting-key-derivation-options.d.ts.map +1 -0
- package/src/lib/voting/interfaces/voting-key-derivation-options.js +3 -0
- package/src/lib/voting/interfaces/voting-key-derivation-options.js.map +1 -0
- package/src/lib/voting/interfaces/voting-poll-results.d.ts +7 -0
- package/src/lib/voting/interfaces/voting-poll-results.d.ts.map +1 -0
- package/src/lib/voting/interfaces/voting-poll-results.js +3 -0
- package/src/lib/voting/interfaces/voting-poll-results.js.map +1 -0
- package/src/lib/voting/interfaces/voting-receipt.d.ts +10 -0
- package/src/lib/voting/interfaces/voting-receipt.d.ts.map +1 -0
- package/src/lib/voting/interfaces/voting-receipt.js +3 -0
- package/src/lib/voting/interfaces/voting-receipt.js.map +1 -0
- package/src/lib/voting/interfaces/voting-security-validator.d.ts +8 -0
- package/src/lib/voting/interfaces/voting-security-validator.d.ts.map +1 -0
- package/src/lib/voting/interfaces/voting-security-validator.js +3 -0
- package/src/lib/voting/interfaces/voting-security-validator.js.map +1 -0
- package/src/lib/voting/node-persistent-state.d.ts +40 -0
- package/src/lib/voting/node-persistent-state.d.ts.map +1 -0
- package/src/lib/voting/node-persistent-state.js +222 -0
- package/src/lib/voting/node-persistent-state.js.map +1 -0
- package/src/lib/voting/persistent-state.d.ts +44 -0
- package/src/lib/voting/persistent-state.d.ts.map +1 -0
- package/src/lib/voting/persistent-state.js +106 -0
- package/src/lib/voting/persistent-state.js.map +1 -0
- package/src/lib/voting/poll-core.d.ts +14 -29
- package/src/lib/voting/poll-core.d.ts.map +1 -1
- package/src/lib/voting/poll-core.js +13 -176
- package/src/lib/voting/poll-core.js.map +1 -1
- package/src/lib/voting/poll.js +3 -3
- package/src/lib/voting/poll.js.map +1 -1
- package/src/lib/voting/security.d.ts +9 -15
- package/src/lib/voting/security.d.ts.map +1 -1
- package/src/lib/voting/security.js +12 -44
- package/src/lib/voting/security.js.map +1 -1
- package/src/lib/voting/tallier.d.ts +11 -20
- package/src/lib/voting/tallier.d.ts.map +1 -1
- package/src/lib/voting/tallier.js +17 -366
- package/src/lib/voting/tallier.js.map +1 -1
- package/src/lib/voting/test-voter-pool.d.ts +16 -0
- package/src/lib/voting/test-voter-pool.d.ts.map +1 -0
- package/src/lib/voting/test-voter-pool.js +69 -0
- package/src/lib/voting/test-voter-pool.js.map +1 -0
- package/src/lib/voting/us-election-example.d.ts +2 -0
- package/src/lib/voting/us-election-example.d.ts.map +1 -0
- package/src/lib/voting/us-election-example.js +170 -0
- package/src/lib/voting/us-election-example.js.map +1 -0
- package/src/member.d.ts +4 -1
- package/src/member.d.ts.map +1 -1
- package/src/member.js +40 -16
- package/src/member.js.map +1 -1
- package/src/secure-buffer.d.ts +1 -2
- package/src/secure-buffer.d.ts.map +1 -1
- package/src/secure-buffer.js +3 -9
- package/src/secure-buffer.js.map +1 -1
- package/src/services/ecies/crypto-core.d.ts.map +1 -1
- package/src/services/ecies/crypto-core.js +24 -0
- package/src/services/ecies/crypto-core.js.map +1 -1
- package/src/services/ecies/multi-recipient.d.ts +9 -1
- package/src/services/ecies/multi-recipient.d.ts.map +1 -1
- package/src/services/ecies/multi-recipient.js +153 -21
- package/src/services/ecies/multi-recipient.js.map +1 -1
- package/src/services/ecies/service.d.ts +56 -15
- package/src/services/ecies/service.d.ts.map +1 -1
- package/src/services/ecies/service.js +196 -39
- package/src/services/ecies/service.js.map +1 -1
- package/src/services/ecies/single-recipient.d.ts.map +1 -1
- package/src/services/ecies/single-recipient.js +4 -2
- package/src/services/ecies/single-recipient.js.map +1 -1
- package/src/services/encryption-stream.d.ts +1 -1
- package/src/services/encryption-stream.d.ts.map +1 -1
- package/src/services/encryption-stream.js +4 -8
- package/src/services/encryption-stream.js.map +1 -1
- package/src/services/multi-recipient-processor.d.ts +5 -2
- package/src/services/multi-recipient-processor.d.ts.map +1 -1
- package/src/services/multi-recipient-processor.js +29 -14
- package/src/services/multi-recipient-processor.js.map +1 -1
- package/src/test-mocks/mock-backend-member.d.ts +22 -3
- package/src/test-mocks/mock-backend-member.d.ts.map +1 -1
- package/src/test-mocks/mock-backend-member.js +71 -0
- package/src/test-mocks/mock-backend-member.js.map +1 -1
- package/src/lib/voting/types.d.ts +0 -67
- package/src/lib/voting/types.d.ts.map +0 -1
- package/src/lib/voting/types.js +0 -29
- package/src/lib/voting/types.js.map +0 -1
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.NodeCheckpointManager = exports.NodeVoteLogger = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Node.js Persistence Implementation for Large-Scale Elections
|
|
6
|
+
* Implements interfaces from node-ecies-lib with actual disk I/O
|
|
7
|
+
*/
|
|
8
|
+
const fs_1 = require("fs");
|
|
9
|
+
const path_1 = require("path");
|
|
10
|
+
/**
|
|
11
|
+
* Streaming vote logger with append-only disk writes
|
|
12
|
+
* Uses Buffer for Node.js-optimized I/O
|
|
13
|
+
*/
|
|
14
|
+
class NodeVoteLogger {
|
|
15
|
+
logPath;
|
|
16
|
+
voteCount = 0;
|
|
17
|
+
writeStream;
|
|
18
|
+
constructor(jurisdictionId, logDir) {
|
|
19
|
+
const id = this.toHex(Buffer.isBuffer(jurisdictionId) ? jurisdictionId : Buffer.from([0]));
|
|
20
|
+
this.logPath = (0, path_1.join)(logDir, `votes-${id}.log`);
|
|
21
|
+
this.writeStream = (0, fs_1.createWriteStream)(this.logPath, { flags: 'a' });
|
|
22
|
+
}
|
|
23
|
+
async appendVote(voterId, encryptedVote, timestamp) {
|
|
24
|
+
// Convert TID to Buffer for serialization
|
|
25
|
+
const voterIdBytes = Buffer.isBuffer(voterId)
|
|
26
|
+
? voterId
|
|
27
|
+
: voterId instanceof Uint8Array
|
|
28
|
+
? Buffer.from(voterId)
|
|
29
|
+
: Buffer.from([0]); // Fallback for other types
|
|
30
|
+
const entry = this.serializeVote(voterIdBytes, encryptedVote, timestamp);
|
|
31
|
+
await new Promise((resolve, reject) => {
|
|
32
|
+
this.writeStream.write(entry, (err) => {
|
|
33
|
+
if (err)
|
|
34
|
+
reject(err);
|
|
35
|
+
else {
|
|
36
|
+
this.voteCount++;
|
|
37
|
+
resolve();
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
getVoteCount() {
|
|
43
|
+
return this.voteCount;
|
|
44
|
+
}
|
|
45
|
+
async *replayVotes() {
|
|
46
|
+
try {
|
|
47
|
+
const stream = (0, fs_1.createReadStream)(this.logPath);
|
|
48
|
+
let buffer = Buffer.alloc(0);
|
|
49
|
+
for await (const chunk of stream) {
|
|
50
|
+
buffer = Buffer.concat([buffer, chunk]);
|
|
51
|
+
while (buffer.length >= 8) {
|
|
52
|
+
const entrySize = buffer.readUInt32BE(0);
|
|
53
|
+
if (buffer.length < entrySize)
|
|
54
|
+
break;
|
|
55
|
+
const entry = buffer.subarray(0, entrySize);
|
|
56
|
+
buffer = buffer.subarray(entrySize);
|
|
57
|
+
const deserialized = this.deserializeVote(entry);
|
|
58
|
+
// Keep as Buffer for node-ecies-lib consistency
|
|
59
|
+
const voterId = deserialized.voterId;
|
|
60
|
+
yield {
|
|
61
|
+
...deserialized,
|
|
62
|
+
voterId,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
catch (error) {
|
|
68
|
+
// If file doesn't exist, just return (empty generator)
|
|
69
|
+
if (error &&
|
|
70
|
+
typeof error === 'object' &&
|
|
71
|
+
'code' in error &&
|
|
72
|
+
error.code === 'ENOENT') {
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
throw error;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
async close() {
|
|
79
|
+
await new Promise((resolve) => this.writeStream.end(resolve));
|
|
80
|
+
}
|
|
81
|
+
serializeVote(voterId, encryptedVote, timestamp) {
|
|
82
|
+
const parts = [
|
|
83
|
+
Buffer.alloc(8), // timestamp
|
|
84
|
+
Buffer.alloc(4), // voterId length
|
|
85
|
+
voterId,
|
|
86
|
+
Buffer.alloc(4), // vote count
|
|
87
|
+
];
|
|
88
|
+
parts[0].writeBigUInt64BE(BigInt(timestamp), 0);
|
|
89
|
+
parts[1].writeUInt32BE(voterId.length, 0);
|
|
90
|
+
parts[3].writeUInt32BE(encryptedVote.length, 0);
|
|
91
|
+
for (const value of encryptedVote) {
|
|
92
|
+
const hex = value.toString(16).padStart(64, '0');
|
|
93
|
+
parts.push(Buffer.from(hex, 'hex'));
|
|
94
|
+
}
|
|
95
|
+
const totalSize = parts.reduce((sum, p) => sum + p.length, 4);
|
|
96
|
+
const result = Buffer.alloc(totalSize);
|
|
97
|
+
result.writeUInt32BE(totalSize, 0);
|
|
98
|
+
let offset = 4;
|
|
99
|
+
for (const part of parts) {
|
|
100
|
+
part.copy(result, offset);
|
|
101
|
+
offset += part.length;
|
|
102
|
+
}
|
|
103
|
+
return result;
|
|
104
|
+
}
|
|
105
|
+
deserializeVote(entry) {
|
|
106
|
+
let offset = 4;
|
|
107
|
+
const timestamp = Number(entry.readBigUInt64BE(offset));
|
|
108
|
+
offset += 8;
|
|
109
|
+
const voterIdLen = entry.readUInt32BE(offset);
|
|
110
|
+
offset += 4;
|
|
111
|
+
const voterId = entry.subarray(offset, offset + voterIdLen);
|
|
112
|
+
offset += voterIdLen;
|
|
113
|
+
const voteCount = entry.readUInt32BE(offset);
|
|
114
|
+
offset += 4;
|
|
115
|
+
const encryptedVote = [];
|
|
116
|
+
for (let i = 0; i < voteCount; i++) {
|
|
117
|
+
const hex = entry.subarray(offset, offset + 32).toString('hex');
|
|
118
|
+
encryptedVote.push(BigInt('0x' + hex));
|
|
119
|
+
offset += 32;
|
|
120
|
+
}
|
|
121
|
+
return { voterId, encryptedVote, timestamp };
|
|
122
|
+
}
|
|
123
|
+
toHex(buf) {
|
|
124
|
+
return buf.toString('hex');
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
exports.NodeVoteLogger = NodeVoteLogger;
|
|
128
|
+
/**
|
|
129
|
+
* Checkpoint manager with disk-based snapshots
|
|
130
|
+
* Uses Buffer for Node.js-optimized I/O
|
|
131
|
+
*/
|
|
132
|
+
class NodeCheckpointManager {
|
|
133
|
+
config;
|
|
134
|
+
checkpointDir;
|
|
135
|
+
checkpointNumber = 0;
|
|
136
|
+
constructor(config, checkpointDir) {
|
|
137
|
+
this.config = config;
|
|
138
|
+
this.checkpointDir = checkpointDir;
|
|
139
|
+
}
|
|
140
|
+
async saveCheckpoint(tally) {
|
|
141
|
+
await fs_1.promises.mkdir(this.checkpointDir, { recursive: true });
|
|
142
|
+
const metadata = {
|
|
143
|
+
jurisdictionId: this.toKey(this.config.id),
|
|
144
|
+
level: this.config.level,
|
|
145
|
+
voterCount: tally.voterCount,
|
|
146
|
+
timestamp: Date.now(),
|
|
147
|
+
checkpointNumber: this.checkpointNumber++,
|
|
148
|
+
};
|
|
149
|
+
const snapshot = {
|
|
150
|
+
metadata,
|
|
151
|
+
tally,
|
|
152
|
+
voteLog: Buffer.alloc(0),
|
|
153
|
+
};
|
|
154
|
+
const path = (0, path_1.join)(this.checkpointDir, `checkpoint-${metadata.checkpointNumber}.json`);
|
|
155
|
+
await fs_1.promises.writeFile(path, JSON.stringify(snapshot, this.bigIntReplacer));
|
|
156
|
+
}
|
|
157
|
+
async loadLatestCheckpoint() {
|
|
158
|
+
try {
|
|
159
|
+
const files = await fs_1.promises.readdir(this.checkpointDir);
|
|
160
|
+
const checkpoints = files
|
|
161
|
+
.filter((f) => f.startsWith('checkpoint-'))
|
|
162
|
+
.sort()
|
|
163
|
+
.reverse();
|
|
164
|
+
if (checkpoints.length === 0)
|
|
165
|
+
return null;
|
|
166
|
+
const path = (0, path_1.join)(this.checkpointDir, checkpoints[0]);
|
|
167
|
+
const data = await fs_1.promises.readFile(path, 'utf-8');
|
|
168
|
+
return JSON.parse(data, this.bigIntReviver);
|
|
169
|
+
}
|
|
170
|
+
catch {
|
|
171
|
+
return null;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
async listCheckpoints() {
|
|
175
|
+
try {
|
|
176
|
+
const files = await fs_1.promises.readdir(this.checkpointDir);
|
|
177
|
+
const checkpoints = [];
|
|
178
|
+
for (const file of files) {
|
|
179
|
+
if (!file.startsWith('checkpoint-'))
|
|
180
|
+
continue;
|
|
181
|
+
const path = (0, path_1.join)(this.checkpointDir, file);
|
|
182
|
+
const data = await fs_1.promises.readFile(path, 'utf-8');
|
|
183
|
+
const snapshot = JSON.parse(data, this.bigIntReviver);
|
|
184
|
+
checkpoints.push(snapshot.metadata);
|
|
185
|
+
}
|
|
186
|
+
return checkpoints.sort((a, b) => b.checkpointNumber - a.checkpointNumber);
|
|
187
|
+
}
|
|
188
|
+
catch {
|
|
189
|
+
return [];
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
toKey(id) {
|
|
193
|
+
if (Buffer.isBuffer(id)) {
|
|
194
|
+
return id.toString('hex');
|
|
195
|
+
}
|
|
196
|
+
if (id instanceof Uint8Array) {
|
|
197
|
+
return Buffer.from(id).toString('hex');
|
|
198
|
+
}
|
|
199
|
+
return String(id);
|
|
200
|
+
}
|
|
201
|
+
bigIntReplacer(_key, value) {
|
|
202
|
+
return typeof value === 'bigint' ? value.toString() : value;
|
|
203
|
+
}
|
|
204
|
+
bigIntReviver(key, value) {
|
|
205
|
+
// Handle encryptedTallies array specifically
|
|
206
|
+
if (key === 'encryptedTallies' && Array.isArray(value)) {
|
|
207
|
+
return value.map((item) => {
|
|
208
|
+
if (typeof item === 'string' && /^\d+$/.test(item)) {
|
|
209
|
+
return BigInt(item);
|
|
210
|
+
}
|
|
211
|
+
return item;
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
// Handle individual BigInt strings
|
|
215
|
+
if (typeof value === 'string' && /^\d+$/.test(value) && value.length > 15) {
|
|
216
|
+
return BigInt(value);
|
|
217
|
+
}
|
|
218
|
+
return value;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
exports.NodeCheckpointManager = NodeCheckpointManager;
|
|
222
|
+
//# sourceMappingURL=node-persistent-state.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"node-persistent-state.js","sourceRoot":"","sources":["../../../../../../packages/digitaldefiance-node-ecies-lib/src/lib/voting/node-persistent-state.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Node.js Persistent State
|
|
3
|
+
* Extends ecies-lib BatchVoteProcessor with Buffer support
|
|
4
|
+
*/
|
|
5
|
+
import { BatchVoteProcessor as BaseBatchVoteProcessor } from '@digitaldefiance/ecies-lib';
|
|
6
|
+
import type { PlatformID } from '../../interfaces';
|
|
7
|
+
import type { IMember } from '../../interfaces/member';
|
|
8
|
+
import type { EncryptedVote, IVoteLogger, ICheckpointManager, StateSnapshot } from './interfaces';
|
|
9
|
+
/**
|
|
10
|
+
* Node.js BatchVoteProcessor that extends ecies-lib BatchVoteProcessor
|
|
11
|
+
* Provides type-safe batch processing for Buffer-based votes
|
|
12
|
+
*/
|
|
13
|
+
export declare class BatchVoteProcessor<TID extends PlatformID = Buffer> extends BaseBatchVoteProcessor {
|
|
14
|
+
private voteLogger?;
|
|
15
|
+
private checkpointManager?;
|
|
16
|
+
private totalVotes;
|
|
17
|
+
constructor(batchSize?: number, voteLogger?: IVoteLogger<TID>, checkpointManager?: ICheckpointManager<TID>);
|
|
18
|
+
/**
|
|
19
|
+
* Add a vote to the current batch
|
|
20
|
+
* Returns true if batch is full and should be processed
|
|
21
|
+
*/
|
|
22
|
+
addVote(voter: IMember<TID>, vote: EncryptedVote<TID>): boolean;
|
|
23
|
+
/**
|
|
24
|
+
* Process a batch of votes directly
|
|
25
|
+
* This method accepts an array of votes and processes them immediately
|
|
26
|
+
*/
|
|
27
|
+
processBatch(votesOrProcessor: Array<{
|
|
28
|
+
voter: IMember<TID>;
|
|
29
|
+
vote: EncryptedVote<TID>;
|
|
30
|
+
}> | ((batch: Array<{
|
|
31
|
+
voter: IMember<TID>;
|
|
32
|
+
vote: EncryptedVote<TID>;
|
|
33
|
+
}>) => Promise<void>)): Promise<void>;
|
|
34
|
+
/**
|
|
35
|
+
* Create a checkpoint of the current state
|
|
36
|
+
*/
|
|
37
|
+
checkpoint(): Promise<StateSnapshot<TID> & {
|
|
38
|
+
totalVotes: number;
|
|
39
|
+
timestamp: number;
|
|
40
|
+
}>;
|
|
41
|
+
}
|
|
42
|
+
export type { IVoteLogger, ICheckpointManager, CheckpointMetadata, StateSnapshot, } from './interfaces';
|
|
43
|
+
export { NodeVoteLogger, NodeCheckpointManager } from './node-persistent-state';
|
|
44
|
+
//# sourceMappingURL=persistent-state.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"persistent-state.d.ts","sourceRoot":"","sources":["../../../../../../packages/digitaldefiance-node-ecies-lib/src/lib/voting/persistent-state.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EACL,kBAAkB,IAAI,sBAAsB,EAE7C,MAAM,4BAA4B,CAAC;AAEpC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAC;AAEvD,OAAO,KAAK,EACV,aAAa,EACb,WAAW,EACX,kBAAkB,EAClB,aAAa,EACd,MAAM,cAAc,CAAC;AAEtB;;;GAGG;AACH,qBAAa,kBAAkB,CAC7B,GAAG,SAAS,UAAU,GAAG,MAAM,CAC/B,SAAQ,sBAAsB;IAC9B,OAAO,CAAC,UAAU,CAAC,CAAmB;IACtC,OAAO,CAAC,iBAAiB,CAAC,CAA0B;IACpD,OAAO,CAAC,UAAU,CAAK;gBAGrB,SAAS,SAAO,EAChB,UAAU,CAAC,EAAE,WAAW,CAAC,GAAG,CAAC,EAC7B,iBAAiB,CAAC,EAAE,kBAAkB,CAAC,GAAG,CAAC;IAO7C;;;OAGG;IACH,OAAO,CAAC,KAAK,EAAE,OAAO,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE,aAAa,CAAC,GAAG,CAAC,GAAG,OAAO;IAI/D;;;OAGG;IACG,YAAY,CAChB,gBAAgB,EACZ,KAAK,CAAC;QAAE,KAAK,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC;QAAC,IAAI,EAAE,aAAa,CAAC,GAAG,CAAC,CAAA;KAAE,CAAC,GACxD,CAAC,CACC,KAAK,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC;QAAC,IAAI,EAAE,aAAa,CAAC,GAAG,CAAC,CAAA;KAAE,CAAC,KAC5D,OAAO,CAAC,IAAI,CAAC,CAAC,GACtB,OAAO,CAAC,IAAI,CAAC;IAqDhB;;OAEG;IACG,UAAU,IAAI,OAAO,CACzB,aAAa,CAAC,GAAG,CAAC,GAAG;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAC/D;CAmCF;AAGD,YAAY,EACV,WAAW,EACX,kBAAkB,EAClB,kBAAkB,EAClB,aAAa,GACd,MAAM,cAAc,CAAC;AAEtB,OAAO,EAAE,cAAc,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC"}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.NodeCheckpointManager = exports.NodeVoteLogger = exports.BatchVoteProcessor = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Node.js Persistent State
|
|
6
|
+
* Extends ecies-lib BatchVoteProcessor with Buffer support
|
|
7
|
+
*/
|
|
8
|
+
const ecies_lib_1 = require("@digitaldefiance/ecies-lib");
|
|
9
|
+
/**
|
|
10
|
+
* Node.js BatchVoteProcessor that extends ecies-lib BatchVoteProcessor
|
|
11
|
+
* Provides type-safe batch processing for Buffer-based votes
|
|
12
|
+
*/
|
|
13
|
+
class BatchVoteProcessor extends ecies_lib_1.BatchVoteProcessor {
|
|
14
|
+
voteLogger;
|
|
15
|
+
checkpointManager;
|
|
16
|
+
totalVotes = 0;
|
|
17
|
+
constructor(batchSize = 1000, voteLogger, checkpointManager) {
|
|
18
|
+
super(batchSize);
|
|
19
|
+
this.voteLogger = voteLogger;
|
|
20
|
+
this.checkpointManager = checkpointManager;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Add a vote to the current batch
|
|
24
|
+
* Returns true if batch is full and should be processed
|
|
25
|
+
*/
|
|
26
|
+
addVote(voter, vote) {
|
|
27
|
+
return super.addVote(voter, vote);
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Process a batch of votes directly
|
|
31
|
+
* This method accepts an array of votes and processes them immediately
|
|
32
|
+
*/
|
|
33
|
+
async processBatch(votesOrProcessor) {
|
|
34
|
+
// If it's an array of votes, process them directly
|
|
35
|
+
if (Array.isArray(votesOrProcessor)) {
|
|
36
|
+
const votes = votesOrProcessor;
|
|
37
|
+
// Log votes if logger is available
|
|
38
|
+
if (this.voteLogger) {
|
|
39
|
+
for (const { voter, vote } of votes) {
|
|
40
|
+
await this.voteLogger.appendVote(voter.id, vote.encrypted, Date.now());
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
this.totalVotes += votes.length;
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
// If it's a processor function, use the base class method
|
|
47
|
+
const processor = votesOrProcessor;
|
|
48
|
+
// Get the current batch from the base class
|
|
49
|
+
const batchSize = this.getBatchSize();
|
|
50
|
+
if (batchSize === 0)
|
|
51
|
+
return;
|
|
52
|
+
// Process with base class method
|
|
53
|
+
await super.processBatch(async (batch) => {
|
|
54
|
+
// Convert the untyped batch to typed batch
|
|
55
|
+
const typedBatch = batch;
|
|
56
|
+
// Log votes if logger is available
|
|
57
|
+
if (this.voteLogger) {
|
|
58
|
+
for (const { voter, vote } of typedBatch) {
|
|
59
|
+
await this.voteLogger.appendVote(voter.id, vote.encrypted, Date.now());
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
this.totalVotes += typedBatch.length;
|
|
63
|
+
// Call the provided processor
|
|
64
|
+
await processor(typedBatch);
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Create a checkpoint of the current state
|
|
69
|
+
*/
|
|
70
|
+
async checkpoint() {
|
|
71
|
+
const snapshot = {
|
|
72
|
+
metadata: {
|
|
73
|
+
jurisdictionId: 'test-jurisdiction',
|
|
74
|
+
level: ecies_lib_1.JurisdictionLevel.Precinct, // Use enum value instead of number
|
|
75
|
+
voterCount: this.totalVotes,
|
|
76
|
+
timestamp: Date.now(),
|
|
77
|
+
checkpointNumber: 0,
|
|
78
|
+
},
|
|
79
|
+
tally: {
|
|
80
|
+
jurisdictionId: Buffer.from([1]), // Required property
|
|
81
|
+
level: ecies_lib_1.JurisdictionLevel.Precinct, // Use enum value instead of number
|
|
82
|
+
voterCount: this.totalVotes,
|
|
83
|
+
encryptedTallies: [], // Required property
|
|
84
|
+
timestamp: Date.now(), // Required property
|
|
85
|
+
jurisdiction: {
|
|
86
|
+
id: Buffer.from([1]),
|
|
87
|
+
name: 'Test Jurisdiction',
|
|
88
|
+
level: ecies_lib_1.JurisdictionLevel.Precinct, // Use enum value
|
|
89
|
+
},
|
|
90
|
+
},
|
|
91
|
+
voteLog: Buffer.alloc(0),
|
|
92
|
+
// Add convenience properties for tests
|
|
93
|
+
totalVotes: this.totalVotes,
|
|
94
|
+
timestamp: Date.now(),
|
|
95
|
+
};
|
|
96
|
+
if (this.checkpointManager) {
|
|
97
|
+
await this.checkpointManager.saveCheckpoint(snapshot.tally);
|
|
98
|
+
}
|
|
99
|
+
return snapshot;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
exports.BatchVoteProcessor = BatchVoteProcessor;
|
|
103
|
+
var node_persistent_state_1 = require("./node-persistent-state");
|
|
104
|
+
Object.defineProperty(exports, "NodeVoteLogger", { enumerable: true, get: function () { return node_persistent_state_1.NodeVoteLogger; } });
|
|
105
|
+
Object.defineProperty(exports, "NodeCheckpointManager", { enumerable: true, get: function () { return node_persistent_state_1.NodeCheckpointManager; } });
|
|
106
|
+
//# sourceMappingURL=persistent-state.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"persistent-state.js","sourceRoot":"","sources":["../../../../../../packages/digitaldefiance-node-ecies-lib/src/lib/voting/persistent-state.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,35 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Secure Voting Poll - Node.js Optimized
|
|
3
|
+
* Extends ecies-lib Poll with Buffer support
|
|
4
|
+
*/
|
|
5
|
+
import { Poll as BasePoll } from '@digitaldefiance/ecies-lib';
|
|
1
6
|
import type { PublicKey } from 'paillier-bigint';
|
|
2
7
|
import type { PlatformID } from '../../interfaces';
|
|
3
8
|
import type { IMember } from '../../interfaces/member';
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
private readonly _receipts;
|
|
14
|
-
private readonly _createdAt;
|
|
15
|
-
private _closedAt?;
|
|
16
|
-
private _maxWeight?;
|
|
17
|
-
private readonly _auditLog;
|
|
9
|
+
import { VotingMethod } from './enumerations';
|
|
10
|
+
/**
|
|
11
|
+
* Node.js Poll that extends ecies-lib Poll
|
|
12
|
+
* Specializes the generic TID parameter to Buffer for Node.js compatibility
|
|
13
|
+
*
|
|
14
|
+
* All core voting logic is inherited from ecies-lib Poll.
|
|
15
|
+
* This class only provides type specialization for Buffer-based operations.
|
|
16
|
+
*/
|
|
17
|
+
export declare class Poll<TID extends PlatformID = Buffer> extends BasePoll<TID> {
|
|
18
18
|
constructor(id: TID, choices: string[], method: VotingMethod, authority: IMember<TID>, votingPublicKey: PublicKey, maxWeight?: bigint, allowInsecure?: boolean);
|
|
19
|
-
get id(): TID;
|
|
20
|
-
get choices(): ReadonlyArray<string>;
|
|
21
|
-
get method(): VotingMethod;
|
|
22
|
-
get isClosed(): boolean;
|
|
23
|
-
get voterCount(): number;
|
|
24
|
-
get createdAt(): number;
|
|
25
|
-
get closedAt(): number | undefined;
|
|
26
|
-
get auditLog(): AuditLog<TID>;
|
|
27
|
-
vote(voter: IMember<TID>, vote: EncryptedVote<TID>): VoteReceipt<TID>;
|
|
28
|
-
verifyReceipt(voter: IMember<TID>, receipt: VoteReceipt<TID>): boolean;
|
|
29
|
-
close(): void;
|
|
30
|
-
getEncryptedVotes(): ReadonlyMap<string, readonly bigint[]>;
|
|
31
|
-
private _validateVote;
|
|
32
|
-
private _generateReceipt;
|
|
33
|
-
private _receiptData;
|
|
34
19
|
}
|
|
35
20
|
//# sourceMappingURL=poll-core.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"poll-core.d.ts","sourceRoot":"","sources":["../../../../../../packages/digitaldefiance-node-ecies-lib/src/lib/voting/poll-core.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"poll-core.d.ts","sourceRoot":"","sources":["../../../../../../packages/digitaldefiance-node-ecies-lib/src/lib/voting/poll-core.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EACL,IAAI,IAAI,QAAQ,EAEjB,MAAM,4BAA4B,CAAC;AACpC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAEjD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAC;AAEvD,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAE9C;;;;;;GAMG;AACH,qBAAa,IAAI,CAAC,GAAG,SAAS,UAAU,GAAG,MAAM,CAAE,SAAQ,QAAQ,CAAC,GAAG,CAAC;gBAEpE,EAAE,EAAE,GAAG,EACP,OAAO,EAAE,MAAM,EAAE,EACjB,MAAM,EAAE,YAAY,EACpB,SAAS,EAAE,OAAO,CAAC,GAAG,CAAC,EACvB,eAAe,EAAE,SAAS,EAC1B,SAAS,CAAC,EAAE,MAAM,EAClB,aAAa,CAAC,EAAE,OAAO;CAkB1B"}
|
|
@@ -3,184 +3,21 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.Poll = void 0;
|
|
4
4
|
/**
|
|
5
5
|
* Secure Voting Poll - Node.js Optimized
|
|
6
|
+
* Extends ecies-lib Poll with Buffer support
|
|
6
7
|
*/
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
class
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
_method;
|
|
17
|
-
_authority;
|
|
18
|
-
___votingPublicKey;
|
|
19
|
-
_votes = new Map();
|
|
20
|
-
_receipts = new Map();
|
|
21
|
-
_createdAt;
|
|
22
|
-
_closedAt;
|
|
23
|
-
_maxWeight;
|
|
24
|
-
_auditLog;
|
|
8
|
+
const ecies_lib_1 = require("@digitaldefiance/ecies-lib");
|
|
9
|
+
/**
|
|
10
|
+
* Node.js Poll that extends ecies-lib Poll
|
|
11
|
+
* Specializes the generic TID parameter to Buffer for Node.js compatibility
|
|
12
|
+
*
|
|
13
|
+
* All core voting logic is inherited from ecies-lib Poll.
|
|
14
|
+
* This class only provides type specialization for Buffer-based operations.
|
|
15
|
+
*/
|
|
16
|
+
class Poll extends ecies_lib_1.Poll {
|
|
25
17
|
constructor(id, choices, method, authority, votingPublicKey, maxWeight, allowInsecure) {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
throw new Error('Authority must have voting keys');
|
|
30
|
-
security_1.VotingSecurityValidator.validate(method, { allowInsecure });
|
|
31
|
-
this._id = id;
|
|
32
|
-
this._choices = Object.freeze([...choices]);
|
|
33
|
-
this._method = method;
|
|
34
|
-
this._authority = authority;
|
|
35
|
-
this.___votingPublicKey = votingPublicKey;
|
|
36
|
-
this._maxWeight = maxWeight;
|
|
37
|
-
this._createdAt = Date.now();
|
|
38
|
-
this._auditLog = new audit_1.ImmutableAuditLog(authority);
|
|
39
|
-
this._auditLog.recordPollCreated(id, {
|
|
40
|
-
method,
|
|
41
|
-
choiceCount: choices.length,
|
|
42
|
-
maxWeight: maxWeight?.toString(),
|
|
43
|
-
});
|
|
44
|
-
}
|
|
45
|
-
get id() {
|
|
46
|
-
return this._id;
|
|
47
|
-
}
|
|
48
|
-
get choices() {
|
|
49
|
-
return this._choices;
|
|
50
|
-
}
|
|
51
|
-
get method() {
|
|
52
|
-
return this._method;
|
|
53
|
-
}
|
|
54
|
-
get isClosed() {
|
|
55
|
-
return this._closedAt !== undefined;
|
|
56
|
-
}
|
|
57
|
-
get voterCount() {
|
|
58
|
-
return this._receipts.size;
|
|
59
|
-
}
|
|
60
|
-
get createdAt() {
|
|
61
|
-
return this._createdAt;
|
|
62
|
-
}
|
|
63
|
-
get closedAt() {
|
|
64
|
-
return this._closedAt;
|
|
65
|
-
}
|
|
66
|
-
get auditLog() {
|
|
67
|
-
return this._auditLog;
|
|
68
|
-
}
|
|
69
|
-
vote(voter, vote) {
|
|
70
|
-
if (this.isClosed)
|
|
71
|
-
throw new Error('Poll is closed');
|
|
72
|
-
const voterId = Buffer.from(voter.id).toString('hex');
|
|
73
|
-
if (this._receipts.has(voterId))
|
|
74
|
-
throw new Error('Already voted');
|
|
75
|
-
this._validateVote(vote);
|
|
76
|
-
this._votes.set(voterId, vote.encrypted);
|
|
77
|
-
const receipt = this._generateReceipt(voter);
|
|
78
|
-
this._receipts.set(voterId, receipt);
|
|
79
|
-
const voterIdHash = (0, crypto_1.createHash)('sha256')
|
|
80
|
-
.update(Buffer.from(voter.id))
|
|
81
|
-
.digest();
|
|
82
|
-
this._auditLog.recordVoteCast(this._id, voterIdHash);
|
|
83
|
-
return receipt;
|
|
84
|
-
}
|
|
85
|
-
verifyReceipt(voter, receipt) {
|
|
86
|
-
const voterId = Buffer.from(voter.id).toString('hex');
|
|
87
|
-
const stored = this._receipts.get(voterId);
|
|
88
|
-
if (!stored)
|
|
89
|
-
return false;
|
|
90
|
-
const data = this._receiptData(receipt);
|
|
91
|
-
return this._authority.verify(receipt.signature, data);
|
|
92
|
-
}
|
|
93
|
-
close() {
|
|
94
|
-
if (this.isClosed)
|
|
95
|
-
throw new Error('Already closed');
|
|
96
|
-
this._closedAt = Date.now();
|
|
97
|
-
this._auditLog.recordPollClosed(this._id, {
|
|
98
|
-
voterCount: this.voterCount,
|
|
99
|
-
closedAt: this._closedAt,
|
|
100
|
-
});
|
|
101
|
-
}
|
|
102
|
-
getEncryptedVotes() {
|
|
103
|
-
const frozenEntries = Array.from(this._votes.entries()).map(([key, value]) => [key, Object.freeze([...value])]);
|
|
104
|
-
const readonlyMap = new Map(frozenEntries);
|
|
105
|
-
return new Proxy(readonlyMap, {
|
|
106
|
-
get(target, prop) {
|
|
107
|
-
if (prop === 'set' || prop === 'delete' || prop === 'clear') {
|
|
108
|
-
throw new Error('Cannot modify readonly map');
|
|
109
|
-
}
|
|
110
|
-
const value = Reflect.get(target, prop);
|
|
111
|
-
if (typeof value === 'function') {
|
|
112
|
-
return value.bind(target);
|
|
113
|
-
}
|
|
114
|
-
return value;
|
|
115
|
-
},
|
|
116
|
-
});
|
|
117
|
-
}
|
|
118
|
-
_validateVote(vote) {
|
|
119
|
-
switch (this._method) {
|
|
120
|
-
case types_1.VotingMethod.Plurality:
|
|
121
|
-
if (vote.choiceIndex === undefined)
|
|
122
|
-
throw new Error('Choice required');
|
|
123
|
-
if (vote.choiceIndex < 0 || vote.choiceIndex >= this._choices.length) {
|
|
124
|
-
throw new Error('Invalid choice');
|
|
125
|
-
}
|
|
126
|
-
break;
|
|
127
|
-
case types_1.VotingMethod.Approval:
|
|
128
|
-
if (!vote.choices?.length)
|
|
129
|
-
throw new Error('Choices required');
|
|
130
|
-
for (const c of vote.choices) {
|
|
131
|
-
if (c < 0 || c >= this._choices.length)
|
|
132
|
-
throw new Error('Invalid choice');
|
|
133
|
-
}
|
|
134
|
-
break;
|
|
135
|
-
case types_1.VotingMethod.Weighted:
|
|
136
|
-
if (vote.choiceIndex === undefined)
|
|
137
|
-
throw new Error('Choice required');
|
|
138
|
-
if (!vote.weight || vote.weight <= 0n)
|
|
139
|
-
throw new Error('Weight must be positive');
|
|
140
|
-
if (this._maxWeight && vote.weight > this._maxWeight) {
|
|
141
|
-
throw new Error('Weight exceeds maximum');
|
|
142
|
-
}
|
|
143
|
-
break;
|
|
144
|
-
case types_1.VotingMethod.Borda:
|
|
145
|
-
case types_1.VotingMethod.RankedChoice: {
|
|
146
|
-
if (!vote.rankings?.length)
|
|
147
|
-
throw new Error('Rankings required');
|
|
148
|
-
const seen = new Set();
|
|
149
|
-
for (const r of vote.rankings) {
|
|
150
|
-
if (r < 0 || r >= this._choices.length)
|
|
151
|
-
throw new Error('Invalid choice');
|
|
152
|
-
if (seen.has(r))
|
|
153
|
-
throw new Error('Duplicate ranking');
|
|
154
|
-
seen.add(r);
|
|
155
|
-
}
|
|
156
|
-
break;
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
if (!vote.encrypted?.length)
|
|
160
|
-
throw new Error('Encrypted data required');
|
|
161
|
-
}
|
|
162
|
-
_generateReceipt(voter) {
|
|
163
|
-
const nonce = (0, crypto_1.randomBytes)(16);
|
|
164
|
-
const receipt = {
|
|
165
|
-
voterId: voter.id,
|
|
166
|
-
pollId: this._id,
|
|
167
|
-
timestamp: Date.now(),
|
|
168
|
-
signature: Buffer.alloc(0),
|
|
169
|
-
nonce,
|
|
170
|
-
};
|
|
171
|
-
const data = this._receiptData(receipt);
|
|
172
|
-
receipt.signature = this._authority.sign(data);
|
|
173
|
-
return receipt;
|
|
174
|
-
}
|
|
175
|
-
_receiptData(receipt) {
|
|
176
|
-
const timestamp = Buffer.alloc(8);
|
|
177
|
-
timestamp.writeBigUInt64BE(BigInt(receipt.timestamp));
|
|
178
|
-
return Buffer.concat([
|
|
179
|
-
Constants.idProvider.toBytes(receipt.voterId),
|
|
180
|
-
Constants.idProvider.toBytes(receipt.pollId),
|
|
181
|
-
timestamp,
|
|
182
|
-
receipt.nonce,
|
|
183
|
-
]);
|
|
18
|
+
// Cast authority to work around type incompatibility between
|
|
19
|
+
// node-ecies-lib IMember (Buffer-based) and ecies-lib IMember (Uint8Array-based)
|
|
20
|
+
super(id, choices, method, authority, votingPublicKey, maxWeight, allowInsecure);
|
|
184
21
|
}
|
|
185
22
|
}
|
|
186
23
|
exports.Poll = Poll;
|