threshold-elgamal 1.0.9 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (98) hide show
  1. package/README.md +33 -35
  2. package/dist/core/bigint.d.ts +2 -1
  3. package/dist/core/bigint.js +6 -1
  4. package/dist/core/bytes.js +4 -0
  5. package/dist/core/crypto.js +5 -0
  6. package/dist/core/errors.d.ts +50 -11
  7. package/dist/core/errors.js +50 -11
  8. package/dist/core/groups.d.ts +6 -1
  9. package/dist/core/groups.js +13 -2
  10. package/dist/core/index.d.ts +4 -0
  11. package/dist/core/index.js +4 -0
  12. package/dist/core/public.d.ts +13 -0
  13. package/dist/core/public.js +12 -0
  14. package/dist/core/random.js +4 -0
  15. package/dist/core/ristretto.d.ts +7 -0
  16. package/dist/core/ristretto.js +7 -0
  17. package/dist/core/types.d.ts +14 -6
  18. package/dist/core/validation.d.ts +45 -12
  19. package/dist/core/validation.js +52 -12
  20. package/dist/dkg/pedersen-share-codec.d.ts +12 -2
  21. package/dist/dkg/pedersen-share-codec.js +19 -2
  22. package/dist/dkg/public.d.ts +12 -0
  23. package/dist/dkg/public.js +11 -0
  24. package/dist/dkg/verification.d.ts +33 -14
  25. package/dist/dkg/verification.js +16 -12
  26. package/dist/elgamal/additive.d.ts +15 -3
  27. package/dist/elgamal/additive.js +27 -23
  28. package/dist/elgamal/bsgs.js +7 -0
  29. package/dist/elgamal/public.d.ts +11 -0
  30. package/dist/elgamal/public.js +10 -0
  31. package/dist/elgamal/types.d.ts +6 -0
  32. package/dist/index.d.ts +27 -25
  33. package/dist/index.js +20 -19
  34. package/dist/proofs/disjunctive.d.ts +11 -16
  35. package/dist/proofs/disjunctive.js +12 -17
  36. package/dist/proofs/dleq.d.ts +17 -13
  37. package/dist/proofs/dleq.js +11 -12
  38. package/dist/proofs/helpers.d.ts +1 -1
  39. package/dist/proofs/helpers.js +5 -4
  40. package/dist/proofs/nonces.js +6 -0
  41. package/dist/proofs/public.d.ts +12 -0
  42. package/dist/proofs/public.js +11 -0
  43. package/dist/proofs/schnorr.d.ts +10 -11
  44. package/dist/proofs/schnorr.js +10 -11
  45. package/dist/proofs/types.d.ts +30 -5
  46. package/dist/protocol/board-audit.d.ts +8 -3
  47. package/dist/protocol/board-audit.js +8 -2
  48. package/dist/protocol/builders.d.ts +77 -13
  49. package/dist/protocol/builders.js +83 -13
  50. package/dist/protocol/canonical-json.js +4 -0
  51. package/dist/protocol/manifest.d.ts +32 -15
  52. package/dist/protocol/manifest.js +65 -18
  53. package/dist/protocol/ordering.js +6 -0
  54. package/dist/protocol/payloads.d.ts +3 -3
  55. package/dist/protocol/payloads.js +7 -3
  56. package/dist/protocol/public.d.ts +17 -0
  57. package/dist/protocol/public.js +16 -0
  58. package/dist/protocol/score-range.d.ts +6 -0
  59. package/dist/protocol/score-range.js +24 -0
  60. package/dist/protocol/transcript.js +4 -0
  61. package/dist/protocol/types.d.ts +110 -17
  62. package/dist/protocol/verification.d.ts +14 -7
  63. package/dist/protocol/verification.js +7 -5
  64. package/dist/protocol/voting-ballot-aggregation.d.ts +10 -2
  65. package/dist/protocol/voting-ballot-aggregation.js +6 -0
  66. package/dist/protocol/voting-ballots.d.ts +3 -5
  67. package/dist/protocol/voting-ballots.js +6 -5
  68. package/dist/protocol/voting-codecs.d.ts +8 -3
  69. package/dist/protocol/voting-codecs.js +18 -2
  70. package/dist/protocol/voting-decryption.d.ts +3 -5
  71. package/dist/protocol/voting-decryption.js +7 -5
  72. package/dist/protocol/voting-shared.d.ts +2 -1
  73. package/dist/protocol/voting-shared.js +9 -2
  74. package/dist/protocol/voting-verification.d.ts +27 -30
  75. package/dist/protocol/voting-verification.js +13 -26
  76. package/dist/serialize/encoding.js +4 -0
  77. package/dist/threshold/decrypt.d.ts +13 -5
  78. package/dist/threshold/decrypt.js +20 -5
  79. package/dist/threshold/public.d.ts +11 -0
  80. package/dist/threshold/public.js +10 -0
  81. package/dist/threshold/types.d.ts +23 -4
  82. package/dist/transport/auth.d.ts +10 -16
  83. package/dist/transport/auth.js +16 -16
  84. package/dist/transport/complaints.d.ts +2 -4
  85. package/dist/transport/complaints.js +8 -4
  86. package/dist/transport/envelopes.d.ts +5 -7
  87. package/dist/transport/envelopes.js +9 -7
  88. package/dist/transport/key-agreement.d.ts +15 -23
  89. package/dist/transport/key-agreement.js +21 -23
  90. package/dist/transport/types.d.ts +16 -2
  91. package/dist/vss/feldman.d.ts +11 -1
  92. package/dist/vss/feldman.js +11 -1
  93. package/dist/vss/pedersen.d.ts +13 -0
  94. package/dist/vss/pedersen.js +13 -0
  95. package/dist/vss/public.d.ts +10 -0
  96. package/dist/vss/public.js +9 -0
  97. package/dist/vss/types.d.ts +4 -0
  98. package/package.json +43 -14
@@ -1,3 +1,10 @@
1
+ /**
2
+ * Top-level full-ceremony verification for the supported voting workflow.
3
+ *
4
+ * This module is the shortest path for auditors and bulletin-board readers who
5
+ * want one call that replays manifest validation, board audit, DKG, ballots,
6
+ * decryption shares, and tally checks.
7
+ */
1
8
  import { InvalidPayloadError } from '../core/index.js';
2
9
  import { decodeScalar } from '../core/ristretto.js';
3
10
  import { verifyDKGTranscript, } from '../dkg/verification.js';
@@ -30,7 +37,7 @@ const recomputePublishedTally = (input) => {
30
37
  sessionId: input.sessionId,
31
38
  optionIndex: input.ballots.optionIndex,
32
39
  });
33
- return combineDecryptionShares(preparedAggregate.ciphertext, input.decryptionShares.map((entry) => entry.share), BigInt(input.ballots.aggregate.ballotCount) * 10n);
40
+ return combineDecryptionShares(preparedAggregate.ciphertext, input.decryptionShares.map((entry) => entry.share), BigInt(input.ballots.aggregate.ballotCount) * input.scoreRangeMax);
34
41
  };
35
42
  const verifyPublishedTallyPayload = (payload, optionIndex, ballots, decryptionShares, tally) => {
36
43
  if (payload.transcriptHash !== ballots.aggregate.transcriptHash) {
@@ -123,17 +130,8 @@ const verifyBallotClosePayload = (input) => {
123
130
  * DKG verification, ballot verification, decryption-share verification, and
124
131
  * per-option tally checks.
125
132
  *
126
- * @param input Full public ceremony input bundle.
127
- * @returns Detailed verified ceremony output.
128
- *
129
- * @example
130
- * ```ts
131
- * const verified = await verifyElectionCeremony(bundle);
132
- *
133
- * console.log(verified.boardAudit.overall.fingerprint);
134
- * console.log(verified.countedParticipantIndices);
135
- * console.log(verified.perOptionTallies);
136
- * ```
133
+ * This is the main verifier entry point for callers that want failures to
134
+ * abort immediately.
137
135
  */
138
136
  export const verifyElectionCeremony = async (input) => {
139
137
  let context;
@@ -282,6 +280,7 @@ export const verifyElectionCeremony = async (input) => {
282
280
  jointPublicKey: dkg.jointPublicKey,
283
281
  protocolVersion: context.protocolVersion,
284
282
  manifestHash: context.manifestHash,
283
+ scoreRangeMax: context.scoreRangeMax,
285
284
  sessionId: context.sessionId,
286
285
  });
287
286
  const publication = tallyPublicationMap.get(optionIndex);
@@ -333,20 +332,8 @@ export const verifyElectionCeremony = async (input) => {
333
332
  * Runs the full ceremony verifier and returns a structured success-or-failure
334
333
  * result without throwing.
335
334
  *
336
- * @param input Full public ceremony input bundle.
337
- * @returns Verified ceremony output or a stable structured failure.
338
- *
339
- * @example
340
- * ```ts
341
- * const result = await tryVerifyElectionCeremony(bundle);
342
- *
343
- * if (!result.ok) {
344
- * console.error(result.error.stage, result.error.code, result.error.reason);
345
- * return;
346
- * }
347
- *
348
- * console.log(result.verified.qualifiedParticipantIndices);
349
- * ```
335
+ * This is the preferred integration point for applications that want stable
336
+ * failure stages and codes instead of exception handling.
350
337
  */
351
338
  export const tryVerifyElectionCeremony = async (input) => {
352
339
  try {
@@ -1,3 +1,7 @@
1
+ /**
2
+ * Deterministic byte encoders used for transcript hashing, proof challenges,
3
+ * session identifiers, and other canonical digest inputs.
4
+ */
1
5
  import { bytesToBigInt, hexToBytes } from '../core/bytes.js';
2
6
  import { utf8ToBytes } from '../core/crypto.js';
3
7
  import { InvalidPayloadError, InvalidScalarError } from '../core/errors.js';
@@ -10,20 +10,28 @@ import { type AggregateDecryptionPreparationInput, type DecryptionShare, type Sh
10
10
  */
11
11
  export declare const lagrangeCoefficient: (participantIndex: bigint, allIndices: readonly bigint[], q: bigint) => bigint;
12
12
  /**
13
- * Creates a partial decryption share `d_i = x_i C_1`.
13
+ * Creates one trustee's partial decryption share `d_i = x_i C_1`.
14
+ *
15
+ * This is the low-level share value that applications typically prove with
16
+ * DLEQ and then publish inside a signed `decryption-share` payload.
14
17
  */
15
18
  export declare const createDecryptionShare: (ciphertext: ElGamalCiphertext, share: Share) => DecryptionShare;
16
19
  /**
17
- * Prepares a verified aggregate for decryption.
20
+ * Prepares a verified aggregate for decryption-share generation and DLEQ
21
+ * proving.
18
22
  *
19
23
  * When the accepted aggregate has identity `c1`, the raw DLEQ statement would
20
24
  * degenerate because every participant would obtain the same identity-valued
21
- * partial share. This helper deterministically adds a public encryption of zero
22
- * in that corner case so the plaintext stays unchanged while the decryption
23
- * proof statement remains meaningful.
25
+ * partial share. This helper deterministically adds a public encryption of
26
+ * zero in that corner case so the plaintext stays unchanged while the
27
+ * decryption proof statement remains meaningful.
24
28
  */
25
29
  export declare const prepareAggregateForDecryption: (input: AggregateDecryptionPreparationInput) => AggregateDecryptionPreparationInput["aggregate"];
26
30
  /**
27
31
  * Combines indexed decryption shares via Lagrange interpolation at `x = 0`.
32
+ *
33
+ * This is the final bounded plaintext-recovery step. In the supported voting
34
+ * workflow it runs only after the transcript, ballot aggregation, and
35
+ * decryption-share proofs have already been verified.
28
36
  */
29
37
  export declare const combineDecryptionShares: (ciphertext: ElGamalCiphertext, decryptionShares: readonly DecryptionShare[], bound: bigint) => bigint;
@@ -1,3 +1,10 @@
1
+ /**
2
+ * Threshold decryption and bounded tally-recovery helpers.
3
+ *
4
+ * These functions are used after ballot aggregation has produced a verified
5
+ * additive ciphertext and before tally publication or verifier-side tally
6
+ * recomputation.
7
+ */
1
8
  import { hexToBytes } from '../core/bytes.js';
2
9
  import { assertInSubgroupOrIdentity, assertScalarInZq, assertValidPublicKey, IndexOutOfRangeError, InvalidShareError, PlaintextDomainError, RISTRETTO_GROUP, modInvQ, modQ, } from '../core/index.js';
3
10
  import { decodePoint, encodePoint, hashChallengeToScalar, pointAdd, pointMultiply, pointSubtract, RISTRETTO_ZERO, } from '../core/ristretto.js';
@@ -57,7 +64,10 @@ export const lagrangeCoefficient = (participantIndex, allIndices, q) => {
57
64
  return modQ(numerator * modInvQ(denominator, q), q);
58
65
  };
59
66
  /**
60
- * Creates a partial decryption share `d_i = x_i C_1`.
67
+ * Creates one trustee's partial decryption share `d_i = x_i C_1`.
68
+ *
69
+ * This is the low-level share value that applications typically prove with
70
+ * DLEQ and then publish inside a signed `decryption-share` payload.
61
71
  */
62
72
  export const createDecryptionShare = (ciphertext, share) => {
63
73
  assertPositiveIndex(share.index, 'Share');
@@ -69,13 +79,14 @@ export const createDecryptionShare = (ciphertext, share) => {
69
79
  };
70
80
  };
71
81
  /**
72
- * Prepares a verified aggregate for decryption.
82
+ * Prepares a verified aggregate for decryption-share generation and DLEQ
83
+ * proving.
73
84
  *
74
85
  * When the accepted aggregate has identity `c1`, the raw DLEQ statement would
75
86
  * degenerate because every participant would obtain the same identity-valued
76
- * partial share. This helper deterministically adds a public encryption of zero
77
- * in that corner case so the plaintext stays unchanged while the decryption
78
- * proof statement remains meaningful.
87
+ * partial share. This helper deterministically adds a public encryption of
88
+ * zero in that corner case so the plaintext stays unchanged while the
89
+ * decryption proof statement remains meaningful.
79
90
  */
80
91
  export const prepareAggregateForDecryption = (input) => {
81
92
  assertVerifiedAggregate(input.aggregate);
@@ -92,6 +103,10 @@ export const prepareAggregateForDecryption = (input) => {
92
103
  };
93
104
  /**
94
105
  * Combines indexed decryption shares via Lagrange interpolation at `x = 0`.
106
+ *
107
+ * This is the final bounded plaintext-recovery step. In the supported voting
108
+ * workflow it runs only after the transcript, ballot aggregation, and
109
+ * decryption-share proofs have already been verified.
95
110
  */
96
111
  export const combineDecryptionShares = (ciphertext, decryptionShares, bound) => {
97
112
  if (decryptionShares.length === 0) {
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Threshold-share and bounded tally-reconstruction helpers.
3
+ *
4
+ * Use this module when you need to prepare aggregates, create decryption
5
+ * shares, or reconstruct tallies directly.
6
+ *
7
+ * @module threshold-elgamal/threshold
8
+ * @packageDocumentation
9
+ */
10
+ export { combineDecryptionShares, createDecryptionShare, prepareAggregateForDecryption, } from './decrypt.js';
11
+ export type { AggregateDecryptionPreparationInput, DecryptionShare, Share, VerifiedAggregateCiphertext, } from './types.js';
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Threshold-share and bounded tally-reconstruction helpers.
3
+ *
4
+ * Use this module when you need to prepare aggregates, create decryption
5
+ * shares, or reconstruct tallies directly.
6
+ *
7
+ * @module threshold-elgamal/threshold
8
+ * @packageDocumentation
9
+ */
10
+ export { combineDecryptionShares, createDecryptionShare, prepareAggregateForDecryption, } from './decrypt.js';
@@ -1,3 +1,7 @@
1
+ /**
2
+ * Threshold-decryption types that bridge verified ballot aggregates, indexed
3
+ * shares, and the final bounded plaintext reconstruction step.
4
+ */
1
5
  import type { EncodedPoint } from '../core/types.js';
2
6
  import type { ElGamalCiphertext } from '../elgamal/types.js';
3
7
  /** A single indexed Shamir share over `Z_q`. */
@@ -7,7 +11,12 @@ export type Share = {
7
11
  /** Share value `f(index) mod q`. */
8
12
  readonly value: bigint;
9
13
  };
10
- /** A participant's partial decryption contribution. */
14
+ /**
15
+ * A participant's partial decryption contribution for one verified aggregate.
16
+ *
17
+ * These values are the low-level shares later wrapped into signed
18
+ * `decryption-share` protocol payloads.
19
+ */
11
20
  export type DecryptionShare = {
12
21
  /** 1-based participant index matching the source share. */
13
22
  readonly index: number;
@@ -15,7 +24,12 @@ export type DecryptionShare = {
15
24
  readonly value: EncodedPoint;
16
25
  };
17
26
  declare const verifiedAggregateBrand: unique symbol;
18
- /** A threshold aggregate tied to a verified additive ciphertext. */
27
+ /**
28
+ * A threshold aggregate tied to a verified additive ciphertext.
29
+ *
30
+ * The branding step prevents callers from skipping ballot verification and
31
+ * constructing arbitrary objects that merely look like verified aggregates.
32
+ */
19
33
  export type VerifiedAggregateCiphertext = {
20
34
  /** Canonical transcript hash that anchors the accepted ballot log. */
21
35
  readonly transcriptHash: string;
@@ -26,13 +40,18 @@ export type VerifiedAggregateCiphertext = {
26
40
  /** Opaque brand preventing arbitrary object-literal construction. */
27
41
  readonly [verifiedAggregateBrand]: true;
28
42
  };
29
- /** Public context needed to prepare a verified aggregate for decryption. */
43
+ /**
44
+ * Public context needed to prepare a verified aggregate for decryption.
45
+ *
46
+ * This binds the rerandomization corner case to the exact ceremony, manifest,
47
+ * and option slot being processed.
48
+ */
30
49
  export type AggregateDecryptionPreparationInput = {
31
50
  /** Verified aggregate recomputed from the accepted ballot transcript. */
32
51
  readonly aggregate: VerifiedAggregateCiphertext;
33
52
  /** Joint public key used to encrypt the original ballots. */
34
53
  readonly publicKey: EncodedPoint;
35
- /** Bound protocol version carried by the ceremony transcript. */
54
+ /** Protocol namespace carried by the ceremony transcript. */
36
55
  readonly protocolVersion: string;
37
56
  /** Manifest hash that anchors the ceremony context. */
38
57
  readonly manifestHash: string;
@@ -7,38 +7,32 @@ type GenerateAuthKeyPairOptions = {
7
7
  /**
8
8
  * Generates a fresh per-ceremony authentication key pair.
9
9
  *
10
- * @returns Authentication key pair. The private key is extractable only when requested.
10
+ * Trustees use this key pair to sign every public payload they publish during
11
+ * setup, DKG, voting, and tally publication.
11
12
  */
12
13
  export declare const generateAuthKeyPair: (options?: GenerateAuthKeyPairOptions) => Promise<CryptoKeyPair>;
13
14
  /**
14
- * Exports an authentication public key as SPKI hex.
15
- *
16
- * @param publicKey Authentication public key.
17
- * @returns Lowercase hexadecimal SPKI bytes.
15
+ * Exports an authentication public key as SPKI hex so it can be published in a
16
+ * registration payload and later imported by verifiers.
18
17
  */
19
18
  export declare const exportAuthPublicKey: (publicKey: CryptoKey) => Promise<EncodedAuthPublicKey>;
20
19
  /**
21
- * Imports an authentication public key from SPKI hex.
22
- *
23
- * @param spkiHex Lowercase hexadecimal SPKI bytes.
24
- * @returns Imported public key.
20
+ * Imports an authentication public key from the canonical published SPKI
21
+ * encoding.
25
22
  */
26
23
  export declare const importAuthPublicKey: (spkiHex: EncodedAuthPublicKey) => Promise<CryptoKey>;
27
24
  /**
28
25
  * Signs canonical payload bytes with an authentication private key.
29
26
  *
30
- * @param privateKey Authentication private key.
31
- * @param payloadBytes Canonical unsigned payload bytes.
32
- * @returns Lowercase hexadecimal raw Ed25519 signature bytes.
27
+ * Protocol builders call this after they have frozen the payload shape and
28
+ * canonical serialization.
33
29
  */
34
30
  export declare const signPayloadBytes: (privateKey: CryptoKey, payloadBytes: Uint8Array) => Promise<string>;
35
31
  /**
36
32
  * Verifies canonical payload bytes against an authentication signature.
37
33
  *
38
- * @param publicKey Authentication public key.
39
- * @param payloadBytes Canonical unsigned payload bytes.
40
- * @param signatureHex Lowercase hexadecimal raw Ed25519 signature bytes.
41
- * @returns `true` when the signature verifies.
34
+ * Signature verification for published board payloads ultimately routes
35
+ * through this helper.
42
36
  */
43
37
  export declare const verifyPayloadSignature: (publicKey: CryptoKey, payloadBytes: Uint8Array, signatureHex: string) => Promise<boolean>;
44
38
  export {};
@@ -1,25 +1,28 @@
1
+ /**
2
+ * Ed25519 authentication-key and signature helpers.
3
+ *
4
+ * Every published protocol payload is signed through this layer, either
5
+ * directly or via the higher-level protocol builders.
6
+ */
1
7
  import { bytesToHex, hexToBytes, toBufferSource } from '../core/bytes.js';
2
8
  import { getWebCrypto } from '../core/index.js';
3
9
  /**
4
10
  * Generates a fresh per-ceremony authentication key pair.
5
11
  *
6
- * @returns Authentication key pair. The private key is extractable only when requested.
12
+ * Trustees use this key pair to sign every public payload they publish during
13
+ * setup, DKG, voting, and tally publication.
7
14
  */
8
15
  export const generateAuthKeyPair = async (options = {}) => getWebCrypto().subtle.generateKey({
9
16
  name: 'Ed25519',
10
17
  }, options.extractable ?? false, ['sign', 'verify']);
11
18
  /**
12
- * Exports an authentication public key as SPKI hex.
13
- *
14
- * @param publicKey Authentication public key.
15
- * @returns Lowercase hexadecimal SPKI bytes.
19
+ * Exports an authentication public key as SPKI hex so it can be published in a
20
+ * registration payload and later imported by verifiers.
16
21
  */
17
22
  export const exportAuthPublicKey = async (publicKey) => bytesToHex(new Uint8Array(await getWebCrypto().subtle.exportKey('spki', publicKey)));
18
23
  /**
19
- * Imports an authentication public key from SPKI hex.
20
- *
21
- * @param spkiHex Lowercase hexadecimal SPKI bytes.
22
- * @returns Imported public key.
24
+ * Imports an authentication public key from the canonical published SPKI
25
+ * encoding.
23
26
  */
24
27
  export const importAuthPublicKey = async (spkiHex) => getWebCrypto().subtle.importKey('spki', toBufferSource(hexToBytes(spkiHex)), {
25
28
  name: 'Ed25519',
@@ -27,17 +30,14 @@ export const importAuthPublicKey = async (spkiHex) => getWebCrypto().subtle.impo
27
30
  /**
28
31
  * Signs canonical payload bytes with an authentication private key.
29
32
  *
30
- * @param privateKey Authentication private key.
31
- * @param payloadBytes Canonical unsigned payload bytes.
32
- * @returns Lowercase hexadecimal raw Ed25519 signature bytes.
33
+ * Protocol builders call this after they have frozen the payload shape and
34
+ * canonical serialization.
33
35
  */
34
36
  export const signPayloadBytes = async (privateKey, payloadBytes) => bytesToHex(new Uint8Array(await getWebCrypto().subtle.sign('Ed25519', privateKey, toBufferSource(payloadBytes))));
35
37
  /**
36
38
  * Verifies canonical payload bytes against an authentication signature.
37
39
  *
38
- * @param publicKey Authentication public key.
39
- * @param payloadBytes Canonical unsigned payload bytes.
40
- * @param signatureHex Lowercase hexadecimal raw Ed25519 signature bytes.
41
- * @returns `true` when the signature verifies.
40
+ * Signature verification for published board payloads ultimately routes
41
+ * through this helper.
42
42
  */
43
43
  export const verifyPayloadSignature = async (publicKey, payloadBytes, signatureHex) => getWebCrypto().subtle.verify('Ed25519', publicKey, toBufferSource(hexToBytes(signatureHex)), toBufferSource(payloadBytes));
@@ -8,10 +8,8 @@ type ComplaintResolution = {
8
8
  * Resolves a dealer challenge using only public transcript material plus the
9
9
  * dealer-revealed sender-ephemeral private key.
10
10
  *
11
- * @param envelope Committed encrypted envelope.
12
- * @param recipientPublicKeyHex Registered recipient transport public key.
13
- * @param revealedEphemeralPrivateKeyHex Revealed sender-ephemeral private key.
14
- * @returns Complaint resolution result.
11
+ * The DKG verifier uses this to decide whether a complaint indicates dealer
12
+ * misconduct or a complaining recipient that published an invalid accusation.
15
13
  */
16
14
  export declare const resolveDealerChallengeFromPublicKey: (envelope: EncryptedEnvelope, recipientPublicKeyHex: EncodedTransportPublicKey, revealedEphemeralPrivateKeyHex: EncodedTransportPrivateKey) => Promise<ComplaintResolution>;
17
15
  export {};
@@ -1,3 +1,9 @@
1
+ /**
2
+ * Complaint-resolution helpers for the encrypted share-transport layer.
3
+ *
4
+ * DKG transcript verification uses this module when it needs to reconstruct
5
+ * the expected public challenge material for a dealer complaint.
6
+ */
1
7
  import { hexToBytes, toBufferSource } from '../core/bytes.js';
2
8
  import { getWebCrypto } from '../core/index.js';
3
9
  import { deriveEnvelopeKey, encodeEnvelopeContext } from './envelopes.js';
@@ -14,10 +20,8 @@ const decryptEnvelopeFromSharedSecret = async (envelope, sharedSecret) => {
14
20
  * Resolves a dealer challenge using only public transcript material plus the
15
21
  * dealer-revealed sender-ephemeral private key.
16
22
  *
17
- * @param envelope Committed encrypted envelope.
18
- * @param recipientPublicKeyHex Registered recipient transport public key.
19
- * @param revealedEphemeralPrivateKeyHex Revealed sender-ephemeral private key.
20
- * @returns Complaint resolution result.
23
+ * The DKG verifier uses this to decide whether a complaint indicates dealer
24
+ * misconduct or a complaining recipient that published an invalid accusation.
21
25
  */
22
26
  export const resolveDealerChallengeFromPublicKey = async (envelope, recipientPublicKeyHex, revealedEphemeralPrivateKeyHex) => {
23
27
  const ephemeralKeyMatches = await verifyLocalTransportKey(revealedEphemeralPrivateKeyHex, envelope.ephemeralPublicKey);
@@ -4,10 +4,9 @@ export declare const deriveEnvelopeKey: (sharedSecret: Uint8Array, context: Enve
4
4
  /**
5
5
  * Encrypts a payload into a sender-ephemeral authenticated envelope.
6
6
  *
7
- * @param plaintext Raw payload bytes to encrypt.
8
- * @param recipientPublicKeyHex Recipient transport public key.
9
- * @param context Envelope binding context.
10
- * @returns Envelope plus the sender-ephemeral private key for complaint recovery.
7
+ * DKG dealers use this when publishing encrypted Pedersen shares for one
8
+ * recipient. The returned ephemeral private key is retained so complaint
9
+ * resolution can later prove what was sent.
11
10
  */
12
11
  export declare const encryptEnvelope: (plaintext: Uint8Array, recipientPublicKeyHex: EncodedTransportPublicKey, context: EnvelopeContext) => Promise<{
13
12
  readonly envelope: EncryptedEnvelope;
@@ -16,8 +15,7 @@ export declare const encryptEnvelope: (plaintext: Uint8Array, recipientPublicKey
16
15
  /**
17
16
  * Decrypts an authenticated envelope with the recipient transport private key.
18
17
  *
19
- * @param envelope Authenticated encrypted envelope.
20
- * @param recipientPrivateKey Recipient transport private key.
21
- * @returns Decrypted plaintext bytes.
18
+ * This is the recipient-side counterpart to {@link encryptEnvelope} and is
19
+ * typically followed by Pedersen share decoding.
22
20
  */
23
21
  export declare const decryptEnvelope: (envelope: EncryptedEnvelope, recipientPrivateKey: CryptoKey | EncodedTransportPrivateKey) => Promise<Uint8Array>;
@@ -1,3 +1,7 @@
1
+ /**
2
+ * Authenticated sender-ephemeral envelope helpers for dealer-to-recipient
3
+ * transport during DKG share distribution.
4
+ */
1
5
  import { bytesToHex, hexToBytes, toBufferSource } from '../core/bytes.js';
2
6
  import { getWebCrypto, hkdfSha256, randomBytes } from '../core/index.js';
3
7
  import { encodeForChallenge } from '../serialize/encoding.js';
@@ -8,10 +12,9 @@ export const deriveEnvelopeKey = async (sharedSecret, context, usages = ['encryp
8
12
  /**
9
13
  * Encrypts a payload into a sender-ephemeral authenticated envelope.
10
14
  *
11
- * @param plaintext Raw payload bytes to encrypt.
12
- * @param recipientPublicKeyHex Recipient transport public key.
13
- * @param context Envelope binding context.
14
- * @returns Envelope plus the sender-ephemeral private key for complaint recovery.
15
+ * DKG dealers use this when publishing encrypted Pedersen shares for one
16
+ * recipient. The returned ephemeral private key is retained so complaint
17
+ * resolution can later prove what was sent.
15
18
  */
16
19
  export const encryptEnvelope = async (plaintext, recipientPublicKeyHex, context) => {
17
20
  const ephemeral = await generateTransportKeyPair({
@@ -39,9 +42,8 @@ export const encryptEnvelope = async (plaintext, recipientPublicKeyHex, context)
39
42
  /**
40
43
  * Decrypts an authenticated envelope with the recipient transport private key.
41
44
  *
42
- * @param envelope Authenticated encrypted envelope.
43
- * @param recipientPrivateKey Recipient transport private key.
44
- * @returns Decrypted plaintext bytes.
45
+ * This is the recipient-side counterpart to {@link encryptEnvelope} and is
46
+ * typically followed by Pedersen share decoding.
45
47
  */
46
48
  export const decryptEnvelope = async (envelope, recipientPrivateKey) => {
47
49
  const resolvedRecipientPrivateKey = typeof recipientPrivateKey === 'string'
@@ -14,53 +14,45 @@ export declare const assertNonZeroSharedSecret: (sharedSecret: Uint8Array) => vo
14
14
  /**
15
15
  * Generates an X25519 transport key pair.
16
16
  *
17
- * @param options Generation options.
18
- * @returns Transport key pair tagged with the shipped X25519 suite.
17
+ * Trustees publish the public half in their registration payloads and keep the
18
+ * private half for decrypting inbound dealer envelopes.
19
19
  */
20
20
  export declare const generateTransportKeyPair: (options?: GenerateTransportKeyPairOptions) => Promise<TransportKeyPair>;
21
21
  /**
22
- * Exports a transport public key as raw lowercase hexadecimal bytes.
23
- *
24
- * @param publicKey Transport public key.
25
- * @returns Lowercase hexadecimal public key bytes.
22
+ * Exports a transport public key as raw lowercase hexadecimal bytes so it can
23
+ * be published in a registration payload.
26
24
  */
27
25
  export declare const exportTransportPublicKey: (publicKey: CryptoKey) => Promise<EncodedTransportPublicKey>;
28
26
  /**
29
27
  * Exports a transport private key as PKCS#8 lowercase hexadecimal bytes.
30
28
  *
31
- * @param privateKey Transport private key.
32
- * @returns Lowercase hexadecimal PKCS#8 bytes.
29
+ * This is mainly useful for persistence and tests.
33
30
  */
34
31
  export declare const exportTransportPrivateKey: (privateKey: CryptoKey) => Promise<EncodedTransportPrivateKey>;
35
32
  /**
36
- * Imports a transport public key from raw hexadecimal bytes.
37
- *
38
- * @param publicKeyHex Lowercase hexadecimal public key bytes.
39
- * @returns Imported transport public key.
33
+ * Imports a transport public key from the canonical raw hexadecimal encoding
34
+ * published on the board.
40
35
  */
41
36
  export declare const importTransportPublicKey: (publicKeyHex: EncodedTransportPublicKey) => Promise<CryptoKey>;
42
37
  export declare const assertSupportedTransportPublicKeyEncoding: (publicKeyHex: EncodedTransportPublicKey, label?: string) => void;
43
38
  /**
44
- * Imports a transport private key from PKCS#8 hexadecimal bytes.
45
- *
46
- * @param privateKeyHex Lowercase hexadecimal PKCS#8 bytes.
47
- * @returns Imported transport private key.
39
+ * Imports a transport private key from the canonical PKCS#8 hexadecimal
40
+ * encoding.
48
41
  */
49
42
  export declare const importTransportPrivateKey: (privateKeyHex: EncodedTransportPrivateKey) => Promise<CryptoKey>;
50
43
  /**
51
44
  * Derives a raw shared secret for X25519.
52
45
  *
53
- * @param privateKey Local transport private key.
54
- * @param publicKey Peer transport public key.
55
- * @returns Raw shared secret bytes.
46
+ * Envelope encryption and decryption both route through this shared-secret
47
+ * derivation step before expanding the result with HKDF.
56
48
  */
57
49
  export declare const deriveTransportSharedSecret: (privateKey: CryptoKey, publicKey: CryptoKey) => Promise<Uint8Array>;
58
50
  /**
59
- * Verifies that a local transport private key matches the registered public key.
51
+ * Verifies that a local transport private key matches the registered public
52
+ * key.
60
53
  *
61
- * @param privateKey Local transport private key.
62
- * @param expectedPublicKeyHex Registered public key bytes.
63
- * @returns `true` when the private key expands to `expectedPublicKeyHex`.
54
+ * This is useful when loading persisted local key material for an already
55
+ * published registration record.
64
56
  */
65
57
  export declare const verifyLocalTransportKey: (privateKey: CryptoKey | EncodedTransportPrivateKey, expectedPublicKeyHex: EncodedTransportPublicKey) => Promise<boolean>;
66
58
  export {};
@@ -1,3 +1,9 @@
1
+ /**
2
+ * X25519 transport-key helpers used for encrypted DKG share delivery.
3
+ *
4
+ * These functions stay lower-level than the protocol builders so applications
5
+ * and tests can manage key export, import, and local verification directly.
6
+ */
1
7
  import { bytesToHex, hexToBytes, toBufferSource } from '../core/bytes.js';
2
8
  import { InvalidPayloadError, getWebCrypto } from '../core/index.js';
3
9
  const X25519_BASE_POINT = (() => {
@@ -30,8 +36,8 @@ export const assertNonZeroSharedSecret = (sharedSecret) => {
30
36
  /**
31
37
  * Generates an X25519 transport key pair.
32
38
  *
33
- * @param options Generation options.
34
- * @returns Transport key pair tagged with the shipped X25519 suite.
39
+ * Trustees publish the public half in their registration payloads and keep the
40
+ * private half for decrypting inbound dealer envelopes.
35
41
  */
36
42
  export const generateTransportKeyPair = async (options = {}) => {
37
43
  const keyPair = await getWebCrypto().subtle.generateKey(x25519Algorithm, options.extractable ?? false, ['deriveBits']);
@@ -42,24 +48,19 @@ export const generateTransportKeyPair = async (options = {}) => {
42
48
  };
43
49
  };
44
50
  /**
45
- * Exports a transport public key as raw lowercase hexadecimal bytes.
46
- *
47
- * @param publicKey Transport public key.
48
- * @returns Lowercase hexadecimal public key bytes.
51
+ * Exports a transport public key as raw lowercase hexadecimal bytes so it can
52
+ * be published in a registration payload.
49
53
  */
50
54
  export const exportTransportPublicKey = async (publicKey) => bytesToHex(new Uint8Array(await getWebCrypto().subtle.exportKey('raw', publicKey)));
51
55
  /**
52
56
  * Exports a transport private key as PKCS#8 lowercase hexadecimal bytes.
53
57
  *
54
- * @param privateKey Transport private key.
55
- * @returns Lowercase hexadecimal PKCS#8 bytes.
58
+ * This is mainly useful for persistence and tests.
56
59
  */
57
60
  export const exportTransportPrivateKey = async (privateKey) => bytesToHex(new Uint8Array(await getWebCrypto().subtle.exportKey('pkcs8', privateKey)));
58
61
  /**
59
- * Imports a transport public key from raw hexadecimal bytes.
60
- *
61
- * @param publicKeyHex Lowercase hexadecimal public key bytes.
62
- * @returns Imported transport public key.
62
+ * Imports a transport public key from the canonical raw hexadecimal encoding
63
+ * published on the board.
63
64
  */
64
65
  export const importTransportPublicKey = async (publicKeyHex) => {
65
66
  const publicKeyBytes = hexToBytes(publicKeyHex);
@@ -77,18 +78,15 @@ export const assertSupportedTransportPublicKeyEncoding = (publicKeyHex, label =
77
78
  assertValidX25519PublicKeyBytes(publicKeyBytes, label);
78
79
  };
79
80
  /**
80
- * Imports a transport private key from PKCS#8 hexadecimal bytes.
81
- *
82
- * @param privateKeyHex Lowercase hexadecimal PKCS#8 bytes.
83
- * @returns Imported transport private key.
81
+ * Imports a transport private key from the canonical PKCS#8 hexadecimal
82
+ * encoding.
84
83
  */
85
84
  export const importTransportPrivateKey = async (privateKeyHex) => getWebCrypto().subtle.importKey('pkcs8', toBufferSource(hexToBytes(privateKeyHex)), x25519Algorithm, true, ['deriveBits']);
86
85
  /**
87
86
  * Derives a raw shared secret for X25519.
88
87
  *
89
- * @param privateKey Local transport private key.
90
- * @param publicKey Peer transport public key.
91
- * @returns Raw shared secret bytes.
88
+ * Envelope encryption and decryption both route through this shared-secret
89
+ * derivation step before expanding the result with HKDF.
92
90
  */
93
91
  export const deriveTransportSharedSecret = async (privateKey, publicKey) => {
94
92
  const sharedSecret = new Uint8Array(await getWebCrypto().subtle.deriveBits({
@@ -109,11 +107,11 @@ const deriveTransportPublicKey = async (privateKey) => {
109
107
  return bytesToHex(await deriveTransportSharedSecret(privateKey, basePoint));
110
108
  };
111
109
  /**
112
- * Verifies that a local transport private key matches the registered public key.
110
+ * Verifies that a local transport private key matches the registered public
111
+ * key.
113
112
  *
114
- * @param privateKey Local transport private key.
115
- * @param expectedPublicKeyHex Registered public key bytes.
116
- * @returns `true` when the private key expands to `expectedPublicKeyHex`.
113
+ * This is useful when loading persisted local key material for an already
114
+ * published registration record.
117
115
  */
118
116
  export const verifyLocalTransportKey = async (privateKey, expectedPublicKeyHex) => {
119
117
  try {