-
Notifications
You must be signed in to change notification settings - Fork 50
/
Copy pathblake2s.ts
135 lines (122 loc) · 3.33 KB
/
blake2s.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
import wasmJson from "../wasm/blake2s.wasm.json";
import {
type IHasher,
type IWASMInterface,
WASMInterface,
} from "./WASMInterface";
import lockedCreate from "./lockedCreate";
import Mutex from "./mutex";
import { type IDataType, getUInt8Buffer } from "./util";
const mutex = new Mutex();
let wasmCache: IWASMInterface = null;
function validateBits(bits: number) {
if (!Number.isInteger(bits) || bits < 8 || bits > 256 || bits % 8 !== 0) {
return new Error("Invalid variant! Valid values: 8, 16, ..., 256");
}
return null;
}
function getInitParam(outputBits, keyBits) {
return outputBits | (keyBits << 16);
}
/**
* Calculates BLAKE2s hash
* @param data Input data (string, Buffer or TypedArray)
* @param bits Number of output bits, which has to be a number
* divisible by 8, between 8 and 256. Defaults to 256.
* @param key Optional key (string, Buffer or TypedArray). Maximum length is 32 bytes.
* @returns Computed hash as a hexadecimal string
*/
export function blake2s(
data: IDataType,
bits = 256,
key: IDataType = null,
): Promise<string> {
if (validateBits(bits)) {
return Promise.reject(validateBits(bits));
}
let keyBuffer = null;
let initParam = bits;
if (key !== null) {
keyBuffer = getUInt8Buffer(key);
if (keyBuffer.length > 32) {
return Promise.reject(new Error("Max key length is 32 bytes"));
}
initParam = getInitParam(bits, keyBuffer.length);
}
const hashLength = bits / 8;
if (wasmCache === null || wasmCache.hashLength !== hashLength) {
return lockedCreate(mutex, wasmJson, hashLength).then((wasm) => {
wasmCache = wasm;
if (initParam > 512) {
wasmCache.writeMemory(keyBuffer);
}
return wasmCache.calculate(data, initParam);
});
}
try {
if (initParam > 512) {
wasmCache.writeMemory(keyBuffer);
}
const hash = wasmCache.calculate(data, initParam);
return Promise.resolve(hash);
} catch (err) {
return Promise.reject(err);
}
}
/**
* Creates a new BLAKE2s hash instance
* @param bits Number of output bits, which has to be a number
* divisible by 8, between 8 and 256. Defaults to 256.
* @param key Optional key (string, Buffer or TypedArray). Maximum length is 32 bytes.
*/
export function createBLAKE2s(
bits = 256,
key: IDataType = null,
): Promise<IHasher> {
if (validateBits(bits)) {
return Promise.reject(validateBits(bits));
}
let keyBuffer = null;
let initParam = bits;
if (key !== null) {
keyBuffer = getUInt8Buffer(key);
if (keyBuffer.length > 32) {
return Promise.reject(new Error("Max key length is 32 bytes"));
}
initParam = getInitParam(bits, keyBuffer.length);
}
const outputSize = bits / 8;
return WASMInterface(wasmJson, outputSize).then((wasm) => {
if (initParam > 512) {
wasm.writeMemory(keyBuffer);
}
wasm.init(initParam);
const obj: IHasher = {
init:
initParam > 512
? () => {
wasm.writeMemory(keyBuffer);
wasm.init(initParam);
return obj;
}
: () => {
wasm.init(initParam);
return obj;
},
update: (data) => {
wasm.update(data);
return obj;
},
// biome-ignore lint/suspicious/noExplicitAny: Conflict with IHasher type
digest: (outputType) => wasm.digest(outputType) as any,
save: () => wasm.save(),
load: (data) => {
wasm.load(data);
return obj;
},
blockSize: 64,
digestSize: outputSize,
};
return obj;
});
}