хуйу нас не матерятся
Понадобилась мне хэш функция, для получения контрольной суммы большийх файлов. И в процессе размышления, что же взять, решил запилить тест и сравнить что и как работает.
Сравнивать будем стандартные sha1, md5, sha256, crc32 функции, на ноде v14.16.0
Так как crc32 не реализована в стандартной нодовской crypto, для сравнения я возьму sse4_crc32 и, конечно её же жс реализацию crc32.
Исходние теста:
const fs = require('fs');
const md5 = require('md5');
const crc32 = require('crc32');
const crypto = require('crypto');
const sse4Crc32 = require('sse4_crc32');
const __raunds = 1000;
function md5native(buf) {
const hash = crypto.createHash('md5');
hash.update(buf);
return hash.digest('hex');
}
function sha256(buf) {
const hash = crypto.createHash('sha256');
hash.update(buf);
return hash.digest('hex');
}
function sha1native(buf) {
const hash = crypto.createHash('sha1');
hash.update(buf);
return hash.digest('hex');
}
function main() {
let testData = fs.readFileSync('./package-lock.json');
//let testData = fs.readFileSync('./15481716168180.webm');
// asm/c++/native libs
console.log('asm/c++/native libs');
let start2 = new Date();
for(let r=0; r<__raunds; r++) {
let res = sse4Crc32.calculate(testData);
}
console.log(new Date(), 'sse4 crc32:', (new Date) - start2);
let start4 = new Date();
for(let r=0; r<__raunds; r++) {
let res = sha256(testData);
}
console.log(new Date(), 'sha256:', (new Date) - start4);
let start5 = new Date();
for(let r=0; r<__raunds; r++) {
let res = md5native(testData);
}
console.log(new Date(), 'md5native:', (new Date) - start5);
let start6 = new Date();
for(let r=0; r<__raunds; r++) {
let res = sha1native(testData);
}
console.log(new Date(), 'sha1native:', (new Date) - start6);
// js libs
console.log('js libs');
let start1 = new Date();
for(let r=0; r<__raunds; r++) {
let res = crc32(testData);
}
console.log(new Date(), 'simple crc32:', (new Date) - start1);
let start3 = new Date();
for(let r=0; r<__raunds; r++) {
let res = md5(testData);
}
console.log(new Date(), 'md5:', (new Date) - start3);
}
main();
Первый тест провожу на файле 150кб и 1000 раундов, результат:
Второй файл 14Мб и 10 раундов, результат:
Даже самая простая crc32 реализованная на js работает в 2 раза медленнее чем криптостойкая sha256 реализованная на c++/asm. md5 реализованная на js оказалась на столько ужастной, что просто прибивалась операционной системой из-за непомерных расходов ресурсов.
Очень помогла статья. Так как требовалось в CodeWars написать функцию-хеширования с алгоритмом md5, нативными средствами Node js. То есть: npm install md5 - не вариант.
Вполне возможно, что биндинги из crypto в ноде не использует simd. Точного подверждения по исходникам ноды я не нашёл (но глубоко не копал). Поэтому если найти сторонние биндинги и компилировать под определенный процессор, то будет быстрей. Хотя если так заморачиваться то лучше уже ноду не брать :)
Могу точно сказать про парсинг hex в Buffer, за столько лет там всё ещё не появилась более эффективная реализация с avx2: https://github.com/zbjornson/fast-hex Вроде видел пулл реквест с предложением, но его отконили и найти не могу =(
md5/sha2 на жс будет быстрей если входной размер очень маленький (например меньше размера блока), в этом случае время переключения на нативный код просто больше чем выигрыш от операций на сгенерированном коде.