1'use strict';
2
3const common = require('../common');
4if (!common.hasCrypto)
5  common.skip('missing crypto');
6
7const assert = require('assert');
8
9const {
10  generatePrime,
11  generatePrimeSync,
12  checkPrime,
13  checkPrimeSync,
14} = require('crypto');
15
16const { promisify } = require('util');
17const pgeneratePrime = promisify(generatePrime);
18const pCheckPrime = promisify(checkPrime);
19
20['hello', false, {}, []].forEach((i) => {
21  assert.throws(() => generatePrime(i), {
22    code: 'ERR_INVALID_ARG_TYPE'
23  });
24  assert.throws(() => generatePrimeSync(i), {
25    code: 'ERR_INVALID_ARG_TYPE'
26  });
27});
28
29['hello', false, 123].forEach((i) => {
30  assert.throws(() => generatePrime(80, i, common.mustNotCall()), {
31    code: 'ERR_INVALID_ARG_TYPE'
32  });
33  assert.throws(() => generatePrimeSync(80, i), {
34    code: 'ERR_INVALID_ARG_TYPE'
35  });
36});
37
38['hello', false, 123].forEach((i) => {
39  assert.throws(() => generatePrime(80, {}), {
40    code: 'ERR_INVALID_ARG_TYPE'
41  });
42});
43
44[-1, 0, 2 ** 31, 2 ** 31 + 1, 2 ** 32 - 1, 2 ** 32].forEach((size) => {
45  assert.throws(() => generatePrime(size, common.mustNotCall()), {
46    code: 'ERR_OUT_OF_RANGE',
47    message: />= 1 && <= 2147483647/
48  });
49  assert.throws(() => generatePrimeSync(size), {
50    code: 'ERR_OUT_OF_RANGE',
51    message: />= 1 && <= 2147483647/
52  });
53});
54
55['test', -1, {}, []].forEach((i) => {
56  assert.throws(() => generatePrime(8, { safe: i }, common.mustNotCall()), {
57    code: 'ERR_INVALID_ARG_TYPE'
58  });
59  assert.throws(() => generatePrime(8, { rem: i }, common.mustNotCall()), {
60    code: 'ERR_INVALID_ARG_TYPE'
61  });
62  assert.throws(() => generatePrime(8, { add: i }, common.mustNotCall()), {
63    code: 'ERR_INVALID_ARG_TYPE'
64  });
65  assert.throws(() => generatePrimeSync(8, { safe: i }), {
66    code: 'ERR_INVALID_ARG_TYPE'
67  });
68  assert.throws(() => generatePrimeSync(8, { rem: i }), {
69    code: 'ERR_INVALID_ARG_TYPE'
70  });
71  assert.throws(() => generatePrimeSync(8, { add: i }), {
72    code: 'ERR_INVALID_ARG_TYPE'
73  });
74});
75
76{
77  // Negative BigInts should not be converted to 0 silently.
78
79  assert.throws(() => generatePrime(20, { add: -1n }, common.mustNotCall()), {
80    code: 'ERR_OUT_OF_RANGE',
81    message: 'The value of "options.add" is out of range. It must be >= 0. ' +
82             'Received -1n'
83  });
84
85  assert.throws(() => generatePrime(20, { rem: -1n }, common.mustNotCall()), {
86    code: 'ERR_OUT_OF_RANGE',
87    message: 'The value of "options.rem" is out of range. It must be >= 0. ' +
88             'Received -1n'
89  });
90
91  assert.throws(() => checkPrime(-1n, common.mustNotCall()), {
92    code: 'ERR_OUT_OF_RANGE',
93    message: 'The value of "candidate" is out of range. It must be >= 0. ' +
94             'Received -1n'
95  });
96}
97
98generatePrime(80, common.mustSucceed((prime) => {
99  assert(checkPrimeSync(prime));
100  checkPrime(prime, common.mustSucceed((result) => {
101    assert(result);
102  }));
103}));
104
105assert(checkPrimeSync(generatePrimeSync(80)));
106
107generatePrime(80, {}, common.mustSucceed((prime) => {
108  assert(checkPrimeSync(prime));
109}));
110
111assert(checkPrimeSync(generatePrimeSync(80, {})));
112
113generatePrime(32, { safe: true }, common.mustSucceed((prime) => {
114  assert(checkPrimeSync(prime));
115  const buf = Buffer.from(prime);
116  const val = buf.readUInt32BE();
117  const check = (val - 1) / 2;
118  buf.writeUInt32BE(check);
119  assert(checkPrimeSync(buf));
120}));
121
122{
123  const prime = generatePrimeSync(32, { safe: true });
124  assert(checkPrimeSync(prime));
125  const buf = Buffer.from(prime);
126  const val = buf.readUInt32BE();
127  const check = (val - 1) / 2;
128  buf.writeUInt32BE(check);
129  assert(checkPrimeSync(buf));
130}
131
132const add = 12;
133const rem = 11;
134const add_buf = Buffer.from([add]);
135const rem_buf = Buffer.from([rem]);
136generatePrime(
137  32,
138  { add: add_buf, rem: rem_buf },
139  common.mustSucceed((prime) => {
140    assert(checkPrimeSync(prime));
141    const buf = Buffer.from(prime);
142    const val = buf.readUInt32BE();
143    assert.strictEqual(val % add, rem);
144  }));
145
146{
147  const prime = generatePrimeSync(32, { add: add_buf, rem: rem_buf });
148  assert(checkPrimeSync(prime));
149  const buf = Buffer.from(prime);
150  const val = buf.readUInt32BE();
151  assert.strictEqual(val % add, rem);
152}
153
154{
155  const prime = generatePrimeSync(32, { add: BigInt(add), rem: BigInt(rem) });
156  assert(checkPrimeSync(prime));
157  const buf = Buffer.from(prime);
158  const val = buf.readUInt32BE();
159  assert.strictEqual(val % add, rem);
160}
161
162{
163  // The behavior when specifying only add without rem should depend on the
164  // safe option.
165
166  if (process.versions.openssl >= '1.1.1f') {
167    generatePrime(128, {
168      bigint: true,
169      add: 5n
170    }, common.mustSucceed((prime) => {
171      assert(checkPrimeSync(prime));
172      assert.strictEqual(prime % 5n, 1n);
173    }));
174
175    generatePrime(128, {
176      bigint: true,
177      safe: true,
178      add: 5n
179    }, common.mustSucceed((prime) => {
180      assert(checkPrimeSync(prime));
181      assert.strictEqual(prime % 5n, 3n);
182    }));
183  }
184}
185
186{
187  // This is impossible because it implies (prime % 2**64) == 1 and
188  // prime < 2**64, meaning prime = 1, but 1 is not prime.
189  for (const add of [2n ** 64n, 2n ** 65n]) {
190    assert.throws(() => {
191      generatePrimeSync(64, { add });
192    }, {
193      code: 'ERR_OUT_OF_RANGE',
194      message: 'invalid options.add'
195    });
196  }
197
198  // Any parameters with rem >= add lead to an impossible condition.
199  for (const rem of [7n, 8n, 3000n]) {
200    assert.throws(() => {
201      generatePrimeSync(64, { add: 7n, rem });
202    }, {
203      code: 'ERR_OUT_OF_RANGE',
204      message: 'invalid options.rem'
205    });
206  }
207
208  // This is possible, but not allowed. It implies prime == 7, which means that
209  // we did not actually generate a random prime.
210  assert.throws(() => {
211    generatePrimeSync(3, { add: 8n, rem: 7n });
212  }, {
213    code: 'ERR_OUT_OF_RANGE'
214  });
215
216  if (process.versions.openssl >= '1.1.1f') {
217    // This is possible and allowed (but makes little sense).
218    assert.strictEqual(generatePrimeSync(4, {
219      add: 15n,
220      rem: 13n,
221      bigint: true
222    }), 13n);
223  }
224}
225
226[1, 'hello', {}, []].forEach((i) => {
227  assert.throws(() => checkPrime(i), {
228    code: 'ERR_INVALID_ARG_TYPE'
229  });
230});
231
232for (const checks of ['hello', {}, []]) {
233  assert.throws(() => checkPrime(2n, { checks }, common.mustNotCall()), {
234    code: 'ERR_INVALID_ARG_TYPE',
235    message: /checks/
236  });
237  assert.throws(() => checkPrimeSync(2n, { checks }), {
238    code: 'ERR_INVALID_ARG_TYPE',
239    message: /checks/
240  });
241}
242
243for (const checks of [-(2 ** 31), -1, 2 ** 31, 2 ** 32 - 1, 2 ** 32, 2 ** 50]) {
244  assert.throws(() => checkPrime(2n, { checks }, common.mustNotCall()), {
245    code: 'ERR_OUT_OF_RANGE',
246    message: /<= 2147483647/
247  });
248  assert.throws(() => checkPrimeSync(2n, { checks }), {
249    code: 'ERR_OUT_OF_RANGE',
250    message: /<= 2147483647/
251  });
252}
253
254assert(!checkPrimeSync(Buffer.from([0x1])));
255assert(checkPrimeSync(Buffer.from([0x2])));
256assert(checkPrimeSync(Buffer.from([0x3])));
257assert(!checkPrimeSync(Buffer.from([0x4])));
258
259assert(
260  !checkPrimeSync(
261    Buffer.from([0x1]),
262    {
263      fast: true,
264      trialDivision: true,
265      checks: 10
266    }));
267
268(async function() {
269  const prime = await pgeneratePrime(36);
270  assert(await pCheckPrime(prime));
271})().then(common.mustCall());
272
273assert.throws(() => {
274  generatePrimeSync(32, { bigint: '' });
275}, { code: 'ERR_INVALID_ARG_TYPE' });
276
277assert.throws(() => {
278  generatePrime(32, { bigint: '' }, common.mustNotCall());
279}, { code: 'ERR_INVALID_ARG_TYPE' });
280
281{
282  const prime = generatePrimeSync(3, { bigint: true });
283  assert.strictEqual(typeof prime, 'bigint');
284  assert.strictEqual(prime, 7n);
285  assert(checkPrimeSync(prime));
286  checkPrime(prime, common.mustSucceed(assert));
287}
288
289{
290  generatePrime(3, { bigint: true }, common.mustSucceed((prime) => {
291    assert.strictEqual(typeof prime, 'bigint');
292    assert.strictEqual(prime, 7n);
293    assert(checkPrimeSync(prime));
294    checkPrime(prime, common.mustSucceed(assert));
295  }));
296}
297