Created
April 18, 2024 15:46
-
-
Save antony-scott/02b1549e1cb66ddbe5315096137e2ff0 to your computer and use it in GitHub Desktop.
Hashing using Crypto.subtle.digest
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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