Skip to content

md5 is faster than fnv1a #91

Open
Open
@Uzlopak

Description

@Uzlopak

Prerequisites

  • I have written a descriptive issue title
  • I have searched existing issues to ensure the issue has not already been raised

Issue

We use by default fnv1a for weak hashing. But md5 is faster than fnv1a

Here is a benchmark with an impememtation of the Java hashCode algorithm and crc32

'use strict'

const crc32 = require('crc-32').buf
const crypto = require('crypto')
const benchmark = require('benchmark')

const LoremString = 'Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim. Donec pede justo, fringilla vel, aliquet nec, vulputate eget, arcu. In enim justo, rhoncus ut, imperdiet a, venenatis vitae, justo. Nullam dictum felis eu pede mollis pretium. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim. Donec pede justo, fringilla vel, aliquet nec, vulputate eget, arcu. In enim justo, rhoncus ut, imperdiet a, venenatis vitae, justo. Nullam dictum felis eu pede mollis pretium. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim. Donec pede justo, fringilla vel, aliquet nec, vulputate eget, arcu. In enim justo, rhoncus ut, imperdiet a, venenatis vitae, justo. Nullam dictum felis eu pede mollis pretium.'
const LoremBuffer = Buffer.from(LoremString)

function hashCode (input) {
  let hash = 0
  let i = 0
  const il = input.length
  for (i = 0; i < il; ++i) {
    hash = (((hash << 5) - hash) + input[i]) & 0xFFFFFFFF
  }

  return hash >>> 0
}

const OFFSET_BASIS_32 = 2166136261

function fnv1a (buf) {
  let hash = OFFSET_BASIS_32

  for (let i = 0; i < buf.length;) {
    hash ^= buf[i++]

    // 32-bit FNV prime: 2**24 + 2**8 + 0x93 = 16777619
    // Using bitshift for accuracy and performance. Numbers in JS suck.
    hash += (hash << 1) + (hash << 4) + (hash << 7) + (hash << 8) + (hash << 24)
  }

  return hash >>> 0
}

new benchmark.Suite()
  .add('crc32', function () {
    crc32(LoremBuffer) >>> 0
  }, { minSamples: 100 })
  .add('md5', function () {
    crypto.createHash('md5').update(LoremBuffer).digest().toString('base64')
  }, { minSamples: 100 })
  .add('hashCode', function () {
    hashCode(LoremBuffer)
  }, { minSamples: 100 })
  .add('fnv1a', function () {
   fnv1a(LoremBuffer)
  }, { minSamples: 100 })
  .on('cycle', function onCycle(event) { console.log(String(event.target)) })
  .run()

result:

node benchmarks/weakHash.js

crc32 x 1,314,889 ops/sec ±0.19% (195 runs sampled)
md5 x 293,537 ops/sec ±2.10% (175 runs sampled)
hashCode x 1,019,507 ops/sec ±0.40% (190 runs sampled)
fnv1a x 154,034 ops/sec ±0.11% (195 runs sampled)

Metadata

Metadata

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions