Skip to content

Commit

Permalink
[sha256] perf updates and benchmarks
Browse files Browse the repository at this point in the history
  • Loading branch information
dmonad committed Jul 12, 2023
1 parent 6a18123 commit 20a94c4
Show file tree
Hide file tree
Showing 5 changed files with 78 additions and 40 deletions.
12 changes: 7 additions & 5 deletions hash/sha256.fallback.js
Expand Up @@ -110,16 +110,18 @@ export const hash = data => {
}
// write length of message (size in bits) as 64 bit uint
// @todo test that this works correctly
W[14] = math.round(data.byteLength / binary.BIT29)
W[14] = math.round(data.byteLength / binary.BIT30)
W[15] = data.byteLength * 8
updateHash(H, W, K)
// correct H endianness and return a Uint8Array view
const dv = new DataView(H.buffer)
const dv = new Uint8Array(H.buffer)
for (let i = 0; i < H.length; i++) {
dv.setUint32(i * 4, H[i], false)
const h = H[i]
for (let ci = 0; ci < 4; ci++) {
dv[i * 4 + ci] = h >>> (3 - ci) * 8
}
}
// logState(H)
return new Uint8Array(H.buffer)
return dv
}

/**
Expand Down
101 changes: 68 additions & 33 deletions hash/sha256.test.js
Expand Up @@ -6,6 +6,9 @@ import * as prng from '../prng.js'
import * as webcrypto from 'lib0/webcrypto'
import * as promise from '../promise.js'
import * as env from '../environment.js'
import * as array from '../array.js'
import * as binary from '../binary.js'
import * as f from '../function.js'

/**
* @param {t.TestCase} _tc
Expand All @@ -30,12 +33,39 @@ export const testSha256Basics = async _tc => {
await test('', 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855')
}

/**
* Test if implementation is correct when length (in bits) exceeds uint32.
*
* @param {t.TestCase} _tc
*/
export const testLargeValue = async _tc => {
t.skip(!t.extensive)
const BS = binary.BIT30
const data = prng.uint8Array(prng.create(42), BS)
let resNode = buffer.fromBase64('WZK5ZK68FVhGoTXZY0XrU9wcfTHsqmJZukf1ULEAD+s=')
let resLib0
t.measureTime(`[lib0] Hash message of size ${BS}`, () => {
resLib0 = sha256.hash(data)
})
if (env.isNode) {
const sha256Node = await import('./sha256.node.js')
t.measureTime(`[node] Hash message of size ${BS}`, () => {
const res = new Uint8Array(sha256Node.hash(data))
if (!f.equalityDeep(res, resNode)) {
console.warn(`Precomputed result should be the same! New result: ${buffer.toBase64(res)}`)
}
resNode = res
t.compare(res, resNode, 'Precomputed result should be the same')
})
}
t.compare(resLib0, resNode)
}

/**
* @param {t.TestCase} tc
*/
export const testRepeatSha256Hashing = async tc => {
const LEN = prng.bool(tc.prng) ? prng.uint32(tc.prng, 0, 512) : prng.uint32(tc.prng, 0, 3003030)
console.log(LEN)
const data = prng.uint8Array(tc.prng, LEN)
const hashedCustom = sha256.hash(data)
const hashedWebcrypto = new Uint8Array(await webcrypto.subtle.digest('SHA-256', data))
Expand All @@ -46,47 +76,52 @@ export const testRepeatSha256Hashing = async tc => {
* @param {t.TestCase} _tc
*/
export const testBenchmarkSha256 = async _tc => {
const N = 100 * 1000
const BS = 500
/**
* @type {Array<Uint8Array>}
* @param {number} N
* @param {number} BS
*/
const datas = []
for (let i = 0; i < N; i++) {
const data = new Uint8Array(BS)
webcrypto.getRandomValues(data)
datas.push(data)
}
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}`, () => {
const bench = (N, BS) => t.groupAsync(`Hash ${N} random values of size ${BS}`, async () => {
const gen = prng.create(42)
const datas = array.unfold(N, () => prng.uint8Array(gen, BS))
t.measureTime('lib0 (fallback))', () => {
for (let i = 0; i < N; i++) {
const x = nodeSha.hash(datas[i])
const x = sha256.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])
if (x === null) throw new Error()
if (env.isNode) {
const nodeSha = await import('./sha256.node.js')
t.measureTime('lib0 (node))', () => {
for (let i = 0; i < N; i++) {
const x = nodeSha.hash(datas[i])
if (x === null) throw new Error()
}
})
}
})
t.measureTime(`[webcrypto concurrent] Time to hash ${N} random values of size ${BS}`, async () => {
await t.measureTimeAsync('webcrypto sequentially', async () => {
for (let i = 0; i < N; i++) {
const x = await webcrypto.subtle.digest('SHA-256', datas[i])
if (x === null) throw new Error()
}
})
await t.measureTimeAsync('webcrypto concurrent', async () => {
/**
* @type {Array<Promise<any>>}
*/
const ps = []
for (let i = 0; i < N; i++) {
ps.push(webcrypto.subtle.digest('SHA-256', datas[i]))
}
const x = await promise.all(ps)
if (x === null) throw new Error()
const ps = []
for (let i = 0; i < N; i++) {
ps.push(webcrypto.subtle.digest('SHA-256', datas[i]))
}
const x = await promise.all(ps)
if (x === null) throw new Error()
})
})
await bench(10 * 1000, 10)
await bench(10 * 1000, 50)
t.skip(!t.extensive)
await bench(10 * 1000, 100)
await bench(10 * 1000, 500)
await bench(10 * 1000, 1000)
await bench(10 * 1000, 4098)
await bench(10, 5 * 1000 * 1000)
}
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Expand Up @@ -110,7 +110,7 @@
"default": "./hash/sha256.node.js"
},
"default": {
"module": "./hash/sha256.fallback.js"
"module": "./hash/sha256.fallback.js",
"require": "./dist/sha256.fallback.cjs",
"default": "./hash/sha256.fallback.js"
}
Expand Down
1 change: 1 addition & 0 deletions test.html
Expand Up @@ -33,6 +33,7 @@
"lib0/crypto/ecdsa": "./crypto/ecdsa.js",
"lib0/crypto/rsa-oaep": "./crypto/rsa-oaep.js",
"lib0/hash/rabin": "./hash/rabin.js",
"lib0/hash/sha256": "./hash/sha256.fallback.js",
"lib0/decoding.js": "./decoding.js",
"lib0/dist/decoding.cjs": "./dist/decoding.cjs",
"lib0/decoding": "./decoding.js",
Expand Down

0 comments on commit 20a94c4

Please sign in to comment.