mirror of
https://github.com/fluencelabs/js-libp2p-crypto
synced 2025-03-15 19:50:58 +00:00
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
This commit is contained in:
parent
fbd42385e3
commit
1974eb92be
3
.gitignore
vendored
3
.gitignore
vendored
@ -33,4 +33,5 @@ node_modules
|
|||||||
|
|
||||||
dist
|
dist
|
||||||
package-lock.json
|
package-lock.json
|
||||||
yarn.lock
|
yarn.lock
|
||||||
|
.vscode
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
|
||||||
language: node_js
|
language: node_js
|
||||||
|
|
||||||
cache: npm
|
cache: npm
|
||||||
@ -41,4 +42,4 @@ jobs:
|
|||||||
- npx aegir test -t browser -- --browsers FirefoxHeadless
|
- npx aegir test -t browser -- --browsers FirefoxHeadless
|
||||||
|
|
||||||
notifications:
|
notifications:
|
||||||
email: false
|
email: false
|
60
README.md
60
README.md
@ -13,9 +13,9 @@
|
|||||||
|
|
||||||
> Support for secp256k1 keys in js-libp2p-crypto
|
> Support for secp256k1 keys in js-libp2p-crypto
|
||||||
|
|
||||||
This repo contains a [js-libp2p-crypto](https://github.com/libp2p/js-libp2p-crypto)-compatible
|
This repo contains a [js-libp2p-crypto](https://github.com/libp2p/js-libp2p-crypto)-compatible
|
||||||
implementation of cryptographic signature generation and verification using the
|
implementation of cryptographic signature generation and verification using the
|
||||||
[secp256k1 elliptic curve](https://en.bitcoin.it/wiki/Secp256k1) popularized by Bitcoin and other
|
[secp256k1 elliptic curve](https://en.bitcoin.it/wiki/Secp256k1) popularized by Bitcoin and other
|
||||||
crypto currencies.
|
crypto currencies.
|
||||||
|
|
||||||
## Lead Captain
|
## Lead Captain
|
||||||
@ -28,14 +28,14 @@ crypto currencies.
|
|||||||
- [Usage](#usage)
|
- [Usage](#usage)
|
||||||
- [Example](#example)
|
- [Example](#example)
|
||||||
- [API](#api)
|
- [API](#api)
|
||||||
- [`generateKeyPair([bits,] callback)`](#generatekeypairbits-callback)
|
- [`generateKeyPair([bits])`](#generatekeypairbits)
|
||||||
- [`unmarshalSecp256k1PublicKey(bytes)`](#unmarshalsecp256k1publickeybytes)
|
- [`unmarshalSecp256k1PublicKey(bytes)`](#unmarshalsecp256k1publickeybytes)
|
||||||
- [`unmarshalSecp256k1PrivateKey(bytes, callback)`](#unmarshalsecp256k1privatekeybytes-callback)
|
- [`unmarshalSecp256k1PrivateKey(bytes)`](#unmarshalsecp256k1privatekeybytes)
|
||||||
- [`Secp256k1PublicKey`](#secp256k1publickey)
|
- [`Secp256k1PublicKey`](#secp256k1publickey)
|
||||||
- [`.verify(data, sig, callback)`](#verifydata-sig-callback)
|
- [`.verify(data, sig)`](#verifydata-sig)
|
||||||
- [`Secp256k1PrivateKey`](#secp256k1privatekey)
|
- [`Secp256k1PrivateKey`](#secp256k1privatekey)
|
||||||
- [`.public`](#public)
|
- [`.public`](#public)
|
||||||
- [`.sign(data, callback)`](#signdata-callback)
|
- [`.sign(data)`](#signdata)
|
||||||
- [Contribute](#contribute)
|
- [Contribute](#contribute)
|
||||||
- [License](#license)
|
- [License](#license)
|
||||||
|
|
||||||
@ -57,48 +57,48 @@ instances of the `Secp256k1PublicKey` or `Secp256k1PrivateKey` classes provided
|
|||||||
|
|
||||||
```js
|
```js
|
||||||
const crypto = require('libp2p-crypto')
|
const crypto = require('libp2p-crypto')
|
||||||
|
|
||||||
const msg = Buffer.from('Hello World')
|
const msg = Buffer.from('Hello World')
|
||||||
|
|
||||||
crypto.generateKeyPair('secp256k1', 256, (err, key) => {
|
const key = await crypto.generateKeyPair('secp256k1', 256)
|
||||||
// assuming no error, key will be an instance of Secp256k1PrivateKey
|
// assuming no error, key will be an instance of Secp256k1PrivateKey
|
||||||
// the public key is available as key.public
|
// the public key is available as key.public
|
||||||
key.sign(msg, (err, sig) => {
|
const sig = await key.sign(msg)
|
||||||
key.public.verify(msg, sig, (err, valid) => {
|
|
||||||
assert(valid, 'Something went horribly wrong')
|
const valid = await key.public.verify(msg, sig)
|
||||||
})
|
assert(valid, 'Something went horribly wrong')
|
||||||
})
|
|
||||||
})
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## API
|
## API
|
||||||
|
|
||||||
The functions below are the public API of this module.
|
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.
|
- `bits: Number` - Optional, included for compatibility with js-libp2p-crypto. Ignored if present; private keys will always be 256 bits.
|
||||||
- `callback: Function`
|
|
||||||
|
Returns `Promise<Secp256k1PrivateKey>`
|
||||||
|
|
||||||
### `unmarshalSecp256k1PublicKey(bytes)`
|
### `unmarshalSecp256k1PublicKey(bytes)`
|
||||||
- `bytes: Buffer`
|
- `bytes: Buffer`
|
||||||
|
|
||||||
Converts a serialized secp256k1 public key into an instance of `Secp256k1PublicKey` and returns it
|
Converts a serialized secp256k1 public key into an instance of `Secp256k1PublicKey` and returns it
|
||||||
|
|
||||||
### `unmarshalSecp256k1PrivateKey(bytes, callback)`
|
### `unmarshalSecp256k1PrivateKey(bytes)`
|
||||||
- `bytes: Buffer`
|
- `bytes: Buffer`
|
||||||
- `callback: Function`
|
|
||||||
|
|
||||||
Converts a serialized secp256k1 private key into an instance of `Secp256k1PrivateKey`, passing it to `callback` on success
|
Returns `Promise<Secp256k1PrivateKey>`
|
||||||
|
|
||||||
|
Converts a serialized secp256k1 private key into an instance of `Secp256k1PrivateKey`.
|
||||||
|
|
||||||
### `Secp256k1PublicKey`
|
### `Secp256k1PublicKey`
|
||||||
|
|
||||||
#### `.verify(data, sig, callback)`
|
#### `.verify(data, sig)`
|
||||||
- `data: Buffer`
|
- `data: Buffer`
|
||||||
- `sig: 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<Boolean>`
|
||||||
|
|
||||||
|
Calculates the SHA-256 hash of `data`, and verifies the DER-encoded signature in `sig`.
|
||||||
|
|
||||||
### `Secp256k1PrivateKey`
|
### `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.
|
Accessor for the `Secp256k1PublicKey` associated with this private key.
|
||||||
|
|
||||||
#### `.sign(data, callback)`
|
#### `.sign(data)`
|
||||||
- `data: Buffer`
|
- `data: Buffer`
|
||||||
|
|
||||||
Calculates the SHA-256 hash of `data` and signs it, passing the DER-encoded signature to `callback`
|
Returns `Promise<Buffer>`
|
||||||
|
|
||||||
|
Calculates the SHA-256 hash of `data` and signs it, resolves with the DER-encoded signature.
|
||||||
|
|
||||||
## Contribute
|
## 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).
|
This repository falls under the IPFS [Code of Conduct](https://github.com/ipfs/community/blob/master/code-of-conduct.md).
|
||||||
|
|
||||||
|
@ -27,15 +27,14 @@
|
|||||||
],
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"async": "^2.6.2",
|
|
||||||
"bs58": "^4.0.1",
|
"bs58": "^4.0.1",
|
||||||
"multihashing-async": "~0.6.0",
|
"multihashing-async": "^0.7.0",
|
||||||
"nodeify": "^1.0.1",
|
"nodeify": "^1.0.1",
|
||||||
"safe-buffer": "^5.1.2",
|
"safe-buffer": "^5.1.2",
|
||||||
"secp256k1": "^3.6.2"
|
"secp256k1": "^3.6.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"aegir": "^18.2.2",
|
"aegir": "^19.0.5",
|
||||||
"benchmark": "^2.1.4",
|
"benchmark": "^2.1.4",
|
||||||
"chai": "^4.2.0",
|
"chai": "^4.2.0",
|
||||||
"dirty-chai": "^2.0.1",
|
"dirty-chai": "^2.0.1",
|
||||||
|
@ -2,49 +2,30 @@
|
|||||||
|
|
||||||
const secp256k1 = require('secp256k1')
|
const secp256k1 = require('secp256k1')
|
||||||
const multihashing = require('multihashing-async')
|
const multihashing = require('multihashing-async')
|
||||||
const setImmediate = require('async/setImmediate')
|
|
||||||
|
|
||||||
const HASH_ALGORITHM = 'sha2-256'
|
const HASH_ALGORITHM = 'sha2-256'
|
||||||
|
|
||||||
module.exports = (randomBytes) => {
|
module.exports = (randomBytes) => {
|
||||||
const privateKeyLength = 32
|
const privateKeyLength = 32
|
||||||
|
|
||||||
function generateKey (callback) {
|
function generateKey () {
|
||||||
const done = (err, res) => setImmediate(() => callback(err, res))
|
|
||||||
|
|
||||||
let privateKey
|
let privateKey
|
||||||
do {
|
do {
|
||||||
privateKey = randomBytes(32)
|
privateKey = randomBytes(32)
|
||||||
} while (!secp256k1.privateKeyVerify(privateKey))
|
} while (!secp256k1.privateKeyVerify(privateKey))
|
||||||
|
return privateKey
|
||||||
done(null, privateKey)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function hashAndSign (key, msg, callback) {
|
async function hashAndSign (key, msg) {
|
||||||
const done = (err, res) => setImmediate(() => callback(err, res))
|
const digest = await multihashing.digest(msg, HASH_ALGORITHM)
|
||||||
|
const sig = secp256k1.sign(digest, key)
|
||||||
multihashing.digest(msg, HASH_ALGORITHM, (err, digest) => {
|
return secp256k1.signatureExport(sig.signature)
|
||||||
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) {
|
async function hashAndVerify (key, sig, msg) {
|
||||||
const done = (err, res) => setImmediate(() => callback(err, res))
|
const digest = await multihashing.digest(msg, HASH_ALGORITHM)
|
||||||
|
sig = secp256k1.signatureImport(sig)
|
||||||
multihashing.digest(msg, HASH_ALGORITHM, (err, digest) => {
|
return secp256k1.verify(digest, sig, key)
|
||||||
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) {
|
function compressPublicKey (key) {
|
||||||
@ -76,14 +57,14 @@ module.exports = (randomBytes) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
generateKey: generateKey,
|
generateKey,
|
||||||
privateKeyLength: privateKeyLength,
|
privateKeyLength,
|
||||||
hashAndSign: hashAndSign,
|
hashAndSign,
|
||||||
hashAndVerify: hashAndVerify,
|
hashAndVerify,
|
||||||
compressPublicKey: compressPublicKey,
|
compressPublicKey,
|
||||||
decompressPublicKey: decompressPublicKey,
|
decompressPublicKey,
|
||||||
validatePrivateKey: validatePrivateKey,
|
validatePrivateKey,
|
||||||
validatePublicKey: validatePublicKey,
|
validatePublicKey,
|
||||||
computePublicKey: computePublicKey
|
computePublicKey
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
61
src/index.js
61
src/index.js
@ -12,9 +12,8 @@ module.exports = (keysProtobuf, randomBytes, crypto) => {
|
|||||||
this._key = key
|
this._key = key
|
||||||
}
|
}
|
||||||
|
|
||||||
verify (data, sig, callback) {
|
verify (data, sig) {
|
||||||
ensure(callback)
|
return crypto.hashAndVerify(this._key, sig, data)
|
||||||
crypto.hashAndVerify(this._key, sig, data, callback)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
marshal () {
|
marshal () {
|
||||||
@ -32,9 +31,8 @@ module.exports = (keysProtobuf, randomBytes, crypto) => {
|
|||||||
return this.bytes.equals(key.bytes)
|
return this.bytes.equals(key.bytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
hash (callback) {
|
hash () {
|
||||||
ensure(callback)
|
return multihashing(this.bytes, 'sha2-256')
|
||||||
multihashing(this.bytes, 'sha2-256', callback)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -46,9 +44,8 @@ module.exports = (keysProtobuf, randomBytes, crypto) => {
|
|||||||
crypto.validatePublicKey(this._publicKey)
|
crypto.validatePublicKey(this._publicKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
sign (message, callback) {
|
sign (message) {
|
||||||
ensure(callback)
|
return crypto.hashAndSign(this._key, message)
|
||||||
crypto.hashAndSign(this._key, message, callback)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
get public () {
|
get public () {
|
||||||
@ -70,9 +67,8 @@ module.exports = (keysProtobuf, randomBytes, crypto) => {
|
|||||||
return this.bytes.equals(key.bytes)
|
return this.bytes.equals(key.bytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
hash (callback) {
|
hash () {
|
||||||
ensure(callback)
|
return multihashing(this.bytes, 'sha2-256')
|
||||||
multihashing(this.bytes, 'sha2-256', callback)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -85,47 +81,24 @@ module.exports = (keysProtobuf, randomBytes, crypto) => {
|
|||||||
* @param {function(Error, id)} callback
|
* @param {function(Error, id)} callback
|
||||||
* @returns {undefined}
|
* @returns {undefined}
|
||||||
*/
|
*/
|
||||||
id (callback) {
|
async id () {
|
||||||
this.public.hash((err, hash) => {
|
const hash = await this.public.hash()
|
||||||
if (err) {
|
|
||||||
return callback(err)
|
return bs58.encode(hash)
|
||||||
}
|
|
||||||
callback(null, bs58.encode(hash))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function unmarshalSecp256k1PrivateKey (bytes, callback) {
|
function unmarshalSecp256k1PrivateKey (bytes) {
|
||||||
callback(null, new Secp256k1PrivateKey(bytes))
|
return new Secp256k1PrivateKey(bytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
function unmarshalSecp256k1PublicKey (bytes) {
|
function unmarshalSecp256k1PublicKey (bytes) {
|
||||||
return new Secp256k1PublicKey(bytes)
|
return new Secp256k1PublicKey(bytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
function generateKeyPair (_bits, callback) {
|
async function generateKeyPair () {
|
||||||
if (callback === undefined && typeof _bits === 'function') {
|
const privateKeyBytes = await crypto.generateKey()
|
||||||
callback = _bits
|
return new Secp256k1PrivateKey(privateKeyBytes)
|
||||||
}
|
|
||||||
|
|
||||||
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')
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -6,8 +6,6 @@ const dirtyChai = require('dirty-chai')
|
|||||||
const expect = chai.expect
|
const expect = chai.expect
|
||||||
chai.use(dirtyChai)
|
chai.use(dirtyChai)
|
||||||
|
|
||||||
const Buffer = require('safe-buffer').Buffer
|
|
||||||
|
|
||||||
const libp2pCrypto = require('libp2p-crypto')
|
const libp2pCrypto = require('libp2p-crypto')
|
||||||
const keysPBM = libp2pCrypto.keys.keysPBM
|
const keysPBM = libp2pCrypto.keys.keysPBM
|
||||||
const randomBytes = libp2pCrypto.randomBytes
|
const randomBytes = libp2pCrypto.randomBytes
|
||||||
@ -17,81 +15,52 @@ describe('secp256k1 keys', () => {
|
|||||||
let key
|
let key
|
||||||
const secp256k1 = require('../src')(keysPBM, randomBytes)
|
const secp256k1 = require('../src')(keysPBM, randomBytes)
|
||||||
|
|
||||||
before((done) => {
|
before(async () => {
|
||||||
secp256k1.generateKeyPair((err, _key) => {
|
key = await secp256k1.generateKeyPair()
|
||||||
expect(err).to.not.exist()
|
|
||||||
key = _key
|
|
||||||
done()
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it('generates a valid key', (done) => {
|
it('generates a valid key', async () => {
|
||||||
expect(key).to.be.an.instanceof(secp256k1.Secp256k1PrivateKey)
|
expect(key).to.be.an.instanceof(secp256k1.Secp256k1PrivateKey)
|
||||||
expect(key.public).to.be.an.instanceof(secp256k1.Secp256k1PublicKey)
|
expect(key.public).to.be.an.instanceof(secp256k1.Secp256k1PublicKey)
|
||||||
|
|
||||||
key.hash((err, digest) => {
|
const digest = await key.hash()
|
||||||
expect(err).to.not.exist()
|
expect(digest).to.have.length(34)
|
||||||
expect(digest).to.have.length(34)
|
|
||||||
|
|
||||||
key.public.hash((err, digest) => {
|
const publicDigest = await key.public.hash()
|
||||||
expect(err).to.not.exist()
|
expect(publicDigest).to.have.length(34)
|
||||||
expect(digest).to.have.length(34)
|
|
||||||
done()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it('optionally accepts a `bits` argument when generating a key', (done) => {
|
it('optionally accepts a `bits` argument when generating a key', async () => {
|
||||||
secp256k1.generateKeyPair(256, (err, _key) => {
|
const _key = await secp256k1.generateKeyPair(256)
|
||||||
expect(err).to.not.exist()
|
expect(_key).to.be.an.instanceof(secp256k1.Secp256k1PrivateKey)
|
||||||
expect(_key).to.be.an.instanceof(secp256k1.Secp256k1PrivateKey)
|
|
||||||
done()
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it('requires a callback to generate a key', () => {
|
it('signs', async () => {
|
||||||
expect(() => secp256k1.generateKeyPair()).to.throw()
|
|
||||||
})
|
|
||||||
|
|
||||||
it('signs', (done) => {
|
|
||||||
const text = randomBytes(512)
|
const text = randomBytes(512)
|
||||||
|
const sig = await key.sign(text)
|
||||||
key.sign(text, (err, sig) => {
|
const res = await key.public.verify(text, sig)
|
||||||
expect(err).to.not.exist()
|
expect(res).to.equal(true)
|
||||||
|
|
||||||
key.public.verify(text, sig, (err, res) => {
|
|
||||||
expect(err).to.not.exist()
|
|
||||||
expect(res).to.equal(true)
|
|
||||||
done()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it('encoding', (done) => {
|
it('encoding', async () => {
|
||||||
const keyMarshal = key.marshal()
|
const keyMarshal = key.marshal()
|
||||||
secp256k1.unmarshalSecp256k1PrivateKey(keyMarshal, (err, key2) => {
|
const key2 = await secp256k1.unmarshalSecp256k1PrivateKey(keyMarshal)
|
||||||
expect(err).to.not.exist()
|
const keyMarshal2 = key2.marshal()
|
||||||
const keyMarshal2 = key2.marshal()
|
|
||||||
|
|
||||||
expect(keyMarshal).to.eql(keyMarshal2)
|
expect(keyMarshal).to.eql(keyMarshal2)
|
||||||
|
|
||||||
const pk = key.public
|
const pk = key.public
|
||||||
const pkMarshal = pk.marshal()
|
const pkMarshal = pk.marshal()
|
||||||
const pk2 = secp256k1.unmarshalSecp256k1PublicKey(pkMarshal)
|
const pk2 = secp256k1.unmarshalSecp256k1PublicKey(pkMarshal)
|
||||||
const pkMarshal2 = pk2.marshal()
|
const pkMarshal2 = pk2.marshal()
|
||||||
|
|
||||||
expect(pkMarshal).to.eql(pkMarshal2)
|
expect(pkMarshal).to.eql(pkMarshal2)
|
||||||
done()
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it('key id', (done) => {
|
it('key id', async () => {
|
||||||
key.id((err, id) => {
|
const id = await key.id()
|
||||||
expect(err).to.not.exist()
|
expect(id).to.exist()
|
||||||
expect(id).to.exist()
|
expect(id).to.be.a('string')
|
||||||
expect(id).to.be.a('string')
|
|
||||||
done()
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('key equals', () => {
|
describe('key equals', () => {
|
||||||
@ -101,43 +70,27 @@ describe('secp256k1 keys', () => {
|
|||||||
expect(key.public.equals(key.public)).to.eql(true)
|
expect(key.public.equals(key.public)).to.eql(true)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('not equals other key', (done) => {
|
it('not equals other key', async () => {
|
||||||
secp256k1.generateKeyPair(256, (err, key2) => {
|
const key2 = await secp256k1.generateKeyPair(256)
|
||||||
expect(err).to.not.exist()
|
expect(key.equals(key2)).to.eql(false)
|
||||||
|
expect(key2.equals(key)).to.eql(false)
|
||||||
expect(key.equals(key2)).to.eql(false)
|
expect(key.public.equals(key2.public)).to.eql(false)
|
||||||
expect(key2.equals(key)).to.eql(false)
|
expect(key2.public.equals(key.public)).to.eql(false)
|
||||||
expect(key.public.equals(key2.public)).to.eql(false)
|
|
||||||
expect(key2.public.equals(key.public)).to.eql(false)
|
|
||||||
done()
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
it('sign and verify', (done) => {
|
it('sign and verify', async () => {
|
||||||
const data = Buffer.from('hello world')
|
const data = Buffer.from('hello world')
|
||||||
key.sign(data, (err, sig) => {
|
const sig = await key.sign(data)
|
||||||
expect(err).to.not.exist()
|
const valid = await key.public.verify(data, sig)
|
||||||
|
expect(valid).to.eql(true)
|
||||||
key.public.verify(data, sig, (err, valid) => {
|
|
||||||
expect(err).to.not.exist()
|
|
||||||
expect(valid).to.eql(true)
|
|
||||||
done()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it('fails to verify for different data', (done) => {
|
it('fails to verify for different data', async () => {
|
||||||
const data = Buffer.from('hello world')
|
const data = Buffer.from('hello world')
|
||||||
key.sign(data, (err, sig) => {
|
const sig = await key.sign(data)
|
||||||
expect(err).to.not.exist()
|
const valid = await key.public.verify(Buffer.from('hello'), sig)
|
||||||
|
expect(valid).to.eql(false)
|
||||||
key.public.verify(Buffer.from('hello'), sig, (err, valid) => {
|
|
||||||
expect(err).to.not.exist()
|
|
||||||
expect(valid).to.eql(false)
|
|
||||||
done()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -145,25 +98,23 @@ describe('key generation error', () => {
|
|||||||
let generateKey
|
let generateKey
|
||||||
let secp256k1
|
let secp256k1
|
||||||
|
|
||||||
before((done) => {
|
before(() => {
|
||||||
generateKey = crypto.generateKey
|
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)
|
secp256k1 = require('../src')(keysPBM, randomBytes, crypto)
|
||||||
|
|
||||||
done()
|
|
||||||
})
|
})
|
||||||
|
|
||||||
after((done) => {
|
after(() => {
|
||||||
crypto.generateKey = generateKey
|
crypto.generateKey = generateKey
|
||||||
done()
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it('returns an error if key generation fails', (done) => {
|
it('returns an error if key generation fails', async () => {
|
||||||
secp256k1.generateKeyPair((err, key) => {
|
try {
|
||||||
expect(err).to.exist()
|
await secp256k1.generateKeyPair()
|
||||||
expect(key).to.not.exist()
|
} catch (err) {
|
||||||
done()
|
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 generateKey
|
||||||
let secp256k1
|
let secp256k1
|
||||||
|
|
||||||
before((done) => {
|
before(() => {
|
||||||
generateKey = crypto.generateKey
|
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)
|
secp256k1 = require('../src')(keysPBM, randomBytes, crypto)
|
||||||
|
|
||||||
done()
|
|
||||||
})
|
})
|
||||||
|
|
||||||
after((done) => {
|
after(() => {
|
||||||
crypto.generateKey = generateKey
|
crypto.generateKey = generateKey
|
||||||
done()
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it('returns an error if key generator returns an invalid key', (done) => {
|
it('returns an error if key generator returns an invalid key', async () => {
|
||||||
secp256k1.generateKeyPair((err, key) => {
|
try {
|
||||||
expect(err).to.exist()
|
await secp256k1.generateKeyPair()
|
||||||
expect(key).to.not.exist()
|
} catch (err) {
|
||||||
done()
|
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 privKey
|
||||||
let pubKey
|
let pubKey
|
||||||
|
|
||||||
before((done) => {
|
before(async () => {
|
||||||
crypto.generateKey((err, _key) => {
|
privKey = await crypto.generateKey()
|
||||||
expect(err).to.not.exist()
|
pubKey = crypto.computePublicKey(privKey)
|
||||||
privKey = _key
|
|
||||||
pubKey = crypto.computePublicKey(privKey)
|
|
||||||
done()
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it('generates valid keys', (done) => {
|
it('generates valid keys', () => {
|
||||||
expect(() => {
|
expect(() => {
|
||||||
crypto.validatePrivateKey(privKey)
|
crypto.validatePrivateKey(privKey)
|
||||||
crypto.validatePublicKey(pubKey)
|
crypto.validatePublicKey(pubKey)
|
||||||
}).to.not.throw()
|
}).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.validatePublicKey(Buffer.from('42'))).to.throw()
|
||||||
expect(() => crypto.validatePrivateKey(Buffer.from('42'))).to.throw()
|
expect(() => crypto.validatePrivateKey(Buffer.from('42'))).to.throw()
|
||||||
done()
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it('validates a correct signature', (done) => {
|
it('validates a correct signature', async () => {
|
||||||
crypto.hashAndSign(privKey, Buffer.from('hello'), (err, sig) => {
|
const sig = await crypto.hashAndSign(privKey, Buffer.from('hello'))
|
||||||
expect(err).to.not.exist()
|
const valid = await crypto.hashAndVerify(pubKey, sig, Buffer.from('hello'))
|
||||||
crypto.hashAndVerify(pubKey, sig, Buffer.from('hello'), (err, valid) => {
|
expect(valid).to.equal(true)
|
||||||
expect(err).to.not.exist()
|
|
||||||
expect(valid).to.equal(true)
|
|
||||||
done()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it('errors if given a null buffer to sign', (done) => {
|
it('errors if given a null buffer to sign', async () => {
|
||||||
crypto.hashAndSign(privKey, null, (err, sig) => {
|
try {
|
||||||
expect(err).to.exist()
|
await crypto.hashAndSign(privKey, null)
|
||||||
expect(sig).to.not.exist()
|
} catch (err) {
|
||||||
done()
|
return // expected
|
||||||
})
|
}
|
||||||
|
throw new Error('Expected error to be thrown')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('errors when signing with an invalid key', (done) => {
|
it('errors when signing with an invalid key', async () => {
|
||||||
crypto.hashAndSign(Buffer.from('42'), Buffer.from('Hello'), (err, sig) => {
|
try {
|
||||||
expect(err).to.exist()
|
await crypto.hashAndSign(Buffer.from('42'), Buffer.from('Hello'))
|
||||||
expect(sig).to.not.exist()
|
} catch (err) {
|
||||||
done()
|
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) => {
|
it('errors if given a null buffer to validate', async () => {
|
||||||
crypto.hashAndSign(privKey, Buffer.from('hello'), (err, sig) => {
|
const sig = await crypto.hashAndSign(privKey, Buffer.from('hello'))
|
||||||
expect(err).to.not.exist()
|
|
||||||
|
|
||||||
crypto.hashAndVerify(privKey, sig, null, (err, valid) => {
|
try {
|
||||||
expect(err).to.exist()
|
await crypto.hashAndVerify(privKey, sig, null)
|
||||||
expect(valid).to.not.exist()
|
} catch (err) {
|
||||||
done()
|
return // expected
|
||||||
})
|
}
|
||||||
})
|
throw new Error('Expected error to be thrown')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('errors when validating a message with an invalid signature', (done) => {
|
it('errors when validating a message with an invalid signature', async () => {
|
||||||
crypto.hashAndVerify(pubKey, Buffer.from('invalid-sig'), Buffer.from('hello'), (err, valid) => {
|
try {
|
||||||
expect(err).to.exist()
|
await crypto.hashAndVerify(pubKey, Buffer.from('invalid-sig'), Buffer.from('hello'))
|
||||||
expect(valid).to.not.exist()
|
} catch (err) {
|
||||||
done()
|
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) => {
|
it('errors when signing with an invalid key', async () => {
|
||||||
crypto.hashAndSign(Buffer.from('42'), Buffer.from('Hello'), (err, sig) => {
|
try {
|
||||||
expect(err).to.exist()
|
await crypto.hashAndSign(Buffer.from('42'), Buffer.from('Hello'))
|
||||||
expect(sig).to.not.exist()
|
} catch (err) {
|
||||||
done()
|
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()
|
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()
|
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)
|
const decompressed = crypto.decompressPublicKey(pubKey)
|
||||||
expect(decompressed).to.exist()
|
expect(decompressed).to.exist()
|
||||||
expect(decompressed.length).to.be.eql(65)
|
expect(decompressed.length).to.be.eql(65)
|
||||||
const recompressed = crypto.compressPublicKey(decompressed)
|
const recompressed = crypto.compressPublicKey(decompressed)
|
||||||
expect(recompressed).to.eql(pubKey)
|
expect(recompressed).to.eql(pubKey)
|
||||||
done()
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -299,43 +237,32 @@ describe('go interop', () => {
|
|||||||
const secp256k1 = require('../src')(keysPBM, randomBytes)
|
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', async () => {
|
||||||
// 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 = keysPBM.PrivateKey.decode(fixtures.privateKey)
|
const decoded = keysPBM.PrivateKey.decode(fixtures.privateKey)
|
||||||
expect(decoded.Type).to.eql(keysPBM.KeyType.Secp256k1)
|
expect(decoded.Type).to.eql(keysPBM.KeyType.Secp256k1)
|
||||||
|
|
||||||
secp256k1.unmarshalSecp256k1PrivateKey(decoded.Data, (err, key) => {
|
const key = await secp256k1.unmarshalSecp256k1PrivateKey(decoded.Data)
|
||||||
expect(err).to.not.exist()
|
expect(key).to.be.an.instanceof(secp256k1.Secp256k1PrivateKey)
|
||||||
|
expect(key.bytes).to.eql(fixtures.privateKey)
|
||||||
expect(key).to.be.an.instanceof(secp256k1.Secp256k1PrivateKey)
|
|
||||||
expect(key.bytes).to.eql(fixtures.privateKey)
|
|
||||||
done()
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|
||||||
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)
|
const decoded = keysPBM.PublicKey.decode(fixtures.publicKey)
|
||||||
expect(decoded.Type).to.be.eql(keysPBM.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)
|
||||||
expect(key.bytes).to.eql(fixtures.publicKey)
|
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)
|
const decoded = keysPBM.PrivateKey.decode(fixtures.privateKey)
|
||||||
expect(decoded.Type).to.eql(keysPBM.KeyType.Secp256k1)
|
expect(decoded.Type).to.eql(keysPBM.KeyType.Secp256k1)
|
||||||
|
|
||||||
secp256k1.unmarshalSecp256k1PrivateKey(decoded.Data, (err, key) => {
|
const key = await secp256k1.unmarshalSecp256k1PrivateKey(decoded.Data)
|
||||||
expect(err).to.not.exist()
|
const sig = await key.sign(fixtures.message)
|
||||||
|
expect(sig).to.eql(fixtures.signature)
|
||||||
key.sign(fixtures.message, (err, sig) => {
|
|
||||||
expect(err).to.not.exist()
|
|
||||||
expect(sig).to.eql(fixtures.signature)
|
|
||||||
done()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
Loading…
x
Reference in New Issue
Block a user