threshold-elgamal 0.1.25 → 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
@@ -90,41 +90,28 @@ Threshold scheme for generating a common public key, sharing a secret to 3 parti
90
90
  import {
91
91
  getGroup,
92
92
  encrypt,
93
- generateSingleKeyShare,
93
+ generateKeys,
94
94
  combinePublicKeys,
95
95
  createDecryptionShare,
96
96
  combineDecryptionShares,
97
97
  thresholdDecrypt,
98
98
  } from "threshold-elgamal";
99
- import type { PartyKeyPair } from "threshold-elgamal";
100
99
 
101
100
  const primeBits = 2048; // Bit length of the prime modulus
102
101
  const threshold = 3; // A scenario for 3 participants with a threshold of 3
103
102
  const { prime, generator } = getGroup(2048);
104
103
 
105
104
  // Each participant generates their public key share and private key individually
106
- const participant1KeyShare: PartyKeyPair = generateSingleKeyShare(
107
- 1,
108
- threshold,
109
- primeBits,
110
- );
111
- const participant2KeyShare: PartyKeyPair = generateSingleKeyShare(
112
- 2,
113
- threshold,
114
- primeBits,
115
- );
116
- const participant3KeyShare: PartyKeyPair = generateSingleKeyShare(
117
- 3,
118
- threshold,
119
- primeBits,
120
- );
105
+ const participant1Keys = generateKeys(1, threshold, primeBits);
106
+ const participant2Keys = generateKeys(2, threshold, primeBits);
107
+ const participant3Keys = generateKeys(3, threshold, primeBits);
121
108
 
122
109
  // Combine the public keys to form a single public key
123
110
  const combinedPublicKey = combinePublicKeys(
124
111
  [
125
- participant1KeyShare.partyPublicKey,
126
- participant2KeyShare.partyPublicKey,
127
- participant3KeyShare.partyPublicKey,
112
+ participant1Keys.publicKey,
113
+ participant2Keys.publicKey,
114
+ participant3Keys.publicKey,
128
115
  ],
129
116
  prime,
130
117
  );
@@ -135,21 +122,9 @@ const encryptedMessage = encrypt(secret, prime, generator, combinedPublicKey);
135
122
 
136
123
  // Decryption shares
137
124
  const decryptionShares = [
138
- createDecryptionShare(
139
- encryptedMessage,
140
- participant1KeyShare.partyPrivateKey,
141
- prime,
142
- ),
143
- createDecryptionShare(
144
- encryptedMessage,
145
- participant2KeyShare.partyPrivateKey,
146
- prime,
147
- ),
148
- createDecryptionShare(
149
- encryptedMessage,
150
- participant3KeyShare.partyPrivateKey,
151
- prime,
152
- ),
125
+ createDecryptionShare(encryptedMessage, participant1Keys.privateKey, prime),
126
+ createDecryptionShare(encryptedMessage, participant2Keys.privateKey, prime),
127
+ createDecryptionShare(encryptedMessage, participant3Keys.privateKey, prime),
153
128
  ];
154
129
  // Combining the decryption shares into one, used to decrypt the message
155
130
  const combinedDecryptionShares = combineDecryptionShares(
@@ -173,7 +148,7 @@ This example demonstrates a 1 to 10 voting scenario where 3 participants cast en
173
148
  ```typescript
174
149
  import {
175
150
  encrypt,
176
- generateSingleKeyShare,
151
+ generateKeys,
177
152
  combinePublicKeys,
178
153
  createDecryptionShare,
179
154
  combineDecryptionShares,
@@ -181,35 +156,22 @@ import {
181
156
  multiplyEncryptedValues,
182
157
  getGroup,
183
158
  } from "threshold-elgamal";
184
- import type { PartyKeyPair } from "threshold-elgamal";
185
159
 
186
160
  const primeBits = 2048; // Bit length of the prime modulus
187
161
  const threshold = 3; // A scenario for 3 participants with a threshold of 3
188
162
  const { prime, generator } = getGroup(2048);
189
163
 
190
164
  // Each participant generates their public key share and private key individually
191
- const participant1KeyShare: PartyKeyPair = generateSingleKeyShare(
192
- 1,
193
- threshold,
194
- primeBits,
195
- );
196
- const participant2KeyShare: PartyKeyPair = generateSingleKeyShare(
197
- 2,
198
- threshold,
199
- primeBits,
200
- );
201
- const participant3KeyShare: PartyKeyPair = generateSingleKeyShare(
202
- 3,
203
- threshold,
204
- primeBits,
205
- );
165
+ const participant1Keys = generateKeys(1, threshold, primeBits);
166
+ const participant2Keys = generateKeys(2, threshold, primeBits);
167
+ const participant3Keys = generateKeys(3, threshold, primeBits);
206
168
 
207
169
  // Combine the public keys to form a single public key
208
170
  const combinedPublicKey = combinePublicKeys(
209
171
  [
210
- participant1KeyShare.partyPublicKey,
211
- participant2KeyShare.partyPublicKey,
212
- participant3KeyShare.partyPublicKey,
172
+ participant1Keys.publicKey,
173
+ participant2Keys.publicKey,
174
+ participant3Keys.publicKey,
213
175
  ],
214
176
  prime,
215
177
  );
@@ -228,11 +190,11 @@ const encryptedVotesOption2 = voteOption2.map((vote) =>
228
190
 
229
191
  // Multiply encrypted votes together to aggregate
230
192
  const aggregatedEncryptedVoteOption1 = encryptedVotesOption1.reduce(
231
- (acc, current) => multiplyEncryptedValues(acc, current, prime),
193
+ (acc, encryptedVote) => multiplyEncryptedValues(acc, encryptedVote, prime),
232
194
  { c1: 1n, c2: 1n },
233
195
  );
234
196
  const aggregatedEncryptedVoteOption2 = encryptedVotesOption2.reduce(
235
- (acc, current) => multiplyEncryptedValues(acc, current, prime),
197
+ (acc, encryptedVote) => multiplyEncryptedValues(acc, encryptedVote, prime),
236
198
  { c1: 1n, c2: 1n },
237
199
  );
238
200
 
@@ -242,34 +204,34 @@ const aggregatedEncryptedVoteOption2 = encryptedVotesOption2.reduce(
242
204
  const decryptionSharesOption1 = [
243
205
  createDecryptionShare(
244
206
  aggregatedEncryptedVoteOption1,
245
- participant1KeyShare.partyPrivateKey,
207
+ participant1Keys.privateKey,
246
208
  prime,
247
209
  ),
248
210
  createDecryptionShare(
249
211
  aggregatedEncryptedVoteOption1,
250
- participant2KeyShare.partyPrivateKey,
212
+ participant2Keys.privateKey,
251
213
  prime,
252
214
  ),
253
215
  createDecryptionShare(
254
216
  aggregatedEncryptedVoteOption1,
255
- participant3KeyShare.partyPrivateKey,
217
+ participant3Keys.privateKey,
256
218
  prime,
257
219
  ),
258
220
  ];
259
221
  const decryptionSharesOption2 = [
260
222
  createDecryptionShare(
261
223
  aggregatedEncryptedVoteOption2,
262
- participant1KeyShare.partyPrivateKey,
224
+ participant1Keys.privateKey,
263
225
  prime,
264
226
  ),
265
227
  createDecryptionShare(
266
228
  aggregatedEncryptedVoteOption2,
267
- participant2KeyShare.partyPrivateKey,
229
+ participant2Keys.privateKey,
268
230
  prime,
269
231
  ),
270
232
  createDecryptionShare(
271
233
  aggregatedEncryptedVoteOption2,
272
- participant3KeyShare.partyPrivateKey,
234
+ participant3Keys.privateKey,
273
235
  prime,
274
236
  ),
275
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.25",
3
+ "version": "0.1.26",
4
4
  "description": "Threshold ElGamal in TypeScript",
5
5
  "author": "Piotr Piech <piotr@piech.dev>",
6
6
  "license": "MIT",