threshold-elgamal 0.1.24 → 0.1.26

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
@@ -29,9 +29,8 @@ The JavaScript/TypeScript ecosystem seems to be lacking in modern, functional El
29
29
  ## Production dependencies
30
30
 
31
31
  - [bigint-mod-arith](https://www.npmjs.com/package/bigint-mod-arith)
32
- - [random-bigint](https://www.npmjs.com/package/random-bigint)
33
32
 
34
- It has no other production dependencies apart from these two. They could be inlined easily, if needed.
33
+ It has no other production dependencies apart from this one. It could be inlined easily, if needed.
35
34
 
36
35
  ## TODO
37
36
 
@@ -91,41 +90,28 @@ Threshold scheme for generating a common public key, sharing a secret to 3 parti
91
90
  import {
92
91
  getGroup,
93
92
  encrypt,
94
- generateSingleKeyShare,
93
+ generateKeys,
95
94
  combinePublicKeys,
96
95
  createDecryptionShare,
97
96
  combineDecryptionShares,
98
97
  thresholdDecrypt,
99
98
  } from "threshold-elgamal";
100
- import type { PartyKeyPair } from "threshold-elgamal";
101
99
 
102
100
  const primeBits = 2048; // Bit length of the prime modulus
103
101
  const threshold = 3; // A scenario for 3 participants with a threshold of 3
104
102
  const { prime, generator } = getGroup(2048);
105
103
 
106
104
  // Each participant generates their public key share and private key individually
107
- const participant1KeyShare: PartyKeyPair = generateSingleKeyShare(
108
- 1,
109
- threshold,
110
- primeBits,
111
- );
112
- const participant2KeyShare: PartyKeyPair = generateSingleKeyShare(
113
- 2,
114
- threshold,
115
- primeBits,
116
- );
117
- const participant3KeyShare: PartyKeyPair = generateSingleKeyShare(
118
- 3,
119
- threshold,
120
- primeBits,
121
- );
105
+ const participant1Keys = generateKeys(1, threshold, primeBits);
106
+ const participant2Keys = generateKeys(2, threshold, primeBits);
107
+ const participant3Keys = generateKeys(3, threshold, primeBits);
122
108
 
123
109
  // Combine the public keys to form a single public key
124
110
  const combinedPublicKey = combinePublicKeys(
125
111
  [
126
- participant1KeyShare.partyPublicKey,
127
- participant2KeyShare.partyPublicKey,
128
- participant3KeyShare.partyPublicKey,
112
+ participant1Keys.publicKey,
113
+ participant2Keys.publicKey,
114
+ participant3Keys.publicKey,
129
115
  ],
130
116
  prime,
131
117
  );
@@ -136,21 +122,9 @@ const encryptedMessage = encrypt(secret, prime, generator, combinedPublicKey);
136
122
 
137
123
  // Decryption shares
138
124
  const decryptionShares = [
139
- createDecryptionShare(
140
- encryptedMessage,
141
- participant1KeyShare.partyPrivateKey,
142
- prime,
143
- ),
144
- createDecryptionShare(
145
- encryptedMessage,
146
- participant2KeyShare.partyPrivateKey,
147
- prime,
148
- ),
149
- createDecryptionShare(
150
- encryptedMessage,
151
- participant3KeyShare.partyPrivateKey,
152
- prime,
153
- ),
125
+ createDecryptionShare(encryptedMessage, participant1Keys.privateKey, prime),
126
+ createDecryptionShare(encryptedMessage, participant2Keys.privateKey, prime),
127
+ createDecryptionShare(encryptedMessage, participant3Keys.privateKey, prime),
154
128
  ];
155
129
  // Combining the decryption shares into one, used to decrypt the message
156
130
  const combinedDecryptionShares = combineDecryptionShares(
@@ -174,7 +148,7 @@ This example demonstrates a 1 to 10 voting scenario where 3 participants cast en
174
148
  ```typescript
175
149
  import {
176
150
  encrypt,
177
- generateSingleKeyShare,
151
+ generateKeys,
178
152
  combinePublicKeys,
179
153
  createDecryptionShare,
180
154
  combineDecryptionShares,
@@ -182,35 +156,22 @@ import {
182
156
  multiplyEncryptedValues,
183
157
  getGroup,
184
158
  } from "threshold-elgamal";
185
- import type { PartyKeyPair } from "threshold-elgamal";
186
159
 
187
160
  const primeBits = 2048; // Bit length of the prime modulus
188
161
  const threshold = 3; // A scenario for 3 participants with a threshold of 3
189
162
  const { prime, generator } = getGroup(2048);
190
163
 
191
164
  // Each participant generates their public key share and private key individually
192
- const participant1KeyShare: PartyKeyPair = generateSingleKeyShare(
193
- 1,
194
- threshold,
195
- primeBits,
196
- );
197
- const participant2KeyShare: PartyKeyPair = generateSingleKeyShare(
198
- 2,
199
- threshold,
200
- primeBits,
201
- );
202
- const participant3KeyShare: PartyKeyPair = generateSingleKeyShare(
203
- 3,
204
- threshold,
205
- primeBits,
206
- );
165
+ const participant1Keys = generateKeys(1, threshold, primeBits);
166
+ const participant2Keys = generateKeys(2, threshold, primeBits);
167
+ const participant3Keys = generateKeys(3, threshold, primeBits);
207
168
 
208
169
  // Combine the public keys to form a single public key
209
170
  const combinedPublicKey = combinePublicKeys(
210
171
  [
211
- participant1KeyShare.partyPublicKey,
212
- participant2KeyShare.partyPublicKey,
213
- participant3KeyShare.partyPublicKey,
172
+ participant1Keys.publicKey,
173
+ participant2Keys.publicKey,
174
+ participant3Keys.publicKey,
214
175
  ],
215
176
  prime,
216
177
  );
@@ -229,11 +190,11 @@ const encryptedVotesOption2 = voteOption2.map((vote) =>
229
190
 
230
191
  // Multiply encrypted votes together to aggregate
231
192
  const aggregatedEncryptedVoteOption1 = encryptedVotesOption1.reduce(
232
- (acc, current) => multiplyEncryptedValues(acc, current, prime),
193
+ (acc, encryptedVote) => multiplyEncryptedValues(acc, encryptedVote, prime),
233
194
  { c1: 1n, c2: 1n },
234
195
  );
235
196
  const aggregatedEncryptedVoteOption2 = encryptedVotesOption2.reduce(
236
- (acc, current) => multiplyEncryptedValues(acc, current, prime),
197
+ (acc, encryptedVote) => multiplyEncryptedValues(acc, encryptedVote, prime),
237
198
  { c1: 1n, c2: 1n },
238
199
  );
239
200
 
@@ -243,34 +204,34 @@ const aggregatedEncryptedVoteOption2 = encryptedVotesOption2.reduce(
243
204
  const decryptionSharesOption1 = [
244
205
  createDecryptionShare(
245
206
  aggregatedEncryptedVoteOption1,
246
- participant1KeyShare.partyPrivateKey,
207
+ participant1Keys.privateKey,
247
208
  prime,
248
209
  ),
249
210
  createDecryptionShare(
250
211
  aggregatedEncryptedVoteOption1,
251
- participant2KeyShare.partyPrivateKey,
212
+ participant2Keys.privateKey,
252
213
  prime,
253
214
  ),
254
215
  createDecryptionShare(
255
216
  aggregatedEncryptedVoteOption1,
256
- participant3KeyShare.partyPrivateKey,
217
+ participant3Keys.privateKey,
257
218
  prime,
258
219
  ),
259
220
  ];
260
221
  const decryptionSharesOption2 = [
261
222
  createDecryptionShare(
262
223
  aggregatedEncryptedVoteOption2,
263
- participant1KeyShare.partyPrivateKey,
224
+ participant1Keys.privateKey,
264
225
  prime,
265
226
  ),
266
227
  createDecryptionShare(
267
228
  aggregatedEncryptedVoteOption2,
268
- participant2KeyShare.partyPrivateKey,
229
+ participant2Keys.privateKey,
269
230
  prime,
270
231
  ),
271
232
  createDecryptionShare(
272
233
  aggregatedEncryptedVoteOption2,
273
- participant3KeyShare.partyPrivateKey,
234
+ participant3Keys.privateKey,
274
235
  prime,
275
236
  ),
276
237
  ];
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { generateParameters, encrypt, decrypt } from './elgamal';
2
- import { generateSingleKeyShare, generateKeyShares, combinePublicKeys, createDecryptionShare, combineDecryptionShares, thresholdDecrypt } from './thresholdElgamal';
3
- import type { EncryptedMessage, Parameters, KeyPair, PartyKeyPair } from './types';
2
+ import { generateKeys, generateKeyShares, combinePublicKeys, createDecryptionShare, combineDecryptionShares, thresholdDecrypt } from './thresholdElgamal';
3
+ import type { EncryptedMessage, Parameters } from './types';
4
4
  import { getRandomBigIntegerInRange, multiplyEncryptedValues, getGroup } from './utils/utils';
5
- export { generateParameters, encrypt, decrypt, generateSingleKeyShare, generateKeyShares, combinePublicKeys, createDecryptionShare, combineDecryptionShares, thresholdDecrypt, getRandomBigIntegerInRange, multiplyEncryptedValues, getGroup, };
6
- export type { EncryptedMessage, Parameters, KeyPair, PartyKeyPair };
5
+ export { generateParameters, encrypt, decrypt, generateKeys, generateKeyShares, combinePublicKeys, createDecryptionShare, combineDecryptionShares, thresholdDecrypt, getRandomBigIntegerInRange, multiplyEncryptedValues, getGroup, };
6
+ export type { EncryptedMessage, Parameters };
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
1
  import { generateParameters, encrypt, decrypt } from "./elgamal.js";
2
- import { generateSingleKeyShare, generateKeyShares, combinePublicKeys, createDecryptionShare, combineDecryptionShares, thresholdDecrypt, } from "./thresholdElgamal.js";
2
+ import { generateKeys, generateKeyShares, combinePublicKeys, createDecryptionShare, combineDecryptionShares, thresholdDecrypt, } from "./thresholdElgamal.js";
3
3
  import { getRandomBigIntegerInRange, multiplyEncryptedValues, getGroup, } from "./utils/utils.js";
4
- export { generateParameters, encrypt, decrypt, generateSingleKeyShare, generateKeyShares, combinePublicKeys, createDecryptionShare, combineDecryptionShares, thresholdDecrypt, getRandomBigIntegerInRange, multiplyEncryptedValues, getGroup, };
4
+ export { generateParameters, encrypt, decrypt, generateKeys, generateKeyShares, combinePublicKeys, createDecryptionShare, combineDecryptionShares, thresholdDecrypt, getRandomBigIntegerInRange, multiplyEncryptedValues, getGroup, };
@@ -1,4 +1,4 @@
1
- import type { EncryptedMessage, PartyKeyPair } from './types';
1
+ import type { EncryptedMessage } from './types';
2
2
  /**
3
3
  * Evaluates a polynomial at a given point using modular arithmetic.
4
4
  *
@@ -14,18 +14,24 @@ export declare const evaluatePolynomial: (polynomial: bigint[], x: number, prime
14
14
  * @param {number} index - The unique index of the participant (starting from 1).
15
15
  * @param {number} threshold - The minimum number of key shares required for decryption.
16
16
  * @param {2048 | 3072 | 4096} primeBits - The bit length of the prime modulus (default: 2048).
17
- * @returns {PartyKeyPair} The key share containing a private and public key share for the participant.
17
+ * @returns { privateKey: bigint; publicKey: bigint} The key share containing a private and public key share for the participant.
18
18
  */
19
- export declare const generateSingleKeyShare: (index: number, threshold: number, primeBits?: 2048 | 3072 | 4096) => PartyKeyPair;
19
+ export declare const generateKeys: (index: number, threshold: number, primeBits?: 2048 | 3072 | 4096) => {
20
+ privateKey: bigint;
21
+ publicKey: bigint;
22
+ };
20
23
  /**
21
24
  * Generates key shares for a threshold ElGamal cryptosystem.
22
25
  *
23
26
  * @param {number} n - The total number of key shares.
24
27
  * @param {number} threshold - The minimum number of key shares required for decryption.
25
28
  * @param {2048 | 3072 | 4096} primeBits - The bit length of the prime modulus (default: 2048).
26
- * @returns {PartyKeyPair[]} An array of key shares, each containing a private and public key share.
29
+ * @returns {{ privateKey: bigint; publicKey: bigint }[]} An array of key shares, each containing a private and public key share.
27
30
  */
28
- export declare const generateKeyShares: (n: number, threshold: number, primeBits?: 2048 | 3072 | 4096) => PartyKeyPair[];
31
+ export declare const generateKeyShares: (n: number, threshold: number, primeBits?: 2048 | 3072 | 4096) => {
32
+ privateKey: bigint;
33
+ publicKey: bigint;
34
+ }[];
29
35
  /**
30
36
  * Combines multiple public keys into a single public key.
31
37
  *
@@ -38,11 +44,11 @@ export declare const combinePublicKeys: (publicKeys: bigint[], prime: bigint) =>
38
44
  * Performs a partial decryption on a ciphertext using an individual's private key share.
39
45
  *
40
46
  * @param {EncryptedMessage} encryptedMessage - The encrypted secret.
41
- * @param {bigint} partyPrivateKey - The private key share of the decrypting party.
47
+ * @param {bigint} privateKey - The private key share of the decrypting party.
42
48
  * @param {bigint} prime - The prime modulus used in the ElGamal system.
43
49
  * @returns {bigint} The result of the partial decryption.
44
50
  */
45
- export declare const createDecryptionShare: (encryptedMessage: EncryptedMessage, partyPrivateKey: bigint, prime: bigint) => bigint;
51
+ export declare const createDecryptionShare: (encryptedMessage: EncryptedMessage, privateKey: bigint, prime: bigint) => bigint;
46
52
  /**
47
53
  * Combines partial decryptions from multiple parties into a single decryption factor.
48
54
  *
@@ -21,20 +21,20 @@ export const evaluatePolynomial = (polynomial, x, prime) => {
21
21
  * @param {number} index - The unique index of the participant (starting from 1).
22
22
  * @param {number} threshold - The minimum number of key shares required for decryption.
23
23
  * @param {2048 | 3072 | 4096} primeBits - The bit length of the prime modulus (default: 2048).
24
- * @returns {PartyKeyPair} The key share containing a private and public key share for the participant.
24
+ * @returns { privateKey: bigint; publicKey: bigint} The key share containing a private and public key share for the participant.
25
25
  */
26
- export const generateSingleKeyShare = (index, threshold, primeBits = 2048) => {
26
+ export const generateKeys = (index, threshold, primeBits = 2048) => {
27
27
  const group = getGroup(primeBits);
28
28
  const prime = group.prime;
29
29
  const generator = group.generator;
30
30
  const polynomial = generatePolynomial(threshold, prime);
31
- let partyPrivateKey = evaluatePolynomial(polynomial, index, prime);
31
+ let privateKey = evaluatePolynomial(polynomial, index, prime);
32
32
  // Ensure non-zero private key, adjusting index if necessary
33
- while (partyPrivateKey === 0n) {
34
- partyPrivateKey = evaluatePolynomial(polynomial, index + 1, prime);
33
+ while (privateKey === 0n) {
34
+ privateKey = evaluatePolynomial(polynomial, index + 1, prime);
35
35
  }
36
- const partyPublicKey = modPow(generator, partyPrivateKey, prime);
37
- return { partyPrivateKey, partyPublicKey };
36
+ const publicKey = modPow(generator, privateKey, prime);
37
+ return { privateKey, publicKey };
38
38
  };
39
39
  /**
40
40
  * Generates key shares for a threshold ElGamal cryptosystem.
@@ -42,12 +42,12 @@ export const generateSingleKeyShare = (index, threshold, primeBits = 2048) => {
42
42
  * @param {number} n - The total number of key shares.
43
43
  * @param {number} threshold - The minimum number of key shares required for decryption.
44
44
  * @param {2048 | 3072 | 4096} primeBits - The bit length of the prime modulus (default: 2048).
45
- * @returns {PartyKeyPair[]} An array of key shares, each containing a private and public key share.
45
+ * @returns {{ privateKey: bigint; publicKey: bigint }[]} An array of key shares, each containing a private and public key share.
46
46
  */
47
47
  export const generateKeyShares = (n, threshold, primeBits = 2048) => {
48
48
  const keyShares = [];
49
49
  for (let i = 1; i <= n; i++) {
50
- const keyShare = generateSingleKeyShare(i, threshold, primeBits);
50
+ const keyShare = generateKeys(i, threshold, primeBits);
51
51
  keyShares.push(keyShare);
52
52
  }
53
53
  return keyShares;
@@ -64,11 +64,11 @@ export const combinePublicKeys = (publicKeys, prime) => publicKeys.reduce((acc,
64
64
  * Performs a partial decryption on a ciphertext using an individual's private key share.
65
65
  *
66
66
  * @param {EncryptedMessage} encryptedMessage - The encrypted secret.
67
- * @param {bigint} partyPrivateKey - The private key share of the decrypting party.
67
+ * @param {bigint} privateKey - The private key share of the decrypting party.
68
68
  * @param {bigint} prime - The prime modulus used in the ElGamal system.
69
69
  * @returns {bigint} The result of the partial decryption.
70
70
  */
71
- export const createDecryptionShare = (encryptedMessage, partyPrivateKey, prime) => modPow(encryptedMessage.c1, partyPrivateKey, prime);
71
+ export const createDecryptionShare = (encryptedMessage, privateKey, prime) => modPow(encryptedMessage.c1, privateKey, prime);
72
72
  /**
73
73
  * Combines partial decryptions from multiple parties into a single decryption factor.
74
74
  *
package/dist/types.d.ts CHANGED
@@ -8,11 +8,3 @@ export type Parameters = {
8
8
  publicKey: bigint;
9
9
  privateKey: bigint;
10
10
  };
11
- export type KeyPair = {
12
- privateKey: bigint;
13
- publicKey: bigint;
14
- };
15
- export type PartyKeyPair = {
16
- partyPrivateKey: bigint;
17
- partyPublicKey: bigint;
18
- };
@@ -1,7 +1,9 @@
1
- import type { PartyKeyPair } from '../types';
2
1
  export declare const getRandomScore: (min?: number, max?: number) => number;
3
2
  export declare const thresholdSetup: (partiesCount: number, threshold: number, primeBits?: 2048 | 3072 | 4096) => {
4
- keyShares: PartyKeyPair[];
3
+ keyShares: {
4
+ privateKey: bigint;
5
+ publicKey: bigint;
6
+ }[];
5
7
  combinedPublicKey: bigint;
6
8
  prime: bigint;
7
9
  generator: bigint;
@@ -6,7 +6,7 @@ export const getRandomScore = (min = 1, max = 10) => Math.floor(Math.random() *
6
6
  export const thresholdSetup = (partiesCount, threshold, primeBits = 2048) => {
7
7
  const { prime, generator } = getGroup(primeBits);
8
8
  const keyShares = generateKeyShares(partiesCount, threshold, primeBits);
9
- const publicKeys = keyShares.map((ks) => ks.partyPublicKey);
9
+ const publicKeys = keyShares.map((ks) => ks.publicKey);
10
10
  const combinedPublicKey = combinePublicKeys(publicKeys, prime);
11
11
  return { keyShares, combinedPublicKey, prime, generator };
12
12
  };
@@ -16,7 +16,7 @@ export const testSecureEncryptionAndDecryption = (participantsCount, threshold,
16
16
  const selectedDecryptionShares = keyShares
17
17
  .sort(() => Math.random() - 0.5)
18
18
  .slice(0, threshold)
19
- .map((keyShare) => createDecryptionShare(encryptedMessage, keyShare.partyPrivateKey, prime));
19
+ .map(({ privateKey }) => createDecryptionShare(encryptedMessage, privateKey, prime));
20
20
  const combinedDecryptionShares = combineDecryptionShares(selectedDecryptionShares, prime);
21
21
  const decryptedMessage = thresholdDecrypt(encryptedMessage, combinedDecryptionShares, prime);
22
22
  expect(decryptedMessage).toBe(secret);
@@ -29,7 +29,7 @@ export const homomorphicMultiplicationTest = (participantsCount, threshold, mess
29
29
  const selectedDecryptionShares = keyShares
30
30
  .sort(() => Math.random() - 0.5)
31
31
  .slice(0, threshold)
32
- .map((keyShare) => createDecryptionShare(encryptedProduct, keyShare.partyPrivateKey, prime));
32
+ .map(({ privateKey }) => createDecryptionShare(encryptedProduct, privateKey, prime));
33
33
  const combinedDecryptionShares = combineDecryptionShares(selectedDecryptionShares, prime);
34
34
  const decryptedProduct = thresholdDecrypt(encryptedProduct, combinedDecryptionShares, prime);
35
35
  expect(decryptedProduct).toBe(expectedProduct);
@@ -42,7 +42,7 @@ export const votingTest = (participantsCount, threshold, candidatesCount) => {
42
42
  const encryptedProducts = Array.from({ length: candidatesCount }, (_, candidateIndex) => encryptedVotesMatrix.reduce((product, encryptedVotes) => multiplyEncryptedValues(product, encryptedVotes[candidateIndex], prime), { c1: 1n, c2: 1n }));
43
43
  const partialDecryptionsMatrix = encryptedProducts.map((product) => keyShares
44
44
  .slice(0, threshold)
45
- .map((keyShare) => createDecryptionShare(product, keyShare.partyPrivateKey, prime)));
45
+ .map((keyShare) => createDecryptionShare(product, keyShare.privateKey, prime)));
46
46
  const decryptedProducts = partialDecryptionsMatrix.map((decryptionShares) => {
47
47
  const combinedDecryptionShares = combineDecryptionShares(decryptionShares, prime);
48
48
  const encryptedProduct = encryptedProducts[partialDecryptionsMatrix.indexOf(decryptionShares)];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "threshold-elgamal",
3
- "version": "0.1.24",
3
+ "version": "0.1.26",
4
4
  "description": "Threshold ElGamal in TypeScript",
5
5
  "author": "Piotr Piech <piotr@piech.dev>",
6
6
  "license": "MIT",