Skip to content
This repository has been archived by the owner on Apr 8, 2020. It is now read-only.

feat: Use async await #18

Merged
merged 2 commits into from
Jul 10, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,5 @@ node_modules

dist
package-lock.json
yarn.lock
yarn.lock
.vscode
3 changes: 2 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@

language: node_js

cache: npm
Expand Down Expand Up @@ -41,4 +42,4 @@ jobs:
- npx aegir test -t browser -- --browsers FirefoxHeadless

notifications:
email: false
email: false
60 changes: 31 additions & 29 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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)

Expand All @@ -57,63 +57,65 @@ 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<Secp256k1PrivateKey>`

### `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<Secp256k1PrivateKey>`

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<Boolean>`

Calculates the SHA-256 hash of `data`, and verifies the DER-encoded signature in `sig`.

### `Secp256k1PrivateKey`

#### `.public`

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<Buffer>`

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).

Expand Down
5 changes: 2 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
57 changes: 19 additions & 38 deletions src/crypto.js
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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
}
}
61 changes: 17 additions & 44 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 () {
Expand All @@ -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')
}
}

Expand All @@ -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 () {
Expand All @@ -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')
}

/**
Expand All @@ -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 {
Expand Down
Loading