| 
									
										
										
										
											2021-10-26 00:13:49 +08:00
										 |  |  | const { randomBytes, createHash } = require("crypto"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const wasmHashes = { | 
					
						
							|  |  |  | 	xxhash64: () => { | 
					
						
							|  |  |  | 		const createHash = require("../lib/util/hash/xxhash64"); | 
					
						
							|  |  |  | 		const createReferenceHash = | 
					
						
							|  |  |  | 			require("hash-wasm/dist/xxhash64.umd.min.js").createXXHash64; | 
					
						
							|  |  |  | 		return { | 
					
						
							|  |  |  | 			createHash, | 
					
						
							|  |  |  | 			createReferenceHash: async () => (await createReferenceHash()).init(), | 
					
						
							|  |  |  | 			regExp: /^[0-9a-f]{16}$/ | 
					
						
							|  |  |  | 		}; | 
					
						
							|  |  |  | 	}, | 
					
						
							| 
									
										
										
										
											2021-11-04 16:42:27 +08:00
										 |  |  | 	"xxhash64-createHash": () => { | 
					
						
							|  |  |  | 		const createXxHash = require("../lib/util/hash/xxhash64"); | 
					
						
							|  |  |  | 		const createHash = require("../lib/util/createHash"); | 
					
						
							|  |  |  | 		return { | 
					
						
							|  |  |  | 			createHash: () => createHash("xxhash64"), | 
					
						
							|  |  |  | 			createReferenceHash: createXxHash, | 
					
						
							|  |  |  | 			regExp: /^[0-9a-f]{16}$/ | 
					
						
							|  |  |  | 		}; | 
					
						
							|  |  |  | 	}, | 
					
						
							| 
									
										
										
										
											2021-10-26 00:13:49 +08:00
										 |  |  | 	md4: () => { | 
					
						
							|  |  |  | 		const createMd4Hash = require("../lib/util/hash/md4"); | 
					
						
							|  |  |  | 		return { | 
					
						
							|  |  |  | 			createHash: createMd4Hash, | 
					
						
							| 
									
										
										
										
											2021-10-29 20:50:39 +08:00
										 |  |  | 			createReferenceHash: | 
					
						
							|  |  |  | 				parseInt(process.version.slice(1), 10) < 17 | 
					
						
							|  |  |  | 					? async () => createHash("md4") | 
					
						
							|  |  |  | 					: createMd4Hash, | 
					
						
							| 
									
										
										
										
											2021-10-26 00:13:49 +08:00
										 |  |  | 			regExp: /^[0-9a-f]{32}$/ | 
					
						
							|  |  |  | 		}; | 
					
						
							| 
									
										
										
										
											2021-11-04 16:42:27 +08:00
										 |  |  | 	}, | 
					
						
							|  |  |  | 	"md4-createHash": () => { | 
					
						
							|  |  |  | 		const createMd4Hash = require("../lib/util/hash/md4"); | 
					
						
							|  |  |  | 		const createHash = require("../lib/util/createHash"); | 
					
						
							|  |  |  | 		return { | 
					
						
							|  |  |  | 			createHash: () => createHash("md4"), | 
					
						
							|  |  |  | 			createReferenceHash: createMd4Hash, | 
					
						
							|  |  |  | 			regExp: /^[0-9a-f]{32}$/ | 
					
						
							|  |  |  | 		}; | 
					
						
							| 
									
										
										
										
											2021-10-26 00:13:49 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | for (const name of Object.keys(wasmHashes)) { | 
					
						
							|  |  |  | 	const { createHash, createReferenceHash, regExp } = wasmHashes[name](); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	describe(name, () => { | 
					
						
							|  |  |  | 		const sizes = [ | 
					
						
							|  |  |  | 			1, | 
					
						
							|  |  |  | 			2, | 
					
						
							|  |  |  | 			3, | 
					
						
							|  |  |  | 			4, | 
					
						
							|  |  |  | 			5, | 
					
						
							|  |  |  | 			7, | 
					
						
							|  |  |  | 			8, | 
					
						
							|  |  |  | 			9, | 
					
						
							|  |  |  | 			16, | 
					
						
							|  |  |  | 			31, | 
					
						
							|  |  |  | 			32, | 
					
						
							|  |  |  | 			33, | 
					
						
							|  |  |  | 			64 - 10, | 
					
						
							|  |  |  | 			64 - 9, | 
					
						
							|  |  |  | 			64 - 8, | 
					
						
							|  |  |  | 			63, | 
					
						
							|  |  |  | 			64, | 
					
						
							|  |  |  | 			65, | 
					
						
							|  |  |  | 			100, | 
					
						
							|  |  |  | 			1000, | 
					
						
							|  |  |  | 			65536 - 1, | 
					
						
							|  |  |  | 			65536, | 
					
						
							|  |  |  | 			65536 + 1, | 
					
						
							|  |  |  | 			65536 + 31, | 
					
						
							|  |  |  | 			65536 * 5, | 
					
						
							|  |  |  | 			65536 * 7 - 1, | 
					
						
							|  |  |  | 			65536 * 9 + 31 | 
					
						
							|  |  |  | 		]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		const test = (name, sizes) => { | 
					
						
							|  |  |  | 			it(name + " should generate a hash from binary data", async () => { | 
					
						
							|  |  |  | 				const hash = createHash(); | 
					
						
							|  |  |  | 				const hashString = createHash(); | 
					
						
							|  |  |  | 				const reference = await createReferenceHash(); | 
					
						
							|  |  |  | 				for (const size of sizes) { | 
					
						
							|  |  |  | 					const bytes = randomBytes(size); | 
					
						
							|  |  |  | 					const string = bytes.toString("base64"); | 
					
						
							|  |  |  | 					hash.update(bytes); | 
					
						
							|  |  |  | 					hashString.update(string, "base64"); | 
					
						
							|  |  |  | 					reference.update(bytes); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				const result = hash.digest("hex"); | 
					
						
							|  |  |  | 				expect(result).toMatch(regExp); | 
					
						
							|  |  |  | 				const resultFromString = hashString.digest("hex"); | 
					
						
							|  |  |  | 				expect(resultFromString).toMatch(regExp); | 
					
						
							|  |  |  | 				const expected = reference.digest("hex"); | 
					
						
							|  |  |  | 				expect(result).toBe(expected); | 
					
						
							|  |  |  | 				expect(resultFromString).toBe(expected); | 
					
						
							|  |  |  | 			}); | 
					
						
							|  |  |  | 		}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		test("empty hash", []); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		for (const size of sizes) { | 
					
						
							|  |  |  | 			test(`single update ${size} bytes`, [size]); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		for (const size1 of sizes) { | 
					
						
							|  |  |  | 			for (const size2 of sizes) { | 
					
						
							|  |  |  | 				test(`two updates ${size1} + ${size2} bytes`, [size1, size2]); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		test(`many updates 1`, sizes); | 
					
						
							|  |  |  | 		test(`many updates 2`, sizes.slice().reverse()); | 
					
						
							|  |  |  | 		test(`many updates 3`, sizes.concat(sizes.slice().reverse())); | 
					
						
							|  |  |  | 		test(`many updates 4`, sizes.slice().reverse().concat(sizes)); | 
					
						
							| 
									
										
										
										
											2021-11-04 16:42:27 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		const unicodeTest = (name, codePoints) => { | 
					
						
							|  |  |  | 			it(name + " should hash unicode chars correctly", async () => { | 
					
						
							|  |  |  | 				const hash = createHash(); | 
					
						
							|  |  |  | 				const reference = await createReferenceHash(); | 
					
						
							|  |  |  | 				const str = | 
					
						
							|  |  |  | 					typeof codePoints === "string" | 
					
						
							|  |  |  | 						? codePoints | 
					
						
							|  |  |  | 						: String.fromCodePoint(...codePoints); | 
					
						
							|  |  |  | 				hash.update(str); | 
					
						
							|  |  |  | 				reference.update(str); | 
					
						
							|  |  |  | 				const result = hash.digest("hex"); | 
					
						
							|  |  |  | 				expect(result).toMatch(regExp); | 
					
						
							|  |  |  | 				const expected = reference.digest("hex"); | 
					
						
							|  |  |  | 				expect(result).toBe(expected); | 
					
						
							|  |  |  | 			}); | 
					
						
							|  |  |  | 		}; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-13 05:57:14 +08:00
										 |  |  | 		const unicodeRangeTest = (name, start, end) => { | 
					
						
							| 
									
										
										
										
											2021-11-04 16:42:27 +08:00
										 |  |  | 			const codePoints = []; | 
					
						
							|  |  |  | 			for (let i = start; i <= end; i++) { | 
					
						
							|  |  |  | 				codePoints.push(i); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			unicodeTest(name, codePoints); | 
					
						
							|  |  |  | 		}; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-18 17:38:06 +08:00
										 |  |  | 		// cspell:word Thaana
 | 
					
						
							| 
									
										
										
										
											2021-12-13 05:57:14 +08:00
										 |  |  | 		unicodeRangeTest("Latin-1 Supplement", 0xa0, 0xff); | 
					
						
							|  |  |  | 		unicodeRangeTest("Latin Extended", 0x100, 0x24f); | 
					
						
							|  |  |  | 		unicodeRangeTest("Thaana", 0x780, 0x7bf); | 
					
						
							|  |  |  | 		unicodeRangeTest("Devanagari", 0x900, 0x97f); | 
					
						
							|  |  |  | 		unicodeRangeTest("Emoticons", 0x1f600, 0x1f64f); | 
					
						
							| 
									
										
										
										
											2021-11-04 16:42:27 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		unicodeTest("with zero char", "abc\0💩"); | 
					
						
							|  |  |  | 		unicodeTest("weird code point after long code point", [1497, 243248]); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		for (let i = 0; i < 1000; i++) { | 
					
						
							|  |  |  | 			const chars = Array.from({ length: 20 }, () => | 
					
						
							|  |  |  | 				Math.floor(Math.random() * 0x10ffff) | 
					
						
							|  |  |  | 			); | 
					
						
							|  |  |  | 			unicodeTest(`fuzzy ${JSON.stringify(chars)}`, chars); | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2021-10-26 00:13:49 +08:00
										 |  |  | 	}); | 
					
						
							|  |  |  | } |