Skip to content

Commit 1974eb9

Browse files
achingbrainjacobheun
authored andcommitted
feat: use async await (libp2p#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 ipfs/js-ipfs#1670 * fix: use latest multihashing-async as it is all promises now
1 parent fbd4238 commit 1974eb9

File tree

7 files changed

+191
-307
lines changed

7 files changed

+191
-307
lines changed

.gitignore

+2-1
Original file line numberDiff line numberDiff line change
@@ -33,4 +33,5 @@ node_modules
3333

3434
dist
3535
package-lock.json
36-
yarn.lock
36+
yarn.lock
37+
.vscode

.travis.yml

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
12
language: node_js
23

34
cache: npm
@@ -41,4 +42,4 @@ jobs:
4142
- npx aegir test -t browser -- --browsers FirefoxHeadless
4243

4344
notifications:
44-
email: false
45+
email: false

README.md

+31-29
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,9 @@
1313

1414
> Support for secp256k1 keys in js-libp2p-crypto
1515
16-
This repo contains a [js-libp2p-crypto](https://github.com/libp2p/js-libp2p-crypto)-compatible
17-
implementation of cryptographic signature generation and verification using the
18-
[secp256k1 elliptic curve](https://en.bitcoin.it/wiki/Secp256k1) popularized by Bitcoin and other
16+
This repo contains a [js-libp2p-crypto](https://github.com/libp2p/js-libp2p-crypto)-compatible
17+
implementation of cryptographic signature generation and verification using the
18+
[secp256k1 elliptic curve](https://en.bitcoin.it/wiki/Secp256k1) popularized by Bitcoin and other
1919
crypto currencies.
2020

2121
## Lead Captain
@@ -28,14 +28,14 @@ crypto currencies.
2828
- [Usage](#usage)
2929
- [Example](#example)
3030
- [API](#api)
31-
- [`generateKeyPair([bits,] callback)`](#generatekeypairbits-callback)
31+
- [`generateKeyPair([bits])`](#generatekeypairbits)
3232
- [`unmarshalSecp256k1PublicKey(bytes)`](#unmarshalsecp256k1publickeybytes)
33-
- [`unmarshalSecp256k1PrivateKey(bytes, callback)`](#unmarshalsecp256k1privatekeybytes-callback)
33+
- [`unmarshalSecp256k1PrivateKey(bytes)`](#unmarshalsecp256k1privatekeybytes)
3434
- [`Secp256k1PublicKey`](#secp256k1publickey)
35-
- [`.verify(data, sig, callback)`](#verifydata-sig-callback)
35+
- [`.verify(data, sig)`](#verifydata-sig)
3636
- [`Secp256k1PrivateKey`](#secp256k1privatekey)
3737
- [`.public`](#public)
38-
- [`.sign(data, callback)`](#signdata-callback)
38+
- [`.sign(data)`](#signdata)
3939
- [Contribute](#contribute)
4040
- [License](#license)
4141

@@ -57,63 +57,65 @@ instances of the `Secp256k1PublicKey` or `Secp256k1PrivateKey` classes provided
5757

5858
```js
5959
const crypto = require('libp2p-crypto')
60-
6160
const msg = Buffer.from('Hello World')
6261

63-
crypto.generateKeyPair('secp256k1', 256, (err, key) => {
64-
// assuming no error, key will be an instance of Secp256k1PrivateKey
65-
// the public key is available as key.public
66-
key.sign(msg, (err, sig) => {
67-
key.public.verify(msg, sig, (err, valid) => {
68-
assert(valid, 'Something went horribly wrong')
69-
})
70-
})
71-
})
62+
const key = await crypto.generateKeyPair('secp256k1', 256)
63+
// assuming no error, key will be an instance of Secp256k1PrivateKey
64+
// the public key is available as key.public
65+
const sig = await key.sign(msg)
66+
67+
const valid = await key.public.verify(msg, sig)
68+
assert(valid, 'Something went horribly wrong')
7269
```
7370

7471
## API
7572

7673
The functions below are the public API of this module.
77-
For usage within libp2p-crypto, see the [libp2p-crypto API documentation](https://github.com/libp2p/js-libp2p-crypto#api).
74+
For usage within `libp2p-crypto`, see the [`libp2p-crypto` API documentation](https://github.com/libp2p/js-libp2p-crypto#api).
7875

79-
### `generateKeyPair([bits, ] callback)`
76+
### `generateKeyPair([bits])`
8077
- `bits: Number` - Optional, included for compatibility with js-libp2p-crypto. Ignored if present; private keys will always be 256 bits.
81-
- `callback: Function`
78+
79+
Returns `Promise<Secp256k1PrivateKey>`
8280

8381
### `unmarshalSecp256k1PublicKey(bytes)`
8482
- `bytes: Buffer`
8583

8684
Converts a serialized secp256k1 public key into an instance of `Secp256k1PublicKey` and returns it
8785

88-
### `unmarshalSecp256k1PrivateKey(bytes, callback)`
86+
### `unmarshalSecp256k1PrivateKey(bytes)`
8987
- `bytes: Buffer`
90-
- `callback: Function`
9188

92-
Converts a serialized secp256k1 private key into an instance of `Secp256k1PrivateKey`, passing it to `callback` on success
89+
Returns `Promise<Secp256k1PrivateKey>`
90+
91+
Converts a serialized secp256k1 private key into an instance of `Secp256k1PrivateKey`.
9392

9493
### `Secp256k1PublicKey`
9594

96-
#### `.verify(data, sig, callback)`
95+
#### `.verify(data, sig)`
9796
- `data: Buffer`
9897
- `sig: Buffer`
99-
- `callback: Function`
10098

101-
Calculates the SHA-256 hash of `data`, and verifies the DER-encoded signature in `sig`, passing the result to `callback`
99+
Returns `Promise<Boolean>`
100+
101+
Calculates the SHA-256 hash of `data`, and verifies the DER-encoded signature in `sig`.
102102

103103
### `Secp256k1PrivateKey`
104104

105105
#### `.public`
106106

107107
Accessor for the `Secp256k1PublicKey` associated with this private key.
108108

109-
#### `.sign(data, callback)`
109+
#### `.sign(data)`
110110
- `data: Buffer`
111111

112-
Calculates the SHA-256 hash of `data` and signs it, passing the DER-encoded signature to `callback`
112+
Returns `Promise<Buffer>`
113+
114+
Calculates the SHA-256 hash of `data` and signs it, resolves with the DER-encoded signature.
113115

114116
## Contribute
115117

116-
Feel free to join in. All welcome. Open an [issue](https://github.com/libp2p/js-libp2p-crypto/issues)!
118+
Feel free to join in. All welcome. Open an [issue](https://github.com/libp2p/js-libp2p-crypto-secp256k1/issues)!
117119

118120
This repository falls under the IPFS [Code of Conduct](https://github.com/ipfs/community/blob/master/code-of-conduct.md).
119121

package.json

+2-3
Original file line numberDiff line numberDiff line change
@@ -27,15 +27,14 @@
2727
],
2828
"license": "MIT",
2929
"dependencies": {
30-
"async": "^2.6.2",
3130
"bs58": "^4.0.1",
32-
"multihashing-async": "~0.6.0",
31+
"multihashing-async": "^0.7.0",
3332
"nodeify": "^1.0.1",
3433
"safe-buffer": "^5.1.2",
3534
"secp256k1": "^3.6.2"
3635
},
3736
"devDependencies": {
38-
"aegir": "^18.2.2",
37+
"aegir": "^19.0.5",
3938
"benchmark": "^2.1.4",
4039
"chai": "^4.2.0",
4140
"dirty-chai": "^2.0.1",

src/crypto.js

+19-38
Original file line numberDiff line numberDiff line change
@@ -2,49 +2,30 @@
22

33
const secp256k1 = require('secp256k1')
44
const multihashing = require('multihashing-async')
5-
const setImmediate = require('async/setImmediate')
65

76
const HASH_ALGORITHM = 'sha2-256'
87

98
module.exports = (randomBytes) => {
109
const privateKeyLength = 32
1110

12-
function generateKey (callback) {
13-
const done = (err, res) => setImmediate(() => callback(err, res))
14-
11+
function generateKey () {
1512
let privateKey
1613
do {
1714
privateKey = randomBytes(32)
1815
} while (!secp256k1.privateKeyVerify(privateKey))
19-
20-
done(null, privateKey)
16+
return privateKey
2117
}
2218

23-
function hashAndSign (key, msg, callback) {
24-
const done = (err, res) => setImmediate(() => callback(err, res))
25-
26-
multihashing.digest(msg, HASH_ALGORITHM, (err, digest) => {
27-
if (err) { return done(err) }
28-
29-
try {
30-
const sig = secp256k1.sign(digest, key)
31-
const sigDER = secp256k1.signatureExport(sig.signature)
32-
return done(null, sigDER)
33-
} catch (err) { done(err) }
34-
})
19+
async function hashAndSign (key, msg) {
20+
const digest = await multihashing.digest(msg, HASH_ALGORITHM)
21+
const sig = secp256k1.sign(digest, key)
22+
return secp256k1.signatureExport(sig.signature)
3523
}
3624

37-
function hashAndVerify (key, sig, msg, callback) {
38-
const done = (err, res) => setImmediate(() => callback(err, res))
39-
40-
multihashing.digest(msg, HASH_ALGORITHM, (err, digest) => {
41-
if (err) { return done(err) }
42-
try {
43-
sig = secp256k1.signatureImport(sig)
44-
const valid = secp256k1.verify(digest, sig, key)
45-
return done(null, valid)
46-
} catch (err) { done(err) }
47-
})
25+
async function hashAndVerify (key, sig, msg) {
26+
const digest = await multihashing.digest(msg, HASH_ALGORITHM)
27+
sig = secp256k1.signatureImport(sig)
28+
return secp256k1.verify(digest, sig, key)
4829
}
4930

5031
function compressPublicKey (key) {
@@ -76,14 +57,14 @@ module.exports = (randomBytes) => {
7657
}
7758

7859
return {
79-
generateKey: generateKey,
80-
privateKeyLength: privateKeyLength,
81-
hashAndSign: hashAndSign,
82-
hashAndVerify: hashAndVerify,
83-
compressPublicKey: compressPublicKey,
84-
decompressPublicKey: decompressPublicKey,
85-
validatePrivateKey: validatePrivateKey,
86-
validatePublicKey: validatePublicKey,
87-
computePublicKey: computePublicKey
60+
generateKey,
61+
privateKeyLength,
62+
hashAndSign,
63+
hashAndVerify,
64+
compressPublicKey,
65+
decompressPublicKey,
66+
validatePrivateKey,
67+
validatePublicKey,
68+
computePublicKey
8869
}
8970
}

src/index.js

+17-44
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,8 @@ module.exports = (keysProtobuf, randomBytes, crypto) => {
1212
this._key = key
1313
}
1414

15-
verify (data, sig, callback) {
16-
ensure(callback)
17-
crypto.hashAndVerify(this._key, sig, data, callback)
15+
verify (data, sig) {
16+
return crypto.hashAndVerify(this._key, sig, data)
1817
}
1918

2019
marshal () {
@@ -32,9 +31,8 @@ module.exports = (keysProtobuf, randomBytes, crypto) => {
3231
return this.bytes.equals(key.bytes)
3332
}
3433

35-
hash (callback) {
36-
ensure(callback)
37-
multihashing(this.bytes, 'sha2-256', callback)
34+
hash () {
35+
return multihashing(this.bytes, 'sha2-256')
3836
}
3937
}
4038

@@ -46,9 +44,8 @@ module.exports = (keysProtobuf, randomBytes, crypto) => {
4644
crypto.validatePublicKey(this._publicKey)
4745
}
4846

49-
sign (message, callback) {
50-
ensure(callback)
51-
crypto.hashAndSign(this._key, message, callback)
47+
sign (message) {
48+
return crypto.hashAndSign(this._key, message)
5249
}
5350

5451
get public () {
@@ -70,9 +67,8 @@ module.exports = (keysProtobuf, randomBytes, crypto) => {
7067
return this.bytes.equals(key.bytes)
7168
}
7269

73-
hash (callback) {
74-
ensure(callback)
75-
multihashing(this.bytes, 'sha2-256', callback)
70+
hash () {
71+
return multihashing(this.bytes, 'sha2-256')
7672
}
7773

7874
/**
@@ -85,47 +81,24 @@ module.exports = (keysProtobuf, randomBytes, crypto) => {
8581
* @param {function(Error, id)} callback
8682
* @returns {undefined}
8783
*/
88-
id (callback) {
89-
this.public.hash((err, hash) => {
90-
if (err) {
91-
return callback(err)
92-
}
93-
callback(null, bs58.encode(hash))
94-
})
84+
async id () {
85+
const hash = await this.public.hash()
86+
87+
return bs58.encode(hash)
9588
}
9689
}
9790

98-
function unmarshalSecp256k1PrivateKey (bytes, callback) {
99-
callback(null, new Secp256k1PrivateKey(bytes))
91+
function unmarshalSecp256k1PrivateKey (bytes) {
92+
return new Secp256k1PrivateKey(bytes)
10093
}
10194

10295
function unmarshalSecp256k1PublicKey (bytes) {
10396
return new Secp256k1PublicKey(bytes)
10497
}
10598

106-
function generateKeyPair (_bits, callback) {
107-
if (callback === undefined && typeof _bits === 'function') {
108-
callback = _bits
109-
}
110-
111-
ensure(callback)
112-
113-
crypto.generateKey((err, privateKeyBytes) => {
114-
if (err) { return callback(err) }
115-
116-
let privkey
117-
try {
118-
privkey = new Secp256k1PrivateKey(privateKeyBytes)
119-
} catch (err) { return callback(err) }
120-
121-
callback(null, privkey)
122-
})
123-
}
124-
125-
function ensure (callback) {
126-
if (typeof callback !== 'function') {
127-
throw new Error('callback is required')
128-
}
99+
async function generateKeyPair () {
100+
const privateKeyBytes = await crypto.generateKey()
101+
return new Secp256k1PrivateKey(privateKeyBytes)
129102
}
130103

131104
return {

0 commit comments

Comments
 (0)