mirror of https://github.com/waku-org/js-waku.git
Merge pull request #599 from status-im/remove-node-crypto
This commit is contained in:
commit
0e42cf6d7f
|
@ -16,6 +16,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
- Prefer the use of `BigInt` over integer literal (`n` postfix) to facilitate the use of a polyfill.
|
- Prefer the use of `BigInt` over integer literal (`n` postfix) to facilitate the use of a polyfill.
|
||||||
|
- Replaced `secp256k1` and hence `elliptic` dependencies with `@noble/secp256k1`,
|
||||||
|
reducing package size, number of dependency and removing need for `crypto-browserify` polyfill.
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ module.exports = {
|
||||||
Object.assign(config.resolve.fallback, {
|
Object.assign(config.resolve.fallback, {
|
||||||
assert: require.resolve("assert"),
|
assert: require.resolve("assert"),
|
||||||
buffer: require.resolve("buffer"),
|
buffer: require.resolve("buffer"),
|
||||||
crypto: require.resolve("crypto-browserify"),
|
crypto: false,
|
||||||
http: require.resolve("http-browserify"),
|
http: require.resolve("http-browserify"),
|
||||||
https: require.resolve("https-browserify"),
|
https: require.resolve("https-browserify"),
|
||||||
stream: require.resolve("stream-browserify"),
|
stream: require.resolve("stream-browserify"),
|
||||||
|
@ -41,7 +41,7 @@ module.exports = {
|
||||||
Object.assign(config.resolve.fallback, {
|
Object.assign(config.resolve.fallback, {
|
||||||
assert: require.resolve("assert"),
|
assert: require.resolve("assert"),
|
||||||
buffer: require.resolve("buffer"),
|
buffer: require.resolve("buffer"),
|
||||||
crypto: require.resolve("crypto-browserify"),
|
crypto: false,
|
||||||
http: require.resolve("http-browserify"),
|
http: require.resolve("http-browserify"),
|
||||||
https: require.resolve("https-browserify"),
|
https: require.resolve("https-browserify"),
|
||||||
stream: require.resolve("stream-browserify"),
|
stream: require.resolve("stream-browserify"),
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@chainsafe/libp2p-noise": "^5.0.0",
|
"@chainsafe/libp2p-noise": "^5.0.0",
|
||||||
"@ethersproject/rlp": "^5.5.0",
|
"@ethersproject/rlp": "^5.5.0",
|
||||||
|
"@noble/secp256k1": "^1.3.4",
|
||||||
"debug": "^4.3.1",
|
"debug": "^4.3.1",
|
||||||
"dns-query": "^0.8.0",
|
"dns-query": "^0.8.0",
|
||||||
"hi-base32": "^0.5.1",
|
"hi-base32": "^0.5.1",
|
||||||
|
@ -25,7 +26,6 @@
|
||||||
"multiaddr": "^10.0.1",
|
"multiaddr": "^10.0.1",
|
||||||
"multihashes": "^4.0.3",
|
"multihashes": "^4.0.3",
|
||||||
"protobufjs": "^6.8.8",
|
"protobufjs": "^6.8.8",
|
||||||
"secp256k1": "^4.0.2",
|
|
||||||
"uuid": "^8.3.2"
|
"uuid": "^8.3.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
@ -45,7 +45,6 @@
|
||||||
"assert": "^2.0.0",
|
"assert": "^2.0.0",
|
||||||
"buffer": "^6.0.3",
|
"buffer": "^6.0.3",
|
||||||
"chai": "^4.3.4",
|
"chai": "^4.3.4",
|
||||||
"crypto-browserify": "^3.12.0",
|
|
||||||
"cspell": "^5.14.0",
|
"cspell": "^5.14.0",
|
||||||
"eslint": "^8.6.0",
|
"eslint": "^8.6.0",
|
||||||
"eslint-config-prettier": "^8.3.0",
|
"eslint-config-prettier": "^8.3.0",
|
||||||
|
@ -2642,7 +2641,8 @@
|
||||||
"node_modules/bn.js": {
|
"node_modules/bn.js": {
|
||||||
"version": "4.12.0",
|
"version": "4.12.0",
|
||||||
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
|
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
|
||||||
"integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA=="
|
"integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==",
|
||||||
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/body-parser": {
|
"node_modules/body-parser": {
|
||||||
"version": "1.19.0",
|
"version": "1.19.0",
|
||||||
|
@ -2756,7 +2756,8 @@
|
||||||
"node_modules/brorand": {
|
"node_modules/brorand": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz",
|
||||||
"integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8="
|
"integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=",
|
||||||
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/browser-process-hrtime": {
|
"node_modules/browser-process-hrtime": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
|
@ -4282,6 +4283,7 @@
|
||||||
"version": "6.5.4",
|
"version": "6.5.4",
|
||||||
"resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz",
|
"resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz",
|
||||||
"integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==",
|
"integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==",
|
||||||
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"bn.js": "^4.11.9",
|
"bn.js": "^4.11.9",
|
||||||
"brorand": "^1.1.0",
|
"brorand": "^1.1.0",
|
||||||
|
@ -6000,6 +6002,7 @@
|
||||||
"version": "1.1.7",
|
"version": "1.1.7",
|
||||||
"resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz",
|
"resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz",
|
||||||
"integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==",
|
"integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==",
|
||||||
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"inherits": "^2.0.3",
|
"inherits": "^2.0.3",
|
||||||
"minimalistic-assert": "^1.0.1"
|
"minimalistic-assert": "^1.0.1"
|
||||||
|
@ -6053,6 +6056,7 @@
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz",
|
||||||
"integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=",
|
"integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=",
|
||||||
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"hash.js": "^1.0.3",
|
"hash.js": "^1.0.3",
|
||||||
"minimalistic-assert": "^1.0.0",
|
"minimalistic-assert": "^1.0.0",
|
||||||
|
@ -8317,12 +8321,14 @@
|
||||||
"node_modules/minimalistic-assert": {
|
"node_modules/minimalistic-assert": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz",
|
||||||
"integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A=="
|
"integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==",
|
||||||
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/minimalistic-crypto-utils": {
|
"node_modules/minimalistic-crypto-utils": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz",
|
||||||
"integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo="
|
"integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=",
|
||||||
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/minimatch": {
|
"node_modules/minimatch": {
|
||||||
"version": "3.0.4",
|
"version": "3.0.4",
|
||||||
|
@ -8703,11 +8709,6 @@
|
||||||
"integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==",
|
"integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/node-addon-api": {
|
|
||||||
"version": "2.0.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-2.0.2.tgz",
|
|
||||||
"integrity": "sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA=="
|
|
||||||
},
|
|
||||||
"node_modules/node-fetch": {
|
"node_modules/node-fetch": {
|
||||||
"name": "@achingbrain/node-fetch",
|
"name": "@achingbrain/node-fetch",
|
||||||
"version": "2.6.7",
|
"version": "2.6.7",
|
||||||
|
@ -8725,16 +8726,6 @@
|
||||||
"node": ">= 6.13.0"
|
"node": ">= 6.13.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/node-gyp-build": {
|
|
||||||
"version": "4.2.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.2.3.tgz",
|
|
||||||
"integrity": "sha512-MN6ZpzmfNCRM+3t57PTJHgHyw/h4OWnZ6mR8P5j/uZtqQr46RRuDE/P+g3n0YR/AiYXeWixZZzaip77gdICfRg==",
|
|
||||||
"bin": {
|
|
||||||
"node-gyp-build": "bin.js",
|
|
||||||
"node-gyp-build-optional": "optional.js",
|
|
||||||
"node-gyp-build-test": "build-test.js"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/node-preload": {
|
"node_modules/node-preload": {
|
||||||
"version": "0.2.1",
|
"version": "0.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/node-preload/-/node-preload-0.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/node-preload/-/node-preload-0.2.1.tgz",
|
||||||
|
@ -10669,20 +10660,6 @@
|
||||||
"url": "https://opencollective.com/webpack"
|
"url": "https://opencollective.com/webpack"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/secp256k1": {
|
|
||||||
"version": "4.0.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-4.0.3.tgz",
|
|
||||||
"integrity": "sha512-NLZVf+ROMxwtEj3Xa562qgv2BK5e2WNmXPiOdVIPLgs6lyTzMvBq0aWTYMI5XCP9jZMVKOcqZLw/Wc4vDkuxhA==",
|
|
||||||
"hasInstallScript": true,
|
|
||||||
"dependencies": {
|
|
||||||
"elliptic": "^6.5.4",
|
|
||||||
"node-addon-api": "^2.0.0",
|
|
||||||
"node-gyp-build": "^4.2.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=10.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/semver": {
|
"node_modules/semver": {
|
||||||
"version": "7.3.5",
|
"version": "7.3.5",
|
||||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz",
|
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz",
|
||||||
|
@ -14803,7 +14780,8 @@
|
||||||
"bn.js": {
|
"bn.js": {
|
||||||
"version": "4.12.0",
|
"version": "4.12.0",
|
||||||
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
|
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
|
||||||
"integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA=="
|
"integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==",
|
||||||
|
"dev": true
|
||||||
},
|
},
|
||||||
"body-parser": {
|
"body-parser": {
|
||||||
"version": "1.19.0",
|
"version": "1.19.0",
|
||||||
|
@ -14901,7 +14879,8 @@
|
||||||
"brorand": {
|
"brorand": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz",
|
||||||
"integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8="
|
"integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=",
|
||||||
|
"dev": true
|
||||||
},
|
},
|
||||||
"browser-process-hrtime": {
|
"browser-process-hrtime": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
|
@ -16124,6 +16103,7 @@
|
||||||
"version": "6.5.4",
|
"version": "6.5.4",
|
||||||
"resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz",
|
"resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz",
|
||||||
"integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==",
|
"integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==",
|
||||||
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"bn.js": "^4.11.9",
|
"bn.js": "^4.11.9",
|
||||||
"brorand": "^1.1.0",
|
"brorand": "^1.1.0",
|
||||||
|
@ -17396,6 +17376,7 @@
|
||||||
"version": "1.1.7",
|
"version": "1.1.7",
|
||||||
"resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz",
|
"resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz",
|
||||||
"integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==",
|
"integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==",
|
||||||
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"inherits": "^2.0.3",
|
"inherits": "^2.0.3",
|
||||||
"minimalistic-assert": "^1.0.1"
|
"minimalistic-assert": "^1.0.1"
|
||||||
|
@ -17439,6 +17420,7 @@
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz",
|
||||||
"integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=",
|
"integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=",
|
||||||
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"hash.js": "^1.0.3",
|
"hash.js": "^1.0.3",
|
||||||
"minimalistic-assert": "^1.0.0",
|
"minimalistic-assert": "^1.0.0",
|
||||||
|
@ -19209,12 +19191,14 @@
|
||||||
"minimalistic-assert": {
|
"minimalistic-assert": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz",
|
||||||
"integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A=="
|
"integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==",
|
||||||
|
"dev": true
|
||||||
},
|
},
|
||||||
"minimalistic-crypto-utils": {
|
"minimalistic-crypto-utils": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz",
|
||||||
"integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo="
|
"integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=",
|
||||||
|
"dev": true
|
||||||
},
|
},
|
||||||
"minimatch": {
|
"minimatch": {
|
||||||
"version": "3.0.4",
|
"version": "3.0.4",
|
||||||
|
@ -19519,11 +19503,6 @@
|
||||||
"integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==",
|
"integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node-addon-api": {
|
|
||||||
"version": "2.0.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-2.0.2.tgz",
|
|
||||||
"integrity": "sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA=="
|
|
||||||
},
|
|
||||||
"node-fetch": {
|
"node-fetch": {
|
||||||
"version": "npm:@achingbrain/node-fetch@2.6.7",
|
"version": "npm:@achingbrain/node-fetch@2.6.7",
|
||||||
"resolved": "https://registry.npmjs.org/@achingbrain/node-fetch/-/node-fetch-2.6.7.tgz",
|
"resolved": "https://registry.npmjs.org/@achingbrain/node-fetch/-/node-fetch-2.6.7.tgz",
|
||||||
|
@ -19534,11 +19513,6 @@
|
||||||
"resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz",
|
||||||
"integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA=="
|
"integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA=="
|
||||||
},
|
},
|
||||||
"node-gyp-build": {
|
|
||||||
"version": "4.2.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.2.3.tgz",
|
|
||||||
"integrity": "sha512-MN6ZpzmfNCRM+3t57PTJHgHyw/h4OWnZ6mR8P5j/uZtqQr46RRuDE/P+g3n0YR/AiYXeWixZZzaip77gdICfRg=="
|
|
||||||
},
|
|
||||||
"node-preload": {
|
"node-preload": {
|
||||||
"version": "0.2.1",
|
"version": "0.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/node-preload/-/node-preload-0.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/node-preload/-/node-preload-0.2.1.tgz",
|
||||||
|
@ -20990,16 +20964,6 @@
|
||||||
"ajv-keywords": "^3.5.2"
|
"ajv-keywords": "^3.5.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"secp256k1": {
|
|
||||||
"version": "4.0.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-4.0.3.tgz",
|
|
||||||
"integrity": "sha512-NLZVf+ROMxwtEj3Xa562qgv2BK5e2WNmXPiOdVIPLgs6lyTzMvBq0aWTYMI5XCP9jZMVKOcqZLw/Wc4vDkuxhA==",
|
|
||||||
"requires": {
|
|
||||||
"elliptic": "^6.5.4",
|
|
||||||
"node-addon-api": "^2.0.0",
|
|
||||||
"node-gyp-build": "^4.2.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"semver": {
|
"semver": {
|
||||||
"version": "7.3.5",
|
"version": "7.3.5",
|
||||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz",
|
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz",
|
||||||
|
|
|
@ -61,12 +61,16 @@
|
||||||
"deploy": "node ci/deploy.js",
|
"deploy": "node ci/deploy.js",
|
||||||
"reset-hard": "git clean -dfx && git reset --hard && npm i && npm run build && for d in examples/*/; do (cd $d; npm i); done"
|
"reset-hard": "git clean -dfx && git reset --hard && npm i && npm run build && for d in examples/*/; do (cd $d; npm i); done"
|
||||||
},
|
},
|
||||||
|
"browser": {
|
||||||
|
"crypto": false
|
||||||
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=16"
|
"node": ">=16"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@chainsafe/libp2p-noise": "^5.0.0",
|
"@chainsafe/libp2p-noise": "^5.0.0",
|
||||||
"@ethersproject/rlp": "^5.5.0",
|
"@ethersproject/rlp": "^5.5.0",
|
||||||
|
"@noble/secp256k1": "^1.3.4",
|
||||||
"debug": "^4.3.1",
|
"debug": "^4.3.1",
|
||||||
"dns-query": "^0.8.0",
|
"dns-query": "^0.8.0",
|
||||||
"hi-base32": "^0.5.1",
|
"hi-base32": "^0.5.1",
|
||||||
|
@ -81,7 +85,6 @@
|
||||||
"multiaddr": "^10.0.1",
|
"multiaddr": "^10.0.1",
|
||||||
"multihashes": "^4.0.3",
|
"multihashes": "^4.0.3",
|
||||||
"protobufjs": "^6.8.8",
|
"protobufjs": "^6.8.8",
|
||||||
"secp256k1": "^4.0.2",
|
|
||||||
"uuid": "^8.3.2"
|
"uuid": "^8.3.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
@ -101,7 +104,6 @@
|
||||||
"assert": "^2.0.0",
|
"assert": "^2.0.0",
|
||||||
"buffer": "^6.0.3",
|
"buffer": "^6.0.3",
|
||||||
"chai": "^4.3.4",
|
"chai": "^4.3.4",
|
||||||
"crypto-browserify": "^3.12.0",
|
|
||||||
"cspell": "^5.14.0",
|
"cspell": "^5.14.0",
|
||||||
"eslint": "^8.6.0",
|
"eslint": "^8.6.0",
|
||||||
"eslint-config-prettier": "^8.3.0",
|
"eslint-config-prettier": "^8.3.0",
|
||||||
|
|
|
@ -1,33 +1,48 @@
|
||||||
import nodeCrypto from "crypto";
|
import nodeCrypto from "crypto";
|
||||||
|
|
||||||
// IE 11
|
import { concat } from "uint8arrays/concat";
|
||||||
declare global {
|
|
||||||
interface Window {
|
|
||||||
msCrypto?: Crypto;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface Crypto {
|
declare const self: Record<string, any> | undefined;
|
||||||
webkitSubtle?: SubtleCrypto;
|
const crypto: { node?: any; web?: any } = {
|
||||||
|
node: nodeCrypto,
|
||||||
|
web: typeof self === "object" && "crypto" in self ? self.crypto : undefined,
|
||||||
|
};
|
||||||
|
|
||||||
|
export function getSubtle(): SubtleCrypto {
|
||||||
|
if (crypto.web) {
|
||||||
|
return crypto.web.subtle;
|
||||||
|
} else if (crypto.node) {
|
||||||
|
return crypto.node.webcrypto.subtle;
|
||||||
|
} else {
|
||||||
|
throw new Error(
|
||||||
|
"The environment doesn't have Crypto Subtle API (if in the browser, be sure to use to be in a secure context, ie, https)"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const crypto =
|
export function randomBytes(bytesLength = 32): Uint8Array {
|
||||||
(typeof window !== "undefined" &&
|
if (crypto.web) {
|
||||||
(window as Window) &&
|
return crypto.web.getRandomValues(new Uint8Array(bytesLength));
|
||||||
(window.crypto || window.msCrypto)) ||
|
} else if (crypto.node) {
|
||||||
(nodeCrypto.webcrypto as unknown as Crypto);
|
const { randomBytes } = crypto.node;
|
||||||
const subtle: SubtleCrypto = crypto.subtle || crypto.webkitSubtle;
|
return Uint8Array.from(randomBytes(bytesLength));
|
||||||
|
} else {
|
||||||
if (subtle === undefined) {
|
throw new Error(
|
||||||
throw new Error("crypto and/or subtle api unavailable");
|
"The environment doesn't have randomBytes function (if in the browser, be sure to use to be in a secure context, ie, https)"
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export { crypto, subtle };
|
export async function sha256(...messages: Uint8Array[]): Promise<Uint8Array> {
|
||||||
|
if (crypto.web) {
|
||||||
export function randomBytes(size: number): Uint8Array {
|
const buffer = await crypto.web.subtle.digest("SHA-256", concat(messages));
|
||||||
return crypto.getRandomValues(new Uint8Array(size));
|
return new Uint8Array(buffer);
|
||||||
}
|
} else if (crypto.node) {
|
||||||
|
const { createHash } = crypto.node;
|
||||||
export function sha256(msg: ArrayBufferLike): Promise<ArrayBuffer> {
|
const hash = createHash("sha256");
|
||||||
return subtle.digest({ name: "SHA-256" }, msg);
|
messages.forEach((m) => hash.update(m));
|
||||||
|
return Uint8Array.from(hash.digest());
|
||||||
|
} else {
|
||||||
|
throw new Error("The environment doesn't have sha256 function");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import assert from "assert";
|
import assert from "assert";
|
||||||
|
|
||||||
|
import * as secp from "@noble/secp256k1";
|
||||||
import * as base32 from "hi-base32";
|
import * as base32 from "hi-base32";
|
||||||
import { ecdsaVerify } from "secp256k1";
|
|
||||||
import { fromString } from "uint8arrays/from-string";
|
import { fromString } from "uint8arrays/from-string";
|
||||||
|
|
||||||
import { ENR } from "../enr";
|
import { ENR } from "../enr";
|
||||||
|
@ -48,11 +48,17 @@ export class ENRTree {
|
||||||
64
|
64
|
||||||
);
|
);
|
||||||
|
|
||||||
const isVerified = ecdsaVerify(
|
let isVerified;
|
||||||
signatureBuffer,
|
try {
|
||||||
keccak256Buf(signedComponentBuffer),
|
const _sig = secp.Signature.fromCompact(signatureBuffer.slice(0, 64));
|
||||||
new Uint8Array(decodedPublicKey)
|
isVerified = secp.verify(
|
||||||
);
|
_sig,
|
||||||
|
keccak256Buf(signedComponentBuffer),
|
||||||
|
new Uint8Array(decodedPublicKey)
|
||||||
|
);
|
||||||
|
} catch {
|
||||||
|
isVerified = false;
|
||||||
|
}
|
||||||
|
|
||||||
assert(isVerified, "Unable to verify ENRTree root signature");
|
assert(isVerified, "Unable to verify ENRTree root signature");
|
||||||
|
|
||||||
|
|
|
@ -37,7 +37,7 @@ describe("ENR", function () {
|
||||||
lightPush: false,
|
lightPush: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
const txt = enr.encodeTxt(keypair.privateKey);
|
const txt = await enr.encodeTxt(keypair.privateKey);
|
||||||
const enr2 = ENR.decodeTxt(txt);
|
const enr2 = ENR.decodeTxt(txt);
|
||||||
|
|
||||||
if (!enr.signature) throw "enr.signature is undefined";
|
if (!enr.signature) throw "enr.signature is undefined";
|
||||||
|
@ -116,7 +116,7 @@ describe("ENR", function () {
|
||||||
enr.setLocationMultiaddr(new Multiaddr("/ip4/18.223.219.100/udp/9000"));
|
enr.setLocationMultiaddr(new Multiaddr("/ip4/18.223.219.100/udp/9000"));
|
||||||
|
|
||||||
enr.set("id", new Uint8Array([0]));
|
enr.set("id", new Uint8Array([0]));
|
||||||
const txt = enr.encodeTxt(keypair.privateKey);
|
const txt = await enr.encodeTxt(keypair.privateKey);
|
||||||
|
|
||||||
ENR.decodeTxt(txt);
|
ENR.decodeTxt(txt);
|
||||||
assert.fail("Expect error here");
|
assert.fail("Expect error here");
|
||||||
|
@ -190,11 +190,11 @@ describe("ENR", function () {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("Static tests", () => {
|
describe("Static tests", function () {
|
||||||
let privateKey: Uint8Array;
|
let privateKey: Uint8Array;
|
||||||
let record: ENR;
|
let record: ENR;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(async function () {
|
||||||
const seq = BigInt(1);
|
const seq = BigInt(1);
|
||||||
privateKey = hexToBytes(
|
privateKey = hexToBytes(
|
||||||
"b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291"
|
"b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291"
|
||||||
|
@ -202,8 +202,7 @@ describe("ENR", function () {
|
||||||
record = ENR.createV4(v4.publicKey(privateKey));
|
record = ENR.createV4(v4.publicKey(privateKey));
|
||||||
record.setLocationMultiaddr(new Multiaddr("/ip4/127.0.0.1/udp/30303"));
|
record.setLocationMultiaddr(new Multiaddr("/ip4/127.0.0.1/udp/30303"));
|
||||||
record.seq = seq;
|
record.seq = seq;
|
||||||
// To set signature
|
await record.encodeTxt(privateKey);
|
||||||
record.encode(privateKey);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should properly compute the node id", () => {
|
it("should properly compute the node id", () => {
|
||||||
|
@ -212,21 +211,24 @@ describe("ENR", function () {
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should encode/decode to RLP encoding", () => {
|
it("should encode/decode to RLP encoding", async function () {
|
||||||
const decoded = ENR.decode(record.encode(privateKey));
|
const decoded = ENR.decode(await record.encode(privateKey));
|
||||||
expect(decoded).to.deep.equal(record);
|
expect(decoded).to.deep.equal(record);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should encode/decode to text encoding", () => {
|
it("should encode/decode to text encoding", async function () {
|
||||||
// spec enr https://eips.ethereum.org/EIPS/eip-778
|
// spec enr https://eips.ethereum.org/EIPS/eip-778
|
||||||
const testTxt =
|
const testTxt =
|
||||||
"enr:-IS4QHCYrYZbAKWCBRlAy5zzaDZXJBGkcnh4MHcBFZntXNFrdvJjX04jRzjzCBOonrkTfj499SZuOh8R33Ls8RRcy5wBgmlkgnY0gmlwhH8AAAGJc2VjcDI1NmsxoQPKY0yuDUmstAHYpMa2_oxVtw0RW_QAdpzBQA8yWM0xOIN1ZHCCdl8";
|
"enr:-IS4QHCYrYZbAKWCBRlAy5zzaDZXJBGkcnh4MHcBFZntXNFrdvJjX04jRzjzCBOonrkTfj499SZuOh8R33Ls8RRcy5wBgmlkgnY0gmlwhH8AAAGJc2VjcDI1NmsxoQPKY0yuDUmstAHYpMa2_oxVtw0RW_QAdpzBQA8yWM0xOIN1ZHCCdl8";
|
||||||
const decoded = ENR.decodeTxt(testTxt);
|
const decoded = ENR.decodeTxt(testTxt);
|
||||||
expect(decoded.udp).to.be.equal(30303);
|
// Note: Signatures are different due to the extra entropy added
|
||||||
expect(decoded.ip).to.be.equal("127.0.0.1");
|
// by @noble/secp256k1:
|
||||||
expect(decoded).to.deep.equal(record);
|
// https://github.com/paulmillr/noble-secp256k1#signmsghash-privatekey
|
||||||
const recordTxt = record.encodeTxt(privateKey);
|
expect(decoded.udp).to.deep.equal(record.udp);
|
||||||
expect(recordTxt).to.equal(testTxt);
|
expect(decoded.ip).to.deep.equal(record.ip);
|
||||||
|
expect(decoded.id).to.deep.equal(record.id);
|
||||||
|
expect(decoded.seq).to.equal(record.seq);
|
||||||
|
expect(decoded.get("secp256k1")).to.deep.equal(record.get("secp256k1"));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -397,10 +399,10 @@ describe("ENR", function () {
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should set field with all protocols disabled", () => {
|
it("should set field with all protocols disabled", async () => {
|
||||||
enr.waku2 = waku2Protocols;
|
enr.waku2 = waku2Protocols;
|
||||||
|
|
||||||
const txt = enr.encodeTxt(keypair.privateKey);
|
const txt = await enr.encodeTxt(keypair.privateKey);
|
||||||
const decoded = ENR.decodeTxt(txt).waku2!;
|
const decoded = ENR.decodeTxt(txt).waku2!;
|
||||||
|
|
||||||
expect(decoded.relay).to.equal(false);
|
expect(decoded.relay).to.equal(false);
|
||||||
|
@ -409,14 +411,14 @@ describe("ENR", function () {
|
||||||
expect(decoded.lightPush).to.equal(false);
|
expect(decoded.lightPush).to.equal(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should set field with all protocols enabled", () => {
|
it("should set field with all protocols enabled", async () => {
|
||||||
waku2Protocols.relay = true;
|
waku2Protocols.relay = true;
|
||||||
waku2Protocols.store = true;
|
waku2Protocols.store = true;
|
||||||
waku2Protocols.filter = true;
|
waku2Protocols.filter = true;
|
||||||
waku2Protocols.lightPush = true;
|
waku2Protocols.lightPush = true;
|
||||||
|
|
||||||
enr.waku2 = waku2Protocols;
|
enr.waku2 = waku2Protocols;
|
||||||
const txt = enr.encodeTxt(keypair.privateKey);
|
const txt = await enr.encodeTxt(keypair.privateKey);
|
||||||
const decoded = ENR.decodeTxt(txt).waku2!;
|
const decoded = ENR.decodeTxt(txt).waku2!;
|
||||||
|
|
||||||
expect(decoded.relay).to.equal(true);
|
expect(decoded.relay).to.equal(true);
|
||||||
|
@ -425,11 +427,11 @@ describe("ENR", function () {
|
||||||
expect(decoded.lightPush).to.equal(true);
|
expect(decoded.lightPush).to.equal(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should set field with only RELAY enabled", () => {
|
it("should set field with only RELAY enabled", async () => {
|
||||||
waku2Protocols.relay = true;
|
waku2Protocols.relay = true;
|
||||||
|
|
||||||
enr.waku2 = waku2Protocols;
|
enr.waku2 = waku2Protocols;
|
||||||
const txt = enr.encodeTxt(keypair.privateKey);
|
const txt = await enr.encodeTxt(keypair.privateKey);
|
||||||
const decoded = ENR.decodeTxt(txt).waku2!;
|
const decoded = ENR.decodeTxt(txt).waku2!;
|
||||||
|
|
||||||
expect(decoded.relay).to.equal(true);
|
expect(decoded.relay).to.equal(true);
|
||||||
|
@ -438,11 +440,11 @@ describe("ENR", function () {
|
||||||
expect(decoded.lightPush).to.equal(false);
|
expect(decoded.lightPush).to.equal(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should set field with only STORE enabled", () => {
|
it("should set field with only STORE enabled", async () => {
|
||||||
waku2Protocols.store = true;
|
waku2Protocols.store = true;
|
||||||
|
|
||||||
enr.waku2 = waku2Protocols;
|
enr.waku2 = waku2Protocols;
|
||||||
const txt = enr.encodeTxt(keypair.privateKey);
|
const txt = await enr.encodeTxt(keypair.privateKey);
|
||||||
const decoded = ENR.decodeTxt(txt).waku2!;
|
const decoded = ENR.decodeTxt(txt).waku2!;
|
||||||
|
|
||||||
expect(decoded.relay).to.equal(false);
|
expect(decoded.relay).to.equal(false);
|
||||||
|
@ -451,11 +453,11 @@ describe("ENR", function () {
|
||||||
expect(decoded.lightPush).to.equal(false);
|
expect(decoded.lightPush).to.equal(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should set field with only FILTER enabled", () => {
|
it("should set field with only FILTER enabled", async () => {
|
||||||
waku2Protocols.filter = true;
|
waku2Protocols.filter = true;
|
||||||
|
|
||||||
enr.waku2 = waku2Protocols;
|
enr.waku2 = waku2Protocols;
|
||||||
const txt = enr.encodeTxt(keypair.privateKey);
|
const txt = await enr.encodeTxt(keypair.privateKey);
|
||||||
const decoded = ENR.decodeTxt(txt).waku2!;
|
const decoded = ENR.decodeTxt(txt).waku2!;
|
||||||
|
|
||||||
expect(decoded.relay).to.equal(false);
|
expect(decoded.relay).to.equal(false);
|
||||||
|
@ -464,11 +466,11 @@ describe("ENR", function () {
|
||||||
expect(decoded.lightPush).to.equal(false);
|
expect(decoded.lightPush).to.equal(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should set field with only LIGHTPUSH enabled", () => {
|
it("should set field with only LIGHTPUSH enabled", async () => {
|
||||||
waku2Protocols.lightPush = true;
|
waku2Protocols.lightPush = true;
|
||||||
|
|
||||||
enr.waku2 = waku2Protocols;
|
enr.waku2 = waku2Protocols;
|
||||||
const txt = enr.encodeTxt(keypair.privateKey);
|
const txt = await enr.encodeTxt(keypair.privateKey);
|
||||||
const decoded = ENR.decodeTxt(txt).waku2!;
|
const decoded = ENR.decodeTxt(txt).waku2!;
|
||||||
|
|
||||||
expect(decoded.relay).to.equal(false);
|
expect(decoded.relay).to.equal(false);
|
||||||
|
|
|
@ -22,6 +22,7 @@ import {
|
||||||
import { decodeMultiaddrs, encodeMultiaddrs } from "./multiaddrs_codec";
|
import { decodeMultiaddrs, encodeMultiaddrs } from "./multiaddrs_codec";
|
||||||
import { ENRKey, ENRValue, NodeId, SequenceNumber } from "./types";
|
import { ENRKey, ENRValue, NodeId, SequenceNumber } from "./types";
|
||||||
import * as v4 from "./v4";
|
import * as v4 from "./v4";
|
||||||
|
import { compressPublicKey } from "./v4";
|
||||||
import { decodeWaku2, encodeWaku2, Waku2 } from "./waku2_codec";
|
import { decodeWaku2, encodeWaku2, Waku2 } from "./waku2_codec";
|
||||||
|
|
||||||
const dbg = debug("waku:enr");
|
const dbg = debug("waku:enr");
|
||||||
|
@ -45,6 +46,10 @@ export class ENR extends Map<ENRKey, ENRValue> {
|
||||||
publicKey: Uint8Array,
|
publicKey: Uint8Array,
|
||||||
kvs: Record<ENRKey, ENRValue> = {}
|
kvs: Record<ENRKey, ENRValue> = {}
|
||||||
): ENR {
|
): ENR {
|
||||||
|
// EIP-778 specifies that the key must be in compressed format, 33 bytes
|
||||||
|
if (publicKey.length !== 33) {
|
||||||
|
publicKey = compressPublicKey(publicKey);
|
||||||
|
}
|
||||||
return new ENR({
|
return new ENR({
|
||||||
...kvs,
|
...kvs,
|
||||||
id: utf8ToBytes("v4"),
|
id: utf8ToBytes("v4"),
|
||||||
|
@ -453,10 +458,10 @@ export class ENR extends Map<ENRKey, ENRValue> {
|
||||||
return v4.verify(this.publicKey, data, signature);
|
return v4.verify(this.publicKey, data, signature);
|
||||||
}
|
}
|
||||||
|
|
||||||
sign(data: Uint8Array, privateKey: Uint8Array): Uint8Array {
|
async sign(data: Uint8Array, privateKey: Uint8Array): Promise<Uint8Array> {
|
||||||
switch (this.id) {
|
switch (this.id) {
|
||||||
case "v4":
|
case "v4":
|
||||||
this.signature = v4.sign(privateKey, data);
|
this.signature = await v4.sign(privateKey, data);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new Error(ERR_INVALID_ID);
|
throw new Error(ERR_INVALID_ID);
|
||||||
|
@ -464,7 +469,9 @@ export class ENR extends Map<ENRKey, ENRValue> {
|
||||||
return this.signature;
|
return this.signature;
|
||||||
}
|
}
|
||||||
|
|
||||||
encodeToValues(privateKey?: Uint8Array): (ENRKey | ENRValue | number[])[] {
|
async encodeToValues(
|
||||||
|
privateKey?: Uint8Array
|
||||||
|
): Promise<(ENRKey | ENRValue | number[])[]> {
|
||||||
// sort keys and flatten into [k, v, k, v, ...]
|
// sort keys and flatten into [k, v, k, v, ...]
|
||||||
const content: Array<ENRKey | ENRValue | number[]> = Array.from(this.keys())
|
const content: Array<ENRKey | ENRValue | number[]> = Array.from(this.keys())
|
||||||
.sort((a, b) => a.localeCompare(b))
|
.sort((a, b) => a.localeCompare(b))
|
||||||
|
@ -473,7 +480,9 @@ export class ENR extends Map<ENRKey, ENRValue> {
|
||||||
.flat();
|
.flat();
|
||||||
content.unshift(new Uint8Array([Number(this.seq)]));
|
content.unshift(new Uint8Array([Number(this.seq)]));
|
||||||
if (privateKey) {
|
if (privateKey) {
|
||||||
content.unshift(this.sign(hexToBytes(RLP.encode(content)), privateKey));
|
content.unshift(
|
||||||
|
await this.sign(hexToBytes(RLP.encode(content)), privateKey)
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
if (!this.signature) {
|
if (!this.signature) {
|
||||||
throw new Error(ERR_NO_SIGNATURE);
|
throw new Error(ERR_NO_SIGNATURE);
|
||||||
|
@ -483,15 +492,19 @@ export class ENR extends Map<ENRKey, ENRValue> {
|
||||||
return content;
|
return content;
|
||||||
}
|
}
|
||||||
|
|
||||||
encode(privateKey?: Uint8Array): Uint8Array {
|
async encode(privateKey?: Uint8Array): Promise<Uint8Array> {
|
||||||
const encoded = hexToBytes(RLP.encode(this.encodeToValues(privateKey)));
|
const encoded = hexToBytes(
|
||||||
|
RLP.encode(await this.encodeToValues(privateKey))
|
||||||
|
);
|
||||||
if (encoded.length >= MAX_RECORD_SIZE) {
|
if (encoded.length >= MAX_RECORD_SIZE) {
|
||||||
throw new Error("ENR must be less than 300 bytes");
|
throw new Error("ENR must be less than 300 bytes");
|
||||||
}
|
}
|
||||||
return encoded;
|
return encoded;
|
||||||
}
|
}
|
||||||
|
|
||||||
encodeTxt(privateKey?: Uint8Array): string {
|
async encodeTxt(privateKey?: Uint8Array): Promise<string> {
|
||||||
return ENR.RECORD_PREFIX + toString(this.encode(privateKey), "base64url");
|
return (
|
||||||
|
ENR.RECORD_PREFIX + toString(await this.encode(privateKey), "base64url")
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import crypto from "crypto";
|
import * as secp from "@noble/secp256k1";
|
||||||
|
|
||||||
import * as secp256k1 from "secp256k1";
|
|
||||||
import { concat } from "uint8arrays/concat";
|
import { concat } from "uint8arrays/concat";
|
||||||
|
|
||||||
|
import { randomBytes } from "../../crypto";
|
||||||
|
|
||||||
import { AbstractKeypair, IKeypair, IKeypairClass, KeypairType } from "./types";
|
import { AbstractKeypair, IKeypair, IKeypairClass, KeypairType } from "./types";
|
||||||
|
|
||||||
export function secp256k1PublicKeyToCompressed(
|
export function secp256k1PublicKeyToCompressed(
|
||||||
|
@ -11,18 +11,22 @@ export function secp256k1PublicKeyToCompressed(
|
||||||
if (publicKey.length === 64) {
|
if (publicKey.length === 64) {
|
||||||
publicKey = concat([[4], publicKey], 65);
|
publicKey = concat([[4], publicKey], 65);
|
||||||
}
|
}
|
||||||
return secp256k1.publicKeyConvert(publicKey, true);
|
const point = secp.Point.fromHex(publicKey);
|
||||||
|
return point.toRawBytes(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function secp256k1PublicKeyToFull(publicKey: Uint8Array): Uint8Array {
|
export function secp256k1PublicKeyToFull(publicKey: Uint8Array): Uint8Array {
|
||||||
if (publicKey.length === 64) {
|
if (publicKey.length === 64) {
|
||||||
publicKey = concat([[4], publicKey], 65);
|
publicKey = concat([[4], publicKey], 65);
|
||||||
}
|
}
|
||||||
return secp256k1.publicKeyConvert(publicKey, false);
|
const point = secp.Point.fromHex(publicKey);
|
||||||
|
|
||||||
|
return point.toRawBytes(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function secp256k1PublicKeyToRaw(publicKey: Uint8Array): Uint8Array {
|
export function secp256k1PublicKeyToRaw(publicKey: Uint8Array): Uint8Array {
|
||||||
return secp256k1.publicKeyConvert(publicKey, false).slice(1);
|
const point = secp.Point.fromHex(publicKey);
|
||||||
|
return point.toRawBytes(false).slice(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Secp256k1Keypair: IKeypairClass = class Secp256k1Keypair
|
export const Secp256k1Keypair: IKeypairClass = class Secp256k1Keypair
|
||||||
|
@ -41,41 +45,44 @@ export const Secp256k1Keypair: IKeypairClass = class Secp256k1Keypair
|
||||||
}
|
}
|
||||||
|
|
||||||
static async generate(): Promise<Secp256k1Keypair> {
|
static async generate(): Promise<Secp256k1Keypair> {
|
||||||
const privateKey = await randomBytes(32);
|
const privateKey = randomBytes(32);
|
||||||
const publicKey = secp256k1.publicKeyCreate(privateKey);
|
const publicKey = secp.getPublicKey(privateKey);
|
||||||
return new Secp256k1Keypair(privateKey, publicKey);
|
return new Secp256k1Keypair(privateKey, publicKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
privateKeyVerify(key = this._privateKey): boolean {
|
privateKeyVerify(key = this._privateKey): boolean {
|
||||||
if (key) {
|
if (key) {
|
||||||
return secp256k1.privateKeyVerify(key);
|
return secp.utils.isValidPrivateKey(key);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
publicKeyVerify(key = this._publicKey): boolean {
|
publicKeyVerify(key = this._publicKey): boolean {
|
||||||
if (key) {
|
if (key) {
|
||||||
return secp256k1.publicKeyVerify(key);
|
try {
|
||||||
|
secp.Point.fromHex(key);
|
||||||
|
return true;
|
||||||
|
} catch {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
sign(msg: Uint8Array): Uint8Array {
|
async sign(msg: Uint8Array): Promise<Uint8Array> {
|
||||||
const { signature, recid } = secp256k1.ecdsaSign(msg, this.privateKey);
|
const [signature, recid] = await secp.sign(msg, this.privateKey, {
|
||||||
|
recovered: true,
|
||||||
|
der: false,
|
||||||
|
});
|
||||||
return concat([signature, [recid]], signature.length + 1);
|
return concat([signature, [recid]], signature.length + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
verify(msg: Uint8Array, sig: Uint8Array): boolean {
|
verify(msg: Uint8Array, sig: Uint8Array): boolean {
|
||||||
return secp256k1.ecdsaVerify(sig, msg, this.publicKey);
|
try {
|
||||||
|
const _sig = secp.Signature.fromCompact(sig.slice(0, 64));
|
||||||
|
return secp.verify(_sig, msg, this.publicKey);
|
||||||
|
} catch {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
function randomBytes(length: number): Uint8Array {
|
|
||||||
if (typeof window !== "undefined" && window && window.crypto) {
|
|
||||||
const array = new Uint8Array(length);
|
|
||||||
window.crypto.getRandomValues(array);
|
|
||||||
return array;
|
|
||||||
} else {
|
|
||||||
return crypto.randomBytes(length);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ export interface IKeypair {
|
||||||
publicKey: Uint8Array;
|
publicKey: Uint8Array;
|
||||||
privateKeyVerify(): boolean;
|
privateKeyVerify(): boolean;
|
||||||
publicKeyVerify(): boolean;
|
publicKeyVerify(): boolean;
|
||||||
sign(msg: Uint8Array): Uint8Array;
|
sign(msg: Uint8Array): Promise<Uint8Array>;
|
||||||
verify(msg: Uint8Array, sig: Uint8Array): boolean;
|
verify(msg: Uint8Array, sig: Uint8Array): boolean;
|
||||||
hasPrivateKey(): boolean;
|
hasPrivateKey(): boolean;
|
||||||
}
|
}
|
||||||
|
@ -29,7 +29,7 @@ export abstract class AbstractKeypair {
|
||||||
throw new Error("Invalid private key");
|
throw new Error("Invalid private key");
|
||||||
}
|
}
|
||||||
if ((this._publicKey = publicKey) && !this.publicKeyVerify()) {
|
if ((this._publicKey = publicKey) && !this.publicKeyVerify()) {
|
||||||
throw new Error("Invalid private key");
|
throw new Error("Invalid public key");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
import crypto from "crypto";
|
import * as secp from "@noble/secp256k1";
|
||||||
|
|
||||||
import { keccak256 } from "js-sha3";
|
import { keccak256 } from "js-sha3";
|
||||||
import * as secp256k1 from "secp256k1";
|
|
||||||
|
import { randomBytes } from "../crypto";
|
||||||
|
import { bytesToHex } from "../utils";
|
||||||
|
|
||||||
import { createNodeId } from "./create";
|
import { createNodeId } from "./create";
|
||||||
import { NodeId } from "./types";
|
import { NodeId } from "./types";
|
||||||
|
@ -10,17 +11,26 @@ export function hash(input: Uint8Array): Uint8Array {
|
||||||
return new Uint8Array(keccak256.arrayBuffer(input));
|
return new Uint8Array(keccak256.arrayBuffer(input));
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function createPrivateKey(): Promise<Uint8Array> {
|
export function createPrivateKey(): Uint8Array {
|
||||||
return randomBytes(32);
|
return randomBytes(32);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function publicKey(privKey: Uint8Array): Uint8Array {
|
export function publicKey(privKey: Uint8Array): Uint8Array {
|
||||||
return secp256k1.publicKeyCreate(privKey);
|
return secp.getPublicKey(privKey, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function sign(privKey: Uint8Array, msg: Uint8Array): Uint8Array {
|
export function compressPublicKey(publicKey: Uint8Array): Uint8Array {
|
||||||
const { signature } = secp256k1.ecdsaSign(hash(msg), privKey);
|
const point = secp.Point.fromHex(bytesToHex(publicKey));
|
||||||
return signature;
|
return point.toRawBytes(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function sign(
|
||||||
|
privKey: Uint8Array,
|
||||||
|
msg: Uint8Array
|
||||||
|
): Promise<Uint8Array> {
|
||||||
|
return secp.sign(hash(msg), privKey, {
|
||||||
|
der: false,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function verify(
|
export function verify(
|
||||||
|
@ -28,12 +38,17 @@ export function verify(
|
||||||
msg: Uint8Array,
|
msg: Uint8Array,
|
||||||
sig: Uint8Array
|
sig: Uint8Array
|
||||||
): boolean {
|
): boolean {
|
||||||
// Remove the recovery id if present (byte #65)
|
try {
|
||||||
return secp256k1.ecdsaVerify(sig.slice(0, 64), hash(msg), pubKey);
|
const _sig = secp.Signature.fromCompact(sig.slice(0, 64));
|
||||||
|
return secp.verify(_sig, hash(msg), pubKey);
|
||||||
|
} catch {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function nodeId(pubKey: Uint8Array): NodeId {
|
export function nodeId(pubKey: Uint8Array): NodeId {
|
||||||
const uncompressedPubkey = secp256k1.publicKeyConvert(pubKey, false);
|
const publicKey = secp.Point.fromHex(pubKey);
|
||||||
|
const uncompressedPubkey = publicKey.toRawBytes(false);
|
||||||
|
|
||||||
return createNodeId(hash(uncompressedPubkey.slice(1)));
|
return createNodeId(hash(uncompressedPubkey.slice(1)));
|
||||||
}
|
}
|
||||||
|
@ -45,20 +60,20 @@ export class ENRKeyPair {
|
||||||
public readonly publicKey: Uint8Array
|
public readonly publicKey: Uint8Array
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
public static async create(privateKey?: Uint8Array): Promise<ENRKeyPair> {
|
public static create(privateKey?: Uint8Array): ENRKeyPair {
|
||||||
if (privateKey) {
|
if (privateKey) {
|
||||||
if (!secp256k1.privateKeyVerify(privateKey)) {
|
if (!secp.utils.isValidPrivateKey(privateKey)) {
|
||||||
throw new Error("Invalid private key");
|
throw new Error("Invalid private key");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const _privateKey = privateKey || (await createPrivateKey());
|
const _privateKey = privateKey || createPrivateKey();
|
||||||
const _publicKey = publicKey(_privateKey);
|
const _publicKey = publicKey(_privateKey);
|
||||||
const _nodeId = nodeId(_publicKey);
|
const _nodeId = nodeId(_publicKey);
|
||||||
|
|
||||||
return new ENRKeyPair(_nodeId, _privateKey, _publicKey);
|
return new ENRKeyPair(_nodeId, _privateKey, _publicKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
public sign(msg: Uint8Array): Uint8Array {
|
public async sign(msg: Uint8Array): Promise<Uint8Array> {
|
||||||
return sign(this.privateKey, msg);
|
return sign(this.privateKey, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,13 +81,3 @@ export class ENRKeyPair {
|
||||||
return verify(this.publicKey, msg, sig);
|
return verify(this.publicKey, msg, sig);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function randomBytes(length: number): Uint8Array {
|
|
||||||
if (typeof window !== "undefined" && window && window.crypto) {
|
|
||||||
const array = new Uint8Array(length);
|
|
||||||
window.crypto.getRandomValues(array);
|
|
||||||
return array;
|
|
||||||
} else {
|
|
||||||
return crypto.randomBytes(length);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import * as secp from "@noble/secp256k1";
|
import * as secp from "@noble/secp256k1";
|
||||||
import { concat } from "uint8arrays/concat";
|
import { concat } from "uint8arrays/concat";
|
||||||
|
|
||||||
import { randomBytes, sha256, subtle } from "../crypto";
|
import { getSubtle, randomBytes, sha256 } from "../crypto";
|
||||||
import { hexToBytes } from "../utils";
|
import { hexToBytes } from "../utils";
|
||||||
/**
|
/**
|
||||||
* HKDF as implemented in go-ethereum.
|
* HKDF as implemented in go-ethereum.
|
||||||
|
@ -37,10 +37,10 @@ function aesCtrEncrypt(
|
||||||
key: ArrayBufferLike,
|
key: ArrayBufferLike,
|
||||||
data: ArrayBufferLike
|
data: ArrayBufferLike
|
||||||
): Promise<Uint8Array> {
|
): Promise<Uint8Array> {
|
||||||
return subtle
|
return getSubtle()
|
||||||
.importKey("raw", key, "AES-CTR", false, ["encrypt"])
|
.importKey("raw", key, "AES-CTR", false, ["encrypt"])
|
||||||
.then((cryptoKey) =>
|
.then((cryptoKey) =>
|
||||||
subtle.encrypt(
|
getSubtle().encrypt(
|
||||||
{ name: "AES-CTR", counter: counter, length: 128 },
|
{ name: "AES-CTR", counter: counter, length: 128 },
|
||||||
cryptoKey,
|
cryptoKey,
|
||||||
data
|
data
|
||||||
|
@ -54,10 +54,10 @@ function aesCtrDecrypt(
|
||||||
key: ArrayBufferLike,
|
key: ArrayBufferLike,
|
||||||
data: ArrayBufferLike
|
data: ArrayBufferLike
|
||||||
): Promise<Uint8Array> {
|
): Promise<Uint8Array> {
|
||||||
return subtle
|
return getSubtle()
|
||||||
.importKey("raw", key, "AES-CTR", false, ["decrypt"])
|
.importKey("raw", key, "AES-CTR", false, ["decrypt"])
|
||||||
.then((cryptoKey) =>
|
.then((cryptoKey) =>
|
||||||
subtle.decrypt(
|
getSubtle().decrypt(
|
||||||
{ name: "AES-CTR", counter: counter, length: 128 },
|
{ name: "AES-CTR", counter: counter, length: 128 },
|
||||||
cryptoKey,
|
cryptoKey,
|
||||||
data
|
data
|
||||||
|
@ -71,9 +71,9 @@ function hmacSha256Sign(
|
||||||
msg: ArrayBufferLike
|
msg: ArrayBufferLike
|
||||||
): PromiseLike<Uint8Array> {
|
): PromiseLike<Uint8Array> {
|
||||||
const algorithm = { name: "HMAC", hash: { name: "SHA-256" } };
|
const algorithm = { name: "HMAC", hash: { name: "SHA-256" } };
|
||||||
return subtle
|
return getSubtle()
|
||||||
.importKey("raw", key, algorithm, false, ["sign"])
|
.importKey("raw", key, algorithm, false, ["sign"])
|
||||||
.then((cryptoKey) => subtle.sign(algorithm, cryptoKey, msg))
|
.then((cryptoKey) => getSubtle().sign(algorithm, cryptoKey, msg))
|
||||||
.then((bytes) => new Uint8Array(bytes));
|
.then((bytes) => new Uint8Array(bytes));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,9 +83,9 @@ function hmacSha256Verify(
|
||||||
sig: ArrayBufferLike
|
sig: ArrayBufferLike
|
||||||
): Promise<boolean> {
|
): Promise<boolean> {
|
||||||
const algorithm = { name: "HMAC", hash: { name: "SHA-256" } };
|
const algorithm = { name: "HMAC", hash: { name: "SHA-256" } };
|
||||||
const _key = subtle.importKey("raw", key, algorithm, false, ["verify"]);
|
const _key = getSubtle().importKey("raw", key, algorithm, false, ["verify"]);
|
||||||
return _key.then((cryptoKey) =>
|
return _key.then((cryptoKey) =>
|
||||||
subtle.verify(algorithm, cryptoKey, sig, msg)
|
getSubtle().verify(algorithm, cryptoKey, sig, msg)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -35,7 +35,7 @@ describe("Waku Message: Browser & Node", function () {
|
||||||
await fc.assert(
|
await fc.assert(
|
||||||
fc.asyncProperty(
|
fc.asyncProperty(
|
||||||
fc.uint8Array({ minLength: 1 }),
|
fc.uint8Array({ minLength: 1 }),
|
||||||
fc.uint8Array({ minLength: 32, maxLength: 32 }),
|
fc.uint8Array({ min: 1, minLength: 32, maxLength: 32 }),
|
||||||
async (payload, key) => {
|
async (payload, key) => {
|
||||||
const publicKey = getPublicKey(key);
|
const publicKey = getPublicKey(key);
|
||||||
|
|
||||||
|
@ -56,8 +56,8 @@ describe("Waku Message: Browser & Node", function () {
|
||||||
await fc.assert(
|
await fc.assert(
|
||||||
fc.asyncProperty(
|
fc.asyncProperty(
|
||||||
fc.uint8Array({ minLength: 1 }),
|
fc.uint8Array({ minLength: 1 }),
|
||||||
fc.uint8Array({ minLength: 32, maxLength: 32 }),
|
fc.uint8Array({ min: 1, minLength: 32, maxLength: 32 }),
|
||||||
fc.uint8Array({ minLength: 32, maxLength: 32 }),
|
fc.uint8Array({ min: 1, minLength: 32, maxLength: 32 }),
|
||||||
async (payload, sigPrivKey, encPrivKey) => {
|
async (payload, sigPrivKey, encPrivKey) => {
|
||||||
const sigPubKey = getPublicKey(sigPrivKey);
|
const sigPubKey = getPublicKey(sigPrivKey);
|
||||||
const encPubKey = getPublicKey(encPrivKey);
|
const encPubKey = getPublicKey(encPrivKey);
|
||||||
|
|
|
@ -89,12 +89,12 @@ export class WakuMessage {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (encPublicKey) {
|
if (encPublicKey) {
|
||||||
const enc = version_1.clearEncode(_payload, sigPrivKey);
|
const enc = await version_1.clearEncode(_payload, sigPrivKey);
|
||||||
_payload = await version_1.encryptAsymmetric(enc.payload, encPublicKey);
|
_payload = await version_1.encryptAsymmetric(enc.payload, encPublicKey);
|
||||||
sig = enc.sig;
|
sig = enc.sig;
|
||||||
version = 1;
|
version = 1;
|
||||||
} else if (symKey) {
|
} else if (symKey) {
|
||||||
const enc = version_1.clearEncode(_payload, sigPrivKey);
|
const enc = await version_1.clearEncode(_payload, sigPrivKey);
|
||||||
_payload = await version_1.encryptSymmetric(enc.payload, symKey);
|
_payload = await version_1.encryptSymmetric(enc.payload, symKey);
|
||||||
sig = enc.sig;
|
sig = enc.sig;
|
||||||
version = 1;
|
version = 1;
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
import { getSubtle, randomBytes } from "../crypto";
|
||||||
|
|
||||||
|
export const KeySize = 32;
|
||||||
|
export const IvSize = 12;
|
||||||
|
export const TagSize = 16;
|
||||||
|
|
||||||
|
const Algorithm = { name: "AES-GCM", length: 128 };
|
||||||
|
|
||||||
|
export async function encrypt(
|
||||||
|
iv: Buffer | Uint8Array,
|
||||||
|
key: Buffer,
|
||||||
|
clearText: Buffer
|
||||||
|
): Promise<Buffer> {
|
||||||
|
return getSubtle()
|
||||||
|
.importKey("raw", key, Algorithm, false, ["encrypt"])
|
||||||
|
.then((cryptoKey) =>
|
||||||
|
getSubtle().encrypt({ iv, ...Algorithm }, cryptoKey, clearText)
|
||||||
|
)
|
||||||
|
.then(Buffer.from);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function decrypt(
|
||||||
|
iv: Buffer,
|
||||||
|
key: Buffer,
|
||||||
|
cipherText: Buffer
|
||||||
|
): Promise<Buffer> {
|
||||||
|
return getSubtle()
|
||||||
|
.importKey("raw", key, Algorithm, false, ["decrypt"])
|
||||||
|
.then((cryptoKey) =>
|
||||||
|
getSubtle().decrypt({ iv, ...Algorithm }, cryptoKey, cipherText)
|
||||||
|
)
|
||||||
|
.then(Buffer.from);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function generateIv(): Uint8Array {
|
||||||
|
return randomBytes(IvSize);
|
||||||
|
}
|
|
@ -1,51 +0,0 @@
|
||||||
import { IvSize } from "./index";
|
|
||||||
|
|
||||||
declare global {
|
|
||||||
interface Window {
|
|
||||||
msCrypto?: Crypto;
|
|
||||||
}
|
|
||||||
interface Crypto {
|
|
||||||
webkitSubtle?: SubtleCrypto;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const crypto = window.crypto || window.msCrypto;
|
|
||||||
const subtle: SubtleCrypto = crypto.subtle || crypto.webkitSubtle;
|
|
||||||
|
|
||||||
const Algorithm = { name: "AES-GCM", length: 128 };
|
|
||||||
|
|
||||||
if (subtle === undefined) {
|
|
||||||
throw new Error("Failed to load Subtle CryptoAPI");
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function encrypt(
|
|
||||||
iv: Buffer | Uint8Array,
|
|
||||||
key: Buffer,
|
|
||||||
clearText: Buffer
|
|
||||||
): Promise<Buffer> {
|
|
||||||
return subtle
|
|
||||||
.importKey("raw", key, Algorithm, false, ["encrypt"])
|
|
||||||
.then((cryptoKey) =>
|
|
||||||
subtle.encrypt({ iv, ...Algorithm }, cryptoKey, clearText)
|
|
||||||
)
|
|
||||||
.then(Buffer.from);
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function decrypt(
|
|
||||||
iv: Buffer,
|
|
||||||
key: Buffer,
|
|
||||||
cipherText: Buffer
|
|
||||||
): Promise<Buffer> {
|
|
||||||
return subtle
|
|
||||||
.importKey("raw", key, Algorithm, false, ["decrypt"])
|
|
||||||
.then((cryptoKey) =>
|
|
||||||
subtle.decrypt({ iv, ...Algorithm }, cryptoKey, cipherText)
|
|
||||||
)
|
|
||||||
.then(Buffer.from);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function generateIv(): Uint8Array {
|
|
||||||
const iv = new Uint8Array(IvSize);
|
|
||||||
crypto.getRandomValues(iv);
|
|
||||||
return iv;
|
|
||||||
}
|
|
|
@ -1,38 +0,0 @@
|
||||||
export const SymmetricKeySize = 32;
|
|
||||||
export const IvSize = 12;
|
|
||||||
export const TagSize = 16;
|
|
||||||
|
|
||||||
export interface Symmetric {
|
|
||||||
/**
|
|
||||||
* Proceed with symmetric encryption of `clearText` value.
|
|
||||||
*/
|
|
||||||
encrypt: (
|
|
||||||
iv: Buffer | Uint8Array,
|
|
||||||
key: Buffer,
|
|
||||||
clearText: Buffer
|
|
||||||
) => Promise<Buffer>;
|
|
||||||
/**
|
|
||||||
* Proceed with symmetric decryption of `cipherText` value.
|
|
||||||
*/
|
|
||||||
decrypt: (iv: Buffer, key: Buffer, cipherText: Buffer) => Promise<Buffer>;
|
|
||||||
/**
|
|
||||||
* Generate an Initialization Vector (iv) for for Symmetric encryption purposes.
|
|
||||||
*/
|
|
||||||
generateIv: () => Uint8Array;
|
|
||||||
}
|
|
||||||
|
|
||||||
export let symmetric: Symmetric = {} as unknown as Symmetric;
|
|
||||||
|
|
||||||
import("./browser")
|
|
||||||
.then((mod) => {
|
|
||||||
symmetric = mod;
|
|
||||||
})
|
|
||||||
.catch((eBrowser) => {
|
|
||||||
import("./node")
|
|
||||||
.then((mod) => {
|
|
||||||
symmetric = mod;
|
|
||||||
})
|
|
||||||
.catch((eNode) => {
|
|
||||||
throw `Could not load any symmetric crypto modules: ${eBrowser}, ${eNode}`;
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -1,36 +0,0 @@
|
||||||
import { createCipheriv, createDecipheriv, randomBytes } from "crypto";
|
|
||||||
|
|
||||||
import { IvSize, TagSize } from "./index";
|
|
||||||
|
|
||||||
const Algorithm = "aes-256-gcm";
|
|
||||||
|
|
||||||
export async function encrypt(
|
|
||||||
iv: Buffer | Uint8Array,
|
|
||||||
key: Buffer,
|
|
||||||
clearText: Buffer
|
|
||||||
): Promise<Buffer> {
|
|
||||||
const cipher = createCipheriv(Algorithm, key, iv);
|
|
||||||
const a = cipher.update(clearText);
|
|
||||||
const b = cipher.final();
|
|
||||||
const tag = cipher.getAuthTag();
|
|
||||||
return Buffer.concat([a, b, tag]);
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function decrypt(
|
|
||||||
iv: Buffer,
|
|
||||||
key: Buffer,
|
|
||||||
data: Buffer
|
|
||||||
): Promise<Buffer> {
|
|
||||||
const tagStart = data.length - TagSize;
|
|
||||||
const cipherText = data.slice(0, tagStart);
|
|
||||||
const tag = data.slice(tagStart);
|
|
||||||
const decipher = createDecipheriv(Algorithm, key, iv);
|
|
||||||
decipher.setAuthTag(tag);
|
|
||||||
const a = decipher.update(cipherText);
|
|
||||||
const b = decipher.final();
|
|
||||||
return Buffer.concat([a, b]);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function generateIv(): Buffer {
|
|
||||||
return randomBytes(IvSize);
|
|
||||||
}
|
|
|
@ -14,11 +14,11 @@ import {
|
||||||
describe("Waku Message Version 1", function () {
|
describe("Waku Message Version 1", function () {
|
||||||
it("Sign & Recover", function () {
|
it("Sign & Recover", function () {
|
||||||
fc.assert(
|
fc.assert(
|
||||||
fc.property(
|
fc.asyncProperty(
|
||||||
fc.uint8Array(),
|
fc.uint8Array(),
|
||||||
fc.uint8Array({ minLength: 32, maxLength: 32 }),
|
fc.uint8Array({ minLength: 32, maxLength: 32 }),
|
||||||
(message, privKey) => {
|
async (message, privKey) => {
|
||||||
const enc = clearEncode(message, privKey);
|
const enc = await clearEncode(message, privKey);
|
||||||
const res = clearDecode(enc.payload);
|
const res = clearDecode(enc.payload);
|
||||||
|
|
||||||
const pubKey = getPublicKey(privKey);
|
const pubKey = getPublicKey(privKey);
|
||||||
|
@ -44,7 +44,7 @@ describe("Waku Message Version 1", function () {
|
||||||
await fc.assert(
|
await fc.assert(
|
||||||
fc.asyncProperty(
|
fc.asyncProperty(
|
||||||
fc.uint8Array({ minLength: 1 }),
|
fc.uint8Array({ minLength: 1 }),
|
||||||
fc.uint8Array({ minLength: 32, maxLength: 32 }),
|
fc.uint8Array({ min: 1, minLength: 32, maxLength: 32 }),
|
||||||
async (message, privKey) => {
|
async (message, privKey) => {
|
||||||
const publicKey = getPublicKey(privKey);
|
const publicKey = getPublicKey(privKey);
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
import { Buffer } from "buffer";
|
import { Buffer } from "buffer";
|
||||||
import * as crypto from "crypto";
|
|
||||||
|
|
||||||
|
import * as secp from "@noble/secp256k1";
|
||||||
import { keccak256 } from "js-sha3";
|
import { keccak256 } from "js-sha3";
|
||||||
import * as secp256k1 from "secp256k1";
|
|
||||||
|
|
||||||
|
import { randomBytes } from "../crypto";
|
||||||
import { hexToBytes } from "../utils";
|
import { hexToBytes } from "../utils";
|
||||||
|
|
||||||
import * as ecies from "./ecies";
|
import * as ecies from "./ecies";
|
||||||
import { IvSize, symmetric, SymmetricKeySize } from "./symmetric";
|
import * as symmetric from "./symmetric";
|
||||||
|
|
||||||
const FlagsLength = 1;
|
const FlagsLength = 1;
|
||||||
const FlagMask = 3; // 0011
|
const FlagMask = 3; // 0011
|
||||||
|
@ -26,10 +26,10 @@ export const PrivateKeySize = 32;
|
||||||
* @returns The encoded payload, ready for encryption using {@link encryptAsymmetric}
|
* @returns The encoded payload, ready for encryption using {@link encryptAsymmetric}
|
||||||
* or {@link encryptSymmetric}.
|
* or {@link encryptSymmetric}.
|
||||||
*/
|
*/
|
||||||
export function clearEncode(
|
export async function clearEncode(
|
||||||
messagePayload: Uint8Array,
|
messagePayload: Uint8Array,
|
||||||
sigPrivKey?: Uint8Array
|
sigPrivKey?: Uint8Array
|
||||||
): { payload: Uint8Array; sig?: Signature } {
|
): Promise<{ payload: Uint8Array; sig?: Signature }> {
|
||||||
let envelope = Buffer.from([0]); // No flags
|
let envelope = Buffer.from([0]); // No flags
|
||||||
envelope = addPayloadSizeField(envelope, messagePayload);
|
envelope = addPayloadSizeField(envelope, messagePayload);
|
||||||
envelope = Buffer.concat([envelope, Buffer.from(messagePayload)]);
|
envelope = Buffer.concat([envelope, Buffer.from(messagePayload)]);
|
||||||
|
@ -58,10 +58,17 @@ export function clearEncode(
|
||||||
if (sigPrivKey) {
|
if (sigPrivKey) {
|
||||||
envelope[0] |= IsSignedMask;
|
envelope[0] |= IsSignedMask;
|
||||||
const hash = keccak256(envelope);
|
const hash = keccak256(envelope);
|
||||||
const s = secp256k1.ecdsaSign(hexToBytes(hash), sigPrivKey);
|
const [signature, recid] = await secp.sign(hash, sigPrivKey, {
|
||||||
envelope = Buffer.concat([envelope, s.signature, Buffer.from([s.recid])]);
|
recovered: true,
|
||||||
|
der: false,
|
||||||
|
});
|
||||||
|
envelope = Buffer.concat([
|
||||||
|
envelope,
|
||||||
|
hexToBytes(signature),
|
||||||
|
Buffer.from([recid]),
|
||||||
|
]);
|
||||||
sig = {
|
sig = {
|
||||||
signature: Buffer.from(s.signature),
|
signature: Buffer.from(signature),
|
||||||
publicKey: getPublicKey(sigPrivKey),
|
publicKey: getPublicKey(sigPrivKey),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -71,7 +78,7 @@ export function clearEncode(
|
||||||
|
|
||||||
export type Signature = {
|
export type Signature = {
|
||||||
signature: Uint8Array;
|
signature: Uint8Array;
|
||||||
publicKey: Uint8Array;
|
publicKey: Uint8Array | undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -170,7 +177,7 @@ export async function decryptSymmetric(
|
||||||
key: Uint8Array | Buffer | string
|
key: Uint8Array | Buffer | string
|
||||||
): Promise<Uint8Array> {
|
): Promise<Uint8Array> {
|
||||||
const data = Buffer.from(payload);
|
const data = Buffer.from(payload);
|
||||||
const ivStart = data.length - IvSize;
|
const ivStart = data.length - symmetric.IvSize;
|
||||||
const cipher = data.slice(0, ivStart);
|
const cipher = data.slice(0, ivStart);
|
||||||
const iv = data.slice(ivStart);
|
const iv = data.slice(ivStart);
|
||||||
|
|
||||||
|
@ -190,7 +197,7 @@ export function generatePrivateKey(): Uint8Array {
|
||||||
* Generate a new symmetric key to be used for symmetric encryption.
|
* Generate a new symmetric key to be used for symmetric encryption.
|
||||||
*/
|
*/
|
||||||
export function generateSymmetricKey(): Uint8Array {
|
export function generateSymmetricKey(): Uint8Array {
|
||||||
return randomBytes(SymmetricKeySize);
|
return randomBytes(symmetric.KeySize);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -198,7 +205,7 @@ export function generateSymmetricKey(): Uint8Array {
|
||||||
* encryption.
|
* encryption.
|
||||||
*/
|
*/
|
||||||
export function getPublicKey(privateKey: Uint8Array | Buffer): Uint8Array {
|
export function getPublicKey(privateKey: Uint8Array | Buffer): Uint8Array {
|
||||||
return secp256k1.publicKeyCreate(privateKey, false);
|
return secp.getPublicKey(privateKey, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -249,22 +256,19 @@ function getHash(message: Buffer, isSigned: boolean): string {
|
||||||
return keccak256(message);
|
return keccak256(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
function ecRecoverPubKey(messageHash: string, signature: Buffer): Uint8Array {
|
function ecRecoverPubKey(
|
||||||
|
messageHash: string,
|
||||||
|
signature: Buffer
|
||||||
|
): Uint8Array | undefined {
|
||||||
const recovery = signature.slice(64).readIntBE(0, 1);
|
const recovery = signature.slice(64).readIntBE(0, 1);
|
||||||
return secp256k1.ecdsaRecover(
|
const _signature = secp.Signature.fromCompact(signature.slice(0, 64));
|
||||||
signature.slice(0, 64),
|
|
||||||
recovery,
|
return secp.recoverPublicKey(
|
||||||
hexToBytes(messageHash),
|
hexToBytes(messageHash),
|
||||||
|
_signature,
|
||||||
|
recovery,
|
||||||
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
|
// @ts-ignore: compressed: false
|
||||||
false
|
false
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function randomBytes(length: number): Uint8Array {
|
|
||||||
if (typeof window !== "undefined" && window && window.crypto) {
|
|
||||||
const array = new Uint8Array(length);
|
|
||||||
window.crypto.getRandomValues(array);
|
|
||||||
return array;
|
|
||||||
} else {
|
|
||||||
return crypto.randomBytes(length);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -24,7 +24,7 @@ module.exports = {
|
||||||
extensions: ['.ts', '.js'],
|
extensions: ['.ts', '.js'],
|
||||||
fallback: {
|
fallback: {
|
||||||
buffer: require.resolve('buffer/'),
|
buffer: require.resolve('buffer/'),
|
||||||
crypto: require.resolve('crypto-browserify'),
|
crypto: false,
|
||||||
stream: require.resolve('stream-browserify'),
|
stream: require.resolve('stream-browserify'),
|
||||||
assert: require.resolve('assert'),
|
assert: require.resolve('assert'),
|
||||||
},
|
},
|
||||||
|
|
|
@ -24,7 +24,7 @@ module.exports = {
|
||||||
extensions: ['.ts', '.js'],
|
extensions: ['.ts', '.js'],
|
||||||
fallback: {
|
fallback: {
|
||||||
buffer: require.resolve('buffer/'),
|
buffer: require.resolve('buffer/'),
|
||||||
crypto: require.resolve('crypto-browserify'),
|
crypto: false,
|
||||||
stream: require.resolve('stream-browserify'),
|
stream: require.resolve('stream-browserify'),
|
||||||
assert: require.resolve('assert'),
|
assert: require.resolve('assert'),
|
||||||
},
|
},
|
||||||
|
|
|
@ -24,7 +24,7 @@ module.exports = {
|
||||||
extensions: ['.ts', '.js'],
|
extensions: ['.ts', '.js'],
|
||||||
fallback: {
|
fallback: {
|
||||||
buffer: require.resolve('buffer/'),
|
buffer: require.resolve('buffer/'),
|
||||||
crypto: require.resolve('crypto-browserify'),
|
crypto: false,
|
||||||
stream: require.resolve('stream-browserify'),
|
stream: require.resolve('stream-browserify'),
|
||||||
assert: require.resolve('assert'),
|
assert: require.resolve('assert'),
|
||||||
},
|
},
|
||||||
|
|
|
@ -24,7 +24,7 @@ module.exports = {
|
||||||
extensions: ['.ts', '.js'],
|
extensions: ['.ts', '.js'],
|
||||||
fallback: {
|
fallback: {
|
||||||
buffer: require.resolve('buffer/'),
|
buffer: require.resolve('buffer/'),
|
||||||
crypto: require.resolve('crypto-browserify'),
|
crypto: false,
|
||||||
stream: require.resolve('stream-browserify'),
|
stream: require.resolve('stream-browserify'),
|
||||||
assert: require.resolve('assert'),
|
assert: require.resolve('assert'),
|
||||||
},
|
},
|
||||||
|
|
Loading…
Reference in New Issue