fix: circular circular dep -> DI

This commit is contained in:
David Dias 2017-07-22 13:31:42 -07:00
parent 8401154102
commit 0dcf1a6f52
5 changed files with 210 additions and 199 deletions

View File

@ -28,7 +28,6 @@
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"async": "^2.5.0", "async": "^2.5.0",
"libp2p-crypto": "~0.9.2",
"multihashing-async": "~0.4.6", "multihashing-async": "~0.4.6",
"nodeify": "^1.0.1", "nodeify": "^1.0.1",
"safe-buffer": "^5.1.1", "safe-buffer": "^5.1.1",
@ -37,6 +36,7 @@
"devDependencies": { "devDependencies": {
"aegir": "^11.0.2", "aegir": "^11.0.2",
"benchmark": "^2.1.4", "benchmark": "^2.1.4",
"libp2p-crypto": "~0.9.4",
"chai": "^4.1.0", "chai": "^4.1.0",
"dirty-chai": "^2.0.1", "dirty-chai": "^2.0.1",
"pre-commit": "^1.2.2" "pre-commit": "^1.2.2"

89
src/crypto.js Normal file
View File

@ -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
}
}

View File

@ -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)
}

View File

@ -1,119 +1,118 @@
'use strict' 'use strict'
const multihashing = require('multihashing-async') const multihashing = require('multihashing-async')
const crypto = require('./crypto')
const pbm = require('libp2p-crypto').keys.pbm
class Secp256k1PublicKey { module.exports = (keysProtobuf, randomBytes, crypto) => {
constructor (key) { crypto = crypto || require('./crypto')(randomBytes)
crypto.validatePublicKey(key)
this._key = key 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) ensure(callback)
crypto.hashAndVerify(this._key, sig, data, callback)
}
marshal () { crypto.generateKey((err, privateKeyBytes) => {
return crypto.compressPublicKey(this._key) if (err) { return callback(err) }
}
get bytes () { let privkey
return pbm.PublicKey.encode({ try {
Type: pbm.KeyType.Secp256k1, privkey = new Secp256k1PrivateKey(privateKeyBytes)
Data: this.marshal() } catch (err) { return callback(err) }
callback(null, privkey)
}) })
} }
equals (key) { function ensure (callback) {
return this.bytes.equals(key.bytes) if (typeof callback !== 'function') {
} throw new Error('callback is required')
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) return {
}) Secp256k1PublicKey,
} Secp256k1PrivateKey,
unmarshalSecp256k1PrivateKey,
function ensure (cb) { unmarshalSecp256k1PublicKey,
if (typeof cb !== 'function') { generateKeyPair
throw new Error('callback is required')
} }
} }
module.exports = {
Secp256k1PublicKey,
Secp256k1PrivateKey,
unmarshalSecp256k1PrivateKey,
unmarshalSecp256k1PublicKey,
generateKeyPair
}

View File

@ -8,14 +8,15 @@ chai.use(dirtyChai)
const Buffer = require('safe-buffer').Buffer const Buffer = require('safe-buffer').Buffer
const secp256k1 = require('../src')
const crypto = require('../src/crypto')
const libp2pCrypto = require('libp2p-crypto') const libp2pCrypto = require('libp2p-crypto')
const pbm = libp2pCrypto.keys.pbm const keysPBM = libp2pCrypto.keys.keysPBM
const randomBytes = libp2pCrypto.randomBytes const randomBytes = libp2pCrypto.randomBytes
const crypto = require('../src/crypto')(randomBytes)
describe('secp256k1 keys', () => { describe('secp256k1 keys', () => {
let key let key
const secp256k1 = require('../src')(keysPBM, randomBytes)
before((done) => { before((done) => {
secp256k1.generateKeyPair((err, _key) => { secp256k1.generateKeyPair((err, _key) => {
expect(err).to.not.exist() expect(err).to.not.exist()
@ -133,10 +134,13 @@ describe('secp256k1 keys', () => {
describe('key generation error', () => { describe('key generation error', () => {
let generateKey let generateKey
let secp256k1
before((done) => { before((done) => {
generateKey = crypto.generateKey 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() done()
}) })
@ -156,10 +160,13 @@ describe('key generation error', () => {
describe('handles generation of invalid key', () => { describe('handles generation of invalid key', () => {
let generateKey let generateKey
let secp256k1
before((done) => { before((done) => {
generateKey = crypto.generateKey generateKey = crypto.generateKey
crypto.generateKey = (callback) => { callback(null, Buffer.from('not a real key')) } crypto.generateKey = (callback) => { callback(null, Buffer.from('not a real key')) }
secp256k1 = require('../src')(keysPBM, randomBytes, crypto)
done() done()
}) })
@ -280,13 +287,14 @@ describe('crypto functions', () => {
}) })
describe('go interop', () => { describe('go interop', () => {
const secp256k1 = require('../src')(keysPBM, randomBytes)
const fixtures = require('./fixtures/go-interop') 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', (done) => {
// we need to first extract the key data from the protobuf, which is // we need to first extract the key data from the protobuf, which is
// normally handled by js-libp2p-crypto // normally handled by js-libp2p-crypto
const decoded = pbm.PrivateKey.decode(fixtures.privateKey) const decoded = keysPBM.PrivateKey.decode(fixtures.privateKey)
expect(decoded.Type).to.eql(pbm.KeyType.Secp256k1) expect(decoded.Type).to.eql(keysPBM.KeyType.Secp256k1)
secp256k1.unmarshalSecp256k1PrivateKey(decoded.Data, (err, key) => { secp256k1.unmarshalSecp256k1PrivateKey(decoded.Data, (err, key) => {
expect(err).to.not.exist() expect(err).to.not.exist()
@ -298,8 +306,8 @@ describe('go interop', () => {
}) })
it('loads a public key marshaled by go-libp2p-crypto', (done) => { it('loads a public key marshaled by go-libp2p-crypto', (done) => {
const decoded = pbm.PublicKey.decode(fixtures.publicKey) const decoded = keysPBM.PublicKey.decode(fixtures.publicKey)
expect(decoded.Type).to.be.eql(pbm.KeyType.Secp256k1) expect(decoded.Type).to.be.eql(keysPBM.KeyType.Secp256k1)
const key = secp256k1.unmarshalSecp256k1PublicKey(decoded.Data) const key = secp256k1.unmarshalSecp256k1PublicKey(decoded.Data)
expect(key).to.be.an.instanceof(secp256k1.Secp256k1PublicKey) 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) => { it('generates the same signature as go-libp2p-crypto', (done) => {
const decoded = pbm.PrivateKey.decode(fixtures.privateKey) const decoded = keysPBM.PrivateKey.decode(fixtures.privateKey)
expect(decoded.Type).to.eql(pbm.KeyType.Secp256k1) expect(decoded.Type).to.eql(keysPBM.KeyType.Secp256k1)
secp256k1.unmarshalSecp256k1PrivateKey(decoded.Data, (err, key) => { secp256k1.unmarshalSecp256k1PrivateKey(decoded.Data, (err, key) => {
expect(err).to.not.exist() expect(err).to.not.exist()