Skip to content

Commit

Permalink
feat: add a new noble-based implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
ChALkeR committed Nov 15, 2024
1 parent 6514b6c commit b6e4850
Show file tree
Hide file tree
Showing 5 changed files with 150 additions and 53 deletions.
37 changes: 8 additions & 29 deletions browser.js
Original file line number Diff line number Diff line change
@@ -1,30 +1,9 @@
'use strict'
var inherits = require('inherits')
var MD5 = require('md5.js')
var RIPEMD160 = require('ripemd160')
var sha = require('sha.js')
var Base = require('cipher-base')

function Hash (hash) {
Base.call(this, 'digest')

this._hash = hash
}

inherits(Hash, Base)

Hash.prototype._update = function (data) {
this._hash.update(data)
}

Hash.prototype._final = function () {
return this._hash.digest()
}

module.exports = function createHash (alg) {
alg = alg.toLowerCase()
if (alg === 'md5') return new MD5()
if (alg === 'rmd160' || alg === 'ripemd160') return new RIPEMD160()

return new Hash(sha(alg))
if (typeof BigInt !== 'undefined') {
try {
module.exports = require('./browser.noble.js')
} catch (err) {
module.exports = require('./browser.old.js')
}
} else {
module.exports = require('./browser.old.js')
}
58 changes: 58 additions & 0 deletions browser.noble.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
'use strict'
var sha1 = require('@noble/hashes/sha1')
var ripemd160 = require('@noble/hashes/ripemd160')
var sha2 = require('@noble/hashes/sha2')
var sha3 = require('@noble/hashes/sha3')
var blake2b = require('@noble/hashes/blake2b')
var blake2s = require('@noble/hashes/blake2s')
var inherits = require('inherits')
var MD5 = require('md5.js')
var Base = require('cipher-base')

function Hash (hash) {
Base.call(this, 'digest')

this._hash = hash
}

inherits(Hash, Base)

Hash.prototype._update = function (data) {
this._hash.update(data)
}

Hash.prototype._final = function () {
return this._hash.digest()
}

const hashes = {
// Supported by browser.old.js
sha1: sha1.sha1,
sha224: sha2.sha224,
sha256: sha2.sha256,
sha384: sha2.sha384,
sha512: sha2.sha512,
ripemd160: ripemd160.ripemd160,
rmd160: ripemd160.ripemd160,

// Not supported by browser.old.js (until sha.js updates?)
'sha512-224': sha2.sha512_224, // for browser.old.js: https://github.com/browserify/sha.js/pull/67
'sha512-256': sha2.sha512_256, // for browser.old.js: https://github.com/browserify/sha.js/pull/67
'sha3-224': sha3.sha3_224,
'sha3-256': sha3.sha3_256,
'sha3-384': sha3.sha3_384,
'sha3-512': sha3.sha3_512,
blake2b512: blake2b.blake2b, // 512 is the default size
blake2s256: blake2s.blake2s // 256 is the default size
}

function getNobleHash (alg) {
if (Object.prototype.hasOwnProperty.call(hashes, alg)) return hashes[alg]
throw new Error('Digest method not supported')
}

module.exports = function createHash (alg) {
alg = alg.toLowerCase()
if (alg === 'md5') return new MD5()
return new Hash(getNobleHash(alg).create())
}
30 changes: 30 additions & 0 deletions browser.old.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
'use strict'
var inherits = require('inherits')
var MD5 = require('md5.js')
var RIPEMD160 = require('ripemd160')
var sha = require('sha.js')
var Base = require('cipher-base')

function Hash (hash) {
Base.call(this, 'digest')

this._hash = hash
}

inherits(Hash, Base)

Hash.prototype._update = function (data) {
this._hash.update(data)
}

Hash.prototype._final = function () {
return this._hash.digest()
}

module.exports = function createHash (alg) {
alg = alg.toLowerCase()
if (alg === 'md5') return new MD5()
if (alg === 'rmd160' || alg === 'ripemd160') return new RIPEMD160()

return new Hash(sha(alg))
}
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
"tape": "^4.6.3"
},
"dependencies": {
"@noble/hashes": "^1.3.3",
"cipher-base": "^1.0.1",
"inherits": "^2.0.1",
"md5.js": "^1.3.4",
Expand Down
77 changes: 53 additions & 24 deletions test.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,35 +7,64 @@ var vectors = require('hash-test-vectors')
vectors.forEach(function (vector) {
vector.ripemd160 = vector.rmd160
})
var createHash = require('./browser')

algorithms.forEach(function (algorithm) {
test('test ' + algorithm + ' against test vectors', function (t) {
vectors.forEach(function (obj, i) {
var input = Buffer.from(obj.input, 'base64')
var node = obj[algorithm]
var js = createHash(algorithm).update(input).digest('hex')
t.equal(js, node, algorithm + '(testVector[' + i + ']) == ' + node)
})
var createHashOld = require('./browser.old.js')
var createHashAuto = require('./browser.js')

var implementations = [createHashOld]
if (createHashAuto !== createHashOld) implementations.push(createHashAuto)

encodings.forEach(function (encoding) {
implementations.forEach(function (createHash) {
algorithms.forEach(function (algorithm) {
test('test ' + algorithm + ' against test vectors', function (t) {
vectors.forEach(function (obj, i) {
var input = Buffer.from(obj.input, 'base64').toString(encoding)
var input = Buffer.from(obj.input, 'base64')
var node = obj[algorithm]
var js = createHash(algorithm).update(input, encoding).digest('hex')
t.equal(js, node, algorithm + '(testVector[' + i + '], ' + encoding + ') == ' + node)
var js = createHash(algorithm).update(input).digest('hex')
t.equal(js, node, algorithm + '(testVector[' + i + ']) == ' + node)
})
})

vectors.forEach(function (obj, i) {
var input = Buffer.from(obj.input, 'base64')
var node = obj[algorithm]
var hash = createHash(algorithm)
hash.end(input)
var js = hash.read().toString('hex')
t.equal(js, node, algorithm + '(testVector[' + i + ']) == ' + node)
})
encodings.forEach(function (encoding) {
vectors.forEach(function (obj, i) {
var input = Buffer.from(obj.input, 'base64').toString(encoding)
var node = obj[algorithm]
var js = createHash(algorithm).update(input, encoding).digest('hex')
t.equal(js, node, algorithm + '(testVector[' + i + '], ' + encoding + ') == ' + node)
})
})

vectors.forEach(function (obj, i) {
var input = Buffer.from(obj.input, 'base64')
var node = obj[algorithm]
var hash = createHash(algorithm)
hash.end(input)
var js = hash.read().toString('hex')
t.equal(js, node, algorithm + '(testVector[' + i + ']) == ' + node)
})

t.end()
t.end()
})
})
})

var createHashNode = require('crypto').createHash
var randomBytes = require('crypto').randomBytes

function crossTest (createHashTest, createHashBase, algorithms) {
var data = randomBytes(32)
algorithms.forEach(function (algorithm) {
test('test ' + algorithm + ' against base implementation', function (t) {
var a = createHashTest(algorithm).update(data).digest('hex')
var b = createHashBase(algorithm).update(data).digest('hex')
t.equal(a, b, algorithm + ' ' + a + ' == ' + b)
t.end()
})
})
}

var baseHashes = ['sha1', 'sha224', 'sha256', 'sha384', 'sha512', 'ripemd160', 'rmd160']
var extraHashes = ['sha512-224', 'sha512-256', 'sha3-224', 'sha3-256', 'sha3-384', 'sha3-512', 'blake2b512', 'blake2s256']

crossTest(createHashOld, createHashNode, baseHashes)

// Only new version supports additional hashes
if (createHashAuto !== createHashOld) crossTest(createHashAuto, createHashNode, extraHashes)

0 comments on commit b6e4850

Please sign in to comment.