Как я выбирал nodejs хэш функцию, или почему не все йогурты одинаково полезны



Понадобилась мне хэш функция, для получения контрольной суммы большийх файлов. И в процессе размышления, что же взять, решил запилить тест и сравнить что и как работает.

Сравнивать будем стандартные 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 оказалась на столько ужастной, что просто прибивалась операционной системой из-за непомерных расходов ресурсов.


Сообщество: AWS

Комментариев(4)


ID: #682   Создан:
Автор: Кирилл

Вполне возможно, что биндинги из crypto в ноде не использует simd. Точного подверждения по исходникам ноды я не нашёл (но глубоко не копал). Поэтому если найти сторонние биндинги и компилировать под определенный процессор, то будет быстрей. Хотя если так заморачиваться то лучше уже ноду не брать :)

Могу точно сказать про парсинг hex в Buffer, за столько лет там всё ещё не появилась более эффективная реализация с avx2: https://github.com/zbjornson/fast-hex Вроде видел пулл реквест с предложением, но его отконили и найти не могу =(

md5/sha2 на жс будет быстрей если входной размер очень маленький (например меньше размера блока), в этом случае время переключения на нативный код просто больше чем выигрыш от операций на сгенерированном коде.

ID: #776   Создан:
Автор: anonym

dsa

ID: #801   Создан:
Автор: Tory

Очень помогла статья. Так как требовалось в CodeWars написать функцию-хеширования с алгоритмом md5, нативными средствами Node js. То есть: npm install md5 - не вариант.

ID: #802   Создан:
Автор: ololoev

>>801 Погоди, а помогла то как? Яж тут не описывал, как её, саму функцию составить?

Всего: 4 комментариев на 1 страницах

Ваш комментарий будет анонимным. Чтобы оставить не анонимный комментарий, пожалуйста, зарегистрируйтесь



Сообщества