-
Notifications
You must be signed in to change notification settings - Fork 582
/
hash.ts
90 lines (76 loc) · 2.24 KB
/
hash.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
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
// This module is browser compatible.
import {
create_hash as createHash,
DenoHash,
digest_hash as digestHash,
update_hash as updateHash,
} from "./wasm.js";
import * as hex from "../../encoding/hex.ts";
import * as base64 from "../../encoding/base64.ts";
import type { Hasher, Message, OutputFormat } from "../hasher.ts";
export class Hash implements Hasher {
#hash: DenoHash;
#digested: boolean;
constructor(algorithm: string) {
this.#hash = createHash(algorithm);
this.#digested = false;
}
update(message: Message): this {
let view: Uint8Array;
if (message instanceof Uint8Array) {
view = message;
} else if (typeof message === "string") {
view = new TextEncoder().encode(message);
} else if (ArrayBuffer.isView(message)) {
view = new Uint8Array(
message.buffer,
message.byteOffset,
message.byteLength,
);
} else if (message instanceof ArrayBuffer) {
view = new Uint8Array(message);
} else {
throw new Error("hash: `data` is invalid type");
}
// Messages will be split into chunks of this size to avoid unnecessarily
// increasing the size of the WASM heap.
const chunkSize = 65_536;
for (
let offset = 0;
offset < view.byteLength;
offset += chunkSize
) {
updateHash(
this.#hash,
new Uint8Array(
view.buffer,
view.byteOffset + offset,
Math.min(chunkSize, view.byteLength - offset),
),
);
}
return this;
}
/** Returns final hash */
digest(): ArrayBuffer {
if (this.#digested) throw new Error("hash: already digested");
this.#digested = true;
return digestHash(this.#hash);
}
/**
* Returns hash as a string of given format
* @param format format of output string (hex or base64). Default is hex
*/
toString(format: OutputFormat = "hex"): string {
const finalized = new Uint8Array(this.digest());
switch (format) {
case "hex":
return new TextDecoder().decode(hex.encode(finalized));
case "base64":
return base64.encode(finalized);
default:
throw new Error("hash: invalid format");
}
}
}