Skip to content

Instantly share code, notes, and snippets.

@antony-scott
Created April 18, 2024 15:46
Show Gist options
  • Save antony-scott/02b1549e1cb66ddbe5315096137e2ff0 to your computer and use it in GitHub Desktop.
Save antony-scott/02b1549e1cb66ddbe5315096137e2ff0 to your computer and use it in GitHub Desktop.
Hashing using Crypto.subtle.digest
const encoder = new TextEncoder();
// BITWISE OPERATIONS
const HexDigits = ['0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'];
function toHexString_BitwiseOperations(arrayBuffer: ArrayBuffer) {
const buffer = new Uint8Array(arrayBuffer);
const result = [];
for (let i=0; i<buffer.length; ++i) {
result.push(HexDigits[(buffer[i] >> 4) & 0x0F]);
result.push(HexDigits[buffer[i] & 0x0F]);
}
return result.join('');
}
async function generateHash(message: string) {
const encodedMessage = encoder.encode(message);
const hash = await crypto.subtle.digest("SHA-256", encodedMessage);
const hashString = toHexString_BitwiseOperations(hash);
return hashString;
}
// MAPPING
function toHexString_Map(arrayBuffer: ArrayBuffer) {
return Array.from(new Uint8Array(arrayBuffer))
.map((b) => b.toString(16).padStart(2, '0'))
.join('');
}
async function generateHash2(message: string) {
const encodedMessage = encoder.encode(message);
const hash = await crypto.subtle.digest("SHA-256", encodedMessage);
const hashString = toHexString_Map(hash);
return hashString;
}
// TYPESCRIPT INTERFACES
interface Fact {
name: string;
value: string;
id: number;
}
interface Input {
facts: Fact[]
}
const input1: Input = {
facts: [
{
name: "fact1",
value: "value1",
id: 1
},
{
name: "fact2",
value: "value2",
id: 2
}
]
};
const input2: Input = {
facts: [
{
name: "fact2",
value: "value2",
id: 2
},
{
name: "fact1",
value: "value1",
id: 1
}
]
};
function sortedInput(input: Input) {
return {
facts: input.facts.sort((a,b) => {
const left = `${a.name}-${a.id}`;
const right = `${b.name}-${b.id}`;
return left.localeCompare(right);
})
}
}
async function doHash(input: Input, strategy: number) {
const startTime = performance.now();
const json = JSON.stringify(sortedInput(input));
let hash: string = '';
for (let i=0; i<100_000; ++i) {
hash = strategy === 1
? await generateHash(json)
: await generateHash2(json);
}
const endTime = performance.now();
const elapsedTime = endTime - startTime;
return {
hash,
elapsedTime
};
}
// MAIN
(async () => {
console.clear();
const result_1 = await doHash(input1, 1);
console.log(`hash = ${result_1.hash}\n${result_1.elapsedTime}ms\ninput1 (using bitwise based toHexString function)`);
const result_2 = await doHash(input2, 1);
console.log(`hash = ${result_2.hash}\n${result_2.elapsedTime}ms\ninput2 (using bitwise based toHexString function)`);
const result_3 = await doHash(input1, 2);
console.log(`hash = ${result_3.hash}\n${result_3.elapsedTime}ms)\ninput1 (using map based toHexString function)`);
const result_4 = await doHash(input2, 2);
console.log(`hash = ${result_4.hash}\n${result_4.elapsedTime}ms)\ninput2 (using map based toHexString function)`);
if (result_1.hash === result_2.hash &&
result_1.hash === result_3.hash &&
result_1.hash === result_4.hash) {
console.log("all hashes are the same 🎉");
}
console.log("That's all folks!")
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment