-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy path1a.ts
145 lines (145 loc) · 3.47 KB
/
1a.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
136
137
138
139
140
141
142
143
144
145
import {
resolveFNVParameter,
type FNVAcceptDataType,
type FNVBitsSize
} from "./_common.ts";
export type {
FNVAcceptDataType,
FNVBitsSize
};
export class FNV1a {
get [Symbol.toStringTag](): string {
return "FNV1a";
}
#freezed: boolean = false;
#hash: bigint;
#prime: bigint;
#size: FNVBitsSize;
/**
* Initialize.
* @param {FNVBitsSize} size Bits size of the non-cryptographic hash.
* @param {FNVAcceptDataType} [data] Data. Can append later via the method {@linkcode FNV1a.update}.
*/
constructor(size: FNVBitsSize, data?: FNVAcceptDataType) {
const {
offset,
prime,
size: sizeFmt
} = resolveFNVParameter(size);
this.#hash = offset;
this.#prime = prime;
this.#size = sizeFmt;
if (typeof data !== "undefined") {
this.update(data);
}
}
/**
* Whether the instance is freezed.
* @returns {boolean}
*/
get freezed(): boolean {
return this.#freezed;
}
/**
* Bits size of the hash.
* @returns {FNVBitsSize}
*/
get size(): FNVBitsSize {
return this.#size;
}
/**
* Freeze the instance to prevent any further update.
* @returns {this}
*/
freeze(): this {
this.#freezed = true;
return this;
}
/**
* Get the non-cryptographic hash of the data, in original format.
* @returns {bigint}
*/
hash(): bigint {
return this.#hash;
}
/**
* Get the non-cryptographic hash of the data, in Base16.
* @returns {string}
*/
hashBase16(): string {
return this.hashBigInt().toString(16).toUpperCase();
}
/**
* Get the non-cryptographic hash of the data, in Base32Hex ({@link https://datatracker.ietf.org/doc/html/rfc4648#section-7 RFC 4648 §7}).
* @returns {string}
*/
hashBase32Hex(): string {
return this.hashBigInt().toString(32).toUpperCase();
}
/**
* Get the non-cryptographic hash of the data, in Base36.
* @returns {string}
*/
hashBase36(): string {
return this.hashBigInt().toString(36).toUpperCase();
}
/**
* Get the non-cryptographic hash of the data, in big integer.
* @returns {bigint}
*/
hashBigInt(): bigint {
return this.hash();
}
/**
* Get the non-cryptographic hash of the data, in big integer.
* @returns {bigint}
*/
hashBigInteger: () => bigint = this.hashBigInt;
/**
* Get the non-cryptographic hash of the data, in hex/hexadecimal without padding.
* @returns {string}
*/
hashHex(): string {
return this.hashBase16();
}
/**
* Get the non-cryptographic hash of the data, in hex/hexadecimal with padding.
* @returns {string}
*/
hashHexPadding(): string {
return this.hashHex().padStart(this.#size / 4, "0");
}
/**
* Append data.
* @param {FNVAcceptDataType} data Data.
* @returns {this}
*/
update(data: FNVAcceptDataType): this {
if (this.#freezed) {
throw new Error(`Instance is freezed!`);
}
for (const byte of (
(data instanceof Uint8Array) ? data
: ((typeof data === "string") ? new TextEncoder().encode(data)
: new Uint8Array(data)
)
)) {
this.#hash = BigInt.asUintN(this.#size, (this.#hash ^ BigInt(byte)) * this.#prime);
}
return this;
}
/**
* Initialize from the readable stream, asynchronously.
* @param {FNVBitsSize} size Bits size of the non-cryptographic hash.
* @param {ReadableStream<FNVAcceptDataType>} stream Readable stream.
* @returns {Promise<FNV1a>}
*/
static async fromStream(size: FNVBitsSize, stream: ReadableStream<FNVAcceptDataType>): Promise<FNV1a> {
const instance: FNV1a = new this(size);
for await (const chunk of stream) {
instance.update(chunk);
}
return instance;
}
}
export default FNV1a;