yescrypt-wasm
Version:
WebAssembly module for Yescrypt
167 lines (150 loc) • 5.09 kB
text/typescript
import { bundled } from './bundled.js';
import { base64ToBytes } from './utils.js';
import yescryptWasm, { MainModule } from './yescrypt_wasm.js';
export * from './utils.js';
type yescrypt_kdf_wasm = (
passwd: number,
passwdLen: number,
salt: number,
saltLen: number,
N: bigint,
r: number,
p: number,
t: number,
) => number;
type yescrypt_hash = (
passwd: number,
passwdLen: number,
salt: number,
saltLen: number,
N: bigint,
r: number,
p: number,
t: number,
) => string;
export class Yescrypt {
nByte: number;
Module: MainModule;
scrypt_kdf_wasm: yescrypt_kdf_wasm;
yescrypt_kdf_wasm: yescrypt_kdf_wasm;
scrypt_hash_: yescrypt_hash;
yescrypt_hash_: yescrypt_hash;
constructor(Module: MainModule) {
this.nByte = 1;
this.Module = Module;
this.scrypt_kdf_wasm = this.Module.cwrap('scrypt_kdf_wasm', undefined, [
'number',
'number',
'number',
'number',
'number',
'number',
'number',
'number',
]) as yescrypt_kdf_wasm;
this.yescrypt_kdf_wasm = this.Module.cwrap('yescrypt_kdf_wasm', undefined, [
'number',
'number',
'number',
'number',
'number',
'number',
'number',
'number',
]) as yescrypt_kdf_wasm;
this.scrypt_hash_ = this.Module.cwrap('scrypt_hash', 'string', [
'number',
'number',
'number',
'number',
'number',
'number',
'number',
'number',
]) as yescrypt_hash;
this.yescrypt_hash_ = this.Module.cwrap('yescrypt_hash', 'string', [
'number',
'number',
'number',
'number',
'number',
'number',
'number',
'number',
]) as yescrypt_hash;
}
static async init() {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
if (typeof (globalThis as any).WebAssembly === 'undefined') {
throw new Error('WebAssembly is not enabled with this browser');
}
const wasmBinary = base64ToBytes(bundled);
const module = await yescryptWasm({
wasmBinary,
locateFile: (file: string) => file,
});
return new Yescrypt(module);
}
// https://stackoverflow.com/questions/41875728/pass-a-javascript-array-as-argument-to-a-webassembly-function
// Takes an Uint8Array, copies it to the heap and returns a pointer
arrayToPtr(array: Uint8Array): number {
const ptr = this.Module._malloc(array.length * this.nByte);
this.Module.HEAPU8.set(array, ptr / this.nByte);
return ptr;
}
// Takes a pointer and array length, and returns a Uint8Array from the heap
ptrToArray(ptr: number, length: number): Uint8Array {
const array = new Uint8Array(length);
const pos = ptr / this.nByte;
array.set(this.Module.HEAPU8.subarray(pos, pos + length));
return array;
}
freePtr(ptr: number) {
this.Module._free(ptr);
}
scrypt_kdf(passwd: Uint8Array, salt: Uint8Array, N = 4096, r = 32, p = 1, t = 0): Uint8Array {
const passwdPtr = this.arrayToPtr(passwd);
const saltPtr = this.arrayToPtr(salt);
const ptr = this.scrypt_kdf_wasm(passwdPtr, passwd.length, saltPtr, salt.length, BigInt(N), r, p, t);
const hash = this.ptrToArray(ptr, 64);
this.freePtr(passwdPtr);
this.freePtr(saltPtr);
this.freePtr(ptr);
return hash;
}
yescrypt_kdf(passwd: Uint8Array, salt: Uint8Array, N = 4096, r = 32, p = 1, t = 0): Uint8Array {
const passwdPtr = this.arrayToPtr(passwd);
const saltPtr = this.arrayToPtr(salt);
const ptr = this.yescrypt_kdf_wasm(
passwdPtr,
passwd.length,
saltPtr,
salt.length,
BigInt(N),
r,
p,
t,
);
const hash = this.ptrToArray(ptr, 64);
this.freePtr(passwdPtr);
this.freePtr(saltPtr);
this.freePtr(ptr);
return hash;
}
scrypt_hash(passwd: Uint8Array, salt: Uint8Array, N = 4096, r = 32, p = 1, t = 0): string {
const passwdPtr = this.arrayToPtr(passwd);
const saltPtr = this.arrayToPtr(salt);
const ptr = this.scrypt_hash_(passwdPtr, passwd.length, saltPtr, salt.length, BigInt(N), r, p, t);
this.freePtr(passwdPtr);
this.freePtr(saltPtr);
return ptr;
}
yescrypt_hash(passwd: Uint8Array, salt: Uint8Array, N = 4096, r = 32, p = 1, t = 0): string {
const passwdPtr = this.arrayToPtr(passwd);
const saltPtr = this.arrayToPtr(salt);
const ptr = this.yescrypt_hash_(passwdPtr, passwd.length, saltPtr, salt.length, BigInt(N), r, p, t);
this.freePtr(passwdPtr);
this.freePtr(saltPtr);
return ptr;
}
}