threshold-elgamal 1.0.0-beta.8 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -41,6 +41,18 @@ npm install threshold-elgamal
41
41
  - Authentication signatures require Web Crypto `Ed25519`.
42
42
  - Transport share exchange requires Web Crypto `X25519`.
43
43
 
44
+ ## Documentation
45
+
46
+ - Hosted documentation site: [tenemo.github.io/threshold-elgamal](https://tenemo.github.io/threshold-elgamal/)
47
+ - Get started: [tenemo.github.io/threshold-elgamal/guides/getting-started](https://tenemo.github.io/threshold-elgamal/guides/getting-started/)
48
+ - Verifying a public board: [tenemo.github.io/threshold-elgamal/guides/verifying-a-public-board](https://tenemo.github.io/threshold-elgamal/guides/verifying-a-public-board/)
49
+ - Browser and worker usage: [tenemo.github.io/threshold-elgamal/guides/browser-and-worker-usage](https://tenemo.github.io/threshold-elgamal/guides/browser-and-worker-usage/)
50
+ - Published payload examples: [tenemo.github.io/threshold-elgamal/guides/published-payload-examples](https://tenemo.github.io/threshold-elgamal/guides/published-payload-examples/)
51
+ - Honest-majority voting flow: [tenemo.github.io/threshold-elgamal/guides/three-participant-voting-flow](https://tenemo.github.io/threshold-elgamal/guides/three-participant-voting-flow/)
52
+ - Security boundary: [tenemo.github.io/threshold-elgamal/guides/security-and-non-goals](https://tenemo.github.io/threshold-elgamal/guides/security-and-non-goals/)
53
+ - Production voting safety review: [tenemo.github.io/threshold-elgamal/guides/production-voting-safety-review](https://tenemo.github.io/threshold-elgamal/guides/production-voting-safety-review/)
54
+ - API docs: [tenemo.github.io/threshold-elgamal/api](https://tenemo.github.io/threshold-elgamal/api/)
55
+
44
56
  ## Browser support
45
57
 
46
58
  The shipped cryptographic browser path is fixed:
@@ -80,6 +92,12 @@ There is no supported `n-of-n` mode and no supported public `k-of-n` configurati
80
92
 
81
93
  Transcript verification requires key-derivation confirmations from every qualified participant.
82
94
 
95
+ ## Choose your entry point
96
+
97
+ - Verifying a public board: start with the hosted guide for `tryVerifyElectionCeremony(...)` and `verifyElectionCeremony(...)`.
98
+ - Browser and worker usage: start with the browser guide for key generation, manifest setup, and encrypted transport envelopes.
99
+ - Payload shapes and storage: start with the payload examples guide if you need concrete JSON, posting, or persistence patterns.
100
+
83
101
  ## Getting started
84
102
 
85
103
  ```typescript
@@ -126,6 +144,34 @@ console.log(majorityThreshold(3)); // 2
126
144
  console.log(sessionId.length); // 64
127
145
  ```
128
146
 
147
+ If your application consumes a complete public board, the shortest safe verifier entry point is:
148
+
149
+ ```typescript
150
+ import {
151
+ tryVerifyElectionCeremony,
152
+ type VerifyElectionCeremonyInput,
153
+ } from "threshold-elgamal";
154
+
155
+ const bundle: VerifyElectionCeremonyInput = {
156
+ manifest,
157
+ sessionId,
158
+ dkgTranscript,
159
+ ballotPayloads,
160
+ ballotClosePayload,
161
+ decryptionSharePayloads,
162
+ tallyPublications,
163
+ };
164
+
165
+ const result = await tryVerifyElectionCeremony(bundle);
166
+
167
+ if (!result.ok) {
168
+ console.error(result.error.stage, result.error.code, result.error.reason);
169
+ } else {
170
+ console.log(result.verified.perOptionTallies);
171
+ console.log(result.verified.boardAudit.overall.fingerprint);
172
+ }
173
+ ```
174
+
129
175
  The root package also exposes public builders for:
130
176
 
131
177
  - manifest publication
@@ -140,7 +186,7 @@ The root package also exposes public builders for:
140
186
  - decryption shares
141
187
  - tally publication
142
188
 
143
- For a full executable ceremony example, use the public node integration tests in this repository.
189
+ For concrete integration examples, start with the hosted guides below. The repository integration harness exercises the same workflow, but it is not part of the supported public API.
144
190
 
145
191
  ## Security boundary
146
192
 
@@ -167,15 +213,6 @@ What it does not claim:
167
213
 
168
214
  For a production-threat-model verdict that maps these boundaries to the shipped verifier and tests, read the production voting safety review in the hosted docs.
169
215
 
170
- ## Documentation
171
-
172
- - Hosted documentation site: [tenemo.github.io/threshold-elgamal](https://tenemo.github.io/threshold-elgamal/)
173
- - Get started: [tenemo.github.io/threshold-elgamal/guides/getting-started](https://tenemo.github.io/threshold-elgamal/guides/getting-started/)
174
- - Honest-majority voting flow: [tenemo.github.io/threshold-elgamal/guides/three-participant-voting-flow](https://tenemo.github.io/threshold-elgamal/guides/three-participant-voting-flow/)
175
- - Security boundary: [tenemo.github.io/threshold-elgamal/guides/security-and-non-goals](https://tenemo.github.io/threshold-elgamal/guides/security-and-non-goals/)
176
- - Production voting safety review: [tenemo.github.io/threshold-elgamal/guides/production-voting-safety-review](https://tenemo.github.io/threshold-elgamal/guides/production-voting-safety-review/)
177
- - API docs: [tenemo.github.io/threshold-elgamal/api](https://tenemo.github.io/threshold-elgamal/api/)
178
-
179
216
  ## Development
180
217
 
181
218
  ```bash
package/dist/index.d.ts CHANGED
@@ -17,14 +17,14 @@ export type { DecryptionShare, Share, VerifiedAggregateCiphertext, } from './thr
17
17
  export { deriveJointPublicKey, deriveTranscriptVerificationKey, verifyDKGTranscript, } from './dkg/verification.js';
18
18
  export { decodePedersenShareEnvelope, encodePedersenShareEnvelope, } from './dkg/pedersen-share-codec.js';
19
19
  export type { VerifyDKGTranscriptInput, VerifiedDKGTranscript, } from './dkg/verification.js';
20
- export { generateFeldmanCommitments, verifyFeldmanShare, } from './vss/feldman.js';
20
+ export { generateFeldmanCommitments, verifyFeldmanShare } from './vss/feldman.js';
21
21
  export { derivePedersenShares, generatePedersenCommitments, verifyPedersenShare, } from './vss/pedersen.js';
22
22
  export type { FeldmanCommitments, PedersenCommitments, PedersenShare, } from './vss/types.js';
23
23
  export { createBallotClosePayload, createBallotSubmissionPayload, createDecryptionSharePayload, createEncryptedDualSharePayload, createFeldmanCommitmentPayload, createKeyDerivationConfirmationPayload, createManifestAcceptancePayload, createManifestPublicationPayload, createPedersenCommitmentPayload, createPhaseCheckpointPayload, createRegistrationPayload, createTallyPublicationPayload, signProtocolPayload, } from './protocol/builders.js';
24
24
  export { canonicalizeElectionManifest, createElectionManifest, deriveSessionId, hashElectionManifest, SHIPPED_PROTOCOL_VERSION, validateElectionManifest, } from './protocol/manifest.js';
25
25
  export { hashRosterEntries } from './protocol/verification.js';
26
26
  export { hashProtocolTranscript } from './protocol/transcript.js';
27
- export { verifyElectionCeremony, tryVerifyElectionCeremony, type ElectionVerificationErrorCode, type ElectionVerificationFailure, type ElectionVerificationResult, type ElectionVerificationStage, type VerifiedElectionCeremony, type VerifyElectionCeremonyInput, } from './protocol/voting-verification.js';
27
+ export { verifyElectionCeremony, tryVerifyElectionCeremony, type ElectionVerificationErrorCode, type ElectionVerificationFailure, type ElectionVerificationResult, type ElectionVerificationStage, type VerifiedElectionCeremony, } from './protocol/voting-verification.js';
28
28
  export { verifyBallotSubmissionPayloadsByOption } from './protocol/voting-ballots.js';
29
29
  export { scoreVotingDomain } from './protocol/voting-codecs.js';
30
- export type { BallotClosePayload, BallotSubmissionPayload, DecryptionSharePayload, ElectionManifest, EncodedCiphertext, EncodedCompactProof, EncodedDisjunctiveProof, EncryptedDualSharePayload, FeldmanCommitmentPayload, KeyDerivationConfirmation, ManifestAcceptancePayload, ManifestPublicationPayload, PedersenCommitmentPayload, PhaseCheckpointPayload, ProtocolMessageType, ProtocolPayload, RegistrationPayload, SignedPayload, TallyPublicationPayload, } from './protocol/types.js';
30
+ export type { BallotClosePayload, BallotSubmissionPayload, DecryptionSharePayload, ElectionManifest, EncodedCiphertext, EncodedCompactProof, EncodedDisjunctiveProof, EncryptedDualSharePayload, FeldmanCommitmentPayload, KeyDerivationConfirmation, ManifestAcceptancePayload, ManifestPublicationPayload, PedersenCommitmentPayload, PhaseCheckpointPayload, ProtocolMessageType, ProtocolPayload, RegistrationPayload, SignedPayload, TallyPublicationPayload, VerifyElectionCeremonyInput, } from './protocol/types.js';
package/dist/index.js CHANGED
@@ -12,7 +12,7 @@ export { exportTransportPublicKey, generateTransportKeyPair, } from './transport
12
12
  export { combineDecryptionShares } from './threshold/decrypt.js';
13
13
  export { deriveJointPublicKey, deriveTranscriptVerificationKey, verifyDKGTranscript, } from './dkg/verification.js';
14
14
  export { decodePedersenShareEnvelope, encodePedersenShareEnvelope, } from './dkg/pedersen-share-codec.js';
15
- export { generateFeldmanCommitments, verifyFeldmanShare, } from './vss/feldman.js';
15
+ export { generateFeldmanCommitments, verifyFeldmanShare } from './vss/feldman.js';
16
16
  export { derivePedersenShares, generatePedersenCommitments, verifyPedersenShare, } from './vss/pedersen.js';
17
17
  export { createBallotClosePayload, createBallotSubmissionPayload, createDecryptionSharePayload, createEncryptedDualSharePayload, createFeldmanCommitmentPayload, createKeyDerivationConfirmationPayload, createManifestAcceptancePayload, createManifestPublicationPayload, createPedersenCommitmentPayload, createPhaseCheckpointPayload, createRegistrationPayload, createTallyPublicationPayload, signProtocolPayload, } from './protocol/builders.js';
18
18
  export { canonicalizeElectionManifest, createElectionManifest, deriveSessionId, hashElectionManifest, SHIPPED_PROTOCOL_VERSION, validateElectionManifest, } from './protocol/manifest.js';
@@ -1,7 +1,7 @@
1
1
  import { InvalidPayloadError } from '../core/index.js';
2
2
  import { compareProtocolPayloads } from './ordering.js';
3
3
  import { classifySlotConflict, payloadSlotKey } from './payloads.js';
4
- import { formatSessionFingerprint, hashProtocolTranscript, } from './transcript.js';
4
+ import { formatSessionFingerprint, hashProtocolTranscript } from './transcript.js';
5
5
  const compareSignedPayloads = (left, right) => {
6
6
  const payloadOrder = compareProtocolPayloads(left.payload, right.payload);
7
7
  if (payloadOrder !== 0) {
@@ -191,8 +191,8 @@ export type VerifyDecryptionSharePayloadsByOptionInput = {
191
191
  readonly manifest: ElectionManifest;
192
192
  readonly sessionId: string;
193
193
  };
194
- /** Input bundle for verifying one full published tally set across all options. */
195
- export type VerifyPublishedVotingResultsInput = {
194
+ /** Input bundle for full ceremony verification across all published options. */
195
+ export type VerifyElectionCeremonyInput = {
196
196
  readonly manifest: ElectionManifest;
197
197
  readonly sessionId: string;
198
198
  readonly dkgTranscript: readonly SignedPayload[];
@@ -1,6 +1,6 @@
1
1
  import { InvalidPayloadError, assertValidParticipantIndex, sha256, utf8ToBytes, } from '../core/index.js';
2
2
  import { bytesToHex } from '../serialize/index.js';
3
- import { importAuthPublicKey, verifyPayloadSignature, } from '../transport/auth.js';
3
+ import { importAuthPublicKey, verifyPayloadSignature } from '../transport/auth.js';
4
4
  import { assertSupportedTransportPublicKeyEncoding } from '../transport/key-agreement.js';
5
5
  import { canonicalizeJson } from './canonical-json.js';
6
6
  import { canonicalUnsignedPayloadBytes } from './payloads.js';
@@ -1,5 +1,5 @@
1
1
  import { assertPositiveParticipantIndex, InvalidPayloadError, RISTRETTO_GROUP, } from '../core/index.js';
2
- import { importAuthPublicKey, verifyPayloadSignature, } from '../transport/auth.js';
2
+ import { importAuthPublicKey, verifyPayloadSignature } from '../transport/auth.js';
3
3
  import { hashElectionManifest, SHIPPED_PROTOCOL_VERSION, validateElectionManifest, } from './manifest.js';
4
4
  import { canonicalUnsignedPayloadBytes } from './payloads.js';
5
5
  import { scoreVotingDomain } from './voting-codecs.js';
@@ -1,6 +1,6 @@
1
1
  import { type VerifiedDKGTranscript } from '../dkg/verification.js';
2
2
  import { type BoardAudit } from './board-audit.js';
3
- import type { BallotClosePayload, BallotSubmissionPayload, DecryptionSharePayload, ElectionManifest, VerifiedPublishedOptionVotingResult, VerifyPublishedVotingResultsInput, TallyPublicationPayload } from './types.js';
3
+ import type { BallotClosePayload, BallotSubmissionPayload, DecryptionSharePayload, ElectionManifest, VerifyElectionCeremonyInput, VerifiedPublishedOptionVotingResult, TallyPublicationPayload } from './types.js';
4
4
  /** Stable high-level failure codes for full ceremony verification. */
5
5
  export type ElectionVerificationErrorCode = 'MANIFEST_INVALID' | 'BOARD_INVALID' | 'DKG_INVALID' | 'SIGNATURE_INVALID' | 'BALLOT_INVALID' | 'DECRYPTION_INVALID' | 'TALLY_INVALID';
6
6
  /** Named verification stage used by the high-level ceremony verifier. */
@@ -38,8 +38,6 @@ export type VerifiedElectionCeremony = {
38
38
  readonly dkg: VerifiedDKGTranscript;
39
39
  readonly options: readonly VerifiedPublishedOptionVotingResult[];
40
40
  };
41
- /** Input bundle for full ceremony verification across all published options. */
42
- export type VerifyElectionCeremonyInput = VerifyPublishedVotingResultsInput;
43
41
  /** Non-throwing result shape for full ceremony verification. */
44
42
  export type ElectionVerificationResult = {
45
43
  readonly ok: true;
@@ -55,6 +53,15 @@ export type ElectionVerificationResult = {
55
53
  *
56
54
  * @param input Full public ceremony input bundle.
57
55
  * @returns Detailed verified ceremony output.
56
+ *
57
+ * @example
58
+ * ```ts
59
+ * const verified = await verifyElectionCeremony(bundle);
60
+ *
61
+ * console.log(verified.boardAudit.overall.fingerprint);
62
+ * console.log(verified.countedParticipantIndices);
63
+ * console.log(verified.perOptionTallies);
64
+ * ```
58
65
  */
59
66
  export declare const verifyElectionCeremony: (input: VerifyElectionCeremonyInput) => Promise<VerifiedElectionCeremony>;
60
67
  /**
@@ -63,5 +70,17 @@ export declare const verifyElectionCeremony: (input: VerifyElectionCeremonyInput
63
70
  *
64
71
  * @param input Full public ceremony input bundle.
65
72
  * @returns Verified ceremony output or a stable structured failure.
73
+ *
74
+ * @example
75
+ * ```ts
76
+ * const result = await tryVerifyElectionCeremony(bundle);
77
+ *
78
+ * if (!result.ok) {
79
+ * console.error(result.error.stage, result.error.code, result.error.reason);
80
+ * return;
81
+ * }
82
+ *
83
+ * console.log(result.verified.qualifiedParticipantIndices);
84
+ * ```
66
85
  */
67
86
  export declare const tryVerifyElectionCeremony: (input: VerifyElectionCeremonyInput) => Promise<ElectionVerificationResult>;
@@ -55,6 +55,15 @@ const findOptionDecryptionShares = (decryptionShares, optionIndex) => {
55
55
  *
56
56
  * @param input Full public ceremony input bundle.
57
57
  * @returns Detailed verified ceremony output.
58
+ *
59
+ * @example
60
+ * ```ts
61
+ * const verified = await verifyElectionCeremony(bundle);
62
+ *
63
+ * console.log(verified.boardAudit.overall.fingerprint);
64
+ * console.log(verified.countedParticipantIndices);
65
+ * console.log(verified.perOptionTallies);
66
+ * ```
58
67
  */
59
68
  export const verifyElectionCeremony = async (input) => {
60
69
  let context;
@@ -249,6 +258,18 @@ export const verifyElectionCeremony = async (input) => {
249
258
  *
250
259
  * @param input Full public ceremony input bundle.
251
260
  * @returns Verified ceremony output or a stable structured failure.
261
+ *
262
+ * @example
263
+ * ```ts
264
+ * const result = await tryVerifyElectionCeremony(bundle);
265
+ *
266
+ * if (!result.ok) {
267
+ * console.error(result.error.stage, result.error.code, result.error.reason);
268
+ * return;
269
+ * }
270
+ *
271
+ * console.log(result.verified.qualifiedParticipantIndices);
272
+ * ```
252
273
  */
253
274
  export const tryVerifyElectionCeremony = async (input) => {
254
275
  try {
@@ -1,6 +1,6 @@
1
1
  import { toBufferSource } from '../core/bytes.js';
2
2
  import { getWebCrypto, hkdfSha256, randomBytes } from '../core/index.js';
3
- import { bytesToHex, encodeForChallenge, hexToBytes, } from '../serialize/index.js';
3
+ import { bytesToHex, encodeForChallenge, hexToBytes } from '../serialize/index.js';
4
4
  import { deriveTransportSharedSecret, exportTransportPrivateKey, exportTransportPublicKey, generateTransportKeyPair, importTransportPrivateKey, importTransportPublicKey, } from './key-agreement.js';
5
5
  const envelopeKeySalt = (rosterHash) => new TextEncoder().encode(rosterHash);
6
6
  export const encodeEnvelopeContext = (context) => encodeForChallenge(context.sessionId, BigInt(context.phase), BigInt(context.dealerIndex), BigInt(context.recipientIndex), context.envelopeId, context.payloadType, context.protocolVersion, context.suite);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "threshold-elgamal",
3
- "version": "1.0.0-beta.8",
3
+ "version": "1.0.0",
4
4
  "description": "A browser-native TypeScript ElGamal library for Ristretto255-based research prototypes, shipping additive ElGamal, threshold decryption, protocol helpers, board auditing, transport primitives, and log-driven DKG state machines.",
5
5
  "author": "Piotr Piech <piotr@piech.dev>",
6
6
  "license": "MPL-2.0",
@@ -23,7 +23,7 @@
23
23
  "coverage:badge": "pnpm run coverage:node && tsx ./tools/generate-coverage-badge.ts",
24
24
  "smoke:pack": "tsx ./tools/ci/verify-packed-package.ts",
25
25
  "prebuild": "pnpm run lint && tsc && knip && tsx ./tools/ci/verify-vectors.ts && pnpm run test",
26
- "build": "pnpm exec del-cli dist && tsc --project tsconfig.build.json",
26
+ "build": "pnpm exec del-cli dist && tsc --project tsconfig.build.json && tsx ./tools/build/rewrite-dist-relative-imports.ts",
27
27
  "vectors:threshold": "tsx ./tools/generate-threshold-vectors.ts",
28
28
  "vectors:protocol": "tsx ./tools/generate-protocol-vectors.ts",
29
29
  "bench:micro": "tsx ./tools/benchmarks/microbench.ts",