Skip to content

Commit 96d9570

Browse files
committed
Optimize WebCrypto bytes to hex conversion.
- Improvement depends on number of digests performed. - Browser: - Precompute a byte-to-hex table. - ~4-9% improvement overall using improved algorithm in Node.js. - Browsers should see similar speedup. Node.js normally will use the method below. - Node.js: - Use native `Buffer.from(...).toString('hex')` conversion. - ~5-12% improvement overall. - The non-WebCrypto MessageDigest on Node.js is still faster.
1 parent 578ae23 commit 96d9570

File tree

4 files changed

+26
-9
lines changed

4 files changed

+26
-9
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@
1717
- Refactor `MessageDigest-browser.js` to `MessageDigest-webcrypto.js` so it can
1818
also be optionally used with Node.js.
1919
- Move platform specific support into `platform.js` and `platform-browser.js`.
20+
- Optimize WebCrypto bytes to hex conversion:
21+
- Improvement depends on number of digests performed.
22+
- Node.js using the improved browser algorithm can be ~4-9% faster overall.
23+
- Node.js native `Buffer` conversion can be ~5-12% faster overall.
2024

2125
### Fixed
2226
- Disable native lib tests in a browser.

lib/MessageDigest-webcrypto.js

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
*/
44
'use strict';
55

6-
const {crypto} = require('./platform');
6+
const {bufferToHex, crypto} = require('./platform');
77

88
module.exports = class MessageDigest {
99
/**
@@ -31,13 +31,7 @@ module.exports = class MessageDigest {
3131

3232
async digest() {
3333
const data = new TextEncoder().encode(this._content);
34-
const buffer = new Uint8Array(
35-
await crypto.subtle.digest(this.algorithm, data));
36-
// return digest in hex
37-
let hex = '';
38-
for(let i = 0; i < buffer.length; ++i) {
39-
hex += buffer[i].toString(16).padStart(2, '0');
40-
}
41-
return hex;
34+
const buffer = await crypto.subtle.digest(this.algorithm, data);
35+
return bufferToHex(buffer);
4236
}
4337
};

lib/platform-browser.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,18 @@ exports.setImmediate = setImmediate;
99

1010
// WebCrypto
1111
exports.crypto = globalThis.crypto;
12+
13+
// precompute byte to hex table
14+
const byteToHex = [];
15+
for(let n = 0; n <= 0xff; ++n) {
16+
byteToHex.push(n.toString(16).padStart(2, '0'));
17+
}
18+
19+
exports.bufferToHex = function bufferToHex(buffer) {
20+
let hex = '';
21+
const bytes = new Uint8Array(buffer);
22+
for(let i = 0; i < bytes.length; ++i) {
23+
hex += byteToHex[bytes[i]];
24+
}
25+
return hex;
26+
};

lib/platform.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,7 @@ exports.setImmediate = setImmediate;
88
// WebCrypto
99
const crypto = require('node:crypto');
1010
exports.crypto = crypto.webcrypto;
11+
12+
exports.bufferToHex = function bufferToHex(buffer) {
13+
return Buffer.from(buffer).toString('hex');
14+
};

0 commit comments

Comments
 (0)