threshold-elgamal 0.1.28 → 0.1.30

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
@@ -54,32 +54,20 @@ First, import the whatever functions you need from the library:
54
54
  import { generateParameters, encrypt, decrypt } from "threshold-elgamal";
55
55
  ```
56
56
 
57
- ### Generating Keys
58
-
59
- Generate a public/private key pair:
57
+ ### Generating keys, encrypting and decrypting a secret
60
58
 
61
59
  ```typescript
60
+ // Generate a public/private key pair
61
+ // If prime and generator aren't specified, they default to the 2048-bit group.
62
62
  const { publicKey, privateKey, prime, generator } = generateParameters();
63
- console.log(publicKey, privateKey, prime, generator); // ffdhe2048 group by default
64
- ```
65
-
66
- ### Encrypting a Message
67
63
 
68
- Encrypt a message using the public key:
64
+ // Encrypt a message using the public key:
65
+ const secret = 859;
66
+ const encryptedMessage = encrypt(secret, publicKey, prime, generator);
69
67
 
70
- ```typescript
71
- const secret = 42;
72
- const encryptedMessage = encrypt(secret, prime, generator, publicKey);
73
- console.log(encryptedMessage);
74
- ```
75
-
76
- ### Decrypting a Message
77
-
78
- Decrypt a message using the private key:
79
-
80
- ```typescript
68
+ // Decrypt the message using the private key:
81
69
  const decryptedMessage = decrypt(encryptedMessage, prime, privateKey);
82
- console.log(decryptedMessage); // 42
70
+ // console.log(decryptedMessage); // 859
83
71
  ```
84
72
 
85
73
  ### Single secret shared with 3 participants
@@ -88,7 +76,6 @@ Threshold scheme for generating a common public key, sharing a secret to 3 parti
88
76
 
89
77
  ```typescript
90
78
  import {
91
- getGroup,
92
79
  encrypt,
93
80
  generateKeys,
94
81
  combinePublicKeys,
@@ -98,7 +85,6 @@ import {
98
85
  } from "threshold-elgamal";
99
86
 
100
87
  const threshold = 3; // A scenario for 3 participants with a threshold of 3
101
- const { prime, generator } = getGroup(); // 2048-bit by default
102
88
 
103
89
  // Each participant generates their public key share and private key individually
104
90
  const participant1Keys = generateKeys(1, threshold);
@@ -114,28 +100,23 @@ const commonPublicKey = combinePublicKeys([
114
100
 
115
101
  // Encrypt a message using the combined public key
116
102
  const secret = 42;
117
- const encryptedMessage = encrypt(secret, prime, generator, commonPublicKey);
103
+ const encryptedMessage = encrypt(secret, commonPublicKey);
118
104
 
119
105
  // Decryption shares
120
106
  const decryptionShares = [
121
- createDecryptionShare(encryptedMessage, participant1Keys.privateKey, prime),
122
- createDecryptionShare(encryptedMessage, participant2Keys.privateKey, prime),
123
- createDecryptionShare(encryptedMessage, participant3Keys.privateKey, prime),
107
+ createDecryptionShare(encryptedMessage, participant1Keys.privateKey),
108
+ createDecryptionShare(encryptedMessage, participant2Keys.privateKey),
109
+ createDecryptionShare(encryptedMessage, participant3Keys.privateKey),
124
110
  ];
125
111
  // Combining the decryption shares into one, used to decrypt the message
126
- const combinedDecryptionShares = combineDecryptionShares(
127
- decryptionShares,
128
- prime,
129
- );
112
+ const combinedDecryptionShares = combineDecryptionShares(decryptionShares);
130
113
 
131
114
  // Decrypting the message using the combined decryption shares
132
115
  const thresholdDecryptedMessage = thresholdDecrypt(
133
116
  encryptedMessage,
134
117
  combinedDecryptionShares,
135
- prime,
136
118
  );
137
119
  console.log(thresholdDecryptedMessage); // 42
138
- expect(thresholdDecryptedMessage).toBe(secret);
139
120
  ```
140
121
 
141
122
  ### Voting and multiplication with threshold scheme for 3 participants
@@ -151,11 +132,9 @@ import {
151
132
  combineDecryptionShares,
152
133
  thresholdDecrypt,
153
134
  multiplyEncryptedValues,
154
- getGroup,
155
135
  } from "threshold-elgamal";
156
136
 
157
137
  const threshold = 3; // A scenario for 3 participants with a threshold of 3
158
- const { prime, generator } = getGroup(); // 2048-bit by default
159
138
 
160
139
  // Each participant generates their public key share and private key individually
161
140
  const participant1Keys = generateKeys(1, threshold);
@@ -175,19 +154,21 @@ const voteOption2 = [10, 7, 4]; // Votes for option 2 by participants 1, 2, and
175
154
 
176
155
  // Encrypt votes for both options
177
156
  const encryptedVotesOption1 = voteOption1.map((vote) =>
178
- encrypt(vote, prime, generator, commonPublicKey),
157
+ encrypt(vote, commonPublicKey),
179
158
  );
180
159
  const encryptedVotesOption2 = voteOption2.map((vote) =>
181
- encrypt(vote, prime, generator, commonPublicKey),
160
+ encrypt(vote, commonPublicKey),
182
161
  );
183
162
 
184
163
  // Multiply encrypted votes together to aggregate
185
164
  const aggregatedEncryptedVoteOption1 = encryptedVotesOption1.reduce(
186
- (acc, encryptedVote) => multiplyEncryptedValues(acc, encryptedVote, prime),
165
+ (talliedVotes, encryptedVote) =>
166
+ multiplyEncryptedValues(talliedVotes, encryptedVote),
187
167
  { c1: 1n, c2: 1n },
188
168
  );
189
169
  const aggregatedEncryptedVoteOption2 = encryptedVotesOption2.reduce(
190
- (acc, encryptedVote) => multiplyEncryptedValues(acc, encryptedVote, prime),
170
+ (talliedVotes, encryptedVote) =>
171
+ multiplyEncryptedValues(talliedVotes, encryptedVote),
191
172
  { c1: 1n, c2: 1n },
192
173
  );
193
174
 
@@ -198,34 +179,28 @@ const decryptionSharesOption1 = [
198
179
  createDecryptionShare(
199
180
  aggregatedEncryptedVoteOption1,
200
181
  participant1Keys.privateKey,
201
- prime,
202
182
  ),
203
183
  createDecryptionShare(
204
184
  aggregatedEncryptedVoteOption1,
205
185
  participant2Keys.privateKey,
206
- prime,
207
186
  ),
208
187
  createDecryptionShare(
209
188
  aggregatedEncryptedVoteOption1,
210
189
  participant3Keys.privateKey,
211
- prime,
212
190
  ),
213
191
  ];
214
192
  const decryptionSharesOption2 = [
215
193
  createDecryptionShare(
216
194
  aggregatedEncryptedVoteOption2,
217
195
  participant1Keys.privateKey,
218
- prime,
219
196
  ),
220
197
  createDecryptionShare(
221
198
  aggregatedEncryptedVoteOption2,
222
199
  participant2Keys.privateKey,
223
- prime,
224
200
  ),
225
201
  createDecryptionShare(
226
202
  aggregatedEncryptedVoteOption2,
227
203
  participant3Keys.privateKey,
228
- prime,
229
204
  ),
230
205
  ];
231
206
 
@@ -234,22 +209,18 @@ const decryptionSharesOption2 = [
234
209
  // Only the decryption shares are shared with other participants.
235
210
  const combinedDecryptionSharesOption1 = combineDecryptionShares(
236
211
  decryptionSharesOption1,
237
- prime,
238
212
  );
239
213
  const combinedDecryptionSharesOption2 = combineDecryptionShares(
240
214
  decryptionSharesOption2,
241
- prime,
242
215
  );
243
216
 
244
217
  const finalTallyOption1 = thresholdDecrypt(
245
218
  aggregatedEncryptedVoteOption1,
246
219
  combinedDecryptionSharesOption1,
247
- prime,
248
220
  );
249
221
  const finalTallyOption2 = thresholdDecrypt(
250
222
  aggregatedEncryptedVoteOption2,
251
223
  combinedDecryptionSharesOption2,
252
- prime,
253
224
  );
254
225
 
255
226
  console.log(
package/dist/elgamal.d.ts CHANGED
@@ -11,12 +11,12 @@ export declare const generateParameters: (primeBits?: 2048 | 3072 | 4096) => Par
11
11
  * Encrypts a secret using ElGamal encryption.
12
12
  *
13
13
  * @param {number} secret - The secret to be encrypted.
14
- * @param {bigint} prime - The prime number used in the encryption system.
15
- * @param {bigint} generator - The generator used in the encryption system.
16
14
  * @param {bigint} publicKey - The public key used for encryption.
15
+ * @param {bigint} prime - The prime number used in the encryption system. Defaults to the 2048-bit group's prime.
16
+ * @param {bigint} generator - The generator used in the encryption system. Defaults to the 2048-bit group's generator.
17
17
  * @returns {EncryptedMessage} The encrypted secret, consisting of two BigIntegers (c1 and c2).
18
18
  */
19
- export declare const encrypt: (secret: number, prime: bigint, generator: bigint, publicKey: bigint) => EncryptedMessage;
19
+ export declare const encrypt: (secret: number, publicKey: bigint, prime?: bigint, generator?: bigint) => EncryptedMessage;
20
20
  /**
21
21
  * Decrypts an ElGamal encrypted secret.
22
22
  *
package/dist/elgamal.js CHANGED
@@ -17,12 +17,12 @@ export const generateParameters = (primeBits = 2048) => {
17
17
  * Encrypts a secret using ElGamal encryption.
18
18
  *
19
19
  * @param {number} secret - The secret to be encrypted.
20
- * @param {bigint} prime - The prime number used in the encryption system.
21
- * @param {bigint} generator - The generator used in the encryption system.
22
20
  * @param {bigint} publicKey - The public key used for encryption.
21
+ * @param {bigint} prime - The prime number used in the encryption system. Defaults to the 2048-bit group's prime.
22
+ * @param {bigint} generator - The generator used in the encryption system. Defaults to the 2048-bit group's generator.
23
23
  * @returns {EncryptedMessage} The encrypted secret, consisting of two BigIntegers (c1 and c2).
24
24
  */
25
- export const encrypt = (secret, prime, generator, publicKey) => {
25
+ export const encrypt = (secret, publicKey, prime = getGroup().prime, generator = getGroup().generator) => {
26
26
  if (secret >= Number(prime)) {
27
27
  throw new Error('Message is too large for direct encryption');
28
28
  }
@@ -45,27 +45,27 @@ export declare const combinePublicKeys: (publicKeys: bigint[], prime?: bigint) =
45
45
  *
46
46
  * @param {EncryptedMessage} encryptedMessage - The encrypted secret.
47
47
  * @param {bigint} privateKey - The private key share of the decrypting party.
48
- * @param {bigint} prime - The prime modulus used in the ElGamal system.
48
+ * @param {bigint} prime - The prime modulus used in the ElGamal system. Defaults to the 2048-bit group prime.
49
49
  * @returns {bigint} The result of the partial decryption.
50
50
  */
51
- export declare const createDecryptionShare: (encryptedMessage: EncryptedMessage, privateKey: bigint, prime: bigint) => bigint;
51
+ export declare const createDecryptionShare: (encryptedMessage: EncryptedMessage, privateKey: bigint, prime?: bigint) => bigint;
52
52
  /**
53
53
  * Combines partial decryptions from multiple parties into a single decryption factor.
54
54
  *
55
55
  * @param {bigint[]} decryptionShares - An array of partial decryption results.
56
- * @param {bigint} prime - The prime modulus used in the ElGamal system.
56
+ * @param {bigint} prime - The prime modulus used in the ElGamal system. Defaults to the 2048-bit group prime.
57
57
  * @returns {bigint} The combined decryption factor.
58
58
  */
59
- export declare const combineDecryptionShares: (decryptionShares: bigint[], prime: bigint) => bigint;
59
+ export declare const combineDecryptionShares: (decryptionShares: bigint[], prime?: bigint) => bigint;
60
60
  /**
61
61
  * Decrypts an encrypted secret using the combined partial decryptions in a threshold ElGamal scheme.
62
62
  *
63
63
  * @param {{ c1: bigint; c2: bigint }} encryptedMessage - The encrypted secret components.
64
64
  * @param {bigint} combinedDecryptionShares - The combined partial decryptions from all parties.
65
- * @param {bigint} prime - The prime modulus used in the ElGamal system.
65
+ * @param {bigint} prime - The prime modulus used in the ElGamal system. Defaults to the 2048-bit group prime.
66
66
  * @returns {number} The decrypted secret, assuming it was small enough to be directly encrypted.
67
67
  */
68
68
  export declare const thresholdDecrypt: (encryptedMessage: {
69
69
  c1: bigint;
70
70
  c2: bigint;
71
- }, combinedDecryptionShares: bigint, prime: bigint) => number;
71
+ }, combinedDecryptionShares: bigint, prime?: bigint) => number;
@@ -59,24 +59,24 @@ export const generateKeyShares = (n, threshold, primeBits = 2048) => {
59
59
  * @param {bigint} prime - The prime modulus used in the ElGamal system.
60
60
  * @returns {bigint} The combined public key.
61
61
  */
62
- export const combinePublicKeys = (publicKeys, prime = getGroup(2048).prime) => publicKeys.reduce((acc, current) => (acc * current) % prime, 1n);
62
+ export const combinePublicKeys = (publicKeys, prime = getGroup().prime) => publicKeys.reduce((combinedPublicKey, current) => (combinedPublicKey * current) % prime, 1n);
63
63
  /**
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
67
  * @param {bigint} privateKey - The private key share of the decrypting party.
68
- * @param {bigint} prime - The prime modulus used in the ElGamal system.
68
+ * @param {bigint} prime - The prime modulus used in the ElGamal system. Defaults to the 2048-bit group prime.
69
69
  * @returns {bigint} The result of the partial decryption.
70
70
  */
71
- export const createDecryptionShare = (encryptedMessage, privateKey, prime) => modPow(encryptedMessage.c1, privateKey, prime);
71
+ export const createDecryptionShare = (encryptedMessage, privateKey, prime = getGroup().prime) => modPow(encryptedMessage.c1, privateKey, prime);
72
72
  /**
73
73
  * Combines partial decryptions from multiple parties into a single decryption factor.
74
74
  *
75
75
  * @param {bigint[]} decryptionShares - An array of partial decryption results.
76
- * @param {bigint} prime - The prime modulus used in the ElGamal system.
76
+ * @param {bigint} prime - The prime modulus used in the ElGamal system. Defaults to the 2048-bit group prime.
77
77
  * @returns {bigint} The combined decryption factor.
78
78
  */
79
- export const combineDecryptionShares = (decryptionShares, prime) => {
79
+ export const combineDecryptionShares = (decryptionShares, prime = getGroup().prime) => {
80
80
  let result = 1n;
81
81
  for (const partialDecryption of decryptionShares) {
82
82
  result = (result * partialDecryption) % prime;
@@ -88,10 +88,10 @@ export const combineDecryptionShares = (decryptionShares, prime) => {
88
88
  *
89
89
  * @param {{ c1: bigint; c2: bigint }} encryptedMessage - The encrypted secret components.
90
90
  * @param {bigint} combinedDecryptionShares - The combined partial decryptions from all parties.
91
- * @param {bigint} prime - The prime modulus used in the ElGamal system.
91
+ * @param {bigint} prime - The prime modulus used in the ElGamal system. Defaults to the 2048-bit group prime.
92
92
  * @returns {number} The decrypted secret, assuming it was small enough to be directly encrypted.
93
93
  */
94
- export const thresholdDecrypt = (encryptedMessage, combinedDecryptionShares, prime) => {
94
+ export const thresholdDecrypt = (encryptedMessage, combinedDecryptionShares, prime = getGroup().prime) => {
95
95
  const combinedDecryptionInverse = modInv(combinedDecryptionShares, prime);
96
96
  const plaintext = (encryptedMessage.c2 * combinedDecryptionInverse) % prime;
97
97
  return Number(plaintext);
@@ -12,7 +12,7 @@ export const thresholdSetup = (partiesCount, threshold, primeBits = 2048) => {
12
12
  };
13
13
  export const testSecureEncryptionAndDecryption = (participantsCount, threshold, secret) => {
14
14
  const { keyShares, commonPublicKey, prime, generator } = thresholdSetup(participantsCount, threshold);
15
- const encryptedMessage = encrypt(secret, prime, generator, commonPublicKey);
15
+ const encryptedMessage = encrypt(secret, commonPublicKey, prime, generator);
16
16
  const selectedDecryptionShares = keyShares
17
17
  .sort(() => Math.random() - 0.5)
18
18
  .slice(0, threshold)
@@ -24,7 +24,7 @@ export const testSecureEncryptionAndDecryption = (participantsCount, threshold,
24
24
  export const homomorphicMultiplicationTest = (participantsCount, threshold, messages) => {
25
25
  const expectedProduct = messages.reduce((product, secret) => product * secret, 1);
26
26
  const { keyShares, commonPublicKey, prime, generator } = thresholdSetup(participantsCount, threshold);
27
- const encryptedMessages = messages.map((secret) => encrypt(secret, prime, generator, commonPublicKey));
27
+ const encryptedMessages = messages.map((secret) => encrypt(secret, commonPublicKey, prime, generator));
28
28
  const encryptedProduct = encryptedMessages.reduce((product, encryptedMessage) => multiplyEncryptedValues(product, encryptedMessage, prime), { c1: 1n, c2: 1n });
29
29
  const selectedDecryptionShares = keyShares
30
30
  .sort(() => Math.random() - 0.5)
@@ -38,7 +38,7 @@ export const votingTest = (participantsCount, threshold, candidatesCount) => {
38
38
  const { keyShares, commonPublicKey, prime, generator } = thresholdSetup(participantsCount, threshold);
39
39
  const votesMatrix = Array.from({ length: participantsCount }, () => Array.from({ length: candidatesCount }, () => getRandomScore(1, 10)));
40
40
  const expectedProducts = Array.from({ length: candidatesCount }, (_, candidateIndex) => votesMatrix.reduce((product, votes) => product * votes[candidateIndex], 1));
41
- const encryptedVotesMatrix = votesMatrix.map((votes) => votes.map((vote) => encrypt(vote, prime, generator, commonPublicKey)));
41
+ const encryptedVotesMatrix = votesMatrix.map((votes) => votes.map((vote) => encrypt(vote, commonPublicKey, prime, generator)));
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)
@@ -36,10 +36,10 @@ export declare const getRandomBigIntegerInRange: (min: bigint, max: bigint) => b
36
36
  * Performs homomorphic multiplication on two encrypted values, allowing for encrypted arithmetic operations.
37
37
  * @param {EncryptedMessage} value1 - The first encrypted value.
38
38
  * @param {EncryptedMessage} value2 - The second encrypted value.
39
- * @param {bigint} prime - The prime modulus used in the encryption system.
39
+ * @param {bigint} prime - The prime modulus used in the encryption system. Defaults to the 2048-bit group prime.
40
40
  * @returns {EncryptedMessage} The result of the multiplication, as a new encrypted message.
41
41
  */
42
- export declare const multiplyEncryptedValues: (value1: EncryptedMessage, value2: EncryptedMessage, prime: bigint) => EncryptedMessage;
42
+ export declare const multiplyEncryptedValues: (value1: EncryptedMessage, value2: EncryptedMessage, prime?: bigint) => EncryptedMessage;
43
43
  /**
44
44
  * Generates a random polynomial of a specified degree, to be used in Shamir's Secret Sharing scheme.
45
45
  * The polynomial is of the form f(x) = a0 + a1*x + a2*x^2 + ... + a_{threshold-1}*x^{threshold-1},
@@ -70,10 +70,10 @@ export const getRandomBigIntegerInRange = (min, max) => {
70
70
  * Performs homomorphic multiplication on two encrypted values, allowing for encrypted arithmetic operations.
71
71
  * @param {EncryptedMessage} value1 - The first encrypted value.
72
72
  * @param {EncryptedMessage} value2 - The second encrypted value.
73
- * @param {bigint} prime - The prime modulus used in the encryption system.
73
+ * @param {bigint} prime - The prime modulus used in the encryption system. Defaults to the 2048-bit group prime.
74
74
  * @returns {EncryptedMessage} The result of the multiplication, as a new encrypted message.
75
75
  */
76
- export const multiplyEncryptedValues = (value1, value2, prime) => {
76
+ export const multiplyEncryptedValues = (value1, value2, prime = getGroup().prime) => {
77
77
  const c1Multiplied = (value1.c1 * value2.c1) % prime;
78
78
  const c2Multiplied = (value1.c2 * value2.c2) % prime;
79
79
  return { c1: c1Multiplied, c2: c2Multiplied };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "threshold-elgamal",
3
- "version": "0.1.28",
3
+ "version": "0.1.30",
4
4
  "description": "Threshold ElGamal in TypeScript",
5
5
  "author": "Piotr Piech <piotr@piech.dev>",
6
6
  "license": "MIT",