diff --git a/README.md b/README.md index 9df12006..981148c4 100644 --- a/README.md +++ b/README.md @@ -1,25 +1,25 @@ -# js-multihashing-async +# js-multihashing-async [![](https://img.shields.io/badge/made%20by-Protocol%20Labs-blue.svg?style=flat-square)](http://ipn.io) [![](https://img.shields.io/badge/project-multiformats-blue.svg?style=flat-square)](https://github.com/multiformats/multiformats) [![](https://img.shields.io/badge/freenode-%23ipfs-blue.svg?style=flat-square)](https://webchat.freenode.net/?channels=%23ipfs) [![Coverage Status](https://coveralls.io/repos/github/multiformats/js-multihashing-async/badge.svg?branch=master)](https://coveralls.io/github/multiformats/js-multihashing-async?branch=master) [![Travis CI](https://flat.badgen.net/travis/ipfs/js-multihashing-async)](https://travis-ci.com/ipfs/js-multihashing-async) -[![Dependency Status](https://david-dm.org/multiformats/js-multihashing-async.svg?style=flat-square)](https://david-dm.org/multiformats/js-multihashing-async) +[![Dependency Status](https://david-dm.org/multiformats/js-multihashing-async.svg?style=flat-square)](https://david-dm.org/multiformats/js-multihashing-async) [![js-standard-style](https://img.shields.io/badge/code%20style-standard-brightgreen.svg?style=flat-square)](https://github.com/feross/standard) [![](https://img.shields.io/badge/readme%20style-standard-brightgreen.svg?style=flat-square)](https://github.com/RichardLitt/standard-readme) > Use all the functions in [multihash](https://github.com/multiformats/multihash). -## Lead Maintainer +## Lead Maintainer [Hugo Dias](https://github.com/hugomrdias) -### Notice -> This module is moving to async/await starting from 0.7.0. +### Notice +> This module is moving to async/await starting from 0.7.0. > The last minor version to support callbacks is 0.6.0, any backports will merged to the branch `callbacks` and released under `>0.6.0 <0.7.0`. -#### Wait, why, how is this different from Node `crypto`? +#### Wait, why, how is this different from Node `crypto`? This module just makes working with multihashes a bit nicer. [js-multihash](//github.com/multiformats/js-multihash) is only for @@ -29,21 +29,18 @@ It currently uses `crypto` and [`sha3`](https://github.com/phusion/node-sha3) in In the browser [`webcrypto`](https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto) and [`browserify-sha3`](https://github.com/wanderer/browserify-sha3) are used. -## Table of Contents - -* [Table of Contents](#table-of-contents) -* [Install](#install) - + [In Node.js through npm](#in-nodejs-through-npm) - + [Use in a browser with browserify, webpack or any other bundler](#use-in-a-browser-with-browserify-webpack-or-any-other-bundler) - + [Use in a browser Using a script tag](#use-in-a-browser-using-a-script-tag) - - [Gotchas](#gotchas) -* [Usage](#usage) -* [Examples](#examples) - + [Multihash output](#multihash-output) -* [API](#api) -* [Maintainers](#maintainers) -* [Contribute](#contribute) -* [License](#license) +## Table of Contents + +- [Install](#install) + - [In Node.js through npm](#in-nodejs-through-npm) + - [Use in a browser with browserify, webpack or any other bundler](#use-in-a-browser-with-browserify-webpack-or-any-other-bundler) + - [Use in a browser Using a script tag](#use-in-a-browser-using-a-script-tag) +- [Usage](#usage) +- [Examples](#examples) + - [Multihash output](#multihash-output) +- [API](#api) +- [Contribute](#contribute) +- [License](#license) ## Install @@ -78,24 +75,20 @@ available in the global namespace. ``` -#### Gotchas - -You will need to use Node.js `Buffer` API compatible, if you are running inside the browser, you can access it by `multihashing.Buffer` or you can install Feross's [Buffer](https://github.com/feross/buffer). - ## Usage ```js const multihashing = require('multihashing-async') -const buf = Buffer.from('beep boop') +const bytes = new TextEncoder().encode('beep boop') -const mh = await multihashing(buf, 'sha1') +const mh = await multihashing(bytes, 'sha1') // Use `.digest(...)` if you want only the hash digest (drops the prefix indicating the hash type). -const digest = await multihashing.digest(buf, 'sha1') +const digest = await multihashing.digest(bytes, 'sha1') // Use `.createHash(...)` for the raw hash functions const hash = multihashing.createHash('sha1') -const digest = await hash(buf) +const digest = await hash(bytes) ``` ## Examples @@ -104,19 +97,19 @@ const digest = await hash(buf) ```js const multihashing = require('multihashing-async') -const buf = Buffer.from('beep boop') +const bytes = new TextEncoder().encode('beep boop') -const mh = await multihashing(buf, 'sha1') +const mh = await multihashing(bytes, 'sha1') console.log(mh) -// => +// => -const mh = await multihashing(buf, 'sha2-256') +const mh = await multihashing(bytes, 'sha2-256') console.log(mh) -// => +// => -const mh = await multihashing(buf, 'sha2-512') +const mh = await multihashing(bytes, 'sha2-512') console.log(mh) -// => +// => ``` ## API diff --git a/benchmarks/hash.js b/benchmarks/hash.js index c9e166d4..8a1d7496 100644 --- a/benchmarks/hash.js +++ b/benchmarks/hash.js @@ -31,7 +31,7 @@ const algs = [ algs.forEach((alg) => { suite.add(alg, async function (d) { - const buf = Buffer.alloc(10 * 1024) + const buf = new Uint8Array(10 * 1024) buf.fill(Math.ceil(Math.random() * 100)) const res = await multihashing(buf, alg) list.push(res) diff --git a/example.js b/example.js index 77bbcba3..59ea8377 100644 --- a/example.js +++ b/example.js @@ -1,7 +1,7 @@ 'use strict' const multihashing = require('multihashing-async') -const buf = Buffer.from('beep boop') +const bytes = new TextEncoder().encode('beep boop') function print (err, mh) { if (err) { @@ -10,11 +10,11 @@ function print (err, mh) { // eslint-disable-next-line console.log(mh) } -multihashing(buf, 'sha1', print) -// => +multihashing(bytes, 'sha1', print) +// => -multihashing(buf, 'sha2-256', print) -// => +multihashing(bytes, 'sha2-256', print) +// => -multihashing(buf, 'sha2-512', print) -// => +multihashing(bytes, 'sha2-512', print) +// => diff --git a/package.json b/package.json index fb704f4f..15ed0f6e 100644 --- a/package.json +++ b/package.json @@ -35,17 +35,15 @@ }, "dependencies": { "blakejs": "^1.1.0", - "buffer": "^5.4.3", "err-code": "^2.0.0", "js-sha3": "^0.8.0", - "multihashes": "^1.0.1", - "murmurhash3js-revisited": "^3.0.0" + "multihashes": "^2.0.0", + "murmurhash3js-revisited": "^3.0.0", + "uint8arrays": "^1.0.0" }, "devDependencies": { "aegir": "^25.0.0", "benchmark": "^2.1.4", - "chai": "^4.1.2", - "dirty-chai": "^2.0.1", "sinon": "^9.0.2" }, "engines": { diff --git a/src/blake.js b/src/blake.js index 3c5bfaaf..4b433056 100644 --- a/src/blake.js +++ b/src/blake.js @@ -1,6 +1,5 @@ 'use strict' -const { Buffer } = require('buffer') const blake = require('blakejs') const minB = 0xb201 @@ -25,7 +24,7 @@ const blake2s = { const makeB2Hash = (size, hf) => async (data) => { const ctx = hf.init(size, null) hf.update(ctx, data) - return Buffer.from(hf.digest(ctx)) + return hf.digest(ctx) } module.exports = (table) => { diff --git a/src/crypto.js b/src/crypto.js index c53674ce..f35aefec 100644 --- a/src/crypto.js +++ b/src/crypto.js @@ -1,10 +1,10 @@ 'use strict' -const { Buffer } = require('buffer') const sha3 = require('js-sha3') const mur = require('murmurhash3js-revisited') const { factory: sha } = require('./sha') const { fromNumberTo32BitBuf } = require('./utils') +const uint8ArrayFromString = require('uint8arrays/from-string') // Note that although this function doesn't do any asynchronous work, we mark // the function as async because it must return a Promise to match the API @@ -13,27 +13,27 @@ const { fromNumberTo32BitBuf } = require('./utils') const hash = (algorithm) => async (data) => { switch (algorithm) { case 'sha3-224': - return Buffer.from(sha3.sha3_224.arrayBuffer(data)) + return new Uint8Array(sha3.sha3_224.arrayBuffer(data)) case 'sha3-256': - return Buffer.from(sha3.sha3_256.arrayBuffer(data)) + return new Uint8Array(sha3.sha3_256.arrayBuffer(data)) case 'sha3-384': - return Buffer.from(sha3.sha3_384.arrayBuffer(data)) + return new Uint8Array(sha3.sha3_384.arrayBuffer(data)) case 'sha3-512': - return Buffer.from(sha3.sha3_512.arrayBuffer(data)) + return new Uint8Array(sha3.sha3_512.arrayBuffer(data)) case 'shake-128': - return Buffer.from(sha3.shake128.create(128).update(data).arrayBuffer()) + return new Uint8Array(sha3.shake128.create(128).update(data).arrayBuffer()) case 'shake-256': - return Buffer.from(sha3.shake256.create(256).update(data).arrayBuffer()) + return new Uint8Array(sha3.shake256.create(256).update(data).arrayBuffer()) case 'keccak-224': - return Buffer.from(sha3.keccak224.arrayBuffer(data)) + return new Uint8Array(sha3.keccak224.arrayBuffer(data)) case 'keccak-256': - return Buffer.from(sha3.keccak256.arrayBuffer(data)) + return new Uint8Array(sha3.keccak256.arrayBuffer(data)) case 'keccak-384': - return Buffer.from(sha3.keccak384.arrayBuffer(data)) + return new Uint8Array(sha3.keccak384.arrayBuffer(data)) case 'keccak-512': - return Buffer.from(sha3.keccak512.arrayBuffer(data)) + return new Uint8Array(sha3.keccak512.arrayBuffer(data)) case 'murmur3-128': - return Buffer.from(mur.x64.hash128(data), 'hex') + return uint8ArrayFromString(mur.x64.hash128(data), 'base16') case 'murmur3-32': return fromNumberTo32BitBuf(mur.x86.hash32(data)) @@ -42,7 +42,7 @@ const hash = (algorithm) => async (data) => { } } -const identity = data => Buffer.from(data) +const identity = data => data module.exports = { identity, diff --git a/src/index.js b/src/index.js index 840dbc17..079ff8c5 100644 --- a/src/index.js +++ b/src/index.js @@ -1,39 +1,32 @@ 'use strict' -const { Buffer } = require('buffer') const errcode = require('err-code') const multihash = require('multihashes') const crypto = require('./crypto') +const equals = require('uint8arrays/equals') /** * Hash the given `buf` using the algorithm specified by `alg`. - * @param {Buffer} buf - The value to hash. + * @param {Uint8Array} buf - The value to hash. * @param {number|string} alg - The algorithm to use eg 'sha1' * @param {number} [length] - Optionally trim the result to this length. - * @returns {Promise} + * @returns {Promise} */ async function Multihashing (buf, alg, length) { const digest = await Multihashing.digest(buf, alg, length) return multihash.encode(digest, alg, length) } -/** - * The `buffer` module for easy use in the browser. - * - * @type {Buffer} - */ -Multihashing.Buffer = Buffer // for browser things - /** * Expose multihash itself, to avoid silly double requires. */ Multihashing.multihash = multihash /** - * @param {Buffer} buf - The value to hash. + * @param {Uint8Array} buf - The value to hash. * @param {number|string} alg - The algorithm to use eg 'sha1' * @param {number} [length] - Optionally trim the result to this length. - * @returns {Promise} + * @returns {Promise} */ Multihashing.digest = async (buf, alg, length) => { const hash = Multihashing.createHash(alg) @@ -108,7 +101,7 @@ crypto.addBlake(Multihashing.functions) Multihashing.validate = async (buf, hash) => { const newHash = await Multihashing(buf, multihash.decode(hash).name) - return Buffer.compare(hash, newHash) === 0 + return equals(hash, newHash) } module.exports = Multihashing diff --git a/src/sha.browser.js b/src/sha.browser.js index f9e548e5..ad4dac0a 100644 --- a/src/sha.browser.js +++ b/src/sha.browser.js @@ -1,7 +1,6 @@ /* eslint-disable require-await */ 'use strict' -const { Buffer } = require('buffer') const multihash = require('multihashes') const crypto = self.crypto || self.msCrypto @@ -14,14 +13,14 @@ const digest = async (data, alg) => { } switch (alg) { case 'sha1': - return Buffer.from(await crypto.subtle.digest({ name: 'SHA-1' }, data)) + return new Uint8Array(await crypto.subtle.digest({ name: 'SHA-1' }, data)) case 'sha2-256': - return Buffer.from(await crypto.subtle.digest({ name: 'SHA-256' }, data)) + return new Uint8Array(await crypto.subtle.digest({ name: 'SHA-256' }, data)) case 'sha2-512': - return Buffer.from(await crypto.subtle.digest({ name: 'SHA-512' }, data)) + return new Uint8Array(await crypto.subtle.digest({ name: 'SHA-512' }, data)) case 'dbl-sha2-256': { const d = await crypto.subtle.digest({ name: 'SHA-256' }, data) - return Buffer.from(await crypto.subtle.digest({ name: 'SHA-256' }, d)) + return new Uint8Array(await crypto.subtle.digest({ name: 'SHA-256' }, d)) } default: throw new Error(`${alg} is not a supported algorithm`) diff --git a/src/utils.js b/src/utils.js index 03415260..e8a65c5e 100644 --- a/src/utils.js +++ b/src/utils.js @@ -1,16 +1,14 @@ 'use strict' -const { Buffer } = require('buffer') - const fromNumberTo32BitBuf = (number) => { - const bytes = new Array(4) + const bytes = new Uint8Array(4) for (let i = 0; i < 4; i++) { bytes[i] = number & 0xff number = number >> 8 } - return Buffer.from(bytes) + return bytes } module.exports = { diff --git a/test/index.spec.js b/test/index.spec.js index a7544bcb..4cd35efe 100644 --- a/test/index.spec.js +++ b/test/index.spec.js @@ -1,12 +1,10 @@ /* eslint-env mocha */ 'use strict' -const { Buffer } = require('buffer') -const chai = require('chai') -const dirtyChai = require('dirty-chai') -chai.use(dirtyChai) -const expect = chai.expect +const { expect } = require('aegir/utils/chai') const sinon = require('sinon') +const uint8ArrayFromString = require('uint8arrays/from-string') +const uint8ArrayToString = require('uint8arrays/to-string') const multihashing = require('../src') const fixtures = require('./fixtures/encodes') @@ -18,49 +16,43 @@ describe('multihashing', () => { const encoded = fixture[2] it(`encodes in ${func}`, async function () { - const digest = await multihashing(Buffer.from(raw), func) - expect(digest.toString('hex')).to.eql(encoded) - }) - - it(`encodes Uint8Array in ${func}`, async function () { - const buffer = Buffer.from(raw) - const bytes = new Uint8Array(buffer, buffer.byteOffset, buffer.byteLength) - const digest = await multihashing(bytes, func) - expect(digest.toString('hex')).to.eql(encoded) + const digest = await multihashing(uint8ArrayFromString(raw), func) + expect(digest).to.be.an.instanceOf(Uint8Array) + expect(uint8ArrayToString(digest, 'base16')).to.eql(encoded) }) } it('cuts the length', async () => { - const buf = Buffer.from('beep boop') + const buf = uint8ArrayFromString('beep boop') const digest = await multihashing(buf, 'sha2-256', 10) expect(digest) - .to.eql(Buffer.from('120a90ea688e275d58056732', 'hex')) + .to.eql(uint8ArrayFromString('120a90ea688e275d58056732', 'base16')) }) it('digest only, without length', async () => { - const buf = Buffer.from('beep boop') - + const buf = uint8ArrayFromString('beep boop') const digest = await multihashing.digest(buf, 'sha2-256') + expect(digest).to.be.an.instanceOf(Uint8Array) expect( digest ).to.eql( - Buffer.from('90ea688e275d580567325032492b597bc77221c62493e76330b85ddda191ef7c', 'hex') + uint8ArrayFromString('90ea688e275d580567325032492b597bc77221c62493e76330b85ddda191ef7c', 'base16') ) }) }) describe('validate', () => { it('true on pass', async () => { - const hash = await multihashing(Buffer.from('test'), 'sha2-256') - const validation = await multihashing.validate(Buffer.from('test'), hash) + const hash = await multihashing(uint8ArrayFromString('test'), 'sha2-256') + const validation = await multihashing.validate(uint8ArrayFromString('test'), hash) return expect(validation).to.eql(true) }) it('false on fail', async () => { - const hash = await multihashing(Buffer.from('test'), 'sha2-256') - const validation = await multihashing.validate(Buffer.from('test-fail'), hash) + const hash = await multihashing(uint8ArrayFromString('test'), 'sha2-256') + const validation = await multihashing.validate(uint8ArrayFromString('test-fail'), hash) return expect(validation).to.eql(false) }) }) @@ -75,7 +67,7 @@ describe('error handling', () => { for (const [name, fn] of Object.entries(methods)) { describe(name, () => { it('throws an error when there is no hashing algorithm specified', async () => { - const buf = Buffer.from('beep boop') + const buf = uint8ArrayFromString('beep boop') try { await fn(buf) @@ -88,7 +80,7 @@ describe('error handling', () => { }) it('throws an error when the hashing algorithm is not supported', async () => { - const buf = Buffer.from('beep boop') + const buf = uint8ArrayFromString('beep boop') const stub = sinon.stub(require('multihashes'), 'coerceCode').returns('snake-oil') try {