@digitaldefiance/node-ecies-lib 4.7.1 → 4.7.2
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 +32 -0
- package/package.json +3 -10
- package/src/lib/voting/audit.d.ts.map +1 -1
- package/src/lib/voting/audit.js +4 -2
- package/src/lib/voting/audit.js.map +1 -1
- package/src/lib/voting/bulletin-board.d.ts +86 -0
- package/src/lib/voting/bulletin-board.d.ts.map +1 -0
- package/src/lib/voting/bulletin-board.js +253 -0
- package/src/lib/voting/bulletin-board.js.map +1 -0
- package/src/lib/voting/event-logger.d.ts +83 -0
- package/src/lib/voting/event-logger.d.ts.map +1 -0
- package/src/lib/voting/event-logger.js +152 -0
- package/src/lib/voting/event-logger.js.map +1 -0
- package/src/lib/voting/index.d.ts +3 -0
- package/src/lib/voting/index.d.ts.map +1 -1
- package/src/lib/voting/index.js +8 -1
- package/src/lib/voting/index.js.map +1 -1
- package/src/lib/voting/poll.d.ts +124 -0
- package/src/lib/voting/poll.d.ts.map +1 -0
- package/src/lib/voting/poll.js +323 -0
- package/src/lib/voting/poll.js.map +1 -0
package/README.md
CHANGED
|
@@ -48,6 +48,24 @@ This library implements a modern, enterprise-grade ECIES protocol (v4.0) featuri
|
|
|
48
48
|
- **Runtime Configuration**: Injectable configuration profiles via `ConstantsRegistry` for dependency injection and testing.
|
|
49
49
|
- **Cross-Platform**: Fully compatible with similarly numbered releases of `@digitaldefiance/ecies-lib` (browser).
|
|
50
50
|
|
|
51
|
+
### 🗳️ Government-Grade Voting System
|
|
52
|
+
|
|
53
|
+
A comprehensive voting system built on homomorphic encryption with 17 voting methods and 1100+ test cases:
|
|
54
|
+
|
|
55
|
+
- **Fully Secure Methods**: Plurality, Approval, Weighted, Borda Count, Score, Yes/No, Supermajority
|
|
56
|
+
- **Multi-Round Methods**: Ranked Choice (IRV), Two-Round, STAR, STV
|
|
57
|
+
- **Core Security Features**:
|
|
58
|
+
- Homomorphic encryption (Paillier cryptosystem) - votes remain encrypted until tally
|
|
59
|
+
- Verifiable receipts with ECDSA signatures
|
|
60
|
+
- Public bulletin board with Merkle tree integrity
|
|
61
|
+
- Immutable audit log with cryptographic hash chain
|
|
62
|
+
- Event logger with microsecond timestamps
|
|
63
|
+
- Role separation (poll aggregator cannot decrypt votes)
|
|
64
|
+
- Double-vote prevention
|
|
65
|
+
- **Government Requirements (EARS)**: Audit Log, Bulletin Board, Event Logger
|
|
66
|
+
|
|
67
|
+
See [Voting System Documentation](src/lib/voting/README.md) for complete details.
|
|
68
|
+
|
|
51
69
|
## Compatibility
|
|
52
70
|
|
|
53
71
|
**Important Note**: This library is **NOT** binary compatible with previous major versions (v1.x, v2.x, v3.x) due to the protocol upgrade to v4.0 (HKDF, AAD binding).
|
|
@@ -233,6 +251,20 @@ const encrypted = member.encryptData('My Secrets');
|
|
|
233
251
|
- `dispose()` method to explicitly zero out memory.
|
|
234
252
|
- Prevents accidental leakage via `console.log` or serialization.
|
|
235
253
|
|
|
254
|
+
### Voting System
|
|
255
|
+
|
|
256
|
+
- **`Poll`**: Core poll with vote aggregation and receipt issuance.
|
|
257
|
+
- **`VotingPoll`**: High-level voting with encrypted receipts.
|
|
258
|
+
- **`PollTallier`**: Decrypts and tallies votes (holds private key).
|
|
259
|
+
- **`VoteEncoder`**: Encrypts votes using Paillier homomorphic encryption.
|
|
260
|
+
- **`PollFactory`**: Convenient poll creation with method-specific configurations.
|
|
261
|
+
- **`VotingSecurityValidator`**: Security level validation and enforcement.
|
|
262
|
+
- **`ImmutableAuditLog`**: Hash-chained audit trail for compliance.
|
|
263
|
+
- **`PublicBulletinBoard`**: Append-only vote publication with Merkle tree.
|
|
264
|
+
- **`PollEventLogger`**: Event tracking with microsecond timestamps.
|
|
265
|
+
- **`VotingMethod`**: Enum with all 17 voting methods.
|
|
266
|
+
- **`SecurityLevel`**: Enum for security classifications (FullyHomomorphic, MultiRound, Insecure).
|
|
267
|
+
|
|
236
268
|
## Development
|
|
237
269
|
|
|
238
270
|
### Commands
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@digitaldefiance/node-ecies-lib",
|
|
3
|
-
"version": "4.7.
|
|
3
|
+
"version": "4.7.2",
|
|
4
4
|
"description": "Digital Defiance Node ECIES Library",
|
|
5
5
|
"homepage": "https://github.com/Digital-Defiance/node-ecies-lib",
|
|
6
6
|
"repository": {
|
|
@@ -56,16 +56,8 @@
|
|
|
56
56
|
"author": "Digital Defiance",
|
|
57
57
|
"license": "MIT",
|
|
58
58
|
"packageManager": "yarn@4.10.3",
|
|
59
|
-
"peerDependencies": {
|
|
60
|
-
"paillier-bigint": "^3.4.1"
|
|
61
|
-
},
|
|
62
|
-
"peerDependenciesMeta": {
|
|
63
|
-
"paillier-bigint": {
|
|
64
|
-
"optional": true
|
|
65
|
-
}
|
|
66
|
-
},
|
|
67
59
|
"dependencies": {
|
|
68
|
-
"@digitaldefiance/ecies-lib": "4.7.
|
|
60
|
+
"@digitaldefiance/ecies-lib": "4.7.1",
|
|
69
61
|
"@digitaldefiance/express-suite-test-utils": "1.0.14",
|
|
70
62
|
"@digitaldefiance/i18n-lib": "3.8.16",
|
|
71
63
|
"@ethereumjs/wallet": "^10.0.0",
|
|
@@ -74,6 +66,7 @@
|
|
|
74
66
|
"@scure/bip32": "1.7.0",
|
|
75
67
|
"bson": "^6.10.4",
|
|
76
68
|
"ethereum-cryptography": "^3.2.0",
|
|
69
|
+
"paillier-bigint": "^3.4.1",
|
|
77
70
|
"ts-brand": "^0.2.0"
|
|
78
71
|
},
|
|
79
72
|
"devDependencies": {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"audit.d.ts","sourceRoot":"","sources":["../../../../../../packages/digitaldefiance-node-ecies-lib/src/lib/voting/audit.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"audit.d.ts","sourceRoot":"","sources":["../../../../../../packages/digitaldefiance-node-ecies-lib/src/lib/voting/audit.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAC;AAGvD,oBAAY,cAAc;IACxB,WAAW,iBAAiB;IAC5B,QAAQ,cAAc;IACtB,UAAU,gBAAgB;CAC3B;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,SAAS,EAAE,cAAc,CAAC;IACnC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC7C;AAED,MAAM,WAAW,QAAQ;IACvB,UAAU,IAAI,SAAS,UAAU,EAAE,CAAC;IACpC,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,UAAU,EAAE,CAAC;IACzD,WAAW,IAAI,OAAO,CAAC;IACvB,WAAW,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC;CACzC;AAED,qBAAa,iBAAkB,YAAW,QAAQ;IAChD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAoB;IAC5C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAU;IACpC,OAAO,CAAC,QAAQ,CAAK;gBAET,SAAS,EAAE,OAAO;IAI9B,iBAAiB,CACf,MAAM,EAAE,MAAM,EACd,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACjC,UAAU;IASb,cAAc,CACZ,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,EACnB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACjC,UAAU;IASb,gBAAgB,CACd,MAAM,EAAE,MAAM,EACd,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACjC,UAAU;IASb,UAAU,IAAI,SAAS,UAAU,EAAE;IAInC,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,UAAU,EAAE;IAOxD,WAAW,IAAI,OAAO;IAetB,WAAW,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO;IAQvC,OAAO,CAAC,WAAW;IAwBnB,OAAO,CAAC,gBAAgB;IAOxB,OAAO,CAAC,wBAAwB;IAiBhC,OAAO,CAAC,wBAAwB;IAShC,OAAO,CAAC,uBAAuB;IAO/B,OAAO,CAAC,YAAY;CAKrB"}
|
package/src/lib/voting/audit.js
CHANGED
|
@@ -6,7 +6,6 @@ exports.ImmutableAuditLog = exports.AuditEventType = void 0;
|
|
|
6
6
|
* Node.js optimized with native crypto
|
|
7
7
|
*/
|
|
8
8
|
const crypto_1 = require("crypto");
|
|
9
|
-
const perf_hooks_1 = require("perf_hooks");
|
|
10
9
|
var AuditEventType;
|
|
11
10
|
(function (AuditEventType) {
|
|
12
11
|
AuditEventType["PollCreated"] = "poll_created";
|
|
@@ -117,7 +116,10 @@ class ImmutableAuditLog {
|
|
|
117
116
|
]);
|
|
118
117
|
}
|
|
119
118
|
getMicrosecondTimestamp() {
|
|
120
|
-
|
|
119
|
+
// Get milliseconds since epoch and convert to microseconds
|
|
120
|
+
// performance.now() is relative to process start, not epoch, so we only use Date.now()
|
|
121
|
+
const now = Date.now();
|
|
122
|
+
return now * 1000;
|
|
121
123
|
}
|
|
122
124
|
encodeNumber(n) {
|
|
123
125
|
const buf = Buffer.alloc(8);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"audit.js","sourceRoot":"","sources":["../../../../../../packages/digitaldefiance-node-ecies-lib/src/lib/voting/audit.ts"],"names":[],"mappings":";;;AAAA;;;GAGG;AACH,mCAAoC;
|
|
1
|
+
{"version":3,"file":"audit.js","sourceRoot":"","sources":["../../../../../../packages/digitaldefiance-node-ecies-lib/src/lib/voting/audit.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import type { IMember } from '../../interfaces/member';
|
|
2
|
+
export interface BulletinBoardEntry {
|
|
3
|
+
/** Sequence number (monotonically increasing) */
|
|
4
|
+
readonly sequence: number;
|
|
5
|
+
/** Microsecond-precision timestamp */
|
|
6
|
+
readonly timestamp: number;
|
|
7
|
+
/** Poll identifier */
|
|
8
|
+
readonly pollId: Buffer;
|
|
9
|
+
/** Encrypted vote data */
|
|
10
|
+
readonly encryptedVote: bigint[];
|
|
11
|
+
/** Hash of voter ID (anonymized) */
|
|
12
|
+
readonly voterIdHash: Buffer;
|
|
13
|
+
/** Merkle root of all entries up to this point */
|
|
14
|
+
readonly merkleRoot: Buffer;
|
|
15
|
+
/** Hash of this entry */
|
|
16
|
+
readonly entryHash: Buffer;
|
|
17
|
+
/** Authority signature */
|
|
18
|
+
readonly signature: Buffer;
|
|
19
|
+
}
|
|
20
|
+
export interface TallyProof {
|
|
21
|
+
/** Poll identifier */
|
|
22
|
+
readonly pollId: Buffer;
|
|
23
|
+
/** Final tallies */
|
|
24
|
+
readonly tallies: bigint[];
|
|
25
|
+
/** Choice names */
|
|
26
|
+
readonly choices: string[];
|
|
27
|
+
/** Timestamp of tally */
|
|
28
|
+
readonly timestamp: number;
|
|
29
|
+
/** Hash of all encrypted votes */
|
|
30
|
+
readonly votesHash: Buffer;
|
|
31
|
+
/** Cryptographic proof of correct decryption */
|
|
32
|
+
readonly decryptionProof: Buffer;
|
|
33
|
+
/** Authority signature */
|
|
34
|
+
readonly signature: Buffer;
|
|
35
|
+
}
|
|
36
|
+
export interface BulletinBoard {
|
|
37
|
+
/** Publish encrypted vote to bulletin board */
|
|
38
|
+
publishVote(pollId: Buffer, encryptedVote: bigint[], voterIdHash: Buffer): BulletinBoardEntry;
|
|
39
|
+
/** Publish tally with cryptographic proof */
|
|
40
|
+
publishTally(pollId: Buffer, tallies: bigint[], choices: string[], encryptedVotes: bigint[][]): TallyProof;
|
|
41
|
+
/** Get all entries for a poll */
|
|
42
|
+
getEntries(pollId: Buffer): readonly BulletinBoardEntry[];
|
|
43
|
+
/** Get all entries (entire bulletin board) */
|
|
44
|
+
getAllEntries(): readonly BulletinBoardEntry[];
|
|
45
|
+
/** Get tally proof for a poll */
|
|
46
|
+
getTallyProof(pollId: Buffer): TallyProof | undefined;
|
|
47
|
+
/** Verify entry signature and hash */
|
|
48
|
+
verifyEntry(entry: BulletinBoardEntry): boolean;
|
|
49
|
+
/** Verify tally proof */
|
|
50
|
+
verifyTallyProof(proof: TallyProof): boolean;
|
|
51
|
+
/** Verify Merkle tree integrity */
|
|
52
|
+
verifyMerkleTree(): boolean;
|
|
53
|
+
/** Export complete bulletin board for archival */
|
|
54
|
+
export(): Buffer;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Append-only public bulletin board with cryptographic verification
|
|
58
|
+
*/
|
|
59
|
+
export declare class PublicBulletinBoard implements BulletinBoard {
|
|
60
|
+
private readonly entries;
|
|
61
|
+
private readonly tallyProofs;
|
|
62
|
+
private readonly authority;
|
|
63
|
+
private sequence;
|
|
64
|
+
constructor(authority: IMember);
|
|
65
|
+
publishVote(pollId: Buffer, encryptedVote: bigint[], voterIdHash: Buffer): BulletinBoardEntry;
|
|
66
|
+
publishTally(pollId: Buffer, tallies: bigint[], choices: string[], encryptedVotes: bigint[][]): TallyProof;
|
|
67
|
+
getEntries(pollId: Buffer): readonly BulletinBoardEntry[];
|
|
68
|
+
getAllEntries(): readonly BulletinBoardEntry[];
|
|
69
|
+
getTallyProof(pollId: Buffer): TallyProof | undefined;
|
|
70
|
+
verifyEntry(entry: BulletinBoardEntry): boolean;
|
|
71
|
+
verifyTallyProof(proof: TallyProof): boolean;
|
|
72
|
+
verifyMerkleTree(): boolean;
|
|
73
|
+
export(): Buffer;
|
|
74
|
+
private computeMerkleRoot;
|
|
75
|
+
private hashEncryptedVotes;
|
|
76
|
+
private generateDecryptionProof;
|
|
77
|
+
private serializeEntryData;
|
|
78
|
+
private serializeTallyProof;
|
|
79
|
+
private serializeEntry;
|
|
80
|
+
private serializeTallyProofFull;
|
|
81
|
+
private getMicrosecondTimestamp;
|
|
82
|
+
private sha256;
|
|
83
|
+
private encodeNumber;
|
|
84
|
+
private encodeBigInt;
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=bulletin-board.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bulletin-board.d.ts","sourceRoot":"","sources":["../../../../../../packages/digitaldefiance-node-ecies-lib/src/lib/voting/bulletin-board.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAC;AAGvD,MAAM,WAAW,kBAAkB;IACjC,iDAAiD;IACjD,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,sCAAsC;IACtC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,sBAAsB;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,0BAA0B;IAC1B,QAAQ,CAAC,aAAa,EAAE,MAAM,EAAE,CAAC;IACjC,oCAAoC;IACpC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,kDAAkD;IAClD,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,yBAAyB;IACzB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,0BAA0B;IAC1B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,UAAU;IACzB,sBAAsB;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,oBAAoB;IACpB,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,CAAC;IAC3B,mBAAmB;IACnB,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,CAAC;IAC3B,yBAAyB;IACzB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,kCAAkC;IAClC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,gDAAgD;IAChD,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,0BAA0B;IAC1B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,aAAa;IAC5B,+CAA+C;IAC/C,WAAW,CACT,MAAM,EAAE,MAAM,EACd,aAAa,EAAE,MAAM,EAAE,EACvB,WAAW,EAAE,MAAM,GAClB,kBAAkB,CAAC;IAEtB,6CAA6C;IAC7C,YAAY,CACV,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,EAAE,EACjB,OAAO,EAAE,MAAM,EAAE,EACjB,cAAc,EAAE,MAAM,EAAE,EAAE,GACzB,UAAU,CAAC;IAEd,iCAAiC;IACjC,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,kBAAkB,EAAE,CAAC;IAE1D,8CAA8C;IAC9C,aAAa,IAAI,SAAS,kBAAkB,EAAE,CAAC;IAE/C,iCAAiC;IACjC,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS,CAAC;IAEtD,sCAAsC;IACtC,WAAW,CAAC,KAAK,EAAE,kBAAkB,GAAG,OAAO,CAAC;IAEhD,yBAAyB;IACzB,gBAAgB,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC;IAE7C,mCAAmC;IACnC,gBAAgB,IAAI,OAAO,CAAC;IAE5B,kDAAkD;IAClD,MAAM,IAAI,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,qBAAa,mBAAoB,YAAW,aAAa;IACvD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA4B;IACpD,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAiC;IAC7D,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAU;IACpC,OAAO,CAAC,QAAQ,CAAK;gBAET,SAAS,EAAE,OAAO;IAI9B,WAAW,CACT,MAAM,EAAE,MAAM,EACd,aAAa,EAAE,MAAM,EAAE,EACvB,WAAW,EAAE,MAAM,GAClB,kBAAkB;IA+BrB,YAAY,CACV,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,EAAE,EACjB,OAAO,EAAE,MAAM,EAAE,EACjB,cAAc,EAAE,MAAM,EAAE,EAAE,GACzB,UAAU;IAiCb,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,kBAAkB,EAAE;IAOzD,aAAa,IAAI,SAAS,kBAAkB,EAAE;IAI9C,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS;IAIrD,WAAW,CAAC,KAAK,EAAE,kBAAkB,GAAG,OAAO;IAqB/C,gBAAgB,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO;IAa5C,gBAAgB,IAAI,OAAO;IAY3B,MAAM,IAAI,MAAM;IAkBhB,OAAO,CAAC,iBAAiB;IAwBzB,OAAO,CAAC,kBAAkB;IAU1B,OAAO,CAAC,uBAAuB;IAkB/B,OAAO,CAAC,kBAAkB;IAuB1B,OAAO,CAAC,mBAAmB;IA0B3B,OAAO,CAAC,cAAc;IA2BtB,OAAO,CAAC,uBAAuB;IA8B/B,OAAO,CAAC,uBAAuB;IAO/B,OAAO,CAAC,MAAM;IAId,OAAO,CAAC,YAAY;IAMpB,OAAO,CAAC,YAAY;CAIrB"}
|
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PublicBulletinBoard = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Public Bulletin Board for Government-Grade Voting
|
|
6
|
+
* Node.js optimized with native crypto
|
|
7
|
+
* Implements requirement 1.2: Append-only, publicly verifiable vote publication
|
|
8
|
+
*/
|
|
9
|
+
const crypto_1 = require("crypto");
|
|
10
|
+
/**
|
|
11
|
+
* Append-only public bulletin board with cryptographic verification
|
|
12
|
+
*/
|
|
13
|
+
class PublicBulletinBoard {
|
|
14
|
+
entries = [];
|
|
15
|
+
tallyProofs = new Map();
|
|
16
|
+
authority;
|
|
17
|
+
sequence = 0;
|
|
18
|
+
constructor(authority) {
|
|
19
|
+
this.authority = authority;
|
|
20
|
+
}
|
|
21
|
+
publishVote(pollId, encryptedVote, voterIdHash) {
|
|
22
|
+
const timestamp = this.getMicrosecondTimestamp();
|
|
23
|
+
const merkleRoot = this.computeMerkleRoot([...this.entries]);
|
|
24
|
+
const entryData = this.serializeEntryData({
|
|
25
|
+
sequence: this.sequence,
|
|
26
|
+
timestamp,
|
|
27
|
+
pollId,
|
|
28
|
+
encryptedVote,
|
|
29
|
+
voterIdHash,
|
|
30
|
+
merkleRoot,
|
|
31
|
+
});
|
|
32
|
+
const entryHash = this.sha256(entryData);
|
|
33
|
+
const signature = this.authority.sign(entryHash);
|
|
34
|
+
const entry = {
|
|
35
|
+
sequence: this.sequence++,
|
|
36
|
+
timestamp,
|
|
37
|
+
pollId,
|
|
38
|
+
encryptedVote,
|
|
39
|
+
voterIdHash,
|
|
40
|
+
merkleRoot,
|
|
41
|
+
entryHash,
|
|
42
|
+
signature,
|
|
43
|
+
};
|
|
44
|
+
this.entries.push(entry);
|
|
45
|
+
return entry;
|
|
46
|
+
}
|
|
47
|
+
publishTally(pollId, tallies, choices, encryptedVotes) {
|
|
48
|
+
const timestamp = this.getMicrosecondTimestamp();
|
|
49
|
+
const votesHash = this.hashEncryptedVotes(encryptedVotes);
|
|
50
|
+
const decryptionProof = this.generateDecryptionProof(encryptedVotes, tallies);
|
|
51
|
+
const proofData = this.serializeTallyProof({
|
|
52
|
+
pollId,
|
|
53
|
+
tallies,
|
|
54
|
+
choices,
|
|
55
|
+
timestamp,
|
|
56
|
+
votesHash,
|
|
57
|
+
decryptionProof,
|
|
58
|
+
});
|
|
59
|
+
const signature = this.authority.sign(proofData);
|
|
60
|
+
const proof = {
|
|
61
|
+
pollId,
|
|
62
|
+
tallies,
|
|
63
|
+
choices,
|
|
64
|
+
timestamp,
|
|
65
|
+
votesHash,
|
|
66
|
+
decryptionProof,
|
|
67
|
+
signature,
|
|
68
|
+
};
|
|
69
|
+
this.tallyProofs.set(pollId.toString('hex'), proof);
|
|
70
|
+
return proof;
|
|
71
|
+
}
|
|
72
|
+
getEntries(pollId) {
|
|
73
|
+
const pollIdStr = pollId.toString('hex');
|
|
74
|
+
return Object.freeze(this.entries.filter((e) => e.pollId.toString('hex') === pollIdStr));
|
|
75
|
+
}
|
|
76
|
+
getAllEntries() {
|
|
77
|
+
return Object.freeze([...this.entries]);
|
|
78
|
+
}
|
|
79
|
+
getTallyProof(pollId) {
|
|
80
|
+
return this.tallyProofs.get(pollId.toString('hex'));
|
|
81
|
+
}
|
|
82
|
+
verifyEntry(entry) {
|
|
83
|
+
const entryData = this.serializeEntryData({
|
|
84
|
+
sequence: entry.sequence,
|
|
85
|
+
timestamp: entry.timestamp,
|
|
86
|
+
pollId: entry.pollId,
|
|
87
|
+
encryptedVote: entry.encryptedVote,
|
|
88
|
+
voterIdHash: entry.voterIdHash,
|
|
89
|
+
merkleRoot: entry.merkleRoot,
|
|
90
|
+
});
|
|
91
|
+
const computedHash = this.sha256(entryData);
|
|
92
|
+
if (!computedHash.equals(entry.entryHash)) {
|
|
93
|
+
return false;
|
|
94
|
+
}
|
|
95
|
+
return this.authority.verify(entry.signature, entry.entryHash);
|
|
96
|
+
}
|
|
97
|
+
verifyTallyProof(proof) {
|
|
98
|
+
const proofData = this.serializeTallyProof({
|
|
99
|
+
pollId: proof.pollId,
|
|
100
|
+
tallies: proof.tallies,
|
|
101
|
+
choices: proof.choices,
|
|
102
|
+
timestamp: proof.timestamp,
|
|
103
|
+
votesHash: proof.votesHash,
|
|
104
|
+
decryptionProof: proof.decryptionProof,
|
|
105
|
+
});
|
|
106
|
+
return this.authority.verify(proof.signature, proofData);
|
|
107
|
+
}
|
|
108
|
+
verifyMerkleTree() {
|
|
109
|
+
for (let i = 0; i < this.entries.length; i++) {
|
|
110
|
+
const entry = this.entries[i];
|
|
111
|
+
const expectedRoot = this.computeMerkleRoot(this.entries.slice(0, i));
|
|
112
|
+
if (!entry.merkleRoot.equals(expectedRoot)) {
|
|
113
|
+
return false;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
return true;
|
|
117
|
+
}
|
|
118
|
+
export() {
|
|
119
|
+
const parts = [];
|
|
120
|
+
// Export entries
|
|
121
|
+
parts.push(this.encodeNumber(this.entries.length));
|
|
122
|
+
for (const entry of this.entries) {
|
|
123
|
+
parts.push(this.serializeEntry(entry));
|
|
124
|
+
}
|
|
125
|
+
// Export tally proofs
|
|
126
|
+
parts.push(this.encodeNumber(this.tallyProofs.size));
|
|
127
|
+
for (const proof of this.tallyProofs.values()) {
|
|
128
|
+
parts.push(this.serializeTallyProofFull(proof));
|
|
129
|
+
}
|
|
130
|
+
return Buffer.concat(parts);
|
|
131
|
+
}
|
|
132
|
+
computeMerkleRoot(entries) {
|
|
133
|
+
if (entries.length === 0) {
|
|
134
|
+
return Buffer.alloc(32);
|
|
135
|
+
}
|
|
136
|
+
let hashes = entries.map((e) => e.entryHash);
|
|
137
|
+
while (hashes.length > 1) {
|
|
138
|
+
const nextLevel = [];
|
|
139
|
+
for (let i = 0; i < hashes.length; i += 2) {
|
|
140
|
+
if (i + 1 < hashes.length) {
|
|
141
|
+
nextLevel.push(this.sha256(Buffer.concat([hashes[i], hashes[i + 1]])));
|
|
142
|
+
}
|
|
143
|
+
else {
|
|
144
|
+
nextLevel.push(hashes[i]);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
hashes = nextLevel;
|
|
148
|
+
}
|
|
149
|
+
return hashes[0];
|
|
150
|
+
}
|
|
151
|
+
hashEncryptedVotes(votes) {
|
|
152
|
+
const parts = [];
|
|
153
|
+
for (const vote of votes) {
|
|
154
|
+
for (const value of vote) {
|
|
155
|
+
parts.push(this.encodeBigInt(value));
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
return this.sha256(Buffer.concat(parts));
|
|
159
|
+
}
|
|
160
|
+
generateDecryptionProof(encryptedVotes, tallies) {
|
|
161
|
+
// Simplified proof: hash of encrypted votes + tallies
|
|
162
|
+
// In production, use ZK-SNARK or similar
|
|
163
|
+
const parts = [];
|
|
164
|
+
for (const vote of encryptedVotes) {
|
|
165
|
+
for (const value of vote) {
|
|
166
|
+
parts.push(this.encodeBigInt(value));
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
for (const tally of tallies) {
|
|
170
|
+
parts.push(this.encodeBigInt(tally));
|
|
171
|
+
}
|
|
172
|
+
return this.sha256(Buffer.concat(parts));
|
|
173
|
+
}
|
|
174
|
+
serializeEntryData(data) {
|
|
175
|
+
const parts = [
|
|
176
|
+
this.encodeNumber(data.sequence),
|
|
177
|
+
this.encodeNumber(data.timestamp),
|
|
178
|
+
data.pollId,
|
|
179
|
+
data.voterIdHash,
|
|
180
|
+
data.merkleRoot,
|
|
181
|
+
];
|
|
182
|
+
for (const value of data.encryptedVote) {
|
|
183
|
+
parts.push(this.encodeBigInt(value));
|
|
184
|
+
}
|
|
185
|
+
return Buffer.concat(parts);
|
|
186
|
+
}
|
|
187
|
+
serializeTallyProof(data) {
|
|
188
|
+
const parts = [
|
|
189
|
+
data.pollId,
|
|
190
|
+
this.encodeNumber(data.timestamp),
|
|
191
|
+
data.votesHash,
|
|
192
|
+
data.decryptionProof,
|
|
193
|
+
];
|
|
194
|
+
for (const tally of data.tallies) {
|
|
195
|
+
parts.push(this.encodeBigInt(tally));
|
|
196
|
+
}
|
|
197
|
+
for (const choice of data.choices) {
|
|
198
|
+
parts.push(Buffer.from(choice, 'utf8'));
|
|
199
|
+
}
|
|
200
|
+
return Buffer.concat(parts);
|
|
201
|
+
}
|
|
202
|
+
serializeEntry(entry) {
|
|
203
|
+
const parts = [
|
|
204
|
+
this.encodeNumber(entry.sequence),
|
|
205
|
+
this.encodeNumber(entry.timestamp),
|
|
206
|
+
this.encodeNumber(entry.pollId.length),
|
|
207
|
+
entry.pollId,
|
|
208
|
+
this.encodeNumber(entry.encryptedVote.length),
|
|
209
|
+
];
|
|
210
|
+
for (const value of entry.encryptedVote) {
|
|
211
|
+
parts.push(this.encodeBigInt(value));
|
|
212
|
+
}
|
|
213
|
+
parts.push(this.encodeNumber(entry.voterIdHash.length), entry.voterIdHash, this.encodeNumber(entry.merkleRoot.length), entry.merkleRoot, this.encodeNumber(entry.entryHash.length), entry.entryHash, this.encodeNumber(entry.signature.length), entry.signature);
|
|
214
|
+
return Buffer.concat(parts);
|
|
215
|
+
}
|
|
216
|
+
serializeTallyProofFull(proof) {
|
|
217
|
+
const parts = [
|
|
218
|
+
this.encodeNumber(proof.pollId.length),
|
|
219
|
+
proof.pollId,
|
|
220
|
+
this.encodeNumber(proof.tallies.length),
|
|
221
|
+
];
|
|
222
|
+
for (const tally of proof.tallies) {
|
|
223
|
+
parts.push(this.encodeBigInt(tally));
|
|
224
|
+
}
|
|
225
|
+
parts.push(this.encodeNumber(proof.choices.length));
|
|
226
|
+
for (const choice of proof.choices) {
|
|
227
|
+
const encoded = Buffer.from(choice, 'utf8');
|
|
228
|
+
parts.push(this.encodeNumber(encoded.length), encoded);
|
|
229
|
+
}
|
|
230
|
+
parts.push(this.encodeNumber(proof.timestamp), this.encodeNumber(proof.votesHash.length), proof.votesHash, this.encodeNumber(proof.decryptionProof.length), proof.decryptionProof, this.encodeNumber(proof.signature.length), proof.signature);
|
|
231
|
+
return Buffer.concat(parts);
|
|
232
|
+
}
|
|
233
|
+
getMicrosecondTimestamp() {
|
|
234
|
+
// Get milliseconds since epoch and convert to microseconds
|
|
235
|
+
// performance.now() is relative to process start, not epoch, so we only use Date.now()
|
|
236
|
+
const now = Date.now();
|
|
237
|
+
return now * 1000;
|
|
238
|
+
}
|
|
239
|
+
sha256(data) {
|
|
240
|
+
return (0, crypto_1.createHash)('sha256').update(data).digest();
|
|
241
|
+
}
|
|
242
|
+
encodeNumber(n) {
|
|
243
|
+
const buffer = Buffer.alloc(8);
|
|
244
|
+
buffer.writeBigUInt64BE(BigInt(n));
|
|
245
|
+
return buffer;
|
|
246
|
+
}
|
|
247
|
+
encodeBigInt(n) {
|
|
248
|
+
const hex = n.toString(16).padStart(64, '0');
|
|
249
|
+
return Buffer.from(hex, 'hex');
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
exports.PublicBulletinBoard = PublicBulletinBoard;
|
|
253
|
+
//# sourceMappingURL=bulletin-board.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bulletin-board.js","sourceRoot":"","sources":["../../../../../../packages/digitaldefiance-node-ecies-lib/src/lib/voting/bulletin-board.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Event Logger for Government-Grade Voting
|
|
3
|
+
* Node.js optimized with native Buffer
|
|
4
|
+
* Implements requirement 1.3: Comprehensive event logging with microsecond timestamps
|
|
5
|
+
*/
|
|
6
|
+
export declare enum EventType {
|
|
7
|
+
PollCreated = "poll_created",
|
|
8
|
+
VoteCast = "vote_cast",
|
|
9
|
+
PollClosed = "poll_closed",
|
|
10
|
+
VoteVerified = "vote_verified",
|
|
11
|
+
TallyComputed = "tally_computed",
|
|
12
|
+
AuditRequested = "audit_requested"
|
|
13
|
+
}
|
|
14
|
+
export interface PollConfiguration {
|
|
15
|
+
readonly method: string;
|
|
16
|
+
readonly choices: string[];
|
|
17
|
+
readonly maxWeight?: bigint;
|
|
18
|
+
readonly threshold?: {
|
|
19
|
+
numerator: number;
|
|
20
|
+
denominator: number;
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
export interface EventLogEntry {
|
|
24
|
+
/** Sequence number (monotonically increasing) */
|
|
25
|
+
readonly sequence: number;
|
|
26
|
+
/** Event type */
|
|
27
|
+
readonly eventType: EventType;
|
|
28
|
+
/** Microsecond-precision timestamp */
|
|
29
|
+
readonly timestamp: number;
|
|
30
|
+
/** Poll identifier */
|
|
31
|
+
readonly pollId: Buffer;
|
|
32
|
+
/** Creator/authority ID (for creation/closure events) */
|
|
33
|
+
readonly creatorId?: Buffer;
|
|
34
|
+
/** Anonymized voter token (for vote events) */
|
|
35
|
+
readonly voterToken?: Buffer;
|
|
36
|
+
/** Poll configuration (for creation events) */
|
|
37
|
+
readonly configuration?: PollConfiguration;
|
|
38
|
+
/** Final tally hash (for closure events) */
|
|
39
|
+
readonly tallyHash?: Buffer;
|
|
40
|
+
/** Additional metadata */
|
|
41
|
+
readonly metadata?: Record<string, unknown>;
|
|
42
|
+
}
|
|
43
|
+
export interface EventLogger {
|
|
44
|
+
/** Log poll creation event */
|
|
45
|
+
logPollCreated(pollId: Buffer, creatorId: Buffer, configuration: PollConfiguration): EventLogEntry;
|
|
46
|
+
/** Log vote cast event */
|
|
47
|
+
logVoteCast(pollId: Buffer, voterToken: Buffer, metadata?: Record<string, unknown>): EventLogEntry;
|
|
48
|
+
/** Log poll closure event */
|
|
49
|
+
logPollClosed(pollId: Buffer, tallyHash: Buffer, metadata?: Record<string, unknown>): EventLogEntry;
|
|
50
|
+
/** Log generic event */
|
|
51
|
+
logEvent(eventType: EventType, pollId: Buffer, data?: Partial<Omit<EventLogEntry, 'sequence' | 'timestamp' | 'eventType' | 'pollId'>>): EventLogEntry;
|
|
52
|
+
/** Get all events */
|
|
53
|
+
getEvents(): readonly EventLogEntry[];
|
|
54
|
+
/** Get events for specific poll */
|
|
55
|
+
getEventsForPoll(pollId: Buffer): readonly EventLogEntry[];
|
|
56
|
+
/** Get events by type */
|
|
57
|
+
getEventsByType(eventType: EventType): readonly EventLogEntry[];
|
|
58
|
+
/** Verify sequence integrity */
|
|
59
|
+
verifySequence(): boolean;
|
|
60
|
+
/** Export events for archival */
|
|
61
|
+
export(): Buffer;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Comprehensive event logger with sequence tracking
|
|
65
|
+
*/
|
|
66
|
+
export declare class PollEventLogger implements EventLogger {
|
|
67
|
+
private readonly events;
|
|
68
|
+
private sequence;
|
|
69
|
+
logPollCreated(pollId: Buffer, creatorId: Buffer, configuration: PollConfiguration): EventLogEntry;
|
|
70
|
+
logVoteCast(pollId: Buffer, voterToken: Buffer, metadata?: Record<string, unknown>): EventLogEntry;
|
|
71
|
+
logPollClosed(pollId: Buffer, tallyHash: Buffer, metadata?: Record<string, unknown>): EventLogEntry;
|
|
72
|
+
logEvent(eventType: EventType, pollId: Buffer, data?: Partial<Omit<EventLogEntry, 'sequence' | 'timestamp' | 'eventType' | 'pollId'>>): EventLogEntry;
|
|
73
|
+
getEvents(): readonly EventLogEntry[];
|
|
74
|
+
getEventsForPoll(pollId: Buffer): readonly EventLogEntry[];
|
|
75
|
+
getEventsByType(eventType: EventType): readonly EventLogEntry[];
|
|
76
|
+
verifySequence(): boolean;
|
|
77
|
+
export(): Buffer;
|
|
78
|
+
private appendEvent;
|
|
79
|
+
private serializeEvent;
|
|
80
|
+
private getMicrosecondTimestamp;
|
|
81
|
+
private encodeNumber;
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=event-logger.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event-logger.d.ts","sourceRoot":"","sources":["../../../../../../packages/digitaldefiance-node-ecies-lib/src/lib/voting/event-logger.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Event Logger for Government-Grade Voting
|
|
4
|
+
* Node.js optimized with native Buffer
|
|
5
|
+
* Implements requirement 1.3: Comprehensive event logging with microsecond timestamps
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.PollEventLogger = exports.EventType = void 0;
|
|
9
|
+
var EventType;
|
|
10
|
+
(function (EventType) {
|
|
11
|
+
EventType["PollCreated"] = "poll_created";
|
|
12
|
+
EventType["VoteCast"] = "vote_cast";
|
|
13
|
+
EventType["PollClosed"] = "poll_closed";
|
|
14
|
+
EventType["VoteVerified"] = "vote_verified";
|
|
15
|
+
EventType["TallyComputed"] = "tally_computed";
|
|
16
|
+
EventType["AuditRequested"] = "audit_requested";
|
|
17
|
+
})(EventType || (exports.EventType = EventType = {}));
|
|
18
|
+
/**
|
|
19
|
+
* Comprehensive event logger with sequence tracking
|
|
20
|
+
*/
|
|
21
|
+
class PollEventLogger {
|
|
22
|
+
events = [];
|
|
23
|
+
sequence = 0;
|
|
24
|
+
logPollCreated(pollId, creatorId, configuration) {
|
|
25
|
+
return this.appendEvent({
|
|
26
|
+
eventType: EventType.PollCreated,
|
|
27
|
+
pollId,
|
|
28
|
+
creatorId,
|
|
29
|
+
configuration,
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
logVoteCast(pollId, voterToken, metadata) {
|
|
33
|
+
return this.appendEvent({
|
|
34
|
+
eventType: EventType.VoteCast,
|
|
35
|
+
pollId,
|
|
36
|
+
voterToken,
|
|
37
|
+
metadata,
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
logPollClosed(pollId, tallyHash, metadata) {
|
|
41
|
+
return this.appendEvent({
|
|
42
|
+
eventType: EventType.PollClosed,
|
|
43
|
+
pollId,
|
|
44
|
+
tallyHash,
|
|
45
|
+
metadata,
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
logEvent(eventType, pollId, data) {
|
|
49
|
+
return this.appendEvent({
|
|
50
|
+
eventType,
|
|
51
|
+
pollId,
|
|
52
|
+
...data,
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
getEvents() {
|
|
56
|
+
return Object.freeze([...this.events]);
|
|
57
|
+
}
|
|
58
|
+
getEventsForPoll(pollId) {
|
|
59
|
+
const pollIdStr = pollId.toString('hex');
|
|
60
|
+
return Object.freeze(this.events.filter((e) => e.pollId.toString('hex') === pollIdStr));
|
|
61
|
+
}
|
|
62
|
+
getEventsByType(eventType) {
|
|
63
|
+
return Object.freeze(this.events.filter((e) => e.eventType === eventType));
|
|
64
|
+
}
|
|
65
|
+
verifySequence() {
|
|
66
|
+
for (let i = 0; i < this.events.length; i++) {
|
|
67
|
+
if (this.events[i].sequence !== i) {
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return true;
|
|
72
|
+
}
|
|
73
|
+
export() {
|
|
74
|
+
const parts = [];
|
|
75
|
+
parts.push(this.encodeNumber(this.events.length));
|
|
76
|
+
for (const event of this.events) {
|
|
77
|
+
parts.push(this.serializeEvent(event));
|
|
78
|
+
}
|
|
79
|
+
return Buffer.concat(parts);
|
|
80
|
+
}
|
|
81
|
+
appendEvent(partial) {
|
|
82
|
+
const entry = {
|
|
83
|
+
sequence: this.sequence++,
|
|
84
|
+
timestamp: this.getMicrosecondTimestamp(),
|
|
85
|
+
...partial,
|
|
86
|
+
};
|
|
87
|
+
this.events.push(entry);
|
|
88
|
+
return entry;
|
|
89
|
+
}
|
|
90
|
+
serializeEvent(event) {
|
|
91
|
+
const parts = [
|
|
92
|
+
this.encodeNumber(event.sequence),
|
|
93
|
+
this.encodeNumber(event.timestamp),
|
|
94
|
+
Buffer.from(event.eventType, 'utf8'),
|
|
95
|
+
this.encodeNumber(event.pollId.length),
|
|
96
|
+
event.pollId,
|
|
97
|
+
];
|
|
98
|
+
if (event.creatorId) {
|
|
99
|
+
parts.push(this.encodeNumber(1), this.encodeNumber(event.creatorId.length), event.creatorId);
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
parts.push(this.encodeNumber(0));
|
|
103
|
+
}
|
|
104
|
+
if (event.voterToken) {
|
|
105
|
+
parts.push(this.encodeNumber(1), this.encodeNumber(event.voterToken.length), event.voterToken);
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
parts.push(this.encodeNumber(0));
|
|
109
|
+
}
|
|
110
|
+
if (event.configuration) {
|
|
111
|
+
const configStr = JSON.stringify({
|
|
112
|
+
method: event.configuration.method,
|
|
113
|
+
choices: event.configuration.choices,
|
|
114
|
+
maxWeight: event.configuration.maxWeight?.toString(),
|
|
115
|
+
threshold: event.configuration.threshold,
|
|
116
|
+
});
|
|
117
|
+
const encoded = Buffer.from(configStr, 'utf8');
|
|
118
|
+
parts.push(this.encodeNumber(1), this.encodeNumber(encoded.length), encoded);
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
parts.push(this.encodeNumber(0));
|
|
122
|
+
}
|
|
123
|
+
if (event.tallyHash) {
|
|
124
|
+
parts.push(this.encodeNumber(1), this.encodeNumber(event.tallyHash.length), event.tallyHash);
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
parts.push(this.encodeNumber(0));
|
|
128
|
+
}
|
|
129
|
+
if (event.metadata) {
|
|
130
|
+
const metaStr = JSON.stringify(event.metadata);
|
|
131
|
+
const encoded = Buffer.from(metaStr, 'utf8');
|
|
132
|
+
parts.push(this.encodeNumber(1), this.encodeNumber(encoded.length), encoded);
|
|
133
|
+
}
|
|
134
|
+
else {
|
|
135
|
+
parts.push(this.encodeNumber(0));
|
|
136
|
+
}
|
|
137
|
+
return Buffer.concat(parts);
|
|
138
|
+
}
|
|
139
|
+
getMicrosecondTimestamp() {
|
|
140
|
+
// Get milliseconds since epoch and convert to microseconds
|
|
141
|
+
// performance.now() is relative to process start, not epoch, so we only use Date.now()
|
|
142
|
+
const now = Date.now();
|
|
143
|
+
return now * 1000;
|
|
144
|
+
}
|
|
145
|
+
encodeNumber(n) {
|
|
146
|
+
const buffer = Buffer.alloc(8);
|
|
147
|
+
buffer.writeBigUInt64BE(BigInt(n));
|
|
148
|
+
return buffer;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
exports.PollEventLogger = PollEventLogger;
|
|
152
|
+
//# sourceMappingURL=event-logger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event-logger.js","sourceRoot":"","sources":["../../../../../../packages/digitaldefiance-node-ecies-lib/src/lib/voting/event-logger.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,10 +2,13 @@
|
|
|
2
2
|
* Secure Voting System - Node.js Optimized
|
|
3
3
|
*/
|
|
4
4
|
export { Poll } from './poll-core';
|
|
5
|
+
export { VotingPoll, type ECKeyPairBuffer, type VotingPollResults, } from './poll';
|
|
5
6
|
export { VoteEncoder } from './encoder';
|
|
6
7
|
export { PollTallier } from './tallier';
|
|
7
8
|
export { PollFactory } from './factory';
|
|
8
9
|
export { VotingSecurityValidator, VOTING_SECURITY, SecurityLevel, } from './security';
|
|
9
10
|
export { ImmutableAuditLog, AuditEventType, type AuditEntry, type AuditLog, } from './audit';
|
|
11
|
+
export { PublicBulletinBoard, type BulletinBoard, type BulletinBoardEntry, type TallyProof, } from './bulletin-board';
|
|
12
|
+
export { PollEventLogger, EventType, type EventLogger, type EventLogEntry, type PollConfiguration, } from './event-logger';
|
|
10
13
|
export { VotingMethod, type VoteReceipt, type PollResults, type RoundResult, type EncryptedVote, type SupermajorityConfig, type PlaintextVote, } from './types';
|
|
11
14
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../packages/digitaldefiance-node-ecies-lib/src/lib/voting/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AACnC,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EACL,uBAAuB,EACvB,eAAe,EACf,aAAa,GACd,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,iBAAiB,EACjB,cAAc,EACd,KAAK,UAAU,EACf,KAAK,QAAQ,GACd,MAAM,SAAS,CAAC;AACjB,OAAO,EACL,YAAY,EACZ,KAAK,WAAW,EAChB,KAAK,WAAW,EAChB,KAAK,WAAW,EAChB,KAAK,aAAa,EAClB,KAAK,mBAAmB,EACxB,KAAK,aAAa,GACnB,MAAM,SAAS,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../packages/digitaldefiance-node-ecies-lib/src/lib/voting/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AACnC,OAAO,EACL,UAAU,EACV,KAAK,eAAe,EACpB,KAAK,iBAAiB,GACvB,MAAM,QAAQ,CAAC;AAChB,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EACL,uBAAuB,EACvB,eAAe,EACf,aAAa,GACd,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,iBAAiB,EACjB,cAAc,EACd,KAAK,UAAU,EACf,KAAK,QAAQ,GACd,MAAM,SAAS,CAAC;AACjB,OAAO,EACL,mBAAmB,EACnB,KAAK,aAAa,EAClB,KAAK,kBAAkB,EACvB,KAAK,UAAU,GAChB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,eAAe,EACf,SAAS,EACT,KAAK,WAAW,EAChB,KAAK,aAAa,EAClB,KAAK,iBAAiB,GACvB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,YAAY,EACZ,KAAK,WAAW,EAChB,KAAK,WAAW,EAChB,KAAK,WAAW,EAChB,KAAK,aAAa,EAClB,KAAK,mBAAmB,EACxB,KAAK,aAAa,GACnB,MAAM,SAAS,CAAC"}
|
package/src/lib/voting/index.js
CHANGED
|
@@ -3,9 +3,11 @@
|
|
|
3
3
|
* Secure Voting System - Node.js Optimized
|
|
4
4
|
*/
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.VotingMethod = exports.AuditEventType = exports.ImmutableAuditLog = exports.SecurityLevel = exports.VOTING_SECURITY = exports.VotingSecurityValidator = exports.PollFactory = exports.PollTallier = exports.VoteEncoder = exports.Poll = void 0;
|
|
6
|
+
exports.VotingMethod = exports.EventType = exports.PollEventLogger = exports.PublicBulletinBoard = exports.AuditEventType = exports.ImmutableAuditLog = exports.SecurityLevel = exports.VOTING_SECURITY = exports.VotingSecurityValidator = exports.PollFactory = exports.PollTallier = exports.VoteEncoder = exports.VotingPoll = exports.Poll = void 0;
|
|
7
7
|
var poll_core_1 = require("./poll-core");
|
|
8
8
|
Object.defineProperty(exports, "Poll", { enumerable: true, get: function () { return poll_core_1.Poll; } });
|
|
9
|
+
var poll_1 = require("./poll");
|
|
10
|
+
Object.defineProperty(exports, "VotingPoll", { enumerable: true, get: function () { return poll_1.VotingPoll; } });
|
|
9
11
|
var encoder_1 = require("./encoder");
|
|
10
12
|
Object.defineProperty(exports, "VoteEncoder", { enumerable: true, get: function () { return encoder_1.VoteEncoder; } });
|
|
11
13
|
var tallier_1 = require("./tallier");
|
|
@@ -19,6 +21,11 @@ Object.defineProperty(exports, "SecurityLevel", { enumerable: true, get: functio
|
|
|
19
21
|
var audit_1 = require("./audit");
|
|
20
22
|
Object.defineProperty(exports, "ImmutableAuditLog", { enumerable: true, get: function () { return audit_1.ImmutableAuditLog; } });
|
|
21
23
|
Object.defineProperty(exports, "AuditEventType", { enumerable: true, get: function () { return audit_1.AuditEventType; } });
|
|
24
|
+
var bulletin_board_1 = require("./bulletin-board");
|
|
25
|
+
Object.defineProperty(exports, "PublicBulletinBoard", { enumerable: true, get: function () { return bulletin_board_1.PublicBulletinBoard; } });
|
|
26
|
+
var event_logger_1 = require("./event-logger");
|
|
27
|
+
Object.defineProperty(exports, "PollEventLogger", { enumerable: true, get: function () { return event_logger_1.PollEventLogger; } });
|
|
28
|
+
Object.defineProperty(exports, "EventType", { enumerable: true, get: function () { return event_logger_1.EventType; } });
|
|
22
29
|
var types_1 = require("./types");
|
|
23
30
|
Object.defineProperty(exports, "VotingMethod", { enumerable: true, get: function () { return types_1.VotingMethod; } });
|
|
24
31
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../../packages/digitaldefiance-node-ecies-lib/src/lib/voting/index.ts"],"names":[],"mappings":";AAAA;;GAEG;;;AAEH,yCAAmC;AAA1B,iGAAA,IAAI,OAAA;AACb,qCAAwC;AAA/B,sGAAA,WAAW,OAAA;AACpB,qCAAwC;AAA/B,sGAAA,WAAW,OAAA;AACpB,qCAAwC;AAA/B,sGAAA,WAAW,OAAA;AACpB,uCAIoB;AAHlB,mHAAA,uBAAuB,OAAA;AACvB,2GAAA,eAAe,OAAA;AACf,yGAAA,aAAa,OAAA;AAEf,iCAKiB;AAJf,0GAAA,iBAAiB,OAAA;AACjB,uGAAA,cAAc,OAAA;AAIhB,iCAQiB;AAPf,qGAAA,YAAY,OAAA"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../../packages/digitaldefiance-node-ecies-lib/src/lib/voting/index.ts"],"names":[],"mappings":";AAAA;;GAEG;;;AAEH,yCAAmC;AAA1B,iGAAA,IAAI,OAAA;AACb,+BAIgB;AAHd,kGAAA,UAAU,OAAA;AAIZ,qCAAwC;AAA/B,sGAAA,WAAW,OAAA;AACpB,qCAAwC;AAA/B,sGAAA,WAAW,OAAA;AACpB,qCAAwC;AAA/B,sGAAA,WAAW,OAAA;AACpB,uCAIoB;AAHlB,mHAAA,uBAAuB,OAAA;AACvB,2GAAA,eAAe,OAAA;AACf,yGAAA,aAAa,OAAA;AAEf,iCAKiB;AAJf,0GAAA,iBAAiB,OAAA;AACjB,uGAAA,cAAc,OAAA;AAIhB,mDAK0B;AAJxB,qHAAA,mBAAmB,OAAA;AAKrB,+CAMwB;AALtB,+GAAA,eAAe,OAAA;AACf,yGAAA,SAAS,OAAA;AAKX,iCAQiB;AAPf,qGAAA,YAAY,OAAA"}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { KeyPair as PaillierKeyPair } from 'paillier-bigint';
|
|
2
|
+
import { Member } from '../../member';
|
|
3
|
+
import { ECIESService } from '../../services/ecies/service';
|
|
4
|
+
import { VotingService } from '../../services/voting.service';
|
|
5
|
+
export interface ECKeyPairBuffer {
|
|
6
|
+
privateKey: Buffer;
|
|
7
|
+
publicKey: Buffer;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Result of a voting poll with decrypted tallies
|
|
11
|
+
*/
|
|
12
|
+
export interface VotingPollResults {
|
|
13
|
+
/** Total number of votes cast */
|
|
14
|
+
totalVotes: bigint;
|
|
15
|
+
/** Tallies for each choice */
|
|
16
|
+
tallies: bigint[];
|
|
17
|
+
/** Choice names */
|
|
18
|
+
choices: string[];
|
|
19
|
+
/** Percentage for each choice (0-100) */
|
|
20
|
+
percentages: number[];
|
|
21
|
+
/** Index of the winning choice */
|
|
22
|
+
winnerIndex: number;
|
|
23
|
+
/** Name of the winning choice */
|
|
24
|
+
winnerName: string;
|
|
25
|
+
/** Number of unique voters */
|
|
26
|
+
voterCount: number;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* VotingPoll provides a high-level interface for conducting secure, verifiable polls
|
|
30
|
+
* using Paillier homomorphic encryption.
|
|
31
|
+
*
|
|
32
|
+
* Features:
|
|
33
|
+
* - Privacy-preserving vote aggregation (votes remain encrypted until tally)
|
|
34
|
+
* - Verifiable receipts for each voter
|
|
35
|
+
* - Multiple tallying and analysis methods
|
|
36
|
+
* - Ranked choice voting support
|
|
37
|
+
* - Weighted voting support
|
|
38
|
+
*/
|
|
39
|
+
export declare class VotingPoll {
|
|
40
|
+
readonly choices: string[];
|
|
41
|
+
readonly votes: bigint[];
|
|
42
|
+
private readonly paillierKeyPair;
|
|
43
|
+
private readonly ecKeyPair;
|
|
44
|
+
private readonly eciesService;
|
|
45
|
+
readonly receipts: Map<string, Buffer>;
|
|
46
|
+
private readonly createdAt;
|
|
47
|
+
private closedAt?;
|
|
48
|
+
constructor(eciesService: ECIESService, choices: string[], paillierKeyPair: PaillierKeyPair, ecKeyPair: ECKeyPairBuffer, votes: bigint[]);
|
|
49
|
+
generateEncryptedReceipt(member: Member): Promise<Buffer>;
|
|
50
|
+
memberVoted(member: Member): boolean;
|
|
51
|
+
verifyReceipt(member: Member, encryptedReceipt: Buffer): boolean;
|
|
52
|
+
vote(choiceIndex: number, member: Member): Promise<Buffer>;
|
|
53
|
+
voteWeighted(choiceIndex: number, weight: bigint, member: Member): Promise<Buffer>;
|
|
54
|
+
voteRanked(rankedChoices: number[], member: Member): Promise<Buffer>;
|
|
55
|
+
voteApproval(approvedChoices: number[], member: Member): Promise<Buffer>;
|
|
56
|
+
get tallies(): bigint[];
|
|
57
|
+
getTally(choiceIndex: number): bigint;
|
|
58
|
+
get leadingChoice(): string;
|
|
59
|
+
/**
|
|
60
|
+
* Get the index of the leading choice
|
|
61
|
+
*/
|
|
62
|
+
get leadingChoiceIndex(): number;
|
|
63
|
+
/**
|
|
64
|
+
* Get complete poll results with percentages and winner
|
|
65
|
+
*/
|
|
66
|
+
getResults(): VotingPollResults;
|
|
67
|
+
/**
|
|
68
|
+
* Get sorted results (descending by vote count)
|
|
69
|
+
*/
|
|
70
|
+
getSortedResults(): Array<{
|
|
71
|
+
choice: string;
|
|
72
|
+
index: number;
|
|
73
|
+
tally: bigint;
|
|
74
|
+
percentage: number;
|
|
75
|
+
}>;
|
|
76
|
+
/**
|
|
77
|
+
* Check if there is a tie for first place
|
|
78
|
+
*/
|
|
79
|
+
get hasTie(): boolean;
|
|
80
|
+
/**
|
|
81
|
+
* Get all choices tied for first place
|
|
82
|
+
*/
|
|
83
|
+
get tiedChoices(): string[];
|
|
84
|
+
/**
|
|
85
|
+
* Get total number of unique voters
|
|
86
|
+
*/
|
|
87
|
+
get voterCount(): number;
|
|
88
|
+
/**
|
|
89
|
+
* Get total encrypted votes (sum of all choice tallies)
|
|
90
|
+
* Note: This returns encrypted sum - decrypt with getTotalVotes()
|
|
91
|
+
*/
|
|
92
|
+
get encryptedTotalVotes(): bigint;
|
|
93
|
+
/**
|
|
94
|
+
* Get total decrypted vote count
|
|
95
|
+
*/
|
|
96
|
+
getTotalVotes(): bigint;
|
|
97
|
+
/**
|
|
98
|
+
* Close the poll (no more votes can be cast)
|
|
99
|
+
*/
|
|
100
|
+
close(): void;
|
|
101
|
+
/**
|
|
102
|
+
* Check if poll is closed
|
|
103
|
+
*/
|
|
104
|
+
get isClosed(): boolean;
|
|
105
|
+
/**
|
|
106
|
+
* Get poll creation timestamp
|
|
107
|
+
*/
|
|
108
|
+
get createdAtTimestamp(): Date;
|
|
109
|
+
/**
|
|
110
|
+
* Get poll closed timestamp (undefined if not closed)
|
|
111
|
+
*/
|
|
112
|
+
get closedAtTimestamp(): Date | undefined;
|
|
113
|
+
/**
|
|
114
|
+
* Get poll duration in milliseconds (undefined if not closed)
|
|
115
|
+
*/
|
|
116
|
+
get durationMs(): number | undefined;
|
|
117
|
+
static newPoll(eciesService: ECIESService, choices: string[], paillierKeyPair: PaillierKeyPair, ecKeyPair: ECKeyPairBuffer): VotingPoll;
|
|
118
|
+
static newPollWithKeys(eciesService: ECIESService, votingService: VotingService, choices: string[]): Promise<{
|
|
119
|
+
poll: VotingPoll;
|
|
120
|
+
paillierKeyPair: PaillierKeyPair;
|
|
121
|
+
ecKeyPair: ECKeyPairBuffer;
|
|
122
|
+
}>;
|
|
123
|
+
}
|
|
124
|
+
//# sourceMappingURL=poll.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"poll.d.ts","sourceRoot":"","sources":["../../../../../../packages/digitaldefiance-node-ecies-lib/src/lib/voting/poll.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,323 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.VotingPoll = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* VotingPoll - High-level interface for secure, verifiable polls
|
|
6
|
+
* Node.js optimized with native crypto and Buffer
|
|
7
|
+
*/
|
|
8
|
+
const crypto_1 = require("crypto");
|
|
9
|
+
const constants_1 = require("../../constants");
|
|
10
|
+
/**
|
|
11
|
+
* VotingPoll provides a high-level interface for conducting secure, verifiable polls
|
|
12
|
+
* using Paillier homomorphic encryption.
|
|
13
|
+
*
|
|
14
|
+
* Features:
|
|
15
|
+
* - Privacy-preserving vote aggregation (votes remain encrypted until tally)
|
|
16
|
+
* - Verifiable receipts for each voter
|
|
17
|
+
* - Multiple tallying and analysis methods
|
|
18
|
+
* - Ranked choice voting support
|
|
19
|
+
* - Weighted voting support
|
|
20
|
+
*/
|
|
21
|
+
class VotingPoll {
|
|
22
|
+
choices;
|
|
23
|
+
votes;
|
|
24
|
+
paillierKeyPair;
|
|
25
|
+
ecKeyPair;
|
|
26
|
+
eciesService;
|
|
27
|
+
receipts = new Map();
|
|
28
|
+
createdAt;
|
|
29
|
+
closedAt;
|
|
30
|
+
constructor(eciesService, choices, paillierKeyPair, ecKeyPair, votes) {
|
|
31
|
+
this.eciesService = eciesService;
|
|
32
|
+
if (choices.length === 0) {
|
|
33
|
+
throw new Error('Poll must have at least one choice');
|
|
34
|
+
}
|
|
35
|
+
if (choices.length !== votes.length) {
|
|
36
|
+
throw new Error('Number of choices must match number of vote tallies');
|
|
37
|
+
}
|
|
38
|
+
this.choices = choices;
|
|
39
|
+
this.paillierKeyPair = paillierKeyPair;
|
|
40
|
+
this.ecKeyPair = ecKeyPair;
|
|
41
|
+
this.votes = votes;
|
|
42
|
+
this.createdAt = new Date();
|
|
43
|
+
}
|
|
44
|
+
async generateEncryptedReceipt(member) {
|
|
45
|
+
const randomNonce = (0, crypto_1.randomBytes)(16).toString(constants_1.Constants.VOTING.KEY_FORMAT);
|
|
46
|
+
const memberId = constants_1.Constants.idProvider.serialize(member.id);
|
|
47
|
+
const hashInput = `${Date.now()}-${randomNonce}-${memberId}`;
|
|
48
|
+
const hash = (0, crypto_1.createHash)('sha256').update(hashInput).digest();
|
|
49
|
+
const signature = this.eciesService.signMessage(this.ecKeyPair.privateKey, hash);
|
|
50
|
+
const receipt = Buffer.concat([hash, signature]);
|
|
51
|
+
// Encrypt to the poll's public key so the poll can decrypt and verify later
|
|
52
|
+
const encryptedReceipt = this.eciesService.encryptSimpleOrSingle(false, this.ecKeyPair.publicKey, receipt);
|
|
53
|
+
this.receipts.set(memberId, encryptedReceipt);
|
|
54
|
+
return encryptedReceipt;
|
|
55
|
+
}
|
|
56
|
+
memberVoted(member) {
|
|
57
|
+
const memberId = constants_1.Constants.idProvider.serialize(member.id);
|
|
58
|
+
return this.receipts.has(memberId);
|
|
59
|
+
}
|
|
60
|
+
verifyReceipt(member, encryptedReceipt) {
|
|
61
|
+
const memberId = constants_1.Constants.idProvider.serialize(member.id);
|
|
62
|
+
const foundReceipt = this.receipts.get(memberId);
|
|
63
|
+
if (!foundReceipt) {
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
if (!foundReceipt.equals(encryptedReceipt)) {
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
const decryptedReceipt = this.eciesService.decryptSimpleOrSingleWithHeader(false, this.ecKeyPair.privateKey, encryptedReceipt);
|
|
70
|
+
const hash = decryptedReceipt.subarray(0, 32);
|
|
71
|
+
const signature = decryptedReceipt.subarray(32);
|
|
72
|
+
return this.eciesService.verifyMessage(this.ecKeyPair.publicKey, hash, signature);
|
|
73
|
+
}
|
|
74
|
+
async vote(choiceIndex, member) {
|
|
75
|
+
if (this.isClosed) {
|
|
76
|
+
throw new Error('Poll is closed');
|
|
77
|
+
}
|
|
78
|
+
if (this.memberVoted(member)) {
|
|
79
|
+
throw new Error('Member has already voted');
|
|
80
|
+
}
|
|
81
|
+
if (choiceIndex < 0 || choiceIndex >= this.choices.length) {
|
|
82
|
+
throw new Error(`Invalid option index ${choiceIndex}`);
|
|
83
|
+
}
|
|
84
|
+
// vote a 1 for the selected candidate and a 0 for all others
|
|
85
|
+
for (let i = 0; i < this.choices.length; i++) {
|
|
86
|
+
if (i == choiceIndex) {
|
|
87
|
+
this.votes[i] = this.paillierKeyPair.publicKey.addition(this.votes[i], this.paillierKeyPair.publicKey.encrypt(1n));
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
this.votes[i] = this.paillierKeyPair.publicKey.addition(this.votes[i], this.paillierKeyPair.publicKey.encrypt(0n));
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return await this.generateEncryptedReceipt(member);
|
|
94
|
+
}
|
|
95
|
+
async voteWeighted(choiceIndex, weight, member) {
|
|
96
|
+
if (this.isClosed) {
|
|
97
|
+
throw new Error('Poll is closed');
|
|
98
|
+
}
|
|
99
|
+
if (this.memberVoted(member)) {
|
|
100
|
+
throw new Error('Member has already voted');
|
|
101
|
+
}
|
|
102
|
+
if (choiceIndex < 0 || choiceIndex >= this.choices.length) {
|
|
103
|
+
throw new Error(`Invalid option index ${choiceIndex}`);
|
|
104
|
+
}
|
|
105
|
+
if (weight <= 0n) {
|
|
106
|
+
throw new Error('Vote weight must be positive');
|
|
107
|
+
}
|
|
108
|
+
// Add weighted vote to selected choice
|
|
109
|
+
this.votes[choiceIndex] = this.paillierKeyPair.publicKey.addition(this.votes[choiceIndex], this.paillierKeyPair.publicKey.encrypt(weight));
|
|
110
|
+
return await this.generateEncryptedReceipt(member);
|
|
111
|
+
}
|
|
112
|
+
async voteRanked(rankedChoices, member) {
|
|
113
|
+
if (this.isClosed) {
|
|
114
|
+
throw new Error('Poll is closed');
|
|
115
|
+
}
|
|
116
|
+
if (this.memberVoted(member)) {
|
|
117
|
+
throw new Error('Member has already voted');
|
|
118
|
+
}
|
|
119
|
+
if (rankedChoices.length === 0) {
|
|
120
|
+
throw new Error('Must provide at least one ranked choice');
|
|
121
|
+
}
|
|
122
|
+
// Validate all choices are valid and unique
|
|
123
|
+
const seen = new Set();
|
|
124
|
+
for (const choiceIndex of rankedChoices) {
|
|
125
|
+
if (choiceIndex < 0 || choiceIndex >= this.choices.length) {
|
|
126
|
+
throw new Error(`Invalid choice index ${choiceIndex}`);
|
|
127
|
+
}
|
|
128
|
+
if (seen.has(choiceIndex)) {
|
|
129
|
+
throw new Error(`Duplicate choice index ${choiceIndex}`);
|
|
130
|
+
}
|
|
131
|
+
seen.add(choiceIndex);
|
|
132
|
+
}
|
|
133
|
+
// Award points based on ranking (first choice gets highest points)
|
|
134
|
+
const maxPoints = BigInt(rankedChoices.length);
|
|
135
|
+
for (let i = 0; i < rankedChoices.length; i++) {
|
|
136
|
+
const choiceIndex = rankedChoices[i];
|
|
137
|
+
const points = maxPoints - BigInt(i); // First choice gets n points, second gets n-1, etc.
|
|
138
|
+
this.votes[choiceIndex] = this.paillierKeyPair.publicKey.addition(this.votes[choiceIndex], this.paillierKeyPair.publicKey.encrypt(points));
|
|
139
|
+
}
|
|
140
|
+
return await this.generateEncryptedReceipt(member);
|
|
141
|
+
}
|
|
142
|
+
async voteApproval(approvedChoices, member) {
|
|
143
|
+
if (this.isClosed) {
|
|
144
|
+
throw new Error('Poll is closed');
|
|
145
|
+
}
|
|
146
|
+
if (this.memberVoted(member)) {
|
|
147
|
+
throw new Error('Member has already voted');
|
|
148
|
+
}
|
|
149
|
+
if (approvedChoices.length === 0) {
|
|
150
|
+
throw new Error('Must approve at least one choice');
|
|
151
|
+
}
|
|
152
|
+
// Validate all choices and check for duplicates
|
|
153
|
+
const seen = new Set();
|
|
154
|
+
for (const choiceIndex of approvedChoices) {
|
|
155
|
+
if (choiceIndex < 0 || choiceIndex >= this.choices.length) {
|
|
156
|
+
throw new Error(`Invalid choice index ${choiceIndex}`);
|
|
157
|
+
}
|
|
158
|
+
if (seen.has(choiceIndex)) {
|
|
159
|
+
throw new Error(`Duplicate choice index ${choiceIndex}`);
|
|
160
|
+
}
|
|
161
|
+
seen.add(choiceIndex);
|
|
162
|
+
}
|
|
163
|
+
// Add 1 vote to each approved choice
|
|
164
|
+
for (const choiceIndex of approvedChoices) {
|
|
165
|
+
this.votes[choiceIndex] = this.paillierKeyPair.publicKey.addition(this.votes[choiceIndex], this.paillierKeyPair.publicKey.encrypt(1n));
|
|
166
|
+
}
|
|
167
|
+
return await this.generateEncryptedReceipt(member);
|
|
168
|
+
}
|
|
169
|
+
get tallies() {
|
|
170
|
+
return this.votes.map((encryptedVote) => this.paillierKeyPair.privateKey.decrypt(encryptedVote));
|
|
171
|
+
}
|
|
172
|
+
getTally(choiceIndex) {
|
|
173
|
+
return this.paillierKeyPair.privateKey.decrypt(this.votes[choiceIndex]);
|
|
174
|
+
}
|
|
175
|
+
get leadingChoice() {
|
|
176
|
+
const tallies = this.tallies;
|
|
177
|
+
let leadingOptionIndex = 0;
|
|
178
|
+
for (let i = 1; i < tallies.length; i++) {
|
|
179
|
+
if (tallies[i] > tallies[leadingOptionIndex]) {
|
|
180
|
+
leadingOptionIndex = i;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
return this.choices[leadingOptionIndex];
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Get the index of the leading choice
|
|
187
|
+
*/
|
|
188
|
+
get leadingChoiceIndex() {
|
|
189
|
+
const tallies = this.tallies;
|
|
190
|
+
let leadingOptionIndex = 0;
|
|
191
|
+
for (let i = 1; i < tallies.length; i++) {
|
|
192
|
+
if (tallies[i] > tallies[leadingOptionIndex]) {
|
|
193
|
+
leadingOptionIndex = i;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
return leadingOptionIndex;
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Get complete poll results with percentages and winner
|
|
200
|
+
*/
|
|
201
|
+
getResults() {
|
|
202
|
+
const tallies = this.tallies;
|
|
203
|
+
const totalVotes = tallies.reduce((sum, tally) => sum + tally, 0n);
|
|
204
|
+
const percentages = tallies.map((tally) => totalVotes > 0n ? Number((tally * 10000n) / totalVotes) / 100 : 0);
|
|
205
|
+
return {
|
|
206
|
+
totalVotes,
|
|
207
|
+
tallies,
|
|
208
|
+
choices: [...this.choices],
|
|
209
|
+
percentages,
|
|
210
|
+
winnerIndex: this.leadingChoiceIndex,
|
|
211
|
+
winnerName: this.leadingChoice,
|
|
212
|
+
voterCount: this.receipts.size,
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Get sorted results (descending by vote count)
|
|
217
|
+
*/
|
|
218
|
+
getSortedResults() {
|
|
219
|
+
const results = this.getResults();
|
|
220
|
+
return this.choices
|
|
221
|
+
.map((choice, index) => ({
|
|
222
|
+
choice,
|
|
223
|
+
index,
|
|
224
|
+
tally: results.tallies[index],
|
|
225
|
+
percentage: results.percentages[index],
|
|
226
|
+
}))
|
|
227
|
+
.sort((a, b) => (b.tally > a.tally ? 1 : b.tally < a.tally ? -1 : 0));
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Check if there is a tie for first place
|
|
231
|
+
*/
|
|
232
|
+
get hasTie() {
|
|
233
|
+
const tallies = this.tallies;
|
|
234
|
+
const maxTally = tallies.reduce((max, tally) => (tally > max ? tally : max), 0n);
|
|
235
|
+
return tallies.filter((tally) => tally === maxTally).length > 1;
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* Get all choices tied for first place
|
|
239
|
+
*/
|
|
240
|
+
get tiedChoices() {
|
|
241
|
+
if (!this.hasTie) {
|
|
242
|
+
return [];
|
|
243
|
+
}
|
|
244
|
+
const tallies = this.tallies;
|
|
245
|
+
const maxTally = tallies.reduce((max, tally) => (tally > max ? tally : max), 0n);
|
|
246
|
+
return this.choices.filter((_, index) => tallies[index] === maxTally);
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* Get total number of unique voters
|
|
250
|
+
*/
|
|
251
|
+
get voterCount() {
|
|
252
|
+
return this.receipts.size;
|
|
253
|
+
}
|
|
254
|
+
/**
|
|
255
|
+
* Get total encrypted votes (sum of all choice tallies)
|
|
256
|
+
* Note: This returns encrypted sum - decrypt with getTotalVotes()
|
|
257
|
+
*/
|
|
258
|
+
get encryptedTotalVotes() {
|
|
259
|
+
return this.votes.reduce((sum, vote) => this.paillierKeyPair.publicKey.addition(sum, vote), this.paillierKeyPair.publicKey.encrypt(0n));
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* Get total decrypted vote count
|
|
263
|
+
*/
|
|
264
|
+
getTotalVotes() {
|
|
265
|
+
return this.paillierKeyPair.privateKey.decrypt(this.encryptedTotalVotes);
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* Close the poll (no more votes can be cast)
|
|
269
|
+
*/
|
|
270
|
+
close() {
|
|
271
|
+
if (this.isClosed) {
|
|
272
|
+
throw new Error('Poll is already closed');
|
|
273
|
+
}
|
|
274
|
+
this.closedAt = new Date();
|
|
275
|
+
}
|
|
276
|
+
/**
|
|
277
|
+
* Check if poll is closed
|
|
278
|
+
*/
|
|
279
|
+
get isClosed() {
|
|
280
|
+
return this.closedAt !== undefined;
|
|
281
|
+
}
|
|
282
|
+
/**
|
|
283
|
+
* Get poll creation timestamp
|
|
284
|
+
*/
|
|
285
|
+
get createdAtTimestamp() {
|
|
286
|
+
return new Date(this.createdAt);
|
|
287
|
+
}
|
|
288
|
+
/**
|
|
289
|
+
* Get poll closed timestamp (undefined if not closed)
|
|
290
|
+
*/
|
|
291
|
+
get closedAtTimestamp() {
|
|
292
|
+
return this.closedAt ? new Date(this.closedAt) : undefined;
|
|
293
|
+
}
|
|
294
|
+
/**
|
|
295
|
+
* Get poll duration in milliseconds (undefined if not closed)
|
|
296
|
+
*/
|
|
297
|
+
get durationMs() {
|
|
298
|
+
if (!this.closedAt) {
|
|
299
|
+
return undefined;
|
|
300
|
+
}
|
|
301
|
+
return this.closedAt.getTime() - this.createdAt.getTime();
|
|
302
|
+
}
|
|
303
|
+
static newPoll(eciesService, choices, paillierKeyPair, ecKeyPair) {
|
|
304
|
+
const votes = new Array(choices.length);
|
|
305
|
+
for (let i = 0; i < choices.length; i++) {
|
|
306
|
+
votes[i] = paillierKeyPair.publicKey.encrypt(0n);
|
|
307
|
+
}
|
|
308
|
+
return new VotingPoll(eciesService, choices, paillierKeyPair, ecKeyPair, votes);
|
|
309
|
+
}
|
|
310
|
+
static async newPollWithKeys(eciesService, votingService, choices) {
|
|
311
|
+
const mnemonic = eciesService.generateNewMnemonic();
|
|
312
|
+
const keyPair = eciesService.mnemonicToSimpleKeyPair(mnemonic);
|
|
313
|
+
const ecKeyPair = {
|
|
314
|
+
privateKey: keyPair.privateKey,
|
|
315
|
+
publicKey: keyPair.publicKey,
|
|
316
|
+
};
|
|
317
|
+
const paillierKeyPair = await votingService.deriveVotingKeysFromECDH(ecKeyPair.privateKey, ecKeyPair.publicKey);
|
|
318
|
+
const poll = VotingPoll.newPoll(eciesService, choices, paillierKeyPair, ecKeyPair);
|
|
319
|
+
return { poll, paillierKeyPair, ecKeyPair };
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
exports.VotingPoll = VotingPoll;
|
|
323
|
+
//# sourceMappingURL=poll.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"poll.js","sourceRoot":"","sources":["../../../../../../packages/digitaldefiance-node-ecies-lib/src/lib/voting/poll.ts"],"names":[],"mappings":"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"}
|