Skip to content

Commit

Permalink
Merge pull request #8 from denorg/move-away-from-async
Browse files Browse the repository at this point in the history
Remove unnecessary async/await
  • Loading branch information
oplik0 authored Jun 13, 2022
2 parents 5fecf11 + 2e7997e commit fc41802
Show file tree
Hide file tree
Showing 12 changed files with 178 additions and 168 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ Import the `hash` and/or `verify` functions and use them:
```ts
import { hash, verify } from "https://deno.land/x/scrypt/mod.ts";

const hashResult = await hash("password");
const verifyResult = await verify("password", hashResult);
const hashResult = hash("password");
const verifyResult = verify("password", hashResult);
```

### CLI with [DPX](https://github.com/denorg/dpx)
Expand Down
14 changes: 7 additions & 7 deletions cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,24 @@ import { genSalt, hash, verify } from "./mod.ts";
* @todo add a proper argument parser ([args](https://deno.land/x/args) perhaps?)
*/
if (import.meta.main) {
let args = Deno.args.slice();
const args = Deno.args.slice();
const command = args.shift();
switch (command) {
case "hash":
for (let arg of args) {
console.log(await hash(arg));
for (const arg of args) {
console.log(hash(arg));
}
break;
case "verify":
console.log(await verify(args[0], args[1]));
console.log(verify(args[0], args[1]));
break;
case "salt":
if (args.length) {
for (let arg of args) {
console.log(await genSalt(parseInt(arg, 10)));
for (const arg of args) {
console.log(genSalt(parseInt(arg, 10)));
}
} else {
console.log(await genSalt());
console.log(genSalt());
}
}
}
8 changes: 8 additions & 0 deletions deno.jsonc
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"$schema": "https://deno.land/x/deno/cli/schemas/config-file.v1.json",
"lint": {
"files": {
"exclude": ["lib/_wasm/wasm.js", "lib/_wasm/out/"]
}
}
}
2 changes: 1 addition & 1 deletion lib/_wasm/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ async function generate(wasm: string, output: string): Promise<void> {
const denoHashScript = "/* eslint-disable */\n"
+ "//deno-fmt-ignore-file\n"
+ `import { decode } from "https://deno.land/x/base91/base91.ts";`
+ `export const source = decode("${wasm.replaceAll('"', '\\"')}");`
+ `export const source = decode("${wasm.replaceAll("\"", "\\\"")}");`
+ initScript;

await Deno.writeFile("wasm.js", new TextEncoder().encode(denoHashScript));
Expand Down
172 changes: 87 additions & 85 deletions lib/_wasm/wasm.js

Large diffs are not rendered by default.

28 changes: 14 additions & 14 deletions lib/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,13 +78,13 @@ export interface ScryptParameters {
}
export type scryptFormat = "scrypt" | "phc" | "raw";

export async function formatScrypt(
export function formatScrypt(
rawHash: string,
logN: logN,
r: number,
p: number,
salt: string | Uint8Array,
): Promise<string> {
): string {
const encoder = new TextEncoder();
const result = new Uint8Array(96);
const dataview = new DataView(result.buffer);
Expand All @@ -106,9 +106,9 @@ export async function formatScrypt(
// encode the result as a base64 string
return encode(result);
}
async function decomposeScrypt(
function decomposeScrypt(
formattedHash: string,
): Promise<ScryptParameters> {
): ScryptParameters {
const bytes: Uint8Array = new Uint8Array(decode(formattedHash));
const dataview: DataView = new DataView(bytes.buffer);
const parameters: ScryptParameters = {};
Expand All @@ -129,19 +129,19 @@ async function decomposeScrypt(
* @param {number} p - parallelism factor
* @param {string|Uint8Array} salt - salt used when hashing
*/
export async function formatPHC(
export function formatPHC(
rawHash: string,
logN: logN,
r: number,
p: number,
salt: string | Uint8Array,
): Promise<string> {
): string {
// convert salt to base64 without padding
salt = encode(salt).replace(/=/g, "");
rawHash = rawHash.replace(/=/g, "");
return `\$scrypt\$ln=${logN},r=${r},p=${p}\$${salt}\$${rawHash}`;
}
async function decomposePHC(formattedHash: string): Promise<ScryptParameters> {
function decomposePHC(formattedHash: string): ScryptParameters {
const regex = /\$scrypt\$ln=(?<logN>\d+),r=(?<r>\d+),p=(?<p>\d+)\$(?<salt>[a-zA-Z0-9\-\_\+\/\=]*)\$/;
const parameters: ScryptParameters = formattedHash.match(regex)
?.groups as ScryptParameters;
Expand All @@ -151,26 +151,26 @@ async function decomposePHC(formattedHash: string): Promise<ScryptParameters> {
return parameters;
}

export async function decomposeFormat(
export function decomposeFormat(
formattedHash: string,
format?: scryptFormat,
): Promise<ScryptParameters> {
format = format ?? await detectFormat(formattedHash);
): ScryptParameters {
format = format ?? detectFormat(formattedHash);
switch (format) {
case "scrypt":
return await decomposeScrypt(formattedHash);
return decomposeScrypt(formattedHash);
case "phc":
return await decomposePHC(formattedHash);
return decomposePHC(formattedHash);
case "raw":
throw new Error("Unable to extract parameters from raw hash");
default:
throw new Error("Unknown hash format");
}
}

export async function detectFormat(
export function detectFormat(
formattedHash: string,
): Promise<scryptFormat> {
): scryptFormat {
switch (formattedHash.substring(0, 6)) {
case "c2NyeX":
case "scrypt":
Expand Down
4 changes: 2 additions & 2 deletions lib/helpers_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import { assertEquals } from "https://deno.land/std@0.143.0/testing/asserts.ts";

import { decomposeFormat, ScryptParameters } from "./helpers.ts";

Deno.test("decompose scrypt with format detection", async (): Promise<void> => {
const params = await decomposeFormat(
Deno.test("decompose scrypt with format detection", (): void => {
const params = decomposeFormat(
"c2NyeXB0AAwAAAAIAAAAAcQ0zwp7QNLklxCn14vB75AYWDIrrT9I/7F9+lVGBfKN/1TH2hs/HboSy1ptzN0YzMmobAXD3CqJJLRLaTK7nOHbjNTWA20LuUmGwEoJtonW",
);
// deno-fmt-ignore
Expand Down
6 changes: 3 additions & 3 deletions lib/scrypt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,17 @@ export type encoding = "utf-8" | "base64" | "hex";
* @param {number} p - parallelism factor
* @param {number} [dklen] - length (in bytes) of the output. Defaults to 32.
* @param {encoding} [outputEncoding] - encoding used, defaults to null (Uint8Array)
* @returns {Promise<string|Uint8Array>} - the resulting hash encoded according to outputEncoding
* @returns {string|Uint8Array} - the resulting hash encoded according to outputEncoding
*/
export async function scrypt(
export function scrypt(
password: string | Uint8Array,
salt: string | Uint8Array,
N: number,
r: number,
p: number,
dklen?: number,
outputEncoding?: encoding,
): Promise<Uint8Array | string> {
): Uint8Array | string {
dklen = dklen ?? 64;
password = typeof password === "string" ? encoder.encode(password) : password;
salt = typeof salt === "string" ? encoder.encode(salt) : salt;
Expand Down
38 changes: 19 additions & 19 deletions lib/scrypt_bench.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,22 @@
* @todo document the benchmarks better
*/
import { scrypt } from "./scrypt.ts";
const extremeSalt: string =
const extremeSalt =
`IkjpewCbNm4A7cuY1VL9KC3y92blEthtLf9Cet6uEoTxz5cyF660da2zeci42fYwVCVwsKogETMCXupSZZAUh6a80ZnnBTk17B3UTCSVQPpYfL8GktJ2BDokE7ox2hV8OwwUT1hFvCuJqwHZpRvZw1RNCO6HfukPdgMHhq9rWLTXXUNwrIjlmkeydKGFJz2mS1xFcvLQtle4olJVK0SXXXYHAigBfpYxxSC2acvoxuacWcXhzSSRZAMysU2J7zDfXdxnYoqz50rvmvi36g7t2WDSAdzZ44JpxVcc3bYD7xYI3UgfVMPOfeblzwJi455QIurHzDuXEUNS0tZX1kWwZ0XcNSCwGzPs7WSVHxHc0KVUNhwSz16wDYFK4pYeA29ThXgFiFICSLVshiRrCfuzRthW7IZtRa9efcf4nFJsVBk51jpHY0b8CLhARrQU92mlBULwmJKe8DgST3Vn9rva98E9jk4y7NfSb4i9g74OjuFQ8yRO3BHksBZoVtBl4wUppM2hsLt72LZKA0ZsaWW7dG9a1bgWUkBBRG5OwzARenDqQIA2Gp5V4JsXuUUYNDylCelkLUVfS7hB1AZHtnIgwVqTaGDxl7nNZGKpAx6MrOd40laTUhrtZo4prwFZROHPNVJGQk2PQDgwqxX5SWoBTK8cCCzrbGBfHq9r8BwBvSVdeQ7bgjUW2j7NCapHHZ6filzxZaVsLsEITGZNcK0t5DdSnaDLRxyOn21ncKVIyZfOdlvpytvqpQaH5RWu4G50IPkEevue8KenXpGLP0pmEseBf6eX02rlN9arqZ4HJWmD7RbAChs7OJwfKlNIawb0V3G3N0eJeXiRsYOk10GIb91pyZRLSr2AJDtiWCcMuOWZfgLVHIrUVftfh9iXmRk2RAT1sigivbNtdqcF2cVvbTVMUCe7MIPRt4dGqwOQqdReGjPy9p1CNfKfJBIgW0xhYsOGMkcUqSurHxPl4wTOnMBx8vEZQsqJCZomENA1`;
const extremePassword: string =
const extremePassword =
`TFImeWrtF2kOIvDjG4P0ybmMrNOq0bQ0aERcC69iHflECWrwuSMO4JPD3Ng5HwNXZrCpHyEwviW8zly3WLsQ6zJ60lnfwhVRdkEQCsFiH4NvGl0tCAuty9Rruf47WHeE3GK7qAJwhcXHx3FCJgWN8KHdoy3vn2zUKJlhhjSFGANJdVYQGSaQTmtoJdhcemmYT5hprkALp7Q9vMwCk9hDvV5vB0evXfxqG0dFV3MPJmywwWAUJEi5MyM2Pio7fL50M5ohPWFmUllpa6G5pVBhi26GtOy6sM3GDGHmnohavtsMvTeRcMX1ds4HWA9U3vH7urQ3XGkCUzulB6WxuxHn8Z3fRz3BL6MZI0EReep2qUVaqJn8onzsI6da6pU6iDtRbufWxi0q8XN1S3BCtFGjzaTU12nvfg5js53PiSw1KUnZj2thKxWtnKcpwzbXdTuuZ9GVhZHIMcOXXrDR0rj539ZLAVyJmqwDOMjTsqPN7BY522PcJHoTElSRNRAsAsFx2m7h9brhcZXOgV1PZohJsdQS7RWhAl9EYBkgF8WCgGw9DXidVduIIHDlEd7mAVJfo9HYX85kFcwrLEpuPiFxfNhubeDpeBu2FAbAo6DNHFlqXUUnyKvMbzptcgisSr2V1pwykB6uLVrwx3AceRnyqg5flldmfsSKw0AFZ4PagGMJuFDMGrV29Vmqhv61SRL9in0ngZx0gJ2vKv26qS3jGN72UUsbkysuGNz6ul0D5jIapvIcCTncIiXSY24pPctxFsawcXvSNw4jEKccsHCTZF0gri6iFS7JqqQd87FNowbrug6sIWSwiWHYGN1VfSwuE5plQHVvNCHNZnMBBIoaMWh45lhtlfCWdUwVpjjK5dAUcOtKftJ2hcl4mIlxs7Fy8ASWhYvWAbpp3fRgmAeTRYAFEwMohN9b03iXyDSNFIeZtQoaL7HYFVWoXV4BfBVlR3CvNIwp6OPBAFFSDlSn9CZU06UziY1tSwqBzkCD`;

Deno.bench("small scrypt", { group: "small scrypt", baseline: true }, async () => {
await scrypt("password", "salt", 1024, 8, 1, 64);
scrypt("password", "salt", 1024, 8, 1, 64);
});
Deno.bench("small scrypt (longer password)", { group: "small scrypt" }, async () => {
await scrypt("long password to test that", "salt", 1024, 8, 1, 64);
scrypt("long password to test that", "salt", 1024, 8, 1, 64);
});
Deno.bench("small scrypt (longer salt)", { group: "small scrypt" }, async () => {
await scrypt("password", "long salt to test that", 1024, 8, 1, 64);
scrypt("password", "long salt to test that", 1024, 8, 1, 64);
});
Deno.bench("small scrypt (longer password and salt)", { group: "small scrypt" }, async () => {
await scrypt(
scrypt(
"long password to test that",
"long salt to test that",
1024,
Expand All @@ -29,29 +29,29 @@ Deno.bench("small scrypt (longer password and salt)", { group: "small scrypt" },
});

Deno.bench("small scrypt (extremely long salt)", { group: "small scrypt" }, async () => {
await scrypt("password", extremeSalt, 1024, 8, 1, 64);
scrypt("password", extremeSalt, 1024, 8, 1, 64);
});

Deno.bench("small scrypt (extremely long password)", { group: "small scrypt" }, async () => {
await scrypt(extremePassword, "NaCl", 1024, 8, 1, 64);
scrypt(extremePassword, "NaCl", 1024, 8, 1, 64);
});

Deno.bench("small scrypt (extremely long password and salt)", { group: "small scrypt" }, async () => {
await scrypt(extremePassword, extremeSalt, 1024, 8, 1, 64);
scrypt(extremePassword, extremeSalt, 1024, 8, 1, 64);
});

Deno.bench("standard scrypt", { group: "scrypt", baseline: true }, async () => {
await scrypt("password", "salt", 16384, 8, 1, 64);
scrypt("password", "salt", 16384, 8, 1, 64);
});

Deno.bench("standard scrypt (longer password)", { group: "scrypt" }, async () => {
await scrypt("long password to test that", "salt", 16384, 8, 1, 64);
scrypt("long password to test that", "salt", 16384, 8, 1, 64);
});
Deno.bench("standard scrypt (longer salt)", { group: "scrypt" }, async () => {
await scrypt("password", "long salt to test that", 16384, 8, 1, 64);
scrypt("password", "long salt to test that", 16384, 8, 1, 64);
});
Deno.bench("standard scrypt (longer password and salt)", { group: "scrypt" }, async () => {
await scrypt(
scrypt(
"long password to test that",
"long salt to test that",
16384,
Expand All @@ -62,23 +62,23 @@ Deno.bench("standard scrypt (longer password and salt)", { group: "scrypt" }, as
});

Deno.bench("standard scrypt (extremely long salt)", { group: "scrypt" }, async () => {
await scrypt("password", extremeSalt, 16384, 8, 1, 64);
scrypt("password", extremeSalt, 16384, 8, 1, 64);
});

Deno.bench("standard scrypt (extremely long password)", { group: "scrypt" }, async () => {
await scrypt(extremePassword, "NaCl", 16384, 8, 1, 64);
scrypt(extremePassword, "NaCl", 16384, 8, 1, 64);
});

Deno.bench("standard scrypt (extremely long password and salt)", { group: "scrypt" }, async () => {
await scrypt(extremePassword, extremeSalt, 16384, 8, 1, 64);
scrypt(extremePassword, extremeSalt, 16384, 8, 1, 64);
});

Deno.bench("large n scrypt (4x standard)", { group: "large scrypt" }, async () => {
await scrypt("password", "salt", 65536, 8, 1, 64);
scrypt("password", "salt", 65536, 8, 1, 64);
});
Deno.bench("large r scrypt (4x standard)", { group: "large scrypt" }, async () => {
await scrypt("password", "salt", 16384, 32, 1, 64);
scrypt("password", "salt", 16384, 32, 1, 64);
});
Deno.bench("large p scrypt (4x standard)", { group: "large scrypt" }, async () => {
await scrypt("password", "salt", 16384, 8, 4, 64);
scrypt("password", "salt", 16384, 8, 4, 64);
});
12 changes: 6 additions & 6 deletions lib/scrypt_test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { assertEquals } from "https://deno.land/std@0.143.0/testing/asserts.ts";
import { scrypt } from "./scrypt.ts";

Deno.test("scrypt #1", async (): Promise<void> => {
Deno.test("scrypt #1", (): void => {
// deno-fmt-ignore
const expectedOutput: Uint8Array = new Uint8Array([
0x77,
Expand Down Expand Up @@ -70,12 +70,12 @@ Deno.test("scrypt #1", async (): Promise<void> => {
0x06,
]);
assertEquals(
(await scrypt("", "", 16, 1, 1, 64)) as Uint8Array,
(scrypt("", "", 16, 1, 1, 64)) as Uint8Array,
expectedOutput,
);
}); // deno-fmt-ignore

Deno.test("scrypt #2", async (): Promise<void> => {
Deno.test("scrypt #2", (): void => {
// deno-fmt-ignore
const expectedOutput: Uint8Array = new Uint8Array([
0xfd,
Expand Down Expand Up @@ -144,12 +144,12 @@ Deno.test("scrypt #2", async (): Promise<void> => {
0x40,
]);
assertEquals(
(await scrypt("password", "NaCl", 1024, 8, 16, 64)) as Uint8Array,
(scrypt("password", "NaCl", 1024, 8, 16, 64)) as Uint8Array,
expectedOutput,
);
});

Deno.test("scrypt #3", async (): Promise<void> => {
Deno.test("scrypt #3", (): void => {
// deno-fmt-ignore
const expectedOutput: Uint8Array = new Uint8Array([
0x70,
Expand Down Expand Up @@ -218,7 +218,7 @@ Deno.test("scrypt #3", async (): Promise<void> => {
0x87,
]);
assertEquals(
(await scrypt(
(scrypt(
"pleaseletmein",
"SodiumChloride",
16384,
Expand Down
26 changes: 13 additions & 13 deletions mod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,32 +30,32 @@ import { scrypt } from "./lib/scrypt.ts";
* @param {scryptFormat} [format="scrypt"] - format of the result. Defaults to scrypt encrypted data format (https://github.com/Tarsnap/scrypt/blob/master/FORMAT)
* @returns {string} - Hash in scrypt format
*/
export async function hash(
export function hash(
password: string,
parameters?: ScryptParameters,
format?: scryptFormat,
): Promise<string> {
): string {
format = format ? format : "scrypt";
parameters = parameters ?? {};
const N = parameters.N ?? 2 ** (parameters.logN ?? 14);
const r = parameters.r ?? 8;
const p = parameters.p ?? 1;
const salt = parameters.salt
? (format === "scrypt" ? to32bytes(parameters.salt) : parameters.salt)
: await genSalt(32, "Uint8Array");
: genSalt(32, "Uint8Array");
const dklen = parameters.dklen
? parameters.dklen
: format === "phc"
? 32
: 64;
let scryptResult: string = (await scrypt(password, salt, N, r, p, dklen, "base64")) as string;
const scryptResult = scrypt(password, salt, N, r, p, dklen, "base64") as string;
switch (format) {
case "raw":
return scryptResult;
case "scrypt":
return await formatScrypt(scryptResult, Math.log2(N) as logN, r, p, salt);
return formatScrypt(scryptResult, Math.log2(N) as logN, r, p, salt);
case "phc":
return await formatPHC(scryptResult, Math.log2(N) as logN, r, p, salt);
return formatPHC(scryptResult, Math.log2(N) as logN, r, p, salt);
default:
throw new Error("invalid output format");
}
Expand All @@ -68,14 +68,14 @@ export async function hash(
* @param {scryptFormat} [format] - format od the tested hash. Will be detected automatically if not provided
* @returns {boolean} result of the check
*/
export async function verify(
export function verify(
password: string,
testedHash: string,
format?: scryptFormat,
): Promise<boolean> {
format = format ?? await detectFormat(testedHash);
const params: ScryptParameters = await decomposeFormat(testedHash, format);
const newHash = await hash(password, params, format);
): boolean {
format = format ?? detectFormat(testedHash);
const params: ScryptParameters = decomposeFormat(testedHash, format);
const newHash = hash(password, params, format);
return newHash === testedHash;
}

Expand All @@ -86,10 +86,10 @@ export async function verify(
* @param {string} [outputType] - either string or Uint8Array
* @returns {string|Uint8Array} random salt
*/
export async function genSalt(
export function genSalt(
length?: number,
outputType?: "string" | "Uint8Array",
): Promise<string | Uint8Array> {
): string | Uint8Array {
const array = new Uint8Array(length || 32);
const decoder = new TextDecoder();
const randomArray = crypto.getRandomValues(array);
Expand Down
Loading

0 comments on commit fc41802

Please sign in to comment.