From 6a18123fec67ad54e26ea77ef8e63e67a4b17cb9 Mon Sep 17 00:00:00 2001 From: Kevin Jahns Date: Wed, 12 Jul 2023 01:16:26 +0200 Subject: [PATCH] [sha256] add node native fallback --- hash/{sha256.js => sha256.fallback.js} | 79 +++++++++++--------------- hash/sha256.node.js | 10 ++++ hash/sha256.test.js | 14 ++++- package.json | 12 ++++ 4 files changed, 67 insertions(+), 48 deletions(-) rename hash/{sha256.js => sha256.fallback.js} (93%) create mode 100644 hash/sha256.node.js diff --git a/hash/sha256.js b/hash/sha256.fallback.js similarity index 93% rename from hash/sha256.js rename to hash/sha256.fallback.js index 5984f1b..7ba8ade 100644 --- a/hash/sha256.js +++ b/hash/sha256.fallback.js @@ -8,6 +8,36 @@ import * as binary from '../binary.js' import * as math from '../math.js' +/** + * @param {number} w - a 32bit uint + * @param {number} shift + */ +const rotr = (w, shift) => (w >>> shift) | (w << (32 - shift)) + +/** + * Helper for SHA-224 & SHA-256. See 4.1.2. + * @param {number} x + */ +const sum0to256 = x => rotr(x, 2) ^ rotr(x, 13) ^ rotr(x, 22) + +/** + * Helper for SHA-224 & SHA-256. See 4.1.2. + * @param {number} x + */ +const sum1to256 = x => rotr(x, 6) ^ rotr(x, 11) ^ rotr(x, 25) + +/** + * Helper for SHA-224 & SHA-256. See 4.1.2. + * @param {number} x + */ +const sigma0to256 = x => rotr(x, 7) ^ rotr(x, 18) ^ x >>> 3 + +/** + * Helper for SHA-224 & SHA-256. See 4.1.2. + * @param {number} x + */ +const sigma1to256 = x => rotr(x, 17) ^ rotr(x, 19) ^ x >>> 10 + // @todo don't init these variables globally /** @@ -26,6 +56,7 @@ const K = new Uint32Array([ 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 ]) + /** * See 5.3.3. Initial hash value. * @@ -111,8 +142,8 @@ const updateHash = (H, W, K) => { let h = H[7] // Step 3 for (let t = 0; t < 64; t++) { - const T1 = (h + sum1to256(e) + ch(e, f, g) + K[t] + W[t]) >>> 0 - const T2 = (sum0to256(a) + maj(a, b, c)) >>> 0 + const T1 = (h + sum1to256(e) + ((e & f) ^ (~e & g)) + K[t] + W[t]) >>> 0 + const T2 = (sum0to256(a) + ((a & b) ^ (a & c) ^ (b & c))) >>> 0 h = g g = f f = e @@ -131,47 +162,3 @@ const updateHash = (H, W, K) => { H[6] += g H[7] += h } - -/** - * @param {number} x - * @param {number} y - * @param {number} z - */ -const ch = (x, y, z) => (x & y) ^ (~x & z) - -/** - * @param {number} x - * @param {number} y - * @param {number} z - */ -const maj = (x, y, z) => (x & y) ^ (x & z) ^ (y & z) - -/** - * @param {number} w - a 32bit uint - * @param {number} shift - */ -const rotr = (w, shift) => (w >>> shift) | (w << (32 - shift)) - -/** - * Helper for SHA-224 & SHA-256. See 4.1.2. - * @param {number} x - */ -const sum0to256 = x => rotr(x, 2) ^ rotr(x, 13) ^ rotr(x, 22) - -/** - * Helper for SHA-224 & SHA-256. See 4.1.2. - * @param {number} x - */ -const sum1to256 = x => rotr(x, 6) ^ rotr(x, 11) ^ rotr(x, 25) - -/** - * Helper for SHA-224 & SHA-256. See 4.1.2. - * @param {number} x - */ -const sigma0to256 = x => rotr(x, 7) ^ rotr(x, 18) ^ x >>> 3 - -/** - * Helper for SHA-224 & SHA-256. See 4.1.2. - * @param {number} x - */ -const sigma1to256 = x => rotr(x, 17) ^ rotr(x, 19) ^ x >>> 10 diff --git a/hash/sha256.node.js b/hash/sha256.node.js new file mode 100644 index 0000000..37e3d78 --- /dev/null +++ b/hash/sha256.node.js @@ -0,0 +1,10 @@ +import { createHash } from 'node:crypto' + +/** + * @param {Uint8Array} data + */ +export const hash = data => { + const hasher = createHash('sha256') + hasher.update(data) + return hasher.digest() +} diff --git a/hash/sha256.test.js b/hash/sha256.test.js index 056446e..78af201 100644 --- a/hash/sha256.test.js +++ b/hash/sha256.test.js @@ -1,10 +1,11 @@ import * as t from '../testing.js' -import * as sha256 from './sha256.js' +import * as sha256 from './sha256.fallback.js' import * as buffer from '../buffer.js' import * as string from '../string.js' import * as prng from '../prng.js' import * as webcrypto from 'lib0/webcrypto' import * as promise from '../promise.js' +import * as env from '../environment.js' /** * @param {t.TestCase} _tc @@ -56,12 +57,21 @@ export const testBenchmarkSha256 = async _tc => { webcrypto.getRandomValues(data) datas.push(data) } - t.measureTime(`[lib0] Time to hash ${N} random values of size ${BS}`, () => { + t.measureTime(`[lib0 (fallback))] Time to hash ${N} random values of size ${BS}`, () => { for (let i = 0; i < N; i++) { const x = sha256.hash(datas[i]) if (x === null) throw new Error() } }) + if (env.isNode) { + const nodeSha = await import('./sha256.node.js') + t.measureTime(`[lib0 (node))] Time to hash ${N} random values of size ${BS}`, () => { + for (let i = 0; i < N; i++) { + const x = nodeSha.hash(datas[i]) + if (x === null) throw new Error() + } + }) + } t.measureTime(`[webcrypto sequentially] Time to hash ${N} random values of size ${BS}`, async () => { for (let i = 0; i < N; i++) { const x = await webcrypto.subtle.digest('SHA-256', datas[i]) diff --git a/package.json b/package.json index c4be3d7..ce2b335 100644 --- a/package.json +++ b/package.json @@ -103,6 +103,18 @@ "import": "./hash/rabin.js", "require": "./dist/rabin.cjs" }, + "./hash/sha256": { + "types": "./hash/sha256.fallback.d.ts", + "node": { + "require": "./dist/sha256.node.cjs", + "default": "./hash/sha256.node.js" + }, + "default": { + "module": "./hash/sha256.fallback.js" + "require": "./dist/sha256.fallback.cjs", + "default": "./hash/sha256.fallback.js" + } + }, "./decoding.js": "./decoding.js", "./dist/decoding.cjs": "./dist/decoding.cjs", "./decoding": {