From e57e4ffa0d2aa90a5b65988babcf0e194a715ffe Mon Sep 17 00:00:00 2001 From: Friedel Ziegelmayer Date: Thu, 19 Jan 2017 17:50:23 +0100 Subject: [PATCH 01/59] Initial commit --- .gitignore | 37 +++++++++++++++++++++++++++++++++++++ LICENSE | 21 +++++++++++++++++++++ README.md | 1 + 3 files changed, 59 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 README.md diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5148e52 --- /dev/null +++ b/.gitignore @@ -0,0 +1,37 @@ +# Logs +logs +*.log +npm-debug.log* + +# Runtime data +pids +*.pid +*.seed + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (http://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules +jspm_packages + +# Optional npm cache directory +.npm + +# Optional REPL history +.node_repl_history diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..bbfffbf --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2017 libp2p + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..f05b59b --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +# js-libp2p-crypto-secp256k1 \ No newline at end of file From 4c36aeba174ce7e1cf8ff8a7fbc7ee39820e0356 Mon Sep 17 00:00:00 2001 From: Yusef Napora Date: Thu, 9 Feb 2017 06:35:39 -0500 Subject: [PATCH 02/59] feat: initial implementation --- .gitignore | 23 +-- .npmignore | 34 ++++ .travis.yml | 38 ++++ README.md | 118 ++++++++++- circle.yml | 12 ++ package.json | 65 ++++++ src/crypto/index.js | 85 ++++++++ src/index.js | 119 +++++++++++ test/fixtures/go-interop.js | 31 +++ test/secp256k1.spec.js | 391 ++++++++++++++++++++++++++++++++++++ 10 files changed, 902 insertions(+), 14 deletions(-) create mode 100644 .npmignore create mode 100644 .travis.yml create mode 100644 circle.yml create mode 100644 package.json create mode 100644 src/crypto/index.js create mode 100644 src/index.js create mode 100644 test/fixtures/go-interop.js create mode 100644 test/secp256k1.spec.js diff --git a/.gitignore b/.gitignore index 5148e52..fb8d1c9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,12 @@ +**/node_modules/ +**/*.log +test/repo-tests* + # Logs logs *.log -npm-debug.log* + +coverage # Runtime data pids @@ -14,24 +19,16 @@ lib-cov # Coverage directory used by tools like istanbul coverage -# nyc test coverage -.nyc_output - # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) .grunt # node-waf configuration .lock-wscript -# Compiled binary addons (http://nodejs.org/api/addons.html) -build/Release +build -# Dependency directories +# Dependency directory +# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git node_modules -jspm_packages -# Optional npm cache directory -.npm - -# Optional REPL history -.node_repl_history +dist diff --git a/.npmignore b/.npmignore new file mode 100644 index 0000000..59335fd --- /dev/null +++ b/.npmignore @@ -0,0 +1,34 @@ +**/node_modules/ +**/*.log +test/repo-tests* + +# Logs +logs +*.log + +coverage + +# Runtime data +pids +*.pid +*.seed + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage + +# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# node-waf configuration +.lock-wscript + +build + +# Dependency directory +# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git +node_modules + +test diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..c601607 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,38 @@ +sudo: false +language: node_js + +matrix: + include: + - node_js: 4 + env: CXX=g++-4.8 + - node_js: 6 + env: + - SAUCE=true + - CXX=g++-4.8 + - node_js: stable + env: CXX=g++-4.8 + +# Make sure we have new NPM. +before_install: + - npm install -g npm + +script: + - npm run lint + - npm test + - npm run coverage + + +before_script: + - export DISPLAY=:99.0 + - sh -e /etc/init.d/xvfb start + +after_success: + - npm run coverage-publish + +addons: + firefox: 'latest' + apt: + sources: + - ubuntu-toolchain-r-test + packages: + - g++-4.8 diff --git a/README.md b/README.md index f05b59b..3670b05 100644 --- a/README.md +++ b/README.md @@ -1 +1,117 @@ -# js-libp2p-crypto-secp256k1 \ No newline at end of file +# js-libp2p-crypto + +[![](https://img.shields.io/badge/made%20by-Protocol%20Labs-blue.svg?style=flat-square)](http://ipn.io) +[![](https://img.shields.io/badge/project-IPFS-blue.svg?style=flat-square)](http://ipfs.io/) +[![](https://img.shields.io/badge/freenode-%23ipfs-blue.svg?style=flat-square)](http://webchat.freenode.net/?channels=%23ipfs) +[![standard-readme compliant](https://img.shields.io/badge/standard--readme-OK-green.svg?style=flat-square)](https://github.com/RichardLitt/standard-readme) +[![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/npm-%3E%3D3.0.0-orange.svg?style=flat-square) +![](https://img.shields.io/badge/Node.js-%3E%3D4.0.0-orange.svg?style=flat-square) + +> Support for secp256k1 keys in js-libp2p-crypto + +This repo contains a [js-libp2p-crypto](https://github.com/libp2p/js-libp2p-crypto)-compatible +implementation of cryptographic signature generation and verification using the +[secp256k1 elliptic curve](https://en.bitcoin.it/wiki/Secp256k1) popularized by Bitcoin and other +crypto currencies. + +## Table of Contents + +- [Install](#install) +- [Usage](#usage) + - [Example](#example) +- [API](#api) + - [`generateKeyPair([bits,] callback)`](#generatekeypairbits-callback) + - [`unmarshalSecp256k1PublicKey(bytes)`](#unmarshalsecp256k1publickeybytes) + - [`unmarshalSecp256k1PrivateKey(bytes, callback)`](#unmarshalsecp256k1privatekeybytes-callback) + - [`Secp256k1PublicKey`](#secp256k1publickey) + - [`.verify(data, sig, callback)`](#verifydata-sig-callback) + - [`Secp256k1PrivateKey`](#secp256k1privatekey) + - [`.public`](#public) + - [`.sign(data, callback)`](#signdata-callback) +- [Contribute](#contribute) +- [License](#license) + +## Install + +```sh +npm install --save libp2p-crypto-secp256k1 +``` + +## Usage + +This module is designed to work with [js-libp2p-crypto](https://github.com/libp2p/js-libp2p-crypto). +Installing `libp2p-crypto-secp256k1` will automatically add support for the `'secp256k1'` key type, which +can be used as an argument to the [libp2p-crypto API functions](https://github.com/libp2p/js-libp2p-crypto#api) +`generateKeyPair`, `unmarshalPublicKey`, and `marshalPrivateKey`. The keys returned from those functions will be +instances of the `Secp256k1PublicKey` or `Secp256k1PrivateKey` classes provided by this module. + +### Example + +```js +const crypto = require('libp2p-crypto') + +const msg = Buffer.from('Hello World') + +crypto.generateKeyPair('secp256k1', 256, (err, key) => { + // assuming no error, key will be an instance of Secp256k1PrivateKey + // the public key is available as key.public + key.sign(msg, (err, sig) => { + key.public.verify(msg, sig, (err, valid) => { + assert(valid, 'Something went horribly wrong') + }) + }) +}) +``` + +## API + +The functions below are the public API of this module. +For usage within libp2p-crypto, see the [libp2p-crypto API documentation](https://github.com/libp2p/js-libp2p-crypto#api). + +### `generateKeyPair([bits, ] callback)` +- `bits: Number` - Optional, included for compatibility with js-libp2p-crypto. Ignored if present; private keys will always be 256 bits. +- `callback: Function` + +### `unmarshalSecp256k1PublicKey(bytes)` +- `bytes: Buffer` + +Converts a serialized secp256k1 public key into an instance of `Secp256k1PublicKey` and returns it + +### `unmarshalSecp256k1PrivateKey(bytes, callback)` +- `bytes: Buffer` +- `callback: Function` + +Converts a serialized secp256k1 private key into an instance of `Secp256k1PrivateKey`, passing it to `callback` on success + +### `Secp256k1PublicKey` + +#### `.verify(data, sig, callback)` +- `data: Buffer` +- `sig: Buffer` +- `callback: Function` + +Calculates the SHA-256 hash of `data`, and verifies the DER-encoded signature in `sig`, passing the result to `callback` + +### `Secp256k1PrivateKey` + +#### `.public` + +Accessor for the `Secp256k1PublicKey` associated with this private key. + +#### `.sign(data, callback)` +- `data: Buffer` + +Calculates the SHA-256 hash of `data` and signs it, passing the DER-encoded signature to `callback` + +## Contribute + +Feel free to join in. All welcome. Open an [issue](https://github.com/libp2p/js-libp2p-crypto/issues)! + +This repository falls under the IPFS [Code of Conduct](https://github.com/ipfs/community/blob/master/code-of-conduct.md). + +[![](https://cdn.rawgit.com/jbenet/contribute-ipfs-gif/master/img/contribute.gif)](https://github.com/ipfs/community/blob/master/contributing.md) + +## License + +[MIT](LICENSE) diff --git a/circle.yml b/circle.yml new file mode 100644 index 0000000..434211a --- /dev/null +++ b/circle.yml @@ -0,0 +1,12 @@ +machine: + node: + version: stable + +dependencies: + pre: + - google-chrome --version + - wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | sudo apt-key add - + - sudo sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list' + - sudo apt-get update + - sudo apt-get --only-upgrade install google-chrome-stable + - google-chrome --version diff --git a/package.json b/package.json new file mode 100644 index 0000000..a3a0d1c --- /dev/null +++ b/package.json @@ -0,0 +1,65 @@ +{ + "name": "libp2p-crypto-secp256k1", + "version": "0.0.1", + "description": "Support for secp256k1 keys in libp2p-crypto", + "main": "src/index.js", + "browser": { + "secp256k1": "secp256k1/js" + }, + "scripts": { + "lint": "aegir-lint", + "build": "aegir-build", + "test": "npm run test:node && npm run test:browser", + "test:node": "aegir-test --env node", + "test:browser": "aegir-test --env browser", + "release": "aegir-release", + "release-minor": "aegir-release --type minor", + "release-major": "aegir-release --type major", + "coverage": "aegir-coverage", + "coverage-publish": "aegir-coverage publish" + }, + "keywords": [ + "IPFS", + "libp2p", + "crypto", + "secp256k1" + ], + "author": "Yusef Napora ", + "license": "MIT", + "dependencies": { + "libp2p-crypto": "^0.8.0", + "multihashing-async": "^0.3.0", + "nodeify": "^1.0.0", + "safe-buffer": "^5.0.1", + "secp256k1": "^3.2.5" + }, + "devDependencies": { + "aegir": "^9.2.1", + "benchmark": "^2.1.2", + "chai": "^3.5.0", + "pre-commit": "^1.1.3" + }, + "pre-commit": [ + "lint", + "test" + ], + "engines": { + "node": ">=4.0.0" + }, + "repository": { + "type": "git", + "url": "https://github.com/libp2p/js-libp2p-crypto-secp256k1.git" + }, + "bugs": { + "url": "https://github.com/libp2p/js-libp2p-crypto-secp256k1/issues" + }, + "homepage": "https://github.com/libp2p/js-libp2p-crypto-secp256k1", + "contributors": [ + "David Dias ", + "Friedel Ziegelmayer ", + "Greenkeeper ", + "Richard Littauer ", + "Yusef Napora ", + "nikuda " + ] +} diff --git a/src/crypto/index.js b/src/crypto/index.js new file mode 100644 index 0000000..ca09fbe --- /dev/null +++ b/src/crypto/index.js @@ -0,0 +1,85 @@ +'use strict' + +const secp256k1 = require('secp256k1') +const multihashing = require('multihashing-async') +const setImmediate = require('async/setImmediate') +const randomBytes = require('libp2p-crypto').randomBytes + +const HASH_ALGORITHM = 'sha2-256' + +exports.privateKeyLength = 32 + +exports.generateKey = function (callback) { + const done = (err, res) => setImmediate(() => { + callback(err, res) + }) + + let privateKey + do { + privateKey = randomBytes(32) + } while (!secp256k1.privateKeyVerify(privateKey)) + + done(null, privateKey) +} + +exports.hashAndSign = function (key, msg, callback) { + const done = (err, res) => setImmediate(() => { + callback(err, res) + }) + + multihashing.digest(msg, HASH_ALGORITHM, (err, digest) => { + if (err) return done(err) + try { + const sig = secp256k1.sign(digest, key) + const sigDER = secp256k1.signatureExport(sig.signature) + return done(null, sigDER) + } catch (err) { + done(err) + } + }) +} + +exports.hashAndVerify = function (key, sig, msg, callback) { + const done = (err, res) => setImmediate(() => { + callback(err, res) + }) + + multihashing.digest(msg, HASH_ALGORITHM, (err, digest) => { + if (err) return done(err) + try { + sig = secp256k1.signatureImport(sig) + const valid = secp256k1.verify(digest, sig, key) + return done(null, valid) + } catch (err) { + done(err) + } + }) +} + +exports.compressPublicKey = function compressPublicKey (key) { + if (!secp256k1.publicKeyVerify(key)) { + throw new Error('Invalid public key') + } + return secp256k1.publicKeyConvert(key, true) +} + +exports.decompressPublicKey = function decompressPublicKey (key) { + return secp256k1.publicKeyConvert(key, false) +} + +exports.validatePrivateKey = function validatePrivateKey (key) { + if (!secp256k1.privateKeyVerify(key)) { + throw new Error('Invalid private key') + } +} + +exports.validatePublicKey = function validatePublicKey (key) { + if (!secp256k1.publicKeyVerify(key)) { + throw new Error('Invalid public key') + } +} + +exports.computePublicKey = function computePublicKey (privateKey) { + exports.validatePrivateKey(privateKey) + return secp256k1.publicKeyCreate(privateKey) +} diff --git a/src/index.js b/src/index.js new file mode 100644 index 0000000..e5dafd0 --- /dev/null +++ b/src/index.js @@ -0,0 +1,119 @@ +'use strict' + +const multihashing = require('multihashing-async') +const crypto = require('./crypto') +const pbm = require('libp2p-crypto').protobuf + +class Secp256k1PublicKey { + constructor (key) { + crypto.validatePublicKey(key) + this._key = key + } + + verify (data, sig, callback) { + ensure(callback) + crypto.hashAndVerify(this._key, sig, data, callback) + } + + marshal () { + return crypto.compressPublicKey(this._key) + } + + get bytes () { + return pbm.PublicKey.encode({ + Type: pbm.KeyType.Secp256k1, + Data: this.marshal() + }) + } + + equals (key) { + return this.bytes.equals(key.bytes) + } + + hash (callback) { + ensure(callback) + multihashing(this.bytes, 'sha2-256', callback) + } +} + +class Secp256k1PrivateKey { + constructor (key, publicKey) { + this._key = key + this._publicKey = publicKey || crypto.computePublicKey(key) + crypto.validatePrivateKey(this._key) + crypto.validatePublicKey(this._publicKey) + } + + sign (message, callback) { + ensure(callback) + crypto.hashAndSign(this._key, message, callback) + } + + get public () { + return new Secp256k1PublicKey(this._publicKey) + } + + marshal () { + return this._key + } + + get bytes () { + return pbm.PrivateKey.encode({ + Type: pbm.KeyType.Secp256k1, + Data: this.marshal() + }) + } + + equals (key) { + return this.bytes.equals(key.bytes) + } + + hash (callback) { + ensure(callback) + multihashing(this.bytes, 'sha2-256', callback) + } +} + +function unmarshalSecp256k1PrivateKey (bytes, callback) { + callback(null, new Secp256k1PrivateKey(bytes), null) +} + +function unmarshalSecp256k1PublicKey (bytes) { + return new Secp256k1PublicKey(bytes) +} + +function generateKeyPair (_bits, cb) { + if (cb === undefined && typeof _bits === 'function') { + cb = _bits + } + ensure(cb) + + crypto.generateKey((err, privateKeyBytes) => { + if (err) { + return cb(err) + } + let privkey + try { + privkey = new Secp256k1PrivateKey(privateKeyBytes) + } catch (err) { + cb(err) + return + } + + cb(null, privkey) + }) +} + +function ensure (cb) { + if (typeof cb !== 'function') { + throw new Error('callback is required') + } +} + +module.exports = { + Secp256k1PublicKey, + Secp256k1PrivateKey, + unmarshalSecp256k1PrivateKey, + unmarshalSecp256k1PublicKey, + generateKeyPair +} diff --git a/test/fixtures/go-interop.js b/test/fixtures/go-interop.js new file mode 100644 index 0000000..8f18c1a --- /dev/null +++ b/test/fixtures/go-interop.js @@ -0,0 +1,31 @@ +'use strict' + +const Buffer = require('safe-buffer').Buffer + +// The keypair and signature below were generated in a gore repl session (https://github.com/motemen/gore) +// using the secp256k1 fork of go-libp2p-crypto by github user @vyzo +// +// gore> :import github.com/vyzo/go-libp2p-crypto +// gore> :import crypto/rand +// gore> :import io/ioutil +// gore> priv, pub, err := crypto.GenerateKeyPairWithReader(crypto.Secp256k1, 256, rand.Reader) +// gore> privBytes, err := priv.Bytes() +// gore> pubBytes, err := pub.Bytes() +// gore> msg := []byte("hello! and welcome to some awesome crypto primitives") +// gore> sig, err := priv.Sign(msg) +// gore> ioutil.WriteFile("/tmp/secp-go-priv.bin", privBytes, 0644) +// gore> ioutil.WriteFile("/tmp/secp-go-pub.bin", pubBytes, 0644) +// gore> ioutil.WriteFile("/tmp/secp-go-sig.bin", sig, 0644) +// +// The generated files were then read in a node repl with e.g.: +// > fs.readFileSync('/tmp/secp-go-pub.bin').toString('hex') +// '08021221029c0ce5d53646ed47112560297a3e59b78b8cbd4bae37c7a0c236eeb91d0fbeaf' +// +// and the results copy/pasted in here + +module.exports = { + privateKey: Buffer.from('08021220358f15db8c2014d570e8e3a622454e2273975a3cca443ec0c45375b13d381d18', 'hex'), + publicKey: Buffer.from('08021221029c0ce5d53646ed47112560297a3e59b78b8cbd4bae37c7a0c236eeb91d0fbeaf', 'hex'), + message: Buffer.from('hello! and welcome to some awesome crypto primitives', 'utf-8'), + signature: Buffer.from('304402200e4c629e9f5d99439115e60989cd40087f6978c36078b0b50cf3d30af5c38d4102204110342c8e7f0809897c1c7a66e49e1c6b7cb0a6ed6993640ec2fe742c1899a9', 'hex') +} diff --git a/test/secp256k1.spec.js b/test/secp256k1.spec.js new file mode 100644 index 0000000..65a95e8 --- /dev/null +++ b/test/secp256k1.spec.js @@ -0,0 +1,391 @@ +/* eslint-env mocha */ +'use strict' + +const expect = require('chai').expect +const Buffer = require('safe-buffer').Buffer + +const secp256k1 = require('../src') +const crypto = require('../src/crypto') +const libp2pCrypto = require('libp2p-crypto') +const pbm = libp2pCrypto.protobuf +const randomBytes = libp2pCrypto.randomBytes + +describe('secp256k1 keys', () => { + let key + before((done) => { + secp256k1.generateKeyPair((err, _key) => { + if (err) return done(err) + key = _key + done() + }) + }) + + it('generates a valid key', (done) => { + expect( + key + ).to.be.an.instanceof( + secp256k1.Secp256k1PrivateKey + ) + expect( + key.public + ).to.be.an.instanceof( + secp256k1.Secp256k1PublicKey + ) + + key.hash((err, digest) => { + if (err) return done(err) + + expect(digest).to.have.length(34) + + key.public.hash((err, digest) => { + if (err) return done(err) + + expect(digest).to.have.length(34) + done() + }) + }) + }) + + it('optionally accepts a `bits` argument when generating a key', (done) => { + secp256k1.generateKeyPair(256, (err, _key) => { + expect(err).to.not.exist + expect(_key).to.be.an.instanceof(secp256k1.Secp256k1PrivateKey) + done() + }) + }) + + it('requires a callback to generate a key', (done) => { + expect(() => + secp256k1.generateKeyPair() + ).to.throw() + done() + }) + + it('signs', (done) => { + const text = randomBytes(512) + + key.sign(text, (err, sig) => { + if (err) { + return done(err) + } + + key.public.verify(text, sig, (err, res) => { + if (err) { + return done(err) + } + + expect(res).to.be.eql(true) + done() + }) + }) + }) + + it('encoding', (done) => { + const keyMarshal = key.marshal() + secp256k1.unmarshalSecp256k1PrivateKey(keyMarshal, (err, key2) => { + if (err) { + return done(err) + } + const keyMarshal2 = key2.marshal() + + expect( + keyMarshal + ).to.be.eql( + keyMarshal2 + ) + + const pk = key.public + const pkMarshal = pk.marshal() + const pk2 = secp256k1.unmarshalSecp256k1PublicKey(pkMarshal) + const pkMarshal2 = pk2.marshal() + + expect( + pkMarshal + ).to.be.eql( + pkMarshal2 + ) + done() + }) + }) + + describe('key equals', () => { + it('equals itself', () => { + expect( + key.equals(key) + ).to.be.eql( + true + ) + + expect( + key.public.equals(key.public) + ).to.be.eql( + true + ) + }) + + it('not equals other key', (done) => { + secp256k1.generateKeyPair(256, (err, key2) => { + if (err) return done(err) + + expect( + key.equals(key2) + ).to.be.eql( + false + ) + + expect( + key2.equals(key) + ).to.be.eql( + false + ) + + expect( + key.public.equals(key2.public) + ).to.be.eql( + false + ) + + expect( + key2.public.equals(key.public) + ).to.be.eql( + false + ) + done() + }) + }) + }) + + it('sign and verify', (done) => { + const data = Buffer.from('hello world') + key.sign(data, (err, sig) => { + if (err) { + return done(err) + } + + key.public.verify(data, sig, (err, valid) => { + if (err) { + return done(err) + } + expect(valid).to.be.eql(true) + done() + }) + }) + }) + + it('fails to verify for different data', (done) => { + const data = Buffer.from('hello world') + key.sign(data, (err, sig) => { + if (err) { + return done(err) + } + + key.public.verify(Buffer.from('hello'), sig, (err, valid) => { + if (err) { + return done(err) + } + expect(valid).to.be.eql(false) + done() + }) + }) + }) +}) + +describe('key generation error', () => { + let generateKey + + before((done) => { + generateKey = crypto.generateKey + crypto.generateKey = (callback) => { callback(new Error('Error generating key')) } + done() + }) + + after((done) => { + crypto.generateKey = generateKey + done() + }) + + it('returns an error if key generation fails', (done) => { + secp256k1.generateKeyPair((err, key) => { + expect(err).to.exist + expect(key).to.not.exist + done() + }) + }) +}) + +describe('handles generation of invalid key', () => { + let generateKey + + before((done) => { + generateKey = crypto.generateKey + crypto.generateKey = (callback) => { callback(null, Buffer.from('not a real key')) } + done() + }) + + after((done) => { + crypto.generateKey = generateKey + done() + }) + + it('returns an error if key generator returns an invalid key', (done) => { + secp256k1.generateKeyPair((err, key) => { + expect(err).to.exist + expect(key).to.not.exist + done() + }) + }) +}) + +describe('crypto functions', () => { + let privKey, pubKey + + before((done) => { + crypto.generateKey((err, _key) => { + if (err) return done(err) + privKey = _key + pubKey = crypto.computePublicKey(privKey) + done() + }) + }) + + it('generates valid keys', (done) => { + expect(() => { + crypto.validatePrivateKey(privKey) + crypto.validatePublicKey(pubKey) + }).to.not.throw() + done() + }) + + it('does not validate an invalid key', (done) => { + expect(() => { + crypto.validatePublicKey(Buffer.from('42')) + }).to.throw() + + expect(() => { + crypto.validatePrivateKey(Buffer.from('42')) + }).to.throw() + done() + }) + + it('validates a correct signature', (done) => { + crypto.hashAndSign(privKey, Buffer.from('hello'), (err, sig) => { + if (err) return done(err) + crypto.hashAndVerify(pubKey, sig, Buffer.from('hello'), (err, valid) => { + if (err) return done(err) + expect(valid).to.be.eql(true) + done() + }) + }) + }) + + it('errors if given a null buffer to sign', (done) => { + crypto.hashAndSign(privKey, null, (err, sig) => { + expect(err).to.exist + expect(sig).to.not.exist + done() + }) + }) + + it('errors when signing with an invalid key', (done) => { + crypto.hashAndSign(Buffer.from('42'), Buffer.from('Hello'), (err, sig) => { + expect(err).to.exist + expect(sig).to.not.exist + done() + }) + }) + + it('errors if given a null buffer to validate', (done) => { + crypto.hashAndSign(privKey, Buffer.from('hello'), (err, sig) => { + if (err) return done(err) + + crypto.hashAndVerify(privKey, sig, null, (err, valid) => { + expect(err).to.exist + expect(valid).to.not.exist + done() + }) + }) + }) + + it('errors when validating a message with an invalid signature', (done) => { + crypto.hashAndVerify(pubKey, Buffer.from('invalid-sig'), Buffer.from('hello'), (err, valid) => { + expect(err).to.exist + expect(valid).to.not.exist + done() + }) + }) + + it('errors when signing with an invalid key', (done) => { + crypto.hashAndSign(Buffer.from('42'), Buffer.from('Hello'), (err, sig) => { + expect(err).to.exist + expect(sig).to.not.exist + done() + }) + }) + + it('throws when compressing an invalid public key', (done) => { + expect(() => { + crypto.compressPublicKey(Buffer.from('42')) + }).to.throw() + done() + }) + + it('throws when decompressing an invalid public key', (done) => { + expect(() => { + crypto.decompressPublicKey(Buffer.from('42')) + }).to.throw() + done() + }) + + it('compresses/decompresses a valid public key', (done) => { + const decompressed = crypto.decompressPublicKey(pubKey) + expect(decompressed).to.exist + expect(decompressed.length).to.be.eql(65) + const recompressed = crypto.compressPublicKey(decompressed) + expect(recompressed).to.be.eql(pubKey) + done() + }) +}) + +describe('go interop', () => { + const fixtures = require('./fixtures/go-interop') + + it('loads a private key marshaled by go-libp2p-crypto', (done) => { + // we need to first extract the key data from the protobuf, which is + // normally handled by js-libp2p-crypto + const decoded = pbm.PrivateKey.decode(fixtures.privateKey) + expect(decoded.Type).to.be.eql(pbm.KeyType.Secp256k1) + + secp256k1.unmarshalSecp256k1PrivateKey(decoded.Data, (err, key) => { + if (err) return done(err) + + expect(key).to.be.an.instanceof(secp256k1.Secp256k1PrivateKey) + expect(key.bytes).to.be.eql(fixtures.privateKey) + done() + }) + }) + + it('loads a public key marshaled by go-libp2p-crypto', (done) => { + const decoded = pbm.PublicKey.decode(fixtures.publicKey) + expect(decoded.Type).to.be.eql(pbm.KeyType.Secp256k1) + + const key = secp256k1.unmarshalSecp256k1PublicKey(decoded.Data) + expect(key).to.be.an.instanceof(secp256k1.Secp256k1PublicKey) + expect(key.bytes).to.be.eql(fixtures.publicKey) + done() + }) + + it('generates the same signature as go-libp2p-crypto', (done) => { + const decoded = pbm.PrivateKey.decode(fixtures.privateKey) + expect(decoded.Type).to.be.eql(pbm.KeyType.Secp256k1) + + secp256k1.unmarshalSecp256k1PrivateKey(decoded.Data, (err, key) => { + if (err) return done(err) + + key.sign(fixtures.message, (err, sig) => { + if (err) return done(err) + expect(sig).to.be.eql(fixtures.signature) + done() + }) + }) + }) +}) From 4c744d3b606de75bc225e1533b67254ccd188ef4 Mon Sep 17 00:00:00 2001 From: Friedel Ziegelmayer Date: Thu, 9 Feb 2017 12:36:35 +0100 Subject: [PATCH 03/59] chore: update dependencies --- package.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index a3a0d1c..59e1f25 100644 --- a/package.json +++ b/package.json @@ -28,16 +28,16 @@ "license": "MIT", "dependencies": { "libp2p-crypto": "^0.8.0", - "multihashing-async": "^0.3.0", + "multihashing-async": "^0.4.1", "nodeify": "^1.0.0", "safe-buffer": "^5.0.1", "secp256k1": "^3.2.5" }, "devDependencies": { - "aegir": "^9.2.1", - "benchmark": "^2.1.2", + "aegir": "^10.0.0", + "benchmark": "^2.1.3", "chai": "^3.5.0", - "pre-commit": "^1.1.3" + "pre-commit": "^1.2.2" }, "pre-commit": [ "lint", From 418a0885ad3ab5c95173751277207b9330ea810c Mon Sep 17 00:00:00 2001 From: Friedel Ziegelmayer Date: Thu, 9 Feb 2017 12:43:43 +0100 Subject: [PATCH 04/59] chore: update contributors --- package.json | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index 59e1f25..fccb61a 100644 --- a/package.json +++ b/package.json @@ -55,11 +55,7 @@ }, "homepage": "https://github.com/libp2p/js-libp2p-crypto-secp256k1", "contributors": [ - "David Dias ", "Friedel Ziegelmayer ", - "Greenkeeper ", - "Richard Littauer ", - "Yusef Napora ", - "nikuda " + "Yusef Napora " ] -} +} \ No newline at end of file From 288c9cff8f129355b526e0eed6c5b509cf4292b9 Mon Sep 17 00:00:00 2001 From: Friedel Ziegelmayer Date: Thu, 9 Feb 2017 12:43:44 +0100 Subject: [PATCH 05/59] chore: release version v0.1.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index fccb61a..b84d24c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "libp2p-crypto-secp256k1", - "version": "0.0.1", + "version": "0.1.0", "description": "Support for secp256k1 keys in libp2p-crypto", "main": "src/index.js", "browser": { From 73b8b39de5108644002bf9d88f454478e944718a Mon Sep 17 00:00:00 2001 From: David Dias Date: Thu, 9 Feb 2017 08:03:23 -0800 Subject: [PATCH 06/59] chore: ^ to ~ --- package.json | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index b84d24c..14f997b 100644 --- a/package.json +++ b/package.json @@ -27,8 +27,8 @@ "author": "Yusef Napora ", "license": "MIT", "dependencies": { - "libp2p-crypto": "^0.8.0", - "multihashing-async": "^0.4.1", + "libp2p-crypto": "~0.8.0", + "multihashing-async": "~0.4.2", "nodeify": "^1.0.0", "safe-buffer": "^5.0.1", "secp256k1": "^3.2.5" @@ -44,7 +44,8 @@ "test" ], "engines": { - "node": ">=4.0.0" + "node": ">=4.0.0", + "npm": ">=3.0.0" }, "repository": { "type": "git", @@ -58,4 +59,4 @@ "Friedel Ziegelmayer ", "Yusef Napora " ] -} \ No newline at end of file +} From de8b16b00bf75f7c386b9e10347833d434b0028d Mon Sep 17 00:00:00 2001 From: David Dias Date: Thu, 9 Feb 2017 08:05:13 -0800 Subject: [PATCH 07/59] chore: update contributors --- package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 14f997b..9d368b2 100644 --- a/package.json +++ b/package.json @@ -56,7 +56,8 @@ }, "homepage": "https://github.com/libp2p/js-libp2p-crypto-secp256k1", "contributors": [ + "David Dias ", "Friedel Ziegelmayer ", "Yusef Napora " ] -} +} \ No newline at end of file From 4c2d42984daa20b2445d4cf2ba4e81c31422c5c7 Mon Sep 17 00:00:00 2001 From: David Dias Date: Thu, 9 Feb 2017 08:05:13 -0800 Subject: [PATCH 08/59] chore: release version v0.1.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 9d368b2..d76b22a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "libp2p-crypto-secp256k1", - "version": "0.1.0", + "version": "0.1.1", "description": "Support for secp256k1 keys in libp2p-crypto", "main": "src/index.js", "browser": { From 42678bba302ca12bddfb73892751fb89e4ae61a1 Mon Sep 17 00:00:00 2001 From: David Dias Date: Thu, 9 Feb 2017 14:08:25 -0800 Subject: [PATCH 10/59] chore: release version v0.1.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d76b22a..31d0e41 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "libp2p-crypto-secp256k1", - "version": "0.1.1", + "version": "0.1.2", "description": "Support for secp256k1 keys in libp2p-crypto", "main": "src/index.js", "browser": { From 9430e7f91e09539675f50dfa6b932e897ab2f3b8 Mon Sep 17 00:00:00 2001 From: David Dias Date: Fri, 10 Feb 2017 18:33:54 -0800 Subject: [PATCH 11/59] chore: update deps --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 31d0e41..98dcee5 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,7 @@ "author": "Yusef Napora ", "license": "MIT", "dependencies": { - "libp2p-crypto": "~0.8.0", + "libp2p-crypto": "~0.8.4", "multihashing-async": "~0.4.2", "nodeify": "^1.0.0", "safe-buffer": "^5.0.1", @@ -60,4 +60,4 @@ "Friedel Ziegelmayer ", "Yusef Napora " ] -} \ No newline at end of file +} From 35abf8fcb40fe17cec0e1277b9a66a0ddc3fbc18 Mon Sep 17 00:00:00 2001 From: David Dias Date: Fri, 10 Feb 2017 18:36:19 -0800 Subject: [PATCH 12/59] chore: update contributors --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 98dcee5..9cf9ffb 100644 --- a/package.json +++ b/package.json @@ -60,4 +60,4 @@ "Friedel Ziegelmayer ", "Yusef Napora " ] -} +} \ No newline at end of file From 638ea963e6c5184cc21f7490ed36ec9d5fe9b1ca Mon Sep 17 00:00:00 2001 From: David Dias Date: Fri, 10 Feb 2017 18:36:19 -0800 Subject: [PATCH 13/59] chore: release version v0.1.3 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 9cf9ffb..517fe75 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "libp2p-crypto-secp256k1", - "version": "0.1.2", + "version": "0.1.3", "description": "Support for secp256k1 keys in libp2p-crypto", "main": "src/index.js", "browser": { From e66383137f05b29f5506543ee2af4e74f37daf1a Mon Sep 17 00:00:00 2001 From: David Dias Date: Sat, 11 Feb 2017 17:27:29 -0800 Subject: [PATCH 14/59] chore: add missing dependency --- package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 517fe75..16eaa5b 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,7 @@ "author": "Yusef Napora ", "license": "MIT", "dependencies": { + "async": "^2.1.4", "libp2p-crypto": "~0.8.4", "multihashing-async": "~0.4.2", "nodeify": "^1.0.0", @@ -60,4 +61,4 @@ "Friedel Ziegelmayer ", "Yusef Napora " ] -} \ No newline at end of file +} From 647fab7170f8f0d20d06b7b2496d2fa05badde79 Mon Sep 17 00:00:00 2001 From: David Dias Date: Sat, 11 Feb 2017 17:27:51 -0800 Subject: [PATCH 15/59] chore: update contributors --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 16eaa5b..b3f940e 100644 --- a/package.json +++ b/package.json @@ -61,4 +61,4 @@ "Friedel Ziegelmayer ", "Yusef Napora " ] -} +} \ No newline at end of file From d8b0c74ec9c22ffa7a2356ec593bc812ea79b81e Mon Sep 17 00:00:00 2001 From: David Dias Date: Sat, 11 Feb 2017 17:27:51 -0800 Subject: [PATCH 16/59] chore: release version v0.1.4 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b3f940e..dc96e55 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "libp2p-crypto-secp256k1", - "version": "0.1.3", + "version": "0.1.4", "description": "Support for secp256k1 keys in libp2p-crypto", "main": "src/index.js", "browser": { From 363cda56da2687a38ea404162c395371d98fd3cf Mon Sep 17 00:00:00 2001 From: David Dias Date: Fri, 21 Jul 2017 11:38:33 -0700 Subject: [PATCH 17/59] chore: update ci --- .travis.yml | 5 ++--- circle.yml | 8 +++++--- package.json | 18 +++++++++--------- 3 files changed, 16 insertions(+), 15 deletions(-) diff --git a/.travis.yml b/.travis.yml index c601607..5cc672b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,20 +7,19 @@ matrix: env: CXX=g++-4.8 - node_js: 6 env: - - SAUCE=true - CXX=g++-4.8 - node_js: stable env: CXX=g++-4.8 # Make sure we have new NPM. before_install: - - npm install -g npm + - npm install -g npm@4 script: - npm run lint - npm test - npm run coverage - + - make test before_script: - export DISPLAY=:99.0 diff --git a/circle.yml b/circle.yml index 434211a..56f7efb 100644 --- a/circle.yml +++ b/circle.yml @@ -5,8 +5,10 @@ machine: dependencies: pre: - google-chrome --version - - wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | sudo apt-key add - - - sudo sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list' + - curl -L -o google-chrome.deb https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb + - sudo dpkg -i google-chrome.deb || true - sudo apt-get update - - sudo apt-get --only-upgrade install google-chrome-stable + - sudo apt-get install -f + - sudo apt-get install --only-upgrade lsb-base + - sudo dpkg -i google-chrome.deb - google-chrome --version diff --git a/package.json b/package.json index dc96e55..9722641 100644 --- a/package.json +++ b/package.json @@ -27,17 +27,17 @@ "author": "Yusef Napora ", "license": "MIT", "dependencies": { - "async": "^2.1.4", - "libp2p-crypto": "~0.8.4", - "multihashing-async": "~0.4.2", - "nodeify": "^1.0.0", - "safe-buffer": "^5.0.1", - "secp256k1": "^3.2.5" + "async": "^2.5.0", + "libp2p-crypto": "~0.8.8", + "multihashing-async": "~0.4.6", + "nodeify": "^1.0.1", + "safe-buffer": "^5.1.1", + "secp256k1": "^3.3.0" }, "devDependencies": { - "aegir": "^10.0.0", - "benchmark": "^2.1.3", - "chai": "^3.5.0", + "aegir": "^11.0.2", + "benchmark": "^2.1.4", + "chai": "^4.1.0", "pre-commit": "^1.2.2" }, "pre-commit": [ From 4ee48a737a34bebff2693db83a49e5c851e39529 Mon Sep 17 00:00:00 2001 From: David Dias Date: Sat, 22 Jul 2017 11:12:30 -0700 Subject: [PATCH 18/59] feat: next libp2p-crypto (#4) * feat: next libp2p-crypto * chore: update deps --- package.json | 5 +- src/crypto/index.js | 4 +- src/index.js | 2 +- test/secp256k1.spec.js | 203 ++++++++++++++--------------------------- 4 files changed, 74 insertions(+), 140 deletions(-) diff --git a/package.json b/package.json index 9722641..e859743 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,7 @@ "license": "MIT", "dependencies": { "async": "^2.5.0", - "libp2p-crypto": "~0.8.8", + "libp2p-crypto": "~0.9.0", "multihashing-async": "~0.4.6", "nodeify": "^1.0.1", "safe-buffer": "^5.1.1", @@ -38,6 +38,7 @@ "aegir": "^11.0.2", "benchmark": "^2.1.4", "chai": "^4.1.0", + "dirty-chai": "^2.0.1", "pre-commit": "^1.2.2" }, "pre-commit": [ @@ -61,4 +62,4 @@ "Friedel Ziegelmayer ", "Yusef Napora " ] -} \ No newline at end of file +} diff --git a/src/crypto/index.js b/src/crypto/index.js index ca09fbe..7e2b494 100644 --- a/src/crypto/index.js +++ b/src/crypto/index.js @@ -28,7 +28,7 @@ exports.hashAndSign = function (key, msg, callback) { }) multihashing.digest(msg, HASH_ALGORITHM, (err, digest) => { - if (err) return done(err) + if (err) { return done(err) } try { const sig = secp256k1.sign(digest, key) const sigDER = secp256k1.signatureExport(sig.signature) @@ -45,7 +45,7 @@ exports.hashAndVerify = function (key, sig, msg, callback) { }) multihashing.digest(msg, HASH_ALGORITHM, (err, digest) => { - if (err) return done(err) + if (err) { return done(err) } try { sig = secp256k1.signatureImport(sig) const valid = secp256k1.verify(digest, sig, key) diff --git a/src/index.js b/src/index.js index e5dafd0..3d3c030 100644 --- a/src/index.js +++ b/src/index.js @@ -2,7 +2,7 @@ const multihashing = require('multihashing-async') const crypto = require('./crypto') -const pbm = require('libp2p-crypto').protobuf +const pbm = require('libp2p-crypto').keys.pbm class Secp256k1PublicKey { constructor (key) { diff --git a/test/secp256k1.spec.js b/test/secp256k1.spec.js index 65a95e8..d68f653 100644 --- a/test/secp256k1.spec.js +++ b/test/secp256k1.spec.js @@ -1,45 +1,39 @@ /* eslint-env mocha */ 'use strict' -const expect = require('chai').expect +const chai = require('chai') +const dirtyChai = require('dirty-chai') +const expect = chai.expect +chai.use(dirtyChai) + const Buffer = require('safe-buffer').Buffer const secp256k1 = require('../src') const crypto = require('../src/crypto') const libp2pCrypto = require('libp2p-crypto') -const pbm = libp2pCrypto.protobuf +const pbm = libp2pCrypto.keys.pbm const randomBytes = libp2pCrypto.randomBytes describe('secp256k1 keys', () => { let key before((done) => { secp256k1.generateKeyPair((err, _key) => { - if (err) return done(err) + expect(err).to.not.exist() key = _key done() }) }) it('generates a valid key', (done) => { - expect( - key - ).to.be.an.instanceof( - secp256k1.Secp256k1PrivateKey - ) - expect( - key.public - ).to.be.an.instanceof( - secp256k1.Secp256k1PublicKey - ) + expect(key).to.be.an.instanceof(secp256k1.Secp256k1PrivateKey) + expect(key.public).to.be.an.instanceof(secp256k1.Secp256k1PublicKey) key.hash((err, digest) => { - if (err) return done(err) - + expect(err).to.not.exist() expect(digest).to.have.length(34) key.public.hash((err, digest) => { - if (err) return done(err) - + expect(err).to.not.exist() expect(digest).to.have.length(34) done() }) @@ -48,33 +42,25 @@ describe('secp256k1 keys', () => { it('optionally accepts a `bits` argument when generating a key', (done) => { secp256k1.generateKeyPair(256, (err, _key) => { - expect(err).to.not.exist + expect(err).to.not.exist() expect(_key).to.be.an.instanceof(secp256k1.Secp256k1PrivateKey) done() }) }) - it('requires a callback to generate a key', (done) => { - expect(() => - secp256k1.generateKeyPair() - ).to.throw() - done() + it('requires a callback to generate a key', () => { + expect(() => secp256k1.generateKeyPair()).to.throw() }) it('signs', (done) => { const text = randomBytes(512) key.sign(text, (err, sig) => { - if (err) { - return done(err) - } + expect(err).to.not.exist() key.public.verify(text, sig, (err, res) => { - if (err) { - return done(err) - } - - expect(res).to.be.eql(true) + expect(err).to.not.exist() + expect(res).to.equal(true) done() }) }) @@ -83,73 +69,36 @@ describe('secp256k1 keys', () => { it('encoding', (done) => { const keyMarshal = key.marshal() secp256k1.unmarshalSecp256k1PrivateKey(keyMarshal, (err, key2) => { - if (err) { - return done(err) - } + expect(err).to.not.exist() const keyMarshal2 = key2.marshal() - expect( - keyMarshal - ).to.be.eql( - keyMarshal2 - ) + expect(keyMarshal).to.eql(keyMarshal2) const pk = key.public const pkMarshal = pk.marshal() const pk2 = secp256k1.unmarshalSecp256k1PublicKey(pkMarshal) const pkMarshal2 = pk2.marshal() - expect( - pkMarshal - ).to.be.eql( - pkMarshal2 - ) + expect(pkMarshal).to.eql(pkMarshal2) done() }) }) describe('key equals', () => { it('equals itself', () => { - expect( - key.equals(key) - ).to.be.eql( - true - ) + expect(key.equals(key)).to.eql(true) - expect( - key.public.equals(key.public) - ).to.be.eql( - true - ) + expect(key.public.equals(key.public)).to.eql(true) }) it('not equals other key', (done) => { secp256k1.generateKeyPair(256, (err, key2) => { - if (err) return done(err) + expect(err).to.not.exist() - expect( - key.equals(key2) - ).to.be.eql( - false - ) - - expect( - key2.equals(key) - ).to.be.eql( - false - ) - - expect( - key.public.equals(key2.public) - ).to.be.eql( - false - ) - - expect( - key2.public.equals(key.public) - ).to.be.eql( - false - ) + expect(key.equals(key2)).to.eql(false) + expect(key2.equals(key)).to.eql(false) + expect(key.public.equals(key2.public)).to.eql(false) + expect(key2.public.equals(key.public)).to.eql(false) done() }) }) @@ -158,15 +107,11 @@ describe('secp256k1 keys', () => { it('sign and verify', (done) => { const data = Buffer.from('hello world') key.sign(data, (err, sig) => { - if (err) { - return done(err) - } + expect(err).to.not.exist() key.public.verify(data, sig, (err, valid) => { - if (err) { - return done(err) - } - expect(valid).to.be.eql(true) + expect(err).to.not.exist() + expect(valid).to.eql(true) done() }) }) @@ -175,15 +120,11 @@ describe('secp256k1 keys', () => { it('fails to verify for different data', (done) => { const data = Buffer.from('hello world') key.sign(data, (err, sig) => { - if (err) { - return done(err) - } + expect(err).to.not.exist() key.public.verify(Buffer.from('hello'), sig, (err, valid) => { - if (err) { - return done(err) - } - expect(valid).to.be.eql(false) + expect(err).to.not.exist() + expect(valid).to.eql(false) done() }) }) @@ -206,8 +147,8 @@ describe('key generation error', () => { it('returns an error if key generation fails', (done) => { secp256k1.generateKeyPair((err, key) => { - expect(err).to.exist - expect(key).to.not.exist + expect(err).to.exist() + expect(key).to.not.exist() done() }) }) @@ -229,19 +170,20 @@ describe('handles generation of invalid key', () => { it('returns an error if key generator returns an invalid key', (done) => { secp256k1.generateKeyPair((err, key) => { - expect(err).to.exist - expect(key).to.not.exist + expect(err).to.exist() + expect(key).to.not.exist() done() }) }) }) describe('crypto functions', () => { - let privKey, pubKey + let privKey + let pubKey before((done) => { crypto.generateKey((err, _key) => { - if (err) return done(err) + expect(err).to.not.exist() privKey = _key pubKey = crypto.computePublicKey(privKey) done() @@ -257,22 +199,17 @@ describe('crypto functions', () => { }) it('does not validate an invalid key', (done) => { - expect(() => { - crypto.validatePublicKey(Buffer.from('42')) - }).to.throw() - - expect(() => { - crypto.validatePrivateKey(Buffer.from('42')) - }).to.throw() + expect(() => crypto.validatePublicKey(Buffer.from('42'))).to.throw() + expect(() => crypto.validatePrivateKey(Buffer.from('42'))).to.throw() done() }) it('validates a correct signature', (done) => { crypto.hashAndSign(privKey, Buffer.from('hello'), (err, sig) => { - if (err) return done(err) + expect(err).to.not.exist() crypto.hashAndVerify(pubKey, sig, Buffer.from('hello'), (err, valid) => { - if (err) return done(err) - expect(valid).to.be.eql(true) + expect(err).to.not.exist() + expect(valid).to.equal(true) done() }) }) @@ -280,27 +217,27 @@ describe('crypto functions', () => { it('errors if given a null buffer to sign', (done) => { crypto.hashAndSign(privKey, null, (err, sig) => { - expect(err).to.exist - expect(sig).to.not.exist + expect(err).to.exist() + expect(sig).to.not.exist() done() }) }) it('errors when signing with an invalid key', (done) => { crypto.hashAndSign(Buffer.from('42'), Buffer.from('Hello'), (err, sig) => { - expect(err).to.exist - expect(sig).to.not.exist + expect(err).to.exist() + expect(sig).to.not.exist() done() }) }) it('errors if given a null buffer to validate', (done) => { crypto.hashAndSign(privKey, Buffer.from('hello'), (err, sig) => { - if (err) return done(err) + expect(err).to.not.exist() crypto.hashAndVerify(privKey, sig, null, (err, valid) => { - expect(err).to.exist - expect(valid).to.not.exist + expect(err).to.exist() + expect(valid).to.not.exist() done() }) }) @@ -308,40 +245,36 @@ describe('crypto functions', () => { it('errors when validating a message with an invalid signature', (done) => { crypto.hashAndVerify(pubKey, Buffer.from('invalid-sig'), Buffer.from('hello'), (err, valid) => { - expect(err).to.exist - expect(valid).to.not.exist + expect(err).to.exist() + expect(valid).to.not.exist() done() }) }) it('errors when signing with an invalid key', (done) => { crypto.hashAndSign(Buffer.from('42'), Buffer.from('Hello'), (err, sig) => { - expect(err).to.exist - expect(sig).to.not.exist + expect(err).to.exist() + expect(sig).to.not.exist() done() }) }) it('throws when compressing an invalid public key', (done) => { - expect(() => { - crypto.compressPublicKey(Buffer.from('42')) - }).to.throw() + expect(() => crypto.compressPublicKey(Buffer.from('42'))).to.throw() done() }) it('throws when decompressing an invalid public key', (done) => { - expect(() => { - crypto.decompressPublicKey(Buffer.from('42')) - }).to.throw() + expect(() => crypto.decompressPublicKey(Buffer.from('42'))).to.throw() done() }) it('compresses/decompresses a valid public key', (done) => { const decompressed = crypto.decompressPublicKey(pubKey) - expect(decompressed).to.exist + expect(decompressed).to.exist() expect(decompressed.length).to.be.eql(65) const recompressed = crypto.compressPublicKey(decompressed) - expect(recompressed).to.be.eql(pubKey) + expect(recompressed).to.eql(pubKey) done() }) }) @@ -353,13 +286,13 @@ describe('go interop', () => { // we need to first extract the key data from the protobuf, which is // normally handled by js-libp2p-crypto const decoded = pbm.PrivateKey.decode(fixtures.privateKey) - expect(decoded.Type).to.be.eql(pbm.KeyType.Secp256k1) + expect(decoded.Type).to.eql(pbm.KeyType.Secp256k1) secp256k1.unmarshalSecp256k1PrivateKey(decoded.Data, (err, key) => { - if (err) return done(err) + expect(err).to.not.exist() expect(key).to.be.an.instanceof(secp256k1.Secp256k1PrivateKey) - expect(key.bytes).to.be.eql(fixtures.privateKey) + expect(key.bytes).to.eql(fixtures.privateKey) done() }) }) @@ -370,20 +303,20 @@ describe('go interop', () => { const key = secp256k1.unmarshalSecp256k1PublicKey(decoded.Data) expect(key).to.be.an.instanceof(secp256k1.Secp256k1PublicKey) - expect(key.bytes).to.be.eql(fixtures.publicKey) + expect(key.bytes).to.eql(fixtures.publicKey) done() }) it('generates the same signature as go-libp2p-crypto', (done) => { const decoded = pbm.PrivateKey.decode(fixtures.privateKey) - expect(decoded.Type).to.be.eql(pbm.KeyType.Secp256k1) + expect(decoded.Type).to.eql(pbm.KeyType.Secp256k1) secp256k1.unmarshalSecp256k1PrivateKey(decoded.Data, (err, key) => { - if (err) return done(err) + expect(err).to.not.exist() key.sign(fixtures.message, (err, sig) => { - if (err) return done(err) - expect(sig).to.be.eql(fixtures.signature) + expect(err).to.not.exist() + expect(sig).to.eql(fixtures.signature) done() }) }) From c21454c4e84b5effd97b21ef98c7afe4430d7b79 Mon Sep 17 00:00:00 2001 From: David Dias Date: Sat, 22 Jul 2017 11:30:07 -0700 Subject: [PATCH 19/59] chore: update contributors --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e859743..6762e9b 100644 --- a/package.json +++ b/package.json @@ -62,4 +62,4 @@ "Friedel Ziegelmayer ", "Yusef Napora " ] -} +} \ No newline at end of file From 1013becd668adad0d740cbc4b63622cbddab2236 Mon Sep 17 00:00:00 2001 From: David Dias Date: Sat, 22 Jul 2017 11:30:07 -0700 Subject: [PATCH 20/59] chore: release version v0.2.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 6762e9b..e7052b9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "libp2p-crypto-secp256k1", - "version": "0.1.4", + "version": "0.2.0", "description": "Support for secp256k1 keys in libp2p-crypto", "main": "src/index.js", "browser": { From 41c03a86a5ab840a119039883b492c5e90745b29 Mon Sep 17 00:00:00 2001 From: David Dias Date: Sat, 22 Jul 2017 11:40:00 -0700 Subject: [PATCH 21/59] chore: update deps --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e7052b9..117069a 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,7 @@ "license": "MIT", "dependencies": { "async": "^2.5.0", - "libp2p-crypto": "~0.9.0", + "libp2p-crypto": "~0.9.1", "multihashing-async": "~0.4.6", "nodeify": "^1.0.1", "safe-buffer": "^5.1.1", From 838ecdbaef6c902361b4d30a9867fefaeb62fd31 Mon Sep 17 00:00:00 2001 From: David Dias Date: Sat, 22 Jul 2017 12:19:08 -0700 Subject: [PATCH 23/59] chore: release version v0.2.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 117069a..5068d0d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "libp2p-crypto-secp256k1", - "version": "0.2.0", + "version": "0.2.1", "description": "Support for secp256k1 keys in libp2p-crypto", "main": "src/index.js", "browser": { From 8401154102fb2f88c08652f9ff2d8677b75561f4 Mon Sep 17 00:00:00 2001 From: David Dias Date: Sat, 22 Jul 2017 12:28:53 -0700 Subject: [PATCH 24/59] chore: update deps --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 5068d0d..c033d32 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,7 @@ "license": "MIT", "dependencies": { "async": "^2.5.0", - "libp2p-crypto": "~0.9.1", + "libp2p-crypto": "~0.9.2", "multihashing-async": "~0.4.6", "nodeify": "^1.0.1", "safe-buffer": "^5.1.1", @@ -62,4 +62,4 @@ "Friedel Ziegelmayer ", "Yusef Napora " ] -} \ No newline at end of file +} From 0dcf1a6f52407f98214e15d173bbaa9e72f528f7 Mon Sep 17 00:00:00 2001 From: David Dias Date: Sat, 22 Jul 2017 13:31:42 -0700 Subject: [PATCH 25/59] fix: circular circular dep -> DI --- package.json | 2 +- src/crypto.js | 89 ++++++++++++++++++ src/crypto/index.js | 85 ----------------- src/index.js | 205 ++++++++++++++++++++--------------------- test/secp256k1.spec.js | 28 ++++-- 5 files changed, 210 insertions(+), 199 deletions(-) create mode 100644 src/crypto.js delete mode 100644 src/crypto/index.js diff --git a/package.json b/package.json index c033d32..467484b 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,6 @@ "license": "MIT", "dependencies": { "async": "^2.5.0", - "libp2p-crypto": "~0.9.2", "multihashing-async": "~0.4.6", "nodeify": "^1.0.1", "safe-buffer": "^5.1.1", @@ -37,6 +36,7 @@ "devDependencies": { "aegir": "^11.0.2", "benchmark": "^2.1.4", + "libp2p-crypto": "~0.9.4", "chai": "^4.1.0", "dirty-chai": "^2.0.1", "pre-commit": "^1.2.2" diff --git a/src/crypto.js b/src/crypto.js new file mode 100644 index 0000000..a336ab4 --- /dev/null +++ b/src/crypto.js @@ -0,0 +1,89 @@ +'use strict' + +const secp256k1 = require('secp256k1') +const multihashing = require('multihashing-async') +const setImmediate = require('async/setImmediate') + +const HASH_ALGORITHM = 'sha2-256' + +module.exports = (randomBytes) => { + const privateKeyLength = 32 + + function generateKey (callback) { + const done = (err, res) => setImmediate(() => callback(err, res)) + + let privateKey + do { + privateKey = randomBytes(32) + } while (!secp256k1.privateKeyVerify(privateKey)) + + done(null, privateKey) + } + + function hashAndSign (key, msg, callback) { + const done = (err, res) => setImmediate(() => callback(err, res)) + + multihashing.digest(msg, HASH_ALGORITHM, (err, digest) => { + if (err) { return done(err) } + + try { + const sig = secp256k1.sign(digest, key) + const sigDER = secp256k1.signatureExport(sig.signature) + return done(null, sigDER) + } catch (err) { done(err) } + }) + } + + function hashAndVerify (key, sig, msg, callback) { + const done = (err, res) => setImmediate(() => callback(err, res)) + + multihashing.digest(msg, HASH_ALGORITHM, (err, digest) => { + if (err) { return done(err) } + try { + sig = secp256k1.signatureImport(sig) + const valid = secp256k1.verify(digest, sig, key) + return done(null, valid) + } catch (err) { done(err) } + }) + } + + function compressPublicKey (key) { + if (!secp256k1.publicKeyVerify(key)) { + throw new Error('Invalid public key') + } + return secp256k1.publicKeyConvert(key, true) + } + + function decompressPublicKey (key) { + return secp256k1.publicKeyConvert(key, false) + } + + function validatePrivateKey (key) { + if (!secp256k1.privateKeyVerify(key)) { + throw new Error('Invalid private key') + } + } + + function validatePublicKey (key) { + if (!secp256k1.publicKeyVerify(key)) { + throw new Error('Invalid public key') + } + } + + function computePublicKey (privateKey) { + validatePrivateKey(privateKey) + return secp256k1.publicKeyCreate(privateKey) + } + + return { + generateKey: generateKey, + privateKeyLength: privateKeyLength, + hashAndSign: hashAndSign, + hashAndVerify: hashAndVerify, + compressPublicKey: compressPublicKey, + decompressPublicKey: decompressPublicKey, + validatePrivateKey: validatePrivateKey, + validatePublicKey: validatePublicKey, + computePublicKey: computePublicKey + } +} diff --git a/src/crypto/index.js b/src/crypto/index.js deleted file mode 100644 index 7e2b494..0000000 --- a/src/crypto/index.js +++ /dev/null @@ -1,85 +0,0 @@ -'use strict' - -const secp256k1 = require('secp256k1') -const multihashing = require('multihashing-async') -const setImmediate = require('async/setImmediate') -const randomBytes = require('libp2p-crypto').randomBytes - -const HASH_ALGORITHM = 'sha2-256' - -exports.privateKeyLength = 32 - -exports.generateKey = function (callback) { - const done = (err, res) => setImmediate(() => { - callback(err, res) - }) - - let privateKey - do { - privateKey = randomBytes(32) - } while (!secp256k1.privateKeyVerify(privateKey)) - - done(null, privateKey) -} - -exports.hashAndSign = function (key, msg, callback) { - const done = (err, res) => setImmediate(() => { - callback(err, res) - }) - - multihashing.digest(msg, HASH_ALGORITHM, (err, digest) => { - if (err) { return done(err) } - try { - const sig = secp256k1.sign(digest, key) - const sigDER = secp256k1.signatureExport(sig.signature) - return done(null, sigDER) - } catch (err) { - done(err) - } - }) -} - -exports.hashAndVerify = function (key, sig, msg, callback) { - const done = (err, res) => setImmediate(() => { - callback(err, res) - }) - - multihashing.digest(msg, HASH_ALGORITHM, (err, digest) => { - if (err) { return done(err) } - try { - sig = secp256k1.signatureImport(sig) - const valid = secp256k1.verify(digest, sig, key) - return done(null, valid) - } catch (err) { - done(err) - } - }) -} - -exports.compressPublicKey = function compressPublicKey (key) { - if (!secp256k1.publicKeyVerify(key)) { - throw new Error('Invalid public key') - } - return secp256k1.publicKeyConvert(key, true) -} - -exports.decompressPublicKey = function decompressPublicKey (key) { - return secp256k1.publicKeyConvert(key, false) -} - -exports.validatePrivateKey = function validatePrivateKey (key) { - if (!secp256k1.privateKeyVerify(key)) { - throw new Error('Invalid private key') - } -} - -exports.validatePublicKey = function validatePublicKey (key) { - if (!secp256k1.publicKeyVerify(key)) { - throw new Error('Invalid public key') - } -} - -exports.computePublicKey = function computePublicKey (privateKey) { - exports.validatePrivateKey(privateKey) - return secp256k1.publicKeyCreate(privateKey) -} diff --git a/src/index.js b/src/index.js index 3d3c030..c3bb1d6 100644 --- a/src/index.js +++ b/src/index.js @@ -1,119 +1,118 @@ 'use strict' const multihashing = require('multihashing-async') -const crypto = require('./crypto') -const pbm = require('libp2p-crypto').keys.pbm -class Secp256k1PublicKey { - constructor (key) { - crypto.validatePublicKey(key) - this._key = key +module.exports = (keysProtobuf, randomBytes, crypto) => { + crypto = crypto || require('./crypto')(randomBytes) + + class Secp256k1PublicKey { + constructor (key) { + crypto.validatePublicKey(key) + this._key = key + } + + verify (data, sig, callback) { + ensure(callback) + crypto.hashAndVerify(this._key, sig, data, callback) + } + + marshal () { + return crypto.compressPublicKey(this._key) + } + + get bytes () { + return keysProtobuf.PublicKey.encode({ + Type: keysProtobuf.KeyType.Secp256k1, + Data: this.marshal() + }) + } + + equals (key) { + return this.bytes.equals(key.bytes) + } + + hash (callback) { + ensure(callback) + multihashing(this.bytes, 'sha2-256', callback) + } } - verify (data, sig, callback) { + class Secp256k1PrivateKey { + constructor (key, publicKey) { + this._key = key + this._publicKey = publicKey || crypto.computePublicKey(key) + crypto.validatePrivateKey(this._key) + crypto.validatePublicKey(this._publicKey) + } + + sign (message, callback) { + ensure(callback) + crypto.hashAndSign(this._key, message, callback) + } + + get public () { + return new Secp256k1PublicKey(this._publicKey) + } + + marshal () { + return this._key + } + + get bytes () { + return keysProtobuf.PrivateKey.encode({ + Type: keysProtobuf.KeyType.Secp256k1, + Data: this.marshal() + }) + } + + equals (key) { + return this.bytes.equals(key.bytes) + } + + hash (callback) { + ensure(callback) + multihashing(this.bytes, 'sha2-256', callback) + } + } + + function unmarshalSecp256k1PrivateKey (bytes, callback) { + callback(null, new Secp256k1PrivateKey(bytes), null) + } + + function unmarshalSecp256k1PublicKey (bytes) { + return new Secp256k1PublicKey(bytes) + } + + function generateKeyPair (_bits, callback) { + if (callback === undefined && typeof _bits === 'function') { + callback = _bits + } + ensure(callback) - crypto.hashAndVerify(this._key, sig, data, callback) - } - marshal () { - return crypto.compressPublicKey(this._key) - } + crypto.generateKey((err, privateKeyBytes) => { + if (err) { return callback(err) } - get bytes () { - return pbm.PublicKey.encode({ - Type: pbm.KeyType.Secp256k1, - Data: this.marshal() + let privkey + try { + privkey = new Secp256k1PrivateKey(privateKeyBytes) + } catch (err) { return callback(err) } + + callback(null, privkey) }) } - equals (key) { - return this.bytes.equals(key.bytes) - } - - hash (callback) { - ensure(callback) - multihashing(this.bytes, 'sha2-256', callback) - } -} - -class Secp256k1PrivateKey { - constructor (key, publicKey) { - this._key = key - this._publicKey = publicKey || crypto.computePublicKey(key) - crypto.validatePrivateKey(this._key) - crypto.validatePublicKey(this._publicKey) - } - - sign (message, callback) { - ensure(callback) - crypto.hashAndSign(this._key, message, callback) - } - - get public () { - return new Secp256k1PublicKey(this._publicKey) - } - - marshal () { - return this._key - } - - get bytes () { - return pbm.PrivateKey.encode({ - Type: pbm.KeyType.Secp256k1, - Data: this.marshal() - }) - } - - equals (key) { - return this.bytes.equals(key.bytes) - } - - hash (callback) { - ensure(callback) - multihashing(this.bytes, 'sha2-256', callback) - } -} - -function unmarshalSecp256k1PrivateKey (bytes, callback) { - callback(null, new Secp256k1PrivateKey(bytes), null) -} - -function unmarshalSecp256k1PublicKey (bytes) { - return new Secp256k1PublicKey(bytes) -} - -function generateKeyPair (_bits, cb) { - if (cb === undefined && typeof _bits === 'function') { - cb = _bits - } - ensure(cb) - - crypto.generateKey((err, privateKeyBytes) => { - if (err) { - return cb(err) - } - let privkey - try { - privkey = new Secp256k1PrivateKey(privateKeyBytes) - } catch (err) { - cb(err) - return + function ensure (callback) { + if (typeof callback !== 'function') { + throw new Error('callback is required') } + } - cb(null, privkey) - }) -} - -function ensure (cb) { - if (typeof cb !== 'function') { - throw new Error('callback is required') + return { + Secp256k1PublicKey, + Secp256k1PrivateKey, + unmarshalSecp256k1PrivateKey, + unmarshalSecp256k1PublicKey, + generateKeyPair } } - -module.exports = { - Secp256k1PublicKey, - Secp256k1PrivateKey, - unmarshalSecp256k1PrivateKey, - unmarshalSecp256k1PublicKey, - generateKeyPair -} diff --git a/test/secp256k1.spec.js b/test/secp256k1.spec.js index d68f653..85d250d 100644 --- a/test/secp256k1.spec.js +++ b/test/secp256k1.spec.js @@ -8,14 +8,15 @@ chai.use(dirtyChai) const Buffer = require('safe-buffer').Buffer -const secp256k1 = require('../src') -const crypto = require('../src/crypto') const libp2pCrypto = require('libp2p-crypto') -const pbm = libp2pCrypto.keys.pbm +const keysPBM = libp2pCrypto.keys.keysPBM const randomBytes = libp2pCrypto.randomBytes +const crypto = require('../src/crypto')(randomBytes) describe('secp256k1 keys', () => { let key + const secp256k1 = require('../src')(keysPBM, randomBytes) + before((done) => { secp256k1.generateKeyPair((err, _key) => { expect(err).to.not.exist() @@ -133,10 +134,13 @@ describe('secp256k1 keys', () => { describe('key generation error', () => { let generateKey + let secp256k1 before((done) => { generateKey = crypto.generateKey - crypto.generateKey = (callback) => { callback(new Error('Error generating key')) } + crypto.generateKey = (callback) => callback(new Error('Error generating key')) + secp256k1 = require('../src')(keysPBM, randomBytes, crypto) + done() }) @@ -156,10 +160,13 @@ describe('key generation error', () => { describe('handles generation of invalid key', () => { let generateKey + let secp256k1 before((done) => { generateKey = crypto.generateKey crypto.generateKey = (callback) => { callback(null, Buffer.from('not a real key')) } + secp256k1 = require('../src')(keysPBM, randomBytes, crypto) + done() }) @@ -280,13 +287,14 @@ describe('crypto functions', () => { }) describe('go interop', () => { + const secp256k1 = require('../src')(keysPBM, randomBytes) const fixtures = require('./fixtures/go-interop') it('loads a private key marshaled by go-libp2p-crypto', (done) => { // we need to first extract the key data from the protobuf, which is // normally handled by js-libp2p-crypto - const decoded = pbm.PrivateKey.decode(fixtures.privateKey) - expect(decoded.Type).to.eql(pbm.KeyType.Secp256k1) + const decoded = keysPBM.PrivateKey.decode(fixtures.privateKey) + expect(decoded.Type).to.eql(keysPBM.KeyType.Secp256k1) secp256k1.unmarshalSecp256k1PrivateKey(decoded.Data, (err, key) => { expect(err).to.not.exist() @@ -298,8 +306,8 @@ describe('go interop', () => { }) it('loads a public key marshaled by go-libp2p-crypto', (done) => { - const decoded = pbm.PublicKey.decode(fixtures.publicKey) - expect(decoded.Type).to.be.eql(pbm.KeyType.Secp256k1) + const decoded = keysPBM.PublicKey.decode(fixtures.publicKey) + expect(decoded.Type).to.be.eql(keysPBM.KeyType.Secp256k1) const key = secp256k1.unmarshalSecp256k1PublicKey(decoded.Data) expect(key).to.be.an.instanceof(secp256k1.Secp256k1PublicKey) @@ -308,8 +316,8 @@ describe('go interop', () => { }) it('generates the same signature as go-libp2p-crypto', (done) => { - const decoded = pbm.PrivateKey.decode(fixtures.privateKey) - expect(decoded.Type).to.eql(pbm.KeyType.Secp256k1) + const decoded = keysPBM.PrivateKey.decode(fixtures.privateKey) + expect(decoded.Type).to.eql(keysPBM.KeyType.Secp256k1) secp256k1.unmarshalSecp256k1PrivateKey(decoded.Data, (err, key) => { expect(err).to.not.exist() From ce5fb8c1b9905cc6816049066a57f500bf4cf05a Mon Sep 17 00:00:00 2001 From: David Dias Date: Sat, 22 Jul 2017 13:32:00 -0700 Subject: [PATCH 26/59] chore: update contributors --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 467484b..7132880 100644 --- a/package.json +++ b/package.json @@ -62,4 +62,4 @@ "Friedel Ziegelmayer ", "Yusef Napora " ] -} +} \ No newline at end of file From 98b285a840896cc51a78defb90ca863695985ecf Mon Sep 17 00:00:00 2001 From: David Dias Date: Sat, 22 Jul 2017 13:32:01 -0700 Subject: [PATCH 27/59] chore: release version v0.2.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 7132880..e3c7902 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "libp2p-crypto-secp256k1", - "version": "0.2.1", + "version": "0.2.2", "description": "Support for secp256k1 keys in libp2p-crypto", "main": "src/index.js", "browser": { From f2b67f7d82014882bf4a4afd9c87fbe717ad8cf0 Mon Sep 17 00:00:00 2001 From: Victor Bjelkholm Date: Fri, 22 Dec 2017 14:16:17 +0100 Subject: [PATCH 28/59] Updating CI files This commit updates all CI scripts to the latest version --- .travis.yml | 17 ++++++----------- appveyor.yml | 29 +++++++++++++++++++++++++++++ ci/Jenkinsfile | 2 ++ circle.yml | 1 + 4 files changed, 38 insertions(+), 11 deletions(-) create mode 100644 appveyor.yml create mode 100644 ci/Jenkinsfile diff --git a/.travis.yml b/.travis.yml index 5cc672b..5102ee5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,25 +1,20 @@ +# Warning: This file is automatically synced from https://github.com/ipfs/ci-sync so if you want to change it, please change it there and ask someone to sync all repositories. sudo: false language: node_js matrix: include: - - node_js: 4 - env: CXX=g++-4.8 - node_js: 6 - env: - - CXX=g++-4.8 - - node_js: stable env: CXX=g++-4.8 - -# Make sure we have new NPM. -before_install: - - npm install -g npm@4 + - node_js: 8 + env: CXX=g++-4.8 + # - node_js: stable + # env: CXX=g++-4.8 script: - npm run lint - - npm test + - npm run test - npm run coverage - - make test before_script: - export DISPLAY=:99.0 diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 0000000..046bf91 --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,29 @@ +# Warning: This file is automatically synced from https://github.com/ipfs/ci-sync so if you want to change it, please change it there and ask someone to sync all repositories. +version: "{build}" + +environment: + matrix: + - nodejs_version: "6" + - nodejs_version: "8" + +matrix: + fast_finish: true + +install: + # Install Node.js + - ps: Install-Product node $env:nodejs_version + + # Upgrade npm + - npm install -g npm + + # Output our current versions for debugging + - node --version + - npm --version + + # Install our package dependencies + - npm install + +test_script: + - npm run test:node + +build: off diff --git a/ci/Jenkinsfile b/ci/Jenkinsfile new file mode 100644 index 0000000..a7da2e5 --- /dev/null +++ b/ci/Jenkinsfile @@ -0,0 +1,2 @@ +// Warning: This file is automatically synced from https://github.com/ipfs/ci-sync so if you want to change it, please change it there and ask someone to sync all repositories. +javascript() diff --git a/circle.yml b/circle.yml index 56f7efb..0009693 100644 --- a/circle.yml +++ b/circle.yml @@ -1,3 +1,4 @@ +# Warning: This file is automatically synced from https://github.com/ipfs/ci-sync so if you want to change it, please change it there and ask someone to sync all repositories. machine: node: version: stable From 937cc767140e2be16613f4d66b873f268c5adfb0 Mon Sep 17 00:00:00 2001 From: David Dias Date: Tue, 1 May 2018 14:41:12 +0100 Subject: [PATCH 29/59] add lead maintainer --- README.md | 6 +++++- package.json | 13 ++++--------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 3670b05..e583c7d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# js-libp2p-crypto +# js-libp2p-crypto-secp256k1 [![](https://img.shields.io/badge/made%20by-Protocol%20Labs-blue.svg?style=flat-square)](http://ipn.io) [![](https://img.shields.io/badge/project-IPFS-blue.svg?style=flat-square)](http://ipfs.io/) @@ -15,6 +15,10 @@ implementation of cryptographic signature generation and verification using the [secp256k1 elliptic curve](https://en.bitcoin.it/wiki/Secp256k1) popularized by Bitcoin and other crypto currencies. +## Lead Captain + +[Friedel Ziegelmayer](https://github.com/dignifiedquire/) + ## Table of Contents - [Install](#install) diff --git a/package.json b/package.json index e3c7902..67def9d 100644 --- a/package.json +++ b/package.json @@ -2,6 +2,7 @@ "name": "libp2p-crypto-secp256k1", "version": "0.2.2", "description": "Support for secp256k1 keys in libp2p-crypto", + "leadMaintainer": "Friedel Ziegelmayer ", "main": "src/index.js", "browser": { "secp256k1": "secp256k1/js" @@ -24,7 +25,6 @@ "crypto", "secp256k1" ], - "author": "Yusef Napora ", "license": "MIT", "dependencies": { "async": "^2.5.0", @@ -38,15 +38,10 @@ "benchmark": "^2.1.4", "libp2p-crypto": "~0.9.4", "chai": "^4.1.0", - "dirty-chai": "^2.0.1", - "pre-commit": "^1.2.2" + "dirty-chai": "^2.0.1" }, - "pre-commit": [ - "lint", - "test" - ], "engines": { - "node": ">=4.0.0", + "node": ">=6.0.0", "npm": ">=3.0.0" }, "repository": { @@ -62,4 +57,4 @@ "Friedel Ziegelmayer ", "Yusef Napora " ] -} \ No newline at end of file +} From 1602c440ad10434030aa1ffdaed168af2b9a04cd Mon Sep 17 00:00:00 2001 From: David Dias Date: Tue, 1 May 2018 14:41:37 +0100 Subject: [PATCH 30/59] chore: update deps --- package.json | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/package.json b/package.json index 67def9d..8a29d34 100644 --- a/package.json +++ b/package.json @@ -27,17 +27,17 @@ ], "license": "MIT", "dependencies": { - "async": "^2.5.0", - "multihashing-async": "~0.4.6", + "async": "^2.6.0", + "multihashing-async": "~0.4.8", "nodeify": "^1.0.1", - "safe-buffer": "^5.1.1", - "secp256k1": "^3.3.0" + "safe-buffer": "^5.1.2", + "secp256k1": "^3.5.0" }, "devDependencies": { - "aegir": "^11.0.2", + "aegir": "^13.1.0", "benchmark": "^2.1.4", - "libp2p-crypto": "~0.9.4", - "chai": "^4.1.0", + "libp2p-crypto": "~0.13.0", + "chai": "^4.1.2", "dirty-chai": "^2.0.1" }, "engines": { From cfdcbe08d4a02586dc636ff69df43f20543f3bb4 Mon Sep 17 00:00:00 2001 From: Hugo Dias Date: Mon, 17 Dec 2018 11:54:05 +0000 Subject: [PATCH 31/59] fix: update deps and repo setup --- .gitignore | 2 ++ .travis.yml | 32 -------------------------------- appveyor.yml | 29 ----------------------------- circle.yml | 15 --------------- package.json | 26 +++++++++++++------------- 5 files changed, 15 insertions(+), 89 deletions(-) delete mode 100644 .travis.yml delete mode 100644 appveyor.yml delete mode 100644 circle.yml diff --git a/.gitignore b/.gitignore index fb8d1c9..23e606c 100644 --- a/.gitignore +++ b/.gitignore @@ -32,3 +32,5 @@ build node_modules dist +package-lock.json +yarn.lock \ No newline at end of file diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 5102ee5..0000000 --- a/.travis.yml +++ /dev/null @@ -1,32 +0,0 @@ -# Warning: This file is automatically synced from https://github.com/ipfs/ci-sync so if you want to change it, please change it there and ask someone to sync all repositories. -sudo: false -language: node_js - -matrix: - include: - - node_js: 6 - env: CXX=g++-4.8 - - node_js: 8 - env: CXX=g++-4.8 - # - node_js: stable - # env: CXX=g++-4.8 - -script: - - npm run lint - - npm run test - - npm run coverage - -before_script: - - export DISPLAY=:99.0 - - sh -e /etc/init.d/xvfb start - -after_success: - - npm run coverage-publish - -addons: - firefox: 'latest' - apt: - sources: - - ubuntu-toolchain-r-test - packages: - - g++-4.8 diff --git a/appveyor.yml b/appveyor.yml deleted file mode 100644 index 046bf91..0000000 --- a/appveyor.yml +++ /dev/null @@ -1,29 +0,0 @@ -# Warning: This file is automatically synced from https://github.com/ipfs/ci-sync so if you want to change it, please change it there and ask someone to sync all repositories. -version: "{build}" - -environment: - matrix: - - nodejs_version: "6" - - nodejs_version: "8" - -matrix: - fast_finish: true - -install: - # Install Node.js - - ps: Install-Product node $env:nodejs_version - - # Upgrade npm - - npm install -g npm - - # Output our current versions for debugging - - node --version - - npm --version - - # Install our package dependencies - - npm install - -test_script: - - npm run test:node - -build: off diff --git a/circle.yml b/circle.yml deleted file mode 100644 index 0009693..0000000 --- a/circle.yml +++ /dev/null @@ -1,15 +0,0 @@ -# Warning: This file is automatically synced from https://github.com/ipfs/ci-sync so if you want to change it, please change it there and ask someone to sync all repositories. -machine: - node: - version: stable - -dependencies: - pre: - - google-chrome --version - - curl -L -o google-chrome.deb https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb - - sudo dpkg -i google-chrome.deb || true - - sudo apt-get update - - sudo apt-get install -f - - sudo apt-get install --only-upgrade lsb-base - - sudo dpkg -i google-chrome.deb - - google-chrome --version diff --git a/package.json b/package.json index 8a29d34..d5359a6 100644 --- a/package.json +++ b/package.json @@ -8,16 +8,16 @@ "secp256k1": "secp256k1/js" }, "scripts": { - "lint": "aegir-lint", - "build": "aegir-build", + "lint": "aegir lint", + "build": "aegir build", "test": "npm run test:node && npm run test:browser", - "test:node": "aegir-test --env node", - "test:browser": "aegir-test --env browser", - "release": "aegir-release", - "release-minor": "aegir-release --type minor", - "release-major": "aegir-release --type major", - "coverage": "aegir-coverage", - "coverage-publish": "aegir-coverage publish" + "test:node": "aegir test --env node", + "test:browser": "aegir test --env browser", + "release": "aegir release", + "release-minor": "aegir release --type minor", + "release-major": "aegir release --type major", + "coverage": "aegir coverage", + "coverage-publish": "aegir coverage publish" }, "keywords": [ "IPFS", @@ -28,17 +28,17 @@ "license": "MIT", "dependencies": { "async": "^2.6.0", - "multihashing-async": "~0.4.8", + "multihashing-async": "~0.5.1", "nodeify": "^1.0.1", "safe-buffer": "^5.1.2", "secp256k1": "^3.5.0" }, "devDependencies": { - "aegir": "^13.1.0", + "aegir": "github:ipfs/aegir#feat/make-exp-build-test-default", "benchmark": "^2.1.4", - "libp2p-crypto": "~0.13.0", "chai": "^4.1.2", - "dirty-chai": "^2.0.1" + "dirty-chai": "^2.0.1", + "libp2p-crypto": "~0.14.1" }, "engines": { "node": ">=6.0.0", From 720246f012ef22fa90e52726191c8af0c6d9e534 Mon Sep 17 00:00:00 2001 From: Hugo Dias Date: Tue, 8 Jan 2019 14:54:21 +0000 Subject: [PATCH 32/59] chore: update deps --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d5359a6..5cfbd45 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "secp256k1": "^3.5.0" }, "devDependencies": { - "aegir": "github:ipfs/aegir#feat/make-exp-build-test-default", + "aegir": "^18.0.2", "benchmark": "^2.1.4", "chai": "^4.1.2", "dirty-chai": "^2.0.1", From 6c9928abd658af037d5145b90e8b96887cb70954 Mon Sep 17 00:00:00 2001 From: David Dias Date: Tue, 8 Jan 2019 16:43:36 +0100 Subject: [PATCH 33/59] chore: update deps --- package.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 5cfbd45..d677589 100644 --- a/package.json +++ b/package.json @@ -27,18 +27,18 @@ ], "license": "MIT", "dependencies": { - "async": "^2.6.0", + "async": "^2.6.1", "multihashing-async": "~0.5.1", "nodeify": "^1.0.1", "safe-buffer": "^5.1.2", - "secp256k1": "^3.5.0" + "secp256k1": "^3.6.1" }, "devDependencies": { - "aegir": "^18.0.2", + "aegir": "^18.0.3", "benchmark": "^2.1.4", - "chai": "^4.1.2", + "chai": "^4.2.0", "dirty-chai": "^2.0.1", - "libp2p-crypto": "~0.14.1" + "libp2p-crypto": "~0.15.0" }, "engines": { "node": ">=6.0.0", From c983edfdb9cbd9cc35d7db2b15ff500955f32475 Mon Sep 17 00:00:00 2001 From: David Dias Date: Tue, 8 Jan 2019 16:44:54 +0100 Subject: [PATCH 34/59] chore: update contributors --- package.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index d677589..eb51be3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "libp2p-crypto-secp256k1", - "version": "0.2.2", + "version": "0.2.3", "description": "Support for secp256k1 keys in libp2p-crypto", "leadMaintainer": "Friedel Ziegelmayer ", "main": "src/index.js", @@ -55,6 +55,8 @@ "contributors": [ "David Dias ", "Friedel Ziegelmayer ", + "Hugo Dias ", + "Victor Bjelkholm ", "Yusef Napora " ] } From 3a8bab9f44c218d42c88e4ff70a52b09851da673 Mon Sep 17 00:00:00 2001 From: David Dias Date: Tue, 8 Jan 2019 16:44:54 +0100 Subject: [PATCH 35/59] chore: release version v0.2.3 --- CHANGELOG.md | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..c7e9a20 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,65 @@ + +## [0.2.3](https://github.com/libp2p/js-libp2p-crypto-secp256k1/compare/v0.2.2...v0.2.3) (2019-01-08) + + +### Bug Fixes + +* update deps and repo setup ([cfdcbe0](https://github.com/libp2p/js-libp2p-crypto-secp256k1/commit/cfdcbe0)) + + + + +## [0.2.2](https://github.com/libp2p/js-libp2p-crypto-secp256k1/compare/v0.2.1...v0.2.2) (2017-07-22) + + +### Bug Fixes + +* circular circular dep -> DI ([0dcf1a6](https://github.com/libp2p/js-libp2p-crypto-secp256k1/commit/0dcf1a6)) + + + + +## [0.2.1](https://github.com/libp2p/js-libp2p-crypto-secp256k1/compare/v0.2.0...v0.2.1) (2017-07-22) + + + + +# [0.2.0](https://github.com/libp2p/js-libp2p-crypto-secp256k1/compare/v0.1.4...v0.2.0) (2017-07-22) + + +### Features + +* next libp2p-crypto ([#4](https://github.com/libp2p/js-libp2p-crypto-secp256k1/issues/4)) ([4ee48a7](https://github.com/libp2p/js-libp2p-crypto-secp256k1/commit/4ee48a7)) + + + + +## [0.1.4](https://github.com/libp2p/js-libp2p-crypto-secp256k1/compare/v0.1.3...v0.1.4) (2017-02-12) + + + + +## [0.1.3](https://github.com/libp2p/js-libp2p-crypto-secp256k1/compare/v0.1.2...v0.1.3) (2017-02-11) + + + + +## [0.1.2](https://github.com/libp2p/js-libp2p-crypto-secp256k1/compare/v0.1.1...v0.1.2) (2017-02-09) + + + + +## [0.1.1](https://github.com/libp2p/js-libp2p-crypto-secp256k1/compare/v0.1.0...v0.1.1) (2017-02-09) + + + + +# [0.1.0](https://github.com/libp2p/js-libp2p-crypto-secp256k1/compare/4c36aeb...v0.1.0) (2017-02-09) + + +### Features + +* initial implementation ([4c36aeb](https://github.com/libp2p/js-libp2p-crypto-secp256k1/commit/4c36aeb)) + + + From f4dbd62e49cc4a7ab044fc1d723888d5b2d43973 Mon Sep 17 00:00:00 2001 From: Alberto Elias Date: Wed, 20 Feb 2019 13:23:05 +0100 Subject: [PATCH 36/59] feat: add `id()` method to Secp256k1PrivateKey Feature parity with ed25519 and rsa --- package.json | 1 + src/index.js | 20 ++++++++++++++++++++ test/secp256k1.spec.js | 9 +++++++++ 3 files changed, 30 insertions(+) diff --git a/package.json b/package.json index eb51be3..43d2dea 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,7 @@ "license": "MIT", "dependencies": { "async": "^2.6.1", + "bs58": "^4.0.1", "multihashing-async": "~0.5.1", "nodeify": "^1.0.1", "safe-buffer": "^5.1.2", diff --git a/src/index.js b/src/index.js index c3bb1d6..727a0e3 100644 --- a/src/index.js +++ b/src/index.js @@ -1,5 +1,6 @@ 'use strict' +const bs58 = require('bs58') const multihashing = require('multihashing-async') module.exports = (keysProtobuf, randomBytes, crypto) => { @@ -73,6 +74,25 @@ module.exports = (keysProtobuf, randomBytes, crypto) => { ensure(callback) multihashing(this.bytes, 'sha2-256', callback) } + + /** + * Gets the ID of the key. + * + * The key id is the base58 encoding of the SHA-256 multihash of its public key. + * The public key is a protobuf encoding containing a type and the DER encoding + * of the PKCS SubjectPublicKeyInfo. + * + * @param {function(Error, id)} callback + * @returns {undefined} + */ + id (callback) { + this.public.hash((err, hash) => { + if (err) { + return callback(err) + } + callback(null, bs58.encode(hash)) + }) + } } function unmarshalSecp256k1PrivateKey (bytes, callback) { diff --git a/test/secp256k1.spec.js b/test/secp256k1.spec.js index 85d250d..7ce0780 100644 --- a/test/secp256k1.spec.js +++ b/test/secp256k1.spec.js @@ -85,6 +85,15 @@ describe('secp256k1 keys', () => { }) }) + it('key id', (done) => { + key.id((err, id) => { + expect(err).to.not.exist() + expect(id).to.exist() + expect(id).to.be.a('string') + done() + }) + }) + describe('key equals', () => { it('equals itself', () => { expect(key.equals(key)).to.eql(true) From 53a2b590a937380218a84969a4a0214b59f0b84e Mon Sep 17 00:00:00 2001 From: dignifiedquire Date: Wed, 20 Feb 2019 13:28:46 +0100 Subject: [PATCH 37/59] chore(dev-deps): update libp2p-crypto --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 43d2dea..8e789e9 100644 --- a/package.json +++ b/package.json @@ -39,7 +39,7 @@ "benchmark": "^2.1.4", "chai": "^4.2.0", "dirty-chai": "^2.0.1", - "libp2p-crypto": "~0.15.0" + "libp2p-crypto": "~0.16.0" }, "engines": { "node": ">=6.0.0", From 5fc391c8e0e876fd2688b2fc451dd48c47da8ae7 Mon Sep 17 00:00:00 2001 From: dignifiedquire Date: Wed, 20 Feb 2019 13:29:17 +0100 Subject: [PATCH 38/59] chore: update contributors --- package.json | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 8e789e9..3e56b5d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "libp2p-crypto-secp256k1", - "version": "0.2.3", + "version": "0.3.0", "description": "Support for secp256k1 keys in libp2p-crypto", "leadMaintainer": "Friedel Ziegelmayer ", "main": "src/index.js", @@ -54,10 +54,12 @@ }, "homepage": "https://github.com/libp2p/js-libp2p-crypto-secp256k1", "contributors": [ + "Alberto Elias ", "David Dias ", "Friedel Ziegelmayer ", "Hugo Dias ", "Victor Bjelkholm ", - "Yusef Napora " + "Yusef Napora ", + "dignifiedquire " ] } From ce22cf13f0c332fb9078c49ed4e596de95b020e7 Mon Sep 17 00:00:00 2001 From: dignifiedquire Date: Wed, 20 Feb 2019 13:29:17 +0100 Subject: [PATCH 39/59] chore: release version v0.3.0 --- CHANGELOG.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c7e9a20..18d8798 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,13 @@ + +# [0.3.0](https://github.com/libp2p/js-libp2p-crypto-secp256k1/compare/v0.2.3...v0.3.0) (2019-02-20) + + +### Features + +* add `id()` method to Secp256k1PrivateKey ([f4dbd62](https://github.com/libp2p/js-libp2p-crypto-secp256k1/commit/f4dbd62)) + + + ## [0.2.3](https://github.com/libp2p/js-libp2p-crypto-secp256k1/compare/v0.2.2...v0.2.3) (2019-01-08) From 3f131d4a0a3b4ea8357144c2d73cc69508e306c0 Mon Sep 17 00:00:00 2001 From: Vasco Santos Date: Thu, 18 Apr 2019 18:30:06 +0100 Subject: [PATCH 40/59] chore: add discourse badge (#15) --- .travis.yml | 44 ++++++++++++++++++++++++++++++++++++++++++++ README.md | 11 +++++++---- ci/Jenkinsfile | 2 -- package.json | 16 ++++++++-------- 4 files changed, 59 insertions(+), 14 deletions(-) create mode 100644 .travis.yml delete mode 100644 ci/Jenkinsfile diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..264f189 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,44 @@ +language: node_js + +cache: npm + +stages: + - check + - test + - cov + +node_js: + - '10' + +os: + - linux + - osx + - windows + +script: npx nyc -s npm run test:node -- --bail +after_success: npx nyc report --reporter=text-lcov > coverage.lcov && npx codecov + +jobs: + include: + - stage: check + script: + - npx aegir commitlint --travis + - npx aegir dep-check + - npm run lint + + - stage: test + name: chrome + addons: + chrome: stable + script: + - npx aegir test -t browser + + - stage: test + name: firefox + addons: + firefox: latest + script: + - npx aegir test -t browser -- --browsers FirefoxHeadless + +notifications: + email: false diff --git a/README.md b/README.md index e583c7d..d3cafac 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,12 @@ # js-libp2p-crypto-secp256k1 -[![](https://img.shields.io/badge/made%20by-Protocol%20Labs-blue.svg?style=flat-square)](http://ipn.io) -[![](https://img.shields.io/badge/project-IPFS-blue.svg?style=flat-square)](http://ipfs.io/) -[![](https://img.shields.io/badge/freenode-%23ipfs-blue.svg?style=flat-square)](http://webchat.freenode.net/?channels=%23ipfs) -[![standard-readme compliant](https://img.shields.io/badge/standard--readme-OK-green.svg?style=flat-square)](https://github.com/RichardLitt/standard-readme) +[![](https://img.shields.io/badge/made%20by-Protocol%20Labs-blue.svg?style=flat-square)](http://protocol.ai) +[![](https://img.shields.io/badge/project-libp2p-yellow.svg?style=flat-square)](http://libp2p.io/) +[![](https://img.shields.io/badge/freenode-%23libp2p-yellow.svg?style=flat-square)](http://webchat.freenode.net/?channels=%23libp2p) +[![Discourse posts](https://img.shields.io/discourse/https/discuss.libp2p.io/posts.svg)](https://discuss.libp2p.io) +[![](https://img.shields.io/codecov/c/github/libp2p/js-libp2p-crypto-secp256k1.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-crypto-secp256k1) +[![](https://img.shields.io/travis/libp2p/js-libp2p-crypto-secp256k1.svg?style=flat-square)](https://travis-ci.com/libp2p/js-libp2p-crypto-secp256k1) +[![Dependency Status](https://david-dm.org/libp2p/js-libp2p-crypto-secp256k1.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-crypto-secp256k1) [![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/npm-%3E%3D3.0.0-orange.svg?style=flat-square) ![](https://img.shields.io/badge/Node.js-%3E%3D4.0.0-orange.svg?style=flat-square) diff --git a/ci/Jenkinsfile b/ci/Jenkinsfile deleted file mode 100644 index a7da2e5..0000000 --- a/ci/Jenkinsfile +++ /dev/null @@ -1,2 +0,0 @@ -// Warning: This file is automatically synced from https://github.com/ipfs/ci-sync so if you want to change it, please change it there and ask someone to sync all repositories. -javascript() diff --git a/package.json b/package.json index 3e56b5d..f1823fb 100644 --- a/package.json +++ b/package.json @@ -10,9 +10,9 @@ "scripts": { "lint": "aegir lint", "build": "aegir build", - "test": "npm run test:node && npm run test:browser", - "test:node": "aegir test --env node", - "test:browser": "aegir test --env browser", + "test": "aegir test -t node -t browser", + "test:node": "aegir test -t node", + "test:browser": "aegir test -t browser", "release": "aegir release", "release-minor": "aegir release --type minor", "release-major": "aegir release --type major", @@ -27,19 +27,19 @@ ], "license": "MIT", "dependencies": { - "async": "^2.6.1", + "async": "^2.6.2", "bs58": "^4.0.1", - "multihashing-async": "~0.5.1", + "multihashing-async": "~0.6.0", "nodeify": "^1.0.1", "safe-buffer": "^5.1.2", - "secp256k1": "^3.6.1" + "secp256k1": "^3.6.2" }, "devDependencies": { - "aegir": "^18.0.3", + "aegir": "^18.2.2", "benchmark": "^2.1.4", "chai": "^4.2.0", "dirty-chai": "^2.0.1", - "libp2p-crypto": "~0.16.0" + "libp2p-crypto": "~0.16.1" }, "engines": { "node": ">=6.0.0", From 3bb84514d19e649afc89d103a1af83f52e8f63c7 Mon Sep 17 00:00:00 2001 From: Arve Knudsen Date: Wed, 10 Jul 2019 10:56:11 +0200 Subject: [PATCH 41/59] fix(unmarshal): provide only one arg to callback (#17) --- src/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/index.js b/src/index.js index 727a0e3..5d23e01 100644 --- a/src/index.js +++ b/src/index.js @@ -96,7 +96,7 @@ module.exports = (keysProtobuf, randomBytes, crypto) => { } function unmarshalSecp256k1PrivateKey (bytes, callback) { - callback(null, new Secp256k1PrivateKey(bytes), null) + callback(null, new Secp256k1PrivateKey(bytes)) } function unmarshalSecp256k1PublicKey (bytes) { From 9f01868c6c3e58255ab93113214e633799cc529e Mon Sep 17 00:00:00 2001 From: Jacob Heun Date: Wed, 10 Jul 2019 10:05:53 +0100 Subject: [PATCH 42/59] chore: update contributors --- package.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index f1823fb..09dcc60 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "libp2p-crypto-secp256k1", - "version": "0.3.0", + "version": "0.3.1", "description": "Support for secp256k1 keys in libp2p-crypto", "leadMaintainer": "Friedel Ziegelmayer ", "main": "src/index.js", @@ -55,9 +55,11 @@ "homepage": "https://github.com/libp2p/js-libp2p-crypto-secp256k1", "contributors": [ "Alberto Elias ", + "Arve Knudsen ", "David Dias ", "Friedel Ziegelmayer ", "Hugo Dias ", + "Vasco Santos ", "Victor Bjelkholm ", "Yusef Napora ", "dignifiedquire " From fbd42385e33f149eff41cfa16fa1e849de53c85b Mon Sep 17 00:00:00 2001 From: Jacob Heun Date: Wed, 10 Jul 2019 10:05:54 +0100 Subject: [PATCH 43/59] chore: release version v0.3.1 --- CHANGELOG.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 18d8798..f9d82b8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,19 @@ + +## [0.3.1](https://github.com/libp2p/js-libp2p-crypto-secp256k1/compare/v0.2.2...v0.3.1) (2019-07-10) + + +### Bug Fixes + +* update deps and repo setup ([cfdcbe0](https://github.com/libp2p/js-libp2p-crypto-secp256k1/commit/cfdcbe0)) +* **unmarshal:** provide only one arg to callback ([#17](https://github.com/libp2p/js-libp2p-crypto-secp256k1/issues/17)) ([3bb8451](https://github.com/libp2p/js-libp2p-crypto-secp256k1/commit/3bb8451)) + + +### Features + +* add `id()` method to Secp256k1PrivateKey ([f4dbd62](https://github.com/libp2p/js-libp2p-crypto-secp256k1/commit/f4dbd62)) + + + # [0.3.0](https://github.com/libp2p/js-libp2p-crypto-secp256k1/compare/v0.2.3...v0.3.0) (2019-02-20) From 1974eb92be8d8e439286b564bc871006bbce5b02 Mon Sep 17 00:00:00 2001 From: Alex Potsides Date: Wed, 10 Jul 2019 11:35:58 +0100 Subject: [PATCH 44/59] feat: use async await (#18) BREAKING CHANGE: Callback support has been dropped in favor of async/await. * feat: use async/await This PR changes this module to remove callbacks and use async/await. The API is unchanged aside from the obvious removal of the `callback` parameter. refs https://github.com/ipfs/js-ipfs/issues/1670 * fix: use latest multihashing-async as it is all promises now --- .gitignore | 3 +- .travis.yml | 3 +- README.md | 60 ++++---- package.json | 5 +- src/crypto.js | 57 +++----- src/index.js | 61 +++----- test/secp256k1.spec.js | 309 ++++++++++++++++------------------------- 7 files changed, 191 insertions(+), 307 deletions(-) diff --git a/.gitignore b/.gitignore index 23e606c..452c69d 100644 --- a/.gitignore +++ b/.gitignore @@ -33,4 +33,5 @@ node_modules dist package-lock.json -yarn.lock \ No newline at end of file +yarn.lock +.vscode diff --git a/.travis.yml b/.travis.yml index 264f189..11e06a6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,3 +1,4 @@ + language: node_js cache: npm @@ -41,4 +42,4 @@ jobs: - npx aegir test -t browser -- --browsers FirefoxHeadless notifications: - email: false + email: false \ No newline at end of file diff --git a/README.md b/README.md index d3cafac..7063200 100644 --- a/README.md +++ b/README.md @@ -13,9 +13,9 @@ > Support for secp256k1 keys in js-libp2p-crypto -This repo contains a [js-libp2p-crypto](https://github.com/libp2p/js-libp2p-crypto)-compatible -implementation of cryptographic signature generation and verification using the -[secp256k1 elliptic curve](https://en.bitcoin.it/wiki/Secp256k1) popularized by Bitcoin and other +This repo contains a [js-libp2p-crypto](https://github.com/libp2p/js-libp2p-crypto)-compatible +implementation of cryptographic signature generation and verification using the +[secp256k1 elliptic curve](https://en.bitcoin.it/wiki/Secp256k1) popularized by Bitcoin and other crypto currencies. ## Lead Captain @@ -28,14 +28,14 @@ crypto currencies. - [Usage](#usage) - [Example](#example) - [API](#api) - - [`generateKeyPair([bits,] callback)`](#generatekeypairbits-callback) + - [`generateKeyPair([bits])`](#generatekeypairbits) - [`unmarshalSecp256k1PublicKey(bytes)`](#unmarshalsecp256k1publickeybytes) - - [`unmarshalSecp256k1PrivateKey(bytes, callback)`](#unmarshalsecp256k1privatekeybytes-callback) + - [`unmarshalSecp256k1PrivateKey(bytes)`](#unmarshalsecp256k1privatekeybytes) - [`Secp256k1PublicKey`](#secp256k1publickey) - - [`.verify(data, sig, callback)`](#verifydata-sig-callback) + - [`.verify(data, sig)`](#verifydata-sig) - [`Secp256k1PrivateKey`](#secp256k1privatekey) - [`.public`](#public) - - [`.sign(data, callback)`](#signdata-callback) + - [`.sign(data)`](#signdata) - [Contribute](#contribute) - [License](#license) @@ -57,48 +57,48 @@ instances of the `Secp256k1PublicKey` or `Secp256k1PrivateKey` classes provided ```js const crypto = require('libp2p-crypto') - const msg = Buffer.from('Hello World') -crypto.generateKeyPair('secp256k1', 256, (err, key) => { - // assuming no error, key will be an instance of Secp256k1PrivateKey - // the public key is available as key.public - key.sign(msg, (err, sig) => { - key.public.verify(msg, sig, (err, valid) => { - assert(valid, 'Something went horribly wrong') - }) - }) -}) +const key = await crypto.generateKeyPair('secp256k1', 256) +// assuming no error, key will be an instance of Secp256k1PrivateKey +// the public key is available as key.public +const sig = await key.sign(msg) + +const valid = await key.public.verify(msg, sig) +assert(valid, 'Something went horribly wrong') ``` ## API The functions below are the public API of this module. -For usage within libp2p-crypto, see the [libp2p-crypto API documentation](https://github.com/libp2p/js-libp2p-crypto#api). +For usage within `libp2p-crypto`, see the [`libp2p-crypto` API documentation](https://github.com/libp2p/js-libp2p-crypto#api). -### `generateKeyPair([bits, ] callback)` +### `generateKeyPair([bits])` - `bits: Number` - Optional, included for compatibility with js-libp2p-crypto. Ignored if present; private keys will always be 256 bits. -- `callback: Function` + +Returns `Promise` ### `unmarshalSecp256k1PublicKey(bytes)` - `bytes: Buffer` Converts a serialized secp256k1 public key into an instance of `Secp256k1PublicKey` and returns it -### `unmarshalSecp256k1PrivateKey(bytes, callback)` +### `unmarshalSecp256k1PrivateKey(bytes)` - `bytes: Buffer` -- `callback: Function` -Converts a serialized secp256k1 private key into an instance of `Secp256k1PrivateKey`, passing it to `callback` on success +Returns `Promise` + +Converts a serialized secp256k1 private key into an instance of `Secp256k1PrivateKey`. ### `Secp256k1PublicKey` -#### `.verify(data, sig, callback)` +#### `.verify(data, sig)` - `data: Buffer` - `sig: Buffer` -- `callback: Function` -Calculates the SHA-256 hash of `data`, and verifies the DER-encoded signature in `sig`, passing the result to `callback` +Returns `Promise` + +Calculates the SHA-256 hash of `data`, and verifies the DER-encoded signature in `sig`. ### `Secp256k1PrivateKey` @@ -106,14 +106,16 @@ Calculates the SHA-256 hash of `data`, and verifies the DER-encoded signature in Accessor for the `Secp256k1PublicKey` associated with this private key. -#### `.sign(data, callback)` +#### `.sign(data)` - `data: Buffer` -Calculates the SHA-256 hash of `data` and signs it, passing the DER-encoded signature to `callback` +Returns `Promise` + +Calculates the SHA-256 hash of `data` and signs it, resolves with the DER-encoded signature. ## Contribute -Feel free to join in. All welcome. Open an [issue](https://github.com/libp2p/js-libp2p-crypto/issues)! +Feel free to join in. All welcome. Open an [issue](https://github.com/libp2p/js-libp2p-crypto-secp256k1/issues)! This repository falls under the IPFS [Code of Conduct](https://github.com/ipfs/community/blob/master/code-of-conduct.md). diff --git a/package.json b/package.json index 09dcc60..3af690d 100644 --- a/package.json +++ b/package.json @@ -27,15 +27,14 @@ ], "license": "MIT", "dependencies": { - "async": "^2.6.2", "bs58": "^4.0.1", - "multihashing-async": "~0.6.0", + "multihashing-async": "^0.7.0", "nodeify": "^1.0.1", "safe-buffer": "^5.1.2", "secp256k1": "^3.6.2" }, "devDependencies": { - "aegir": "^18.2.2", + "aegir": "^19.0.5", "benchmark": "^2.1.4", "chai": "^4.2.0", "dirty-chai": "^2.0.1", diff --git a/src/crypto.js b/src/crypto.js index a336ab4..fbafb91 100644 --- a/src/crypto.js +++ b/src/crypto.js @@ -2,49 +2,30 @@ const secp256k1 = require('secp256k1') const multihashing = require('multihashing-async') -const setImmediate = require('async/setImmediate') const HASH_ALGORITHM = 'sha2-256' module.exports = (randomBytes) => { const privateKeyLength = 32 - function generateKey (callback) { - const done = (err, res) => setImmediate(() => callback(err, res)) - + function generateKey () { let privateKey do { privateKey = randomBytes(32) } while (!secp256k1.privateKeyVerify(privateKey)) - - done(null, privateKey) + return privateKey } - function hashAndSign (key, msg, callback) { - const done = (err, res) => setImmediate(() => callback(err, res)) - - multihashing.digest(msg, HASH_ALGORITHM, (err, digest) => { - if (err) { return done(err) } - - try { - const sig = secp256k1.sign(digest, key) - const sigDER = secp256k1.signatureExport(sig.signature) - return done(null, sigDER) - } catch (err) { done(err) } - }) + async function hashAndSign (key, msg) { + const digest = await multihashing.digest(msg, HASH_ALGORITHM) + const sig = secp256k1.sign(digest, key) + return secp256k1.signatureExport(sig.signature) } - function hashAndVerify (key, sig, msg, callback) { - const done = (err, res) => setImmediate(() => callback(err, res)) - - multihashing.digest(msg, HASH_ALGORITHM, (err, digest) => { - if (err) { return done(err) } - try { - sig = secp256k1.signatureImport(sig) - const valid = secp256k1.verify(digest, sig, key) - return done(null, valid) - } catch (err) { done(err) } - }) + async function hashAndVerify (key, sig, msg) { + const digest = await multihashing.digest(msg, HASH_ALGORITHM) + sig = secp256k1.signatureImport(sig) + return secp256k1.verify(digest, sig, key) } function compressPublicKey (key) { @@ -76,14 +57,14 @@ module.exports = (randomBytes) => { } return { - generateKey: generateKey, - privateKeyLength: privateKeyLength, - hashAndSign: hashAndSign, - hashAndVerify: hashAndVerify, - compressPublicKey: compressPublicKey, - decompressPublicKey: decompressPublicKey, - validatePrivateKey: validatePrivateKey, - validatePublicKey: validatePublicKey, - computePublicKey: computePublicKey + generateKey, + privateKeyLength, + hashAndSign, + hashAndVerify, + compressPublicKey, + decompressPublicKey, + validatePrivateKey, + validatePublicKey, + computePublicKey } } diff --git a/src/index.js b/src/index.js index 5d23e01..a1299b2 100644 --- a/src/index.js +++ b/src/index.js @@ -12,9 +12,8 @@ module.exports = (keysProtobuf, randomBytes, crypto) => { this._key = key } - verify (data, sig, callback) { - ensure(callback) - crypto.hashAndVerify(this._key, sig, data, callback) + verify (data, sig) { + return crypto.hashAndVerify(this._key, sig, data) } marshal () { @@ -32,9 +31,8 @@ module.exports = (keysProtobuf, randomBytes, crypto) => { return this.bytes.equals(key.bytes) } - hash (callback) { - ensure(callback) - multihashing(this.bytes, 'sha2-256', callback) + hash () { + return multihashing(this.bytes, 'sha2-256') } } @@ -46,9 +44,8 @@ module.exports = (keysProtobuf, randomBytes, crypto) => { crypto.validatePublicKey(this._publicKey) } - sign (message, callback) { - ensure(callback) - crypto.hashAndSign(this._key, message, callback) + sign (message) { + return crypto.hashAndSign(this._key, message) } get public () { @@ -70,9 +67,8 @@ module.exports = (keysProtobuf, randomBytes, crypto) => { return this.bytes.equals(key.bytes) } - hash (callback) { - ensure(callback) - multihashing(this.bytes, 'sha2-256', callback) + hash () { + return multihashing(this.bytes, 'sha2-256') } /** @@ -85,47 +81,24 @@ module.exports = (keysProtobuf, randomBytes, crypto) => { * @param {function(Error, id)} callback * @returns {undefined} */ - id (callback) { - this.public.hash((err, hash) => { - if (err) { - return callback(err) - } - callback(null, bs58.encode(hash)) - }) + async id () { + const hash = await this.public.hash() + + return bs58.encode(hash) } } - function unmarshalSecp256k1PrivateKey (bytes, callback) { - callback(null, new Secp256k1PrivateKey(bytes)) + function unmarshalSecp256k1PrivateKey (bytes) { + return new Secp256k1PrivateKey(bytes) } function unmarshalSecp256k1PublicKey (bytes) { return new Secp256k1PublicKey(bytes) } - function generateKeyPair (_bits, callback) { - if (callback === undefined && typeof _bits === 'function') { - callback = _bits - } - - ensure(callback) - - crypto.generateKey((err, privateKeyBytes) => { - if (err) { return callback(err) } - - let privkey - try { - privkey = new Secp256k1PrivateKey(privateKeyBytes) - } catch (err) { return callback(err) } - - callback(null, privkey) - }) - } - - function ensure (callback) { - if (typeof callback !== 'function') { - throw new Error('callback is required') - } + async function generateKeyPair () { + const privateKeyBytes = await crypto.generateKey() + return new Secp256k1PrivateKey(privateKeyBytes) } return { diff --git a/test/secp256k1.spec.js b/test/secp256k1.spec.js index 7ce0780..c039216 100644 --- a/test/secp256k1.spec.js +++ b/test/secp256k1.spec.js @@ -6,8 +6,6 @@ const dirtyChai = require('dirty-chai') const expect = chai.expect chai.use(dirtyChai) -const Buffer = require('safe-buffer').Buffer - const libp2pCrypto = require('libp2p-crypto') const keysPBM = libp2pCrypto.keys.keysPBM const randomBytes = libp2pCrypto.randomBytes @@ -17,81 +15,52 @@ describe('secp256k1 keys', () => { let key const secp256k1 = require('../src')(keysPBM, randomBytes) - before((done) => { - secp256k1.generateKeyPair((err, _key) => { - expect(err).to.not.exist() - key = _key - done() - }) + before(async () => { + key = await secp256k1.generateKeyPair() }) - it('generates a valid key', (done) => { + it('generates a valid key', async () => { expect(key).to.be.an.instanceof(secp256k1.Secp256k1PrivateKey) expect(key.public).to.be.an.instanceof(secp256k1.Secp256k1PublicKey) - key.hash((err, digest) => { - expect(err).to.not.exist() - expect(digest).to.have.length(34) + const digest = await key.hash() + expect(digest).to.have.length(34) - key.public.hash((err, digest) => { - expect(err).to.not.exist() - expect(digest).to.have.length(34) - done() - }) - }) + const publicDigest = await key.public.hash() + expect(publicDigest).to.have.length(34) }) - it('optionally accepts a `bits` argument when generating a key', (done) => { - secp256k1.generateKeyPair(256, (err, _key) => { - expect(err).to.not.exist() - expect(_key).to.be.an.instanceof(secp256k1.Secp256k1PrivateKey) - done() - }) + it('optionally accepts a `bits` argument when generating a key', async () => { + const _key = await secp256k1.generateKeyPair(256) + expect(_key).to.be.an.instanceof(secp256k1.Secp256k1PrivateKey) }) - it('requires a callback to generate a key', () => { - expect(() => secp256k1.generateKeyPair()).to.throw() - }) - - it('signs', (done) => { + it('signs', async () => { const text = randomBytes(512) - - key.sign(text, (err, sig) => { - expect(err).to.not.exist() - - key.public.verify(text, sig, (err, res) => { - expect(err).to.not.exist() - expect(res).to.equal(true) - done() - }) - }) + const sig = await key.sign(text) + const res = await key.public.verify(text, sig) + expect(res).to.equal(true) }) - it('encoding', (done) => { + it('encoding', async () => { const keyMarshal = key.marshal() - secp256k1.unmarshalSecp256k1PrivateKey(keyMarshal, (err, key2) => { - expect(err).to.not.exist() - const keyMarshal2 = key2.marshal() + const key2 = await secp256k1.unmarshalSecp256k1PrivateKey(keyMarshal) + const keyMarshal2 = key2.marshal() - expect(keyMarshal).to.eql(keyMarshal2) + expect(keyMarshal).to.eql(keyMarshal2) - const pk = key.public - const pkMarshal = pk.marshal() - const pk2 = secp256k1.unmarshalSecp256k1PublicKey(pkMarshal) - const pkMarshal2 = pk2.marshal() + const pk = key.public + const pkMarshal = pk.marshal() + const pk2 = secp256k1.unmarshalSecp256k1PublicKey(pkMarshal) + const pkMarshal2 = pk2.marshal() - expect(pkMarshal).to.eql(pkMarshal2) - done() - }) + expect(pkMarshal).to.eql(pkMarshal2) }) - it('key id', (done) => { - key.id((err, id) => { - expect(err).to.not.exist() - expect(id).to.exist() - expect(id).to.be.a('string') - done() - }) + it('key id', async () => { + const id = await key.id() + expect(id).to.exist() + expect(id).to.be.a('string') }) describe('key equals', () => { @@ -101,43 +70,27 @@ describe('secp256k1 keys', () => { expect(key.public.equals(key.public)).to.eql(true) }) - it('not equals other key', (done) => { - secp256k1.generateKeyPair(256, (err, key2) => { - expect(err).to.not.exist() - - expect(key.equals(key2)).to.eql(false) - expect(key2.equals(key)).to.eql(false) - expect(key.public.equals(key2.public)).to.eql(false) - expect(key2.public.equals(key.public)).to.eql(false) - done() - }) + it('not equals other key', async () => { + const key2 = await secp256k1.generateKeyPair(256) + expect(key.equals(key2)).to.eql(false) + expect(key2.equals(key)).to.eql(false) + expect(key.public.equals(key2.public)).to.eql(false) + expect(key2.public.equals(key.public)).to.eql(false) }) }) - it('sign and verify', (done) => { + it('sign and verify', async () => { const data = Buffer.from('hello world') - key.sign(data, (err, sig) => { - expect(err).to.not.exist() - - key.public.verify(data, sig, (err, valid) => { - expect(err).to.not.exist() - expect(valid).to.eql(true) - done() - }) - }) + const sig = await key.sign(data) + const valid = await key.public.verify(data, sig) + expect(valid).to.eql(true) }) - it('fails to verify for different data', (done) => { + it('fails to verify for different data', async () => { const data = Buffer.from('hello world') - key.sign(data, (err, sig) => { - expect(err).to.not.exist() - - key.public.verify(Buffer.from('hello'), sig, (err, valid) => { - expect(err).to.not.exist() - expect(valid).to.eql(false) - done() - }) - }) + const sig = await key.sign(data) + const valid = await key.public.verify(Buffer.from('hello'), sig) + expect(valid).to.eql(false) }) }) @@ -145,25 +98,23 @@ describe('key generation error', () => { let generateKey let secp256k1 - before((done) => { + before(() => { generateKey = crypto.generateKey - crypto.generateKey = (callback) => callback(new Error('Error generating key')) + crypto.generateKey = () => { throw new Error('Error generating key') } secp256k1 = require('../src')(keysPBM, randomBytes, crypto) - - done() }) - after((done) => { + after(() => { crypto.generateKey = generateKey - done() }) - it('returns an error if key generation fails', (done) => { - secp256k1.generateKeyPair((err, key) => { - expect(err).to.exist() - expect(key).to.not.exist() - done() - }) + it('returns an error if key generation fails', async () => { + try { + await secp256k1.generateKeyPair() + } catch (err) { + return expect(err.message).to.equal('Error generating key') + } + throw new Error('Expected error to be thrown') }) }) @@ -171,25 +122,23 @@ describe('handles generation of invalid key', () => { let generateKey let secp256k1 - before((done) => { + before(() => { generateKey = crypto.generateKey - crypto.generateKey = (callback) => { callback(null, Buffer.from('not a real key')) } + crypto.generateKey = () => Buffer.from('not a real key') secp256k1 = require('../src')(keysPBM, randomBytes, crypto) - - done() }) - after((done) => { + after(() => { crypto.generateKey = generateKey - done() }) - it('returns an error if key generator returns an invalid key', (done) => { - secp256k1.generateKeyPair((err, key) => { - expect(err).to.exist() - expect(key).to.not.exist() - done() - }) + it('returns an error if key generator returns an invalid key', async () => { + try { + await secp256k1.generateKeyPair() + } catch (err) { + return expect(err.message).to.equal('Invalid private key') + } + throw new Error('Expected error to be thrown') }) }) @@ -197,101 +146,90 @@ describe('crypto functions', () => { let privKey let pubKey - before((done) => { - crypto.generateKey((err, _key) => { - expect(err).to.not.exist() - privKey = _key - pubKey = crypto.computePublicKey(privKey) - done() - }) + before(async () => { + privKey = await crypto.generateKey() + pubKey = crypto.computePublicKey(privKey) }) - it('generates valid keys', (done) => { + it('generates valid keys', () => { expect(() => { crypto.validatePrivateKey(privKey) crypto.validatePublicKey(pubKey) }).to.not.throw() - done() }) - it('does not validate an invalid key', (done) => { + it('does not validate an invalid key', () => { expect(() => crypto.validatePublicKey(Buffer.from('42'))).to.throw() expect(() => crypto.validatePrivateKey(Buffer.from('42'))).to.throw() - done() }) - it('validates a correct signature', (done) => { - crypto.hashAndSign(privKey, Buffer.from('hello'), (err, sig) => { - expect(err).to.not.exist() - crypto.hashAndVerify(pubKey, sig, Buffer.from('hello'), (err, valid) => { - expect(err).to.not.exist() - expect(valid).to.equal(true) - done() - }) - }) + it('validates a correct signature', async () => { + const sig = await crypto.hashAndSign(privKey, Buffer.from('hello')) + const valid = await crypto.hashAndVerify(pubKey, sig, Buffer.from('hello')) + expect(valid).to.equal(true) }) - it('errors if given a null buffer to sign', (done) => { - crypto.hashAndSign(privKey, null, (err, sig) => { - expect(err).to.exist() - expect(sig).to.not.exist() - done() - }) + it('errors if given a null buffer to sign', async () => { + try { + await crypto.hashAndSign(privKey, null) + } catch (err) { + return // expected + } + throw new Error('Expected error to be thrown') }) - it('errors when signing with an invalid key', (done) => { - crypto.hashAndSign(Buffer.from('42'), Buffer.from('Hello'), (err, sig) => { - expect(err).to.exist() - expect(sig).to.not.exist() - done() - }) + it('errors when signing with an invalid key', async () => { + try { + await crypto.hashAndSign(Buffer.from('42'), Buffer.from('Hello')) + } catch (err) { + return expect(err.message).to.equal('private key length is invalid') + } + throw new Error('Expected error to be thrown') }) - it('errors if given a null buffer to validate', (done) => { - crypto.hashAndSign(privKey, Buffer.from('hello'), (err, sig) => { - expect(err).to.not.exist() + it('errors if given a null buffer to validate', async () => { + const sig = await crypto.hashAndSign(privKey, Buffer.from('hello')) - crypto.hashAndVerify(privKey, sig, null, (err, valid) => { - expect(err).to.exist() - expect(valid).to.not.exist() - done() - }) - }) + try { + await crypto.hashAndVerify(privKey, sig, null) + } catch (err) { + return // expected + } + throw new Error('Expected error to be thrown') }) - it('errors when validating a message with an invalid signature', (done) => { - crypto.hashAndVerify(pubKey, Buffer.from('invalid-sig'), Buffer.from('hello'), (err, valid) => { - expect(err).to.exist() - expect(valid).to.not.exist() - done() - }) + it('errors when validating a message with an invalid signature', async () => { + try { + await crypto.hashAndVerify(pubKey, Buffer.from('invalid-sig'), Buffer.from('hello')) + } catch (err) { + return expect(err.message).to.equal('couldn\'t parse DER signature') + } + throw new Error('Expected error to be thrown') }) - it('errors when signing with an invalid key', (done) => { - crypto.hashAndSign(Buffer.from('42'), Buffer.from('Hello'), (err, sig) => { - expect(err).to.exist() - expect(sig).to.not.exist() - done() - }) + it('errors when signing with an invalid key', async () => { + try { + await crypto.hashAndSign(Buffer.from('42'), Buffer.from('Hello')) + } catch (err) { + return expect(err.message).to.equal('private key length is invalid') + } + throw new Error('Expected error to be thrown') }) - it('throws when compressing an invalid public key', (done) => { + it('throws when compressing an invalid public key', () => { expect(() => crypto.compressPublicKey(Buffer.from('42'))).to.throw() - done() }) - it('throws when decompressing an invalid public key', (done) => { + it('throws when decompressing an invalid public key', () => { expect(() => crypto.decompressPublicKey(Buffer.from('42'))).to.throw() - done() }) - it('compresses/decompresses a valid public key', (done) => { + it('compresses/decompresses a valid public key', () => { const decompressed = crypto.decompressPublicKey(pubKey) expect(decompressed).to.exist() expect(decompressed.length).to.be.eql(65) const recompressed = crypto.compressPublicKey(decompressed) expect(recompressed).to.eql(pubKey) - done() }) }) @@ -299,43 +237,32 @@ describe('go interop', () => { const secp256k1 = require('../src')(keysPBM, randomBytes) const fixtures = require('./fixtures/go-interop') - it('loads a private key marshaled by go-libp2p-crypto', (done) => { + it('loads a private key marshaled by go-libp2p-crypto', async () => { // we need to first extract the key data from the protobuf, which is // normally handled by js-libp2p-crypto const decoded = keysPBM.PrivateKey.decode(fixtures.privateKey) expect(decoded.Type).to.eql(keysPBM.KeyType.Secp256k1) - secp256k1.unmarshalSecp256k1PrivateKey(decoded.Data, (err, key) => { - expect(err).to.not.exist() - - expect(key).to.be.an.instanceof(secp256k1.Secp256k1PrivateKey) - expect(key.bytes).to.eql(fixtures.privateKey) - done() - }) + const key = await secp256k1.unmarshalSecp256k1PrivateKey(decoded.Data) + expect(key).to.be.an.instanceof(secp256k1.Secp256k1PrivateKey) + expect(key.bytes).to.eql(fixtures.privateKey) }) - it('loads a public key marshaled by go-libp2p-crypto', (done) => { + it('loads a public key marshaled by go-libp2p-crypto', () => { const decoded = keysPBM.PublicKey.decode(fixtures.publicKey) expect(decoded.Type).to.be.eql(keysPBM.KeyType.Secp256k1) const key = secp256k1.unmarshalSecp256k1PublicKey(decoded.Data) expect(key).to.be.an.instanceof(secp256k1.Secp256k1PublicKey) expect(key.bytes).to.eql(fixtures.publicKey) - done() }) - it('generates the same signature as go-libp2p-crypto', (done) => { + it('generates the same signature as go-libp2p-crypto', async () => { const decoded = keysPBM.PrivateKey.decode(fixtures.privateKey) expect(decoded.Type).to.eql(keysPBM.KeyType.Secp256k1) - secp256k1.unmarshalSecp256k1PrivateKey(decoded.Data, (err, key) => { - expect(err).to.not.exist() - - key.sign(fixtures.message, (err, sig) => { - expect(err).to.not.exist() - expect(sig).to.eql(fixtures.signature) - done() - }) - }) + const key = await secp256k1.unmarshalSecp256k1PrivateKey(decoded.Data) + const sig = await key.sign(fixtures.message) + expect(sig).to.eql(fixtures.signature) }) }) From ed670209adaa2268a8847752f3db211ff3f8c534 Mon Sep 17 00:00:00 2001 From: Jacob Heun Date: Wed, 10 Jul 2019 11:45:02 +0100 Subject: [PATCH 45/59] chore: update contributors --- package.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 3af690d..ca95aed 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "libp2p-crypto-secp256k1", - "version": "0.3.1", + "version": "0.4.0", "description": "Support for secp256k1 keys in libp2p-crypto", "leadMaintainer": "Friedel Ziegelmayer ", "main": "src/index.js", @@ -54,10 +54,12 @@ "homepage": "https://github.com/libp2p/js-libp2p-crypto-secp256k1", "contributors": [ "Alberto Elias ", + "Alex Potsides ", "Arve Knudsen ", "David Dias ", "Friedel Ziegelmayer ", "Hugo Dias ", + "Jacob Heun ", "Vasco Santos ", "Victor Bjelkholm ", "Yusef Napora ", From a521cd9b11a35ebd94897c8723842f20122ce2a1 Mon Sep 17 00:00:00 2001 From: Jacob Heun Date: Wed, 10 Jul 2019 11:45:02 +0100 Subject: [PATCH 46/59] chore: release version v0.4.0 --- CHANGELOG.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f9d82b8..63827c0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,26 @@ + +# [0.4.0](https://github.com/libp2p/js-libp2p-crypto-secp256k1/compare/v0.3.1...v0.4.0) (2019-07-10) + + +### Features + +* use async await ([#18](https://github.com/libp2p/js-libp2p-crypto-secp256k1/issues/18)) ([1974eb9](https://github.com/libp2p/js-libp2p-crypto-secp256k1/commit/1974eb9)) + + +### BREAKING CHANGES + +* Callback support has been dropped in favor of async/await. + +* feat: use async/await + +This PR changes this module to remove callbacks and use async/await. The API is unchanged aside from the obvious removal of the `callback` parameter. + +refs https://github.com/ipfs/js-ipfs/issues/1670 + +* fix: use latest multihashing-async as it is all promises now + + + ## [0.3.1](https://github.com/libp2p/js-libp2p-crypto-secp256k1/compare/v0.2.2...v0.3.1) (2019-07-10) From e36a9f6b79dd27eb1f8285f036a755517f54bd76 Mon Sep 17 00:00:00 2001 From: Alan Shaw Date: Mon, 6 Jan 2020 17:07:09 +0000 Subject: [PATCH 47/59] chore: update multihashing-async dep (#19) --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ca95aed..9ff764b 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,7 @@ "license": "MIT", "dependencies": { "bs58": "^4.0.1", - "multihashing-async": "^0.7.0", + "multihashing-async": "^0.8.0", "nodeify": "^1.0.1", "safe-buffer": "^5.1.2", "secp256k1": "^3.6.2" From 9894c34f9495d061e4fb34acb290fd4e9237b7b7 Mon Sep 17 00:00:00 2001 From: Jacob Heun Date: Mon, 6 Jan 2020 18:10:49 +0100 Subject: [PATCH 48/59] chore: update contributors --- package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 9ff764b..2ad27a4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "libp2p-crypto-secp256k1", - "version": "0.4.0", + "version": "0.4.1", "description": "Support for secp256k1 keys in libp2p-crypto", "leadMaintainer": "Friedel Ziegelmayer ", "main": "src/index.js", @@ -53,6 +53,7 @@ }, "homepage": "https://github.com/libp2p/js-libp2p-crypto-secp256k1", "contributors": [ + "Alan Shaw ", "Alberto Elias ", "Alex Potsides ", "Arve Knudsen ", From 89901f70973d8d13dc13621ab4c70f777ebface7 Mon Sep 17 00:00:00 2001 From: Jacob Heun Date: Mon, 6 Jan 2020 18:10:59 +0100 Subject: [PATCH 49/59] chore: release version v0.4.1 --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 63827c0..0f4d72b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ + +## [0.4.1](https://github.com/libp2p/js-libp2p-crypto-secp256k1/compare/v0.4.0...v0.4.1) (2020-01-06) + + + # [0.4.0](https://github.com/libp2p/js-libp2p-crypto-secp256k1/compare/v0.3.1...v0.4.0) (2019-07-10) From 3e88839c2b18ad7f0fb41e613356bfb1decc9e6b Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Tue, 4 Feb 2020 12:45:26 +0000 Subject: [PATCH 50/59] chore(deps-dev): bump libp2p-crypto from 0.16.3 to 0.17.2 Bumps [libp2p-crypto](https://github.com/libp2p/js-libp2p-crypto) from 0.16.3 to 0.17.2. - [Release notes](https://github.com/libp2p/js-libp2p-crypto/releases) - [Changelog](https://github.com/libp2p/js-libp2p-crypto/blob/master/CHANGELOG.md) - [Commits](https://github.com/libp2p/js-libp2p-crypto/compare/v0.16.3...v0.17.2) Signed-off-by: dependabot-preview[bot] --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 2ad27a4..3561def 100644 --- a/package.json +++ b/package.json @@ -38,7 +38,7 @@ "benchmark": "^2.1.4", "chai": "^4.2.0", "dirty-chai": "^2.0.1", - "libp2p-crypto": "~0.16.1" + "libp2p-crypto": "~0.17.2" }, "engines": { "node": ">=6.0.0", From 41c9cd1691b2678093ea5deee5b3287e7f02f57d Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 5 Feb 2020 12:11:00 +0000 Subject: [PATCH 51/59] chore(deps-dev): bump aegir from 19.0.5 to 20.6.0 Bumps [aegir](https://github.com/ipfs/aegir) from 19.0.5 to 20.6.0. - [Release notes](https://github.com/ipfs/aegir/releases) - [Changelog](https://github.com/ipfs/aegir/blob/master/CHANGELOG.md) - [Commits](https://github.com/ipfs/aegir/compare/v19.0.5...v20.6.0) Signed-off-by: dependabot-preview[bot] --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 3561def..19d0dbe 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "secp256k1": "^3.6.2" }, "devDependencies": { - "aegir": "^19.0.5", + "aegir": "^20.6.0", "benchmark": "^2.1.4", "chai": "^4.2.0", "dirty-chai": "^2.0.1", From ae109d46f7849dd5f32d369c5ca57c8f50342a0e Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 17 Feb 2020 13:36:19 +0000 Subject: [PATCH 52/59] chore(deps-dev): bump aegir from 20.6.1 to 21.0.2 Bumps [aegir](https://github.com/ipfs/aegir) from 20.6.1 to 21.0.2. - [Release notes](https://github.com/ipfs/aegir/releases) - [Changelog](https://github.com/ipfs/aegir/blob/master/CHANGELOG.md) - [Commits](https://github.com/ipfs/aegir/compare/v20.6.1...v21.0.2) Signed-off-by: dependabot-preview[bot] --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 19d0dbe..e1499b9 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "secp256k1": "^3.6.2" }, "devDependencies": { - "aegir": "^20.6.0", + "aegir": "^21.0.2", "benchmark": "^2.1.4", "chai": "^4.2.0", "dirty-chai": "^2.0.1", From 35f196ea4deffd9f0de53afff6bd8aba5e4db9f2 Mon Sep 17 00:00:00 2001 From: Hugo Dias Date: Tue, 17 Mar 2020 10:59:23 +0000 Subject: [PATCH 53/59] fix: add buffer and update deps (#25) * fix: add buffer and update deps update secp256k1 dep and fix code use multibase to encode b58 avoid un-necessary circular dependency no libp2p-crypto use only sha256 from multihashing-async * Update src/crypto.js Co-Authored-By: Jacob Heun * chore: remove commitlint from CI Co-authored-by: Jacob Heun --- .gitignore | 1 + .travis.yml | 2 +- package.json | 16 +++++++--------- src/crypto.js | 38 ++++++++++++++++++++++++++----------- src/index.js | 11 +++++------ test/fixtures/go-interop.js | 2 +- test/secp256k1.spec.js | 16 ++++++++-------- 7 files changed, 50 insertions(+), 36 deletions(-) diff --git a/.gitignore b/.gitignore index 452c69d..f99b5ca 100644 --- a/.gitignore +++ b/.gitignore @@ -32,6 +32,7 @@ build node_modules dist +docs package-lock.json yarn.lock .vscode diff --git a/.travis.yml b/.travis.yml index 11e06a6..cb1d170 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,6 +10,7 @@ stages: node_js: - '10' + - '12' os: - linux @@ -23,7 +24,6 @@ jobs: include: - stage: check script: - - npx aegir commitlint --travis - npx aegir dep-check - npm run lint diff --git a/package.json b/package.json index e1499b9..9c90f28 100644 --- a/package.json +++ b/package.json @@ -4,9 +4,6 @@ "description": "Support for secp256k1 keys in libp2p-crypto", "leadMaintainer": "Friedel Ziegelmayer ", "main": "src/index.js", - "browser": { - "secp256k1": "secp256k1/js" - }, "scripts": { "lint": "aegir lint", "build": "aegir build", @@ -27,18 +24,19 @@ ], "license": "MIT", "dependencies": { - "bs58": "^4.0.1", - "multihashing-async": "^0.8.0", - "nodeify": "^1.0.1", - "safe-buffer": "^5.1.2", - "secp256k1": "^3.6.2" + "buffer": "^5.5.0", + "is-typedarray": "^1.0.0", + "multibase": "^0.6.0", + "multihashing-async": "^0.8.1", + "secp256k1": "^4.0.0" }, "devDependencies": { "aegir": "^21.0.2", "benchmark": "^2.1.4", "chai": "^4.2.0", "dirty-chai": "^2.0.1", - "libp2p-crypto": "~0.17.2" + "libp2p-crypto": "~0.17.2", + "protons": "^1.1.0" }, "engines": { "node": ">=6.0.0", diff --git a/src/crypto.js b/src/crypto.js index fbafb91..1db25c4 100644 --- a/src/crypto.js +++ b/src/crypto.js @@ -1,10 +1,26 @@ 'use strict' +const { Buffer } = require('buffer') +var isTypedArray = require('is-typedarray').strict const secp256k1 = require('secp256k1') -const multihashing = require('multihashing-async') - +const sha = require('multihashing-async/src/sha') const HASH_ALGORITHM = 'sha2-256' +function typedArrayTobuffer (arr) { + if (isTypedArray(arr)) { + // To avoid a copy, use the typed array's underlying ArrayBuffer to back new Buffer + var buf = Buffer.from(arr.buffer) + if (arr.byteLength !== arr.buffer.byteLength) { + // Respect the "view", i.e. byteOffset and byteLength, without doing a copy + buf = buf.slice(arr.byteOffset, arr.byteOffset + arr.byteLength) + } + return buf + } else { + // Pass through all other types to `Buffer.from` + return Buffer.from(arr) + } +} + module.exports = (randomBytes) => { const privateKeyLength = 32 @@ -17,26 +33,26 @@ module.exports = (randomBytes) => { } async function hashAndSign (key, msg) { - const digest = await multihashing.digest(msg, HASH_ALGORITHM) - const sig = secp256k1.sign(digest, key) - return secp256k1.signatureExport(sig.signature) + const digest = await sha.digest(msg, HASH_ALGORITHM) + const sig = secp256k1.ecdsaSign(digest, key) + return typedArrayTobuffer(secp256k1.signatureExport(sig.signature)) } async function hashAndVerify (key, sig, msg) { - const digest = await multihashing.digest(msg, HASH_ALGORITHM) - sig = secp256k1.signatureImport(sig) - return secp256k1.verify(digest, sig, key) + const digest = await sha.digest(msg, HASH_ALGORITHM) + sig = typedArrayTobuffer(secp256k1.signatureImport(sig)) + return secp256k1.ecdsaVerify(sig, digest, key) } function compressPublicKey (key) { if (!secp256k1.publicKeyVerify(key)) { throw new Error('Invalid public key') } - return secp256k1.publicKeyConvert(key, true) + return typedArrayTobuffer(secp256k1.publicKeyConvert(key, true)) } function decompressPublicKey (key) { - return secp256k1.publicKeyConvert(key, false) + return typedArrayTobuffer(secp256k1.publicKeyConvert(key, false)) } function validatePrivateKey (key) { @@ -53,7 +69,7 @@ module.exports = (randomBytes) => { function computePublicKey (privateKey) { validatePrivateKey(privateKey) - return secp256k1.publicKeyCreate(privateKey) + return typedArrayTobuffer(secp256k1.publicKeyCreate(privateKey)) } return { diff --git a/src/index.js b/src/index.js index a1299b2..13ebfe8 100644 --- a/src/index.js +++ b/src/index.js @@ -1,7 +1,7 @@ 'use strict' -const bs58 = require('bs58') -const multihashing = require('multihashing-async') +const multibase = require('multibase') +const sha = require('multihashing-async/src/sha') module.exports = (keysProtobuf, randomBytes, crypto) => { crypto = crypto || require('./crypto')(randomBytes) @@ -32,7 +32,7 @@ module.exports = (keysProtobuf, randomBytes, crypto) => { } hash () { - return multihashing(this.bytes, 'sha2-256') + return sha.multihashing(this.bytes, 'sha2-256') } } @@ -68,7 +68,7 @@ module.exports = (keysProtobuf, randomBytes, crypto) => { } hash () { - return multihashing(this.bytes, 'sha2-256') + return sha.multihashing(this.bytes, 'sha2-256') } /** @@ -83,8 +83,7 @@ module.exports = (keysProtobuf, randomBytes, crypto) => { */ async id () { const hash = await this.public.hash() - - return bs58.encode(hash) + return multibase.encode('base58btc', hash).toString().slice(1) } } diff --git a/test/fixtures/go-interop.js b/test/fixtures/go-interop.js index 8f18c1a..bebda0b 100644 --- a/test/fixtures/go-interop.js +++ b/test/fixtures/go-interop.js @@ -1,6 +1,6 @@ 'use strict' -const Buffer = require('safe-buffer').Buffer +const { Buffer } = require('buffer') // The keypair and signature below were generated in a gore repl session (https://github.com/motemen/gore) // using the secp256k1 fork of go-libp2p-crypto by github user @vyzo diff --git a/test/secp256k1.spec.js b/test/secp256k1.spec.js index c039216..0863ca4 100644 --- a/test/secp256k1.spec.js +++ b/test/secp256k1.spec.js @@ -1,14 +1,14 @@ /* eslint-env mocha */ 'use strict' +const { Buffer } = require('buffer') const chai = require('chai') const dirtyChai = require('dirty-chai') const expect = chai.expect chai.use(dirtyChai) - -const libp2pCrypto = require('libp2p-crypto') -const keysPBM = libp2pCrypto.keys.keysPBM -const randomBytes = libp2pCrypto.randomBytes +const protobuf = require('protons') +const keysPBM = protobuf(require('libp2p-crypto/src/keys/keys.proto')) +const randomBytes = require('libp2p-crypto/src/random-bytes') const crypto = require('../src/crypto')(randomBytes) describe('secp256k1 keys', () => { @@ -136,7 +136,7 @@ describe('handles generation of invalid key', () => { try { await secp256k1.generateKeyPair() } catch (err) { - return expect(err.message).to.equal('Invalid private key') + return expect(err.message).to.equal('Expected private key to be an Uint8Array with length 32') } throw new Error('Expected error to be thrown') }) @@ -182,7 +182,7 @@ describe('crypto functions', () => { try { await crypto.hashAndSign(Buffer.from('42'), Buffer.from('Hello')) } catch (err) { - return expect(err.message).to.equal('private key length is invalid') + return expect(err.message).to.equal('Expected private key to be an Uint8Array with length 32') } throw new Error('Expected error to be thrown') }) @@ -202,7 +202,7 @@ describe('crypto functions', () => { try { await crypto.hashAndVerify(pubKey, Buffer.from('invalid-sig'), Buffer.from('hello')) } catch (err) { - return expect(err.message).to.equal('couldn\'t parse DER signature') + return expect(err.message).to.equal('Signature could not be parsed') } throw new Error('Expected error to be thrown') }) @@ -211,7 +211,7 @@ describe('crypto functions', () => { try { await crypto.hashAndSign(Buffer.from('42'), Buffer.from('Hello')) } catch (err) { - return expect(err.message).to.equal('private key length is invalid') + return expect(err.message).to.equal('Expected private key to be an Uint8Array with length 32') } throw new Error('Expected error to be thrown') }) From fdab19b7d9af813fb625778960da1fcf12bc033c Mon Sep 17 00:00:00 2001 From: Jacob Heun Date: Tue, 17 Mar 2020 12:11:28 +0100 Subject: [PATCH 54/59] chore: update contributors --- package.json | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/package.json b/package.json index 9c90f28..8c13453 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "libp2p-crypto-secp256k1", - "version": "0.4.1", + "version": "0.4.2", "description": "Support for secp256k1 keys in libp2p-crypto", "leadMaintainer": "Friedel Ziegelmayer ", "main": "src/index.js", @@ -51,17 +51,16 @@ }, "homepage": "https://github.com/libp2p/js-libp2p-crypto-secp256k1", "contributors": [ + "David Dias ", + "Jacob Heun ", + "Friedel Ziegelmayer ", + "Hugo Dias ", + "ᴠɪᴄᴛᴏʀ ʙᴊᴇʟᴋʜᴏʟᴍ ", + "Yusef Napora ", "Alan Shaw ", "Alberto Elias ", "Alex Potsides ", "Arve Knudsen ", - "David Dias ", - "Friedel Ziegelmayer ", - "Hugo Dias ", - "Jacob Heun ", - "Vasco Santos ", - "Victor Bjelkholm ", - "Yusef Napora ", - "dignifiedquire " + "Vasco Santos " ] } From 9b4231eb75be6f56c5dfbbe20bdd2b5c3412beca Mon Sep 17 00:00:00 2001 From: Jacob Heun Date: Tue, 17 Mar 2020 12:11:28 +0100 Subject: [PATCH 55/59] chore: release version v0.4.2 --- CHANGELOG.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0f4d72b..4152010 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,13 @@ + +## [0.4.2](https://github.com/libp2p/js-libp2p-crypto-secp256k1/compare/v0.4.1...v0.4.2) (2020-03-17) + + +### Bug Fixes + +* add buffer and update deps ([#25](https://github.com/libp2p/js-libp2p-crypto-secp256k1/issues/25)) ([35f196e](https://github.com/libp2p/js-libp2p-crypto-secp256k1/commit/35f196e)) + + + ## [0.4.1](https://github.com/libp2p/js-libp2p-crypto-secp256k1/compare/v0.4.0...v0.4.1) (2020-01-06) From d73a0ca52ec329c7a6affd317022b7b65f5ea70a Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 25 Mar 2020 12:55:12 +0100 Subject: [PATCH 56/59] chore(deps): bump multibase from 0.6.1 to 0.7.0 (#26) Bumps [multibase](https://github.com/multiformats/js-multibase) from 0.6.1 to 0.7.0. - [Release notes](https://github.com/multiformats/js-multibase/releases) - [Changelog](https://github.com/multiformats/js-multibase/blob/master/CHANGELOG.md) - [Commits](https://github.com/multiformats/js-multibase/compare/v0.6.1...v0.7.0) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 8c13453..21a97fe 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,7 @@ "dependencies": { "buffer": "^5.5.0", "is-typedarray": "^1.0.0", - "multibase": "^0.6.0", + "multibase": "^0.7.0", "multihashing-async": "^0.8.1", "secp256k1": "^4.0.0" }, From a68fc2e98d13030f43ab9965336c112fd58fb465 Mon Sep 17 00:00:00 2001 From: Jacob Heun Date: Wed, 25 Mar 2020 12:59:03 +0100 Subject: [PATCH 57/59] chore: update contributors --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 21a97fe..0a41bd6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "libp2p-crypto-secp256k1", - "version": "0.4.2", + "version": "0.4.3", "description": "Support for secp256k1 keys in libp2p-crypto", "leadMaintainer": "Friedel Ziegelmayer ", "main": "src/index.js", From 6bbf12c169140d5abbb367fa1608a4436e6f50c5 Mon Sep 17 00:00:00 2001 From: Jacob Heun Date: Wed, 25 Mar 2020 12:59:04 +0100 Subject: [PATCH 58/59] chore: release version v0.4.3 --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4152010..4dd03a4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ + +## [0.4.3](https://github.com/libp2p/js-libp2p-crypto-secp256k1/compare/v0.4.2...v0.4.3) (2020-03-25) + + + ## [0.4.2](https://github.com/libp2p/js-libp2p-crypto-secp256k1/compare/v0.4.1...v0.4.2) (2020-03-17) From 42bd594068c62ab7276c34cd6d319d1b3b279a99 Mon Sep 17 00:00:00 2001 From: Cayman Date: Mon, 6 Apr 2020 11:55:35 -0500 Subject: [PATCH 59/59] chore: move files to secp256k1 directory --- .gitignore => secp256k1/.gitignore | 0 .npmignore => secp256k1/.npmignore | 0 .travis.yml => secp256k1/.travis.yml | 0 CHANGELOG.md => secp256k1/CHANGELOG.md | 0 LICENSE => secp256k1/LICENSE | 0 README.md => secp256k1/README.md | 0 package.json => secp256k1/package.json | 0 {src => secp256k1/src}/crypto.js | 0 {src => secp256k1/src}/index.js | 0 {test => secp256k1/test}/fixtures/go-interop.js | 0 {test => secp256k1/test}/secp256k1.spec.js | 0 11 files changed, 0 insertions(+), 0 deletions(-) rename .gitignore => secp256k1/.gitignore (100%) rename .npmignore => secp256k1/.npmignore (100%) rename .travis.yml => secp256k1/.travis.yml (100%) rename CHANGELOG.md => secp256k1/CHANGELOG.md (100%) rename LICENSE => secp256k1/LICENSE (100%) rename README.md => secp256k1/README.md (100%) rename package.json => secp256k1/package.json (100%) rename {src => secp256k1/src}/crypto.js (100%) rename {src => secp256k1/src}/index.js (100%) rename {test => secp256k1/test}/fixtures/go-interop.js (100%) rename {test => secp256k1/test}/secp256k1.spec.js (100%) diff --git a/.gitignore b/secp256k1/.gitignore similarity index 100% rename from .gitignore rename to secp256k1/.gitignore diff --git a/.npmignore b/secp256k1/.npmignore similarity index 100% rename from .npmignore rename to secp256k1/.npmignore diff --git a/.travis.yml b/secp256k1/.travis.yml similarity index 100% rename from .travis.yml rename to secp256k1/.travis.yml diff --git a/CHANGELOG.md b/secp256k1/CHANGELOG.md similarity index 100% rename from CHANGELOG.md rename to secp256k1/CHANGELOG.md diff --git a/LICENSE b/secp256k1/LICENSE similarity index 100% rename from LICENSE rename to secp256k1/LICENSE diff --git a/README.md b/secp256k1/README.md similarity index 100% rename from README.md rename to secp256k1/README.md diff --git a/package.json b/secp256k1/package.json similarity index 100% rename from package.json rename to secp256k1/package.json diff --git a/src/crypto.js b/secp256k1/src/crypto.js similarity index 100% rename from src/crypto.js rename to secp256k1/src/crypto.js diff --git a/src/index.js b/secp256k1/src/index.js similarity index 100% rename from src/index.js rename to secp256k1/src/index.js diff --git a/test/fixtures/go-interop.js b/secp256k1/test/fixtures/go-interop.js similarity index 100% rename from test/fixtures/go-interop.js rename to secp256k1/test/fixtures/go-interop.js diff --git a/test/secp256k1.spec.js b/secp256k1/test/secp256k1.spec.js similarity index 100% rename from test/secp256k1.spec.js rename to secp256k1/test/secp256k1.spec.js