mirror of
https://github.com/fluencelabs/js-libp2p-crypto
synced 2025-03-15 08:41:05 +00:00
fix: circular circular dep -> DI
This commit is contained in:
parent
8401154102
commit
0dcf1a6f52
@ -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"
|
||||
|
89
src/crypto.js
Normal file
89
src/crypto.js
Normal 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
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
205
src/index.js
205
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
|
||||
}
|
||||
|
@ -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()
|
||||
|
Loading…
x
Reference in New Issue
Block a user