summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cli/tests/node_compat/test/parallel/test-crypto-prime.js216
-rw-r--r--ext/node/lib.rs2
-rw-r--r--ext/node/ops/crypto/mod.rs17
-rw-r--r--ext/node/ops/crypto/primes.rs2
-rw-r--r--ext/node/polyfills/internal/crypto/random.ts179
5 files changed, 259 insertions, 157 deletions
diff --git a/cli/tests/node_compat/test/parallel/test-crypto-prime.js b/cli/tests/node_compat/test/parallel/test-crypto-prime.js
index de1e88fd7..fc2218c2a 100644
--- a/cli/tests/node_compat/test/parallel/test-crypto-prime.js
+++ b/cli/tests/node_compat/test/parallel/test-crypto-prime.js
@@ -36,129 +36,129 @@ assert(
checks: 10
}));
-// (async function() {
-// const prime = await pgeneratePrime(36);
-// assert(await pCheckPrime(prime));
-// })().then(common.mustCall());
-
-// assert.throws(() => {
-// generatePrimeSync(32, { bigint: '' });
-// }, { code: 'ERR_INVALID_ARG_TYPE' });
-
-// assert.throws(() => {
-// generatePrime(32, { bigint: '' }, common.mustNotCall());
-// }, { code: 'ERR_INVALID_ARG_TYPE' });
-
-// {
-// const prime = generatePrimeSync(3, { bigint: true });
-// assert.strictEqual(typeof prime, 'bigint');
-// assert.strictEqual(prime, 7n);
-// assert(checkPrimeSync(prime));
-// checkPrime(prime, common.mustSucceed(assert));
-// }
+(async function() {
+ const prime = await pgeneratePrime(36);
+ assert(await pCheckPrime(prime));
+})().then(common.mustCall());
+
+assert.throws(() => {
+ generatePrimeSync(32, { bigint: '' });
+}, { code: 'ERR_INVALID_ARG_TYPE' });
+
+assert.throws(() => {
+ generatePrime(32, { bigint: '' }, common.mustNotCall());
+}, { code: 'ERR_INVALID_ARG_TYPE' });
+
+{
+ const prime = generatePrimeSync(3, { bigint: true });
+ assert.strictEqual(typeof prime, 'bigint');
+ assert.strictEqual(prime, 7n);
+ assert(checkPrimeSync(prime));
+ checkPrime(prime, common.mustSucceed(assert));
+}
-// {
-// generatePrime(3, { bigint: true }, common.mustSucceed((prime) => {
-// assert.strictEqual(typeof prime, 'bigint');
-// assert.strictEqual(prime, 7n);
-// assert(checkPrimeSync(prime));
-// checkPrime(prime, common.mustSucceed(assert));
-// }));
-// }
+{
+ generatePrime(3, { bigint: true }, common.mustSucceed((prime) => {
+ assert.strictEqual(typeof prime, 'bigint');
+ assert.strictEqual(prime, 7n);
+ assert(checkPrimeSync(prime));
+ checkPrime(prime, common.mustSucceed(assert));
+ }));
+}
-// ['hello', false, {}, []].forEach((i) => {
-// assert.throws(() => generatePrime(i), {
-// code: 'ERR_INVALID_ARG_TYPE'
-// });
-// assert.throws(() => generatePrimeSync(i), {
-// code: 'ERR_INVALID_ARG_TYPE'
-// });
-// });
+['hello', false, {}, []].forEach((i) => {
+ assert.throws(() => generatePrime(i), {
+ code: 'ERR_INVALID_ARG_TYPE'
+ });
+ assert.throws(() => generatePrimeSync(i), {
+ code: 'ERR_INVALID_ARG_TYPE'
+ });
+});
-// ['hello', false, 123].forEach((i) => {
-// assert.throws(() => generatePrime(80, i, common.mustNotCall()), {
-// code: 'ERR_INVALID_ARG_TYPE'
-// });
-// assert.throws(() => generatePrimeSync(80, i), {
-// code: 'ERR_INVALID_ARG_TYPE'
-// });
-// });
+['hello', false, 123].forEach((i) => {
+ assert.throws(() => generatePrime(80, i, common.mustNotCall()), {
+ code: 'ERR_INVALID_ARG_TYPE'
+ });
+ assert.throws(() => generatePrimeSync(80, i), {
+ code: 'ERR_INVALID_ARG_TYPE'
+ });
+});
-// ['hello', false, 123].forEach((i) => {
-// assert.throws(() => generatePrime(80, {}), {
-// code: 'ERR_INVALID_ARG_TYPE'
-// });
-// });
+['hello', false, 123].forEach((i) => {
+ assert.throws(() => generatePrime(80, {}), {
+ code: 'ERR_INVALID_ARG_TYPE'
+ });
+});
-// [-1, 0, 2 ** 31, 2 ** 31 + 1, 2 ** 32 - 1, 2 ** 32].forEach((size) => {
-// assert.throws(() => generatePrime(size, common.mustNotCall()), {
-// code: 'ERR_OUT_OF_RANGE',
-// message: />= 1 && <= 2147483647/
-// });
-// assert.throws(() => generatePrimeSync(size), {
-// code: 'ERR_OUT_OF_RANGE',
-// message: />= 1 && <= 2147483647/
-// });
-// });
+[-1, 0, 2 ** 31, 2 ** 31 + 1, 2 ** 32 - 1, 2 ** 32].forEach((size) => {
+ assert.throws(() => generatePrime(size, common.mustNotCall()), {
+ code: 'ERR_OUT_OF_RANGE',
+ message: />= 1 && <= 2147483647/
+ });
+ assert.throws(() => generatePrimeSync(size), {
+ code: 'ERR_OUT_OF_RANGE',
+ message: />= 1 && <= 2147483647/
+ });
+});
-// ['test', -1, {}, []].forEach((i) => {
-// assert.throws(() => generatePrime(8, { safe: i }, common.mustNotCall()), {
-// code: 'ERR_INVALID_ARG_TYPE'
-// });
-// assert.throws(() => generatePrime(8, { rem: i }, common.mustNotCall()), {
-// code: 'ERR_INVALID_ARG_TYPE'
-// });
-// assert.throws(() => generatePrime(8, { add: i }, common.mustNotCall()), {
-// code: 'ERR_INVALID_ARG_TYPE'
-// });
-// assert.throws(() => generatePrimeSync(8, { safe: i }), {
-// code: 'ERR_INVALID_ARG_TYPE'
-// });
-// assert.throws(() => generatePrimeSync(8, { rem: i }), {
-// code: 'ERR_INVALID_ARG_TYPE'
-// });
-// assert.throws(() => generatePrimeSync(8, { add: i }), {
-// code: 'ERR_INVALID_ARG_TYPE'
-// });
-// });
+['test', -1, {}, []].forEach((i) => {
+ assert.throws(() => generatePrime(8, { safe: i }, common.mustNotCall()), {
+ code: 'ERR_INVALID_ARG_TYPE'
+ });
+ assert.throws(() => generatePrime(8, { rem: i }, common.mustNotCall()), {
+ code: 'ERR_INVALID_ARG_TYPE'
+ });
+ assert.throws(() => generatePrime(8, { add: i }, common.mustNotCall()), {
+ code: 'ERR_INVALID_ARG_TYPE'
+ });
+ assert.throws(() => generatePrimeSync(8, { safe: i }), {
+ code: 'ERR_INVALID_ARG_TYPE'
+ });
+ assert.throws(() => generatePrimeSync(8, { rem: i }), {
+ code: 'ERR_INVALID_ARG_TYPE'
+ });
+ assert.throws(() => generatePrimeSync(8, { add: i }), {
+ code: 'ERR_INVALID_ARG_TYPE'
+ });
+});
-// {
-// // Negative BigInts should not be converted to 0 silently.
+{
+ // Negative BigInts should not be converted to 0 silently.
-// assert.throws(() => generatePrime(20, { add: -1n }, common.mustNotCall()), {
-// code: 'ERR_OUT_OF_RANGE',
-// message: 'The value of "options.add" is out of range. It must be >= 0. ' +
-// 'Received -1n'
-// });
+ assert.throws(() => generatePrime(20, { add: -1n }, common.mustNotCall()), {
+ code: 'ERR_OUT_OF_RANGE',
+ message: 'The value of "options.add" is out of range. It must be >= 0. ' +
+ 'Received -1n'
+ });
-// assert.throws(() => generatePrime(20, { rem: -1n }, common.mustNotCall()), {
-// code: 'ERR_OUT_OF_RANGE',
-// message: 'The value of "options.rem" is out of range. It must be >= 0. ' +
-// 'Received -1n'
-// });
+ assert.throws(() => generatePrime(20, { rem: -1n }, common.mustNotCall()), {
+ code: 'ERR_OUT_OF_RANGE',
+ message: 'The value of "options.rem" is out of range. It must be >= 0. ' +
+ 'Received -1n'
+ });
-// assert.throws(() => checkPrime(-1n, common.mustNotCall()), {
-// code: 'ERR_OUT_OF_RANGE',
-// message: 'The value of "candidate" is out of range. It must be >= 0. ' +
-// 'Received -1n'
-// });
-// }
+ // assert.throws(() => checkPrime(-1n, common.mustNotCall()), {
+ // code: 'ERR_OUT_OF_RANGE',
+ // message: 'The value of "candidate" is out of range. It must be >= 0. ' +
+ // 'Received -1n'
+ // });
+}
-// generatePrime(80, common.mustSucceed((prime) => {
-// assert(checkPrimeSync(prime));
-// checkPrime(prime, common.mustSucceed((result) => {
-// assert(result);
-// }));
-// }));
+generatePrime(80, common.mustSucceed((prime) => {
+ assert(checkPrimeSync(prime));
+ checkPrime(prime, common.mustSucceed((result) => {
+ assert(result);
+ }));
+}));
-// assert(checkPrimeSync(generatePrimeSync(80)));
+assert(checkPrimeSync(generatePrimeSync(80)));
-// generatePrime(80, {}, common.mustSucceed((prime) => {
-// assert(checkPrimeSync(prime));
-// }));
+generatePrime(80, {}, common.mustSucceed((prime) => {
+ assert(checkPrimeSync(prime));
+}));
-// assert(checkPrimeSync(generatePrimeSync(80, {})));
+assert(checkPrimeSync(generatePrimeSync(80, {})));
// generatePrime(32, { safe: true }, common.mustSucceed((prime) => {
// assert(checkPrimeSync(prime));
diff --git a/ext/node/lib.rs b/ext/node/lib.rs
index 53b4f5c08..cef92328d 100644
--- a/ext/node/lib.rs
+++ b/ext/node/lib.rs
@@ -213,6 +213,8 @@ deno_core::extension!(deno_node,
ops::crypto::op_node_check_prime_async,
ops::crypto::op_node_check_prime_bytes,
ops::crypto::op_node_check_prime_bytes_async,
+ ops::crypto::op_node_gen_prime,
+ ops::crypto::op_node_gen_prime_async,
ops::crypto::op_node_pbkdf2,
ops::crypto::op_node_pbkdf2_async,
ops::crypto::op_node_hkdf,
diff --git a/ext/node/ops/crypto/mod.rs b/ext/node/ops/crypto/mod.rs
index d224b40f7..92e3029e0 100644
--- a/ext/node/ops/crypto/mod.rs
+++ b/ext/node/ops/crypto/mod.rs
@@ -901,3 +901,20 @@ pub async fn op_node_scrypt_async(
})
.await?
}
+
+#[inline]
+fn gen_prime(size: usize) -> ZeroCopyBuf {
+ primes::Prime::generate(size).0.to_bytes_be().into()
+}
+
+#[op]
+pub fn op_node_gen_prime(size: usize) -> ZeroCopyBuf {
+ gen_prime(size)
+}
+
+#[op]
+pub async fn op_node_gen_prime_async(
+ size: usize,
+) -> Result<ZeroCopyBuf, AnyError> {
+ Ok(tokio::task::spawn_blocking(move || gen_prime(size)).await?)
+}
diff --git a/ext/node/ops/crypto/primes.rs b/ext/node/ops/crypto/primes.rs
index d03398f02..15aa643ad 100644
--- a/ext/node/ops/crypto/primes.rs
+++ b/ext/node/ops/crypto/primes.rs
@@ -8,7 +8,7 @@ use num_traits::Zero;
use rand::Rng;
use std::ops::Deref;
-pub struct Prime(num_bigint_dig::BigUint);
+pub struct Prime(pub num_bigint_dig::BigUint);
impl Prime {
pub fn generate(n: usize) -> Self {
diff --git a/ext/node/polyfills/internal/crypto/random.ts b/ext/node/polyfills/internal/crypto/random.ts
index 04678b6be..32256b13b 100644
--- a/ext/node/polyfills/internal/crypto/random.ts
+++ b/ext/node/polyfills/internal/crypto/random.ts
@@ -8,6 +8,7 @@ import randomFill, {
} from "ext:deno_node/internal/crypto/_randomFill.ts";
import randomInt from "ext:deno_node/internal/crypto/_randomInt.ts";
import {
+ validateBoolean,
validateFunction,
validateInt32,
validateObject,
@@ -16,7 +17,10 @@ import {
isAnyArrayBuffer,
isArrayBufferView,
} from "ext:deno_node/internal/util/types.ts";
-import { ERR_INVALID_ARG_TYPE } from "ext:deno_node/internal/errors.ts";
+import {
+ ERR_INVALID_ARG_TYPE,
+ ERR_OUT_OF_RANGE,
+} from "ext:deno_node/internal/errors.ts";
export { default as randomBytes } from "ext:deno_node/internal/crypto/_randomBytes.ts";
export {
@@ -142,62 +146,141 @@ export interface GeneratePrimeOptions {
bigint?: boolean | undefined;
}
-export interface GeneratePrimeOptionsBigInt extends GeneratePrimeOptions {
- bigint: true;
-}
-
-export interface GeneratePrimeOptionsArrayBuffer extends GeneratePrimeOptions {
- bigint?: false | undefined;
-}
-
-export function generatePrime(
- size: number,
- callback: (err: Error | null, prime: ArrayBuffer) => void,
-): void;
-export function generatePrime(
- size: number,
- options: GeneratePrimeOptionsBigInt,
- callback: (err: Error | null, prime: bigint) => void,
-): void;
-export function generatePrime(
- size: number,
- options: GeneratePrimeOptionsArrayBuffer,
- callback: (err: Error | null, prime: ArrayBuffer) => void,
-): void;
export function generatePrime(
size: number,
- options: GeneratePrimeOptions,
- callback: (err: Error | null, prime: ArrayBuffer | bigint) => void,
-): void;
-export function generatePrime(
- _size: number,
- _options?: unknown,
- _callback?: unknown,
+ options: GeneratePrimeOptions = {},
+ callback?: (err: Error | null, prime: ArrayBuffer | bigint) => void,
) {
- notImplemented("crypto.generatePrime");
+ validateInt32(size, "size", 1);
+ if (typeof options === "function") {
+ callback = options;
+ options = {};
+ }
+ validateFunction(callback, "callback");
+ const {
+ bigint,
+ } = validateRandomPrimeJob(size, options);
+ core.opAsync2("op_node_gen_prime_async", size).then((prime: Uint8Array) =>
+ bigint ? arrayBufferToUnsignedBigInt(prime.buffer) : prime.buffer
+ ).then((prime: ArrayBuffer | bigint) => {
+ callback?.(null, prime);
+ });
}
-export function generatePrimeSync(size: number): ArrayBuffer;
export function generatePrimeSync(
size: number,
- options: GeneratePrimeOptionsBigInt,
-): bigint;
-export function generatePrimeSync(
- size: number,
- options: GeneratePrimeOptionsArrayBuffer,
-): ArrayBuffer;
-export function generatePrimeSync(
+ options: GeneratePrimeOptions = {},
+): ArrayBuffer | bigint {
+ const {
+ bigint,
+ } = validateRandomPrimeJob(size, options);
+
+ const prime = ops.op_node_gen_prime(size);
+ if (bigint) return arrayBufferToUnsignedBigInt(prime.buffer);
+ return prime.buffer;
+}
+
+function validateRandomPrimeJob(
size: number,
options: GeneratePrimeOptions,
-): ArrayBuffer | bigint;
-export function generatePrimeSync(
- _size: number,
- _options?:
- | GeneratePrimeOptionsBigInt
- | GeneratePrimeOptionsArrayBuffer
- | GeneratePrimeOptions,
-): ArrayBuffer | bigint {
- notImplemented("crypto.generatePrimeSync");
+): GeneratePrimeOptions {
+ validateInt32(size, "size", 1);
+ validateObject(options, "options");
+
+ let {
+ safe = false,
+ bigint = false,
+ add,
+ rem,
+ } = options!;
+
+ validateBoolean(safe, "options.safe");
+ validateBoolean(bigint, "options.bigint");
+
+ if (add !== undefined) {
+ if (typeof add === "bigint") {
+ add = unsignedBigIntToBuffer(add, "options.add");
+ } else if (!isAnyArrayBuffer(add) && !isArrayBufferView(add)) {
+ throw new ERR_INVALID_ARG_TYPE(
+ "options.add",
+ [
+ "ArrayBuffer",
+ "TypedArray",
+ "Buffer",
+ "DataView",
+ "bigint",
+ ],
+ add,
+ );
+ }
+ }
+
+ if (rem !== undefined) {
+ if (typeof rem === "bigint") {
+ rem = unsignedBigIntToBuffer(rem, "options.rem");
+ } else if (!isAnyArrayBuffer(rem) && !isArrayBufferView(rem)) {
+ throw new ERR_INVALID_ARG_TYPE(
+ "options.rem",
+ [
+ "ArrayBuffer",
+ "TypedArray",
+ "Buffer",
+ "DataView",
+ "bigint",
+ ],
+ rem,
+ );
+ }
+ }
+
+ // TODO(@littledivy): safe, add and rem options are not implemented.
+ if (safe || add || rem) {
+ notImplemented("safe, add and rem options are not implemented.");
+ }
+
+ return {
+ safe,
+ bigint,
+ add,
+ rem,
+ };
+}
+
+/**
+ * 48 is the ASCII code for '0', 97 is the ASCII code for 'a'.
+ * @param {number} number An integer between 0 and 15.
+ * @returns {number} corresponding to the ASCII code of the hex representation
+ * of the parameter.
+ */
+const numberToHexCharCode = (number: number): number =>
+ (number < 10 ? 48 : 87) + number;
+
+/**
+ * @param {ArrayBuffer} buf An ArrayBuffer.
+ * @return {bigint}
+ */
+function arrayBufferToUnsignedBigInt(buf: ArrayBuffer): bigint {
+ const length = buf.byteLength;
+ const chars: number[] = Array(length * 2);
+ const view = new DataView(buf);
+
+ for (let i = 0; i < length; i++) {
+ const val = view.getUint8(i);
+ chars[2 * i] = numberToHexCharCode(val >> 4);
+ chars[2 * i + 1] = numberToHexCharCode(val & 0xf);
+ }
+
+ return BigInt(`0x${String.fromCharCode(...chars)}`);
+}
+
+function unsignedBigIntToBuffer(bigint: bigint, name: string) {
+ if (bigint < 0) {
+ throw new ERR_OUT_OF_RANGE(name, ">= 0", bigint);
+ }
+
+ const hex = bigint.toString(16);
+ const padded = hex.padStart(hex.length + (hex.length % 2), 0);
+ return Buffer.from(padded, "hex");
}
export const randomUUID = () => globalThis.crypto.randomUUID();