From d1babe25eea27b0230f367c4e535623c726aa48f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 16 Aug 2023 14:49:21 +0000 Subject: [PATCH 1/6] chore(deps)(deps): bump @noble/secp256k1 from 1.7.1 to 2.0.0 Bumps [@noble/secp256k1](https://github.com/paulmillr/noble-secp256k1) from 1.7.1 to 2.0.0. - [Release notes](https://github.com/paulmillr/noble-secp256k1/releases) - [Commits](https://github.com/paulmillr/noble-secp256k1/compare/1.7.1...2.0.0) --- updated-dependencies: - dependency-name: "@noble/secp256k1" dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- package-lock.json | 149 +++++++++++++++++++++-- packages/enr/package.json | 2 +- packages/message-encryption/package.json | 2 +- 3 files changed, 143 insertions(+), 10 deletions(-) diff --git a/package-lock.json b/package-lock.json index 1daf179d10..96b4a40c3e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1563,6 +1563,17 @@ "uint8arrays": "^4.0.4" } }, + "node_modules/@chainsafe/libp2p-gossipsub/node_modules/@noble/secp256k1": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@noble/secp256k1/-/secp256k1-1.7.1.tgz", + "integrity": "sha512-hOUk6AyBFmqVrv7k5WAw/LpszxVbj9gGN4JRkIX52fdFAj1UA61KXmZDvqVEm+pOyec3+fIeZB02LYa/pWOArw==", + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ] + }, "node_modules/@chainsafe/libp2p-gossipsub/node_modules/multiformats": { "version": "12.0.1", "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-12.0.1.tgz", @@ -1636,6 +1647,17 @@ "uint8arrays": "^4.0.4" } }, + "node_modules/@chainsafe/libp2p-noise/node_modules/@noble/secp256k1": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@noble/secp256k1/-/secp256k1-1.7.1.tgz", + "integrity": "sha512-hOUk6AyBFmqVrv7k5WAw/LpszxVbj9gGN4JRkIX52fdFAj1UA61KXmZDvqVEm+pOyec3+fIeZB02LYa/pWOArw==", + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ] + }, "node_modules/@chainsafe/libp2p-noise/node_modules/it-stream-types": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/it-stream-types/-/it-stream-types-2.0.1.tgz", @@ -2896,6 +2918,17 @@ "npm": ">=7.0.0" } }, + "node_modules/@libp2p/crypto/node_modules/@noble/secp256k1": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@noble/secp256k1/-/secp256k1-1.7.1.tgz", + "integrity": "sha512-hOUk6AyBFmqVrv7k5WAw/LpszxVbj9gGN4JRkIX52fdFAj1UA61KXmZDvqVEm+pOyec3+fIeZB02LYa/pWOArw==", + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ] + }, "node_modules/@libp2p/interface": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/@libp2p/interface/-/interface-0.1.2.tgz", @@ -3046,6 +3079,17 @@ "uint8arrays": "^4.0.4" } }, + "node_modules/@libp2p/keychain/node_modules/@noble/secp256k1": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@noble/secp256k1/-/secp256k1-1.7.1.tgz", + "integrity": "sha512-hOUk6AyBFmqVrv7k5WAw/LpszxVbj9gGN4JRkIX52fdFAj1UA61KXmZDvqVEm+pOyec3+fIeZB02LYa/pWOArw==", + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ] + }, "node_modules/@libp2p/keychain/node_modules/multiformats": { "version": "12.0.1", "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-12.0.1.tgz", @@ -3298,6 +3342,17 @@ "uint8arrays": "^4.0.4" } }, + "node_modules/@libp2p/peer-store/node_modules/@noble/secp256k1": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@noble/secp256k1/-/secp256k1-1.7.1.tgz", + "integrity": "sha512-hOUk6AyBFmqVrv7k5WAw/LpszxVbj9gGN4JRkIX52fdFAj1UA61KXmZDvqVEm+pOyec3+fIeZB02LYa/pWOArw==", + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ] + }, "node_modules/@libp2p/peer-store/node_modules/multiformats": { "version": "12.0.1", "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-12.0.1.tgz", @@ -3374,6 +3429,17 @@ "uint8arrays": "^4.0.4" } }, + "node_modules/@libp2p/pubsub/node_modules/@noble/secp256k1": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@noble/secp256k1/-/secp256k1-1.7.1.tgz", + "integrity": "sha512-hOUk6AyBFmqVrv7k5WAw/LpszxVbj9gGN4JRkIX52fdFAj1UA61KXmZDvqVEm+pOyec3+fIeZB02LYa/pWOArw==", + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ] + }, "node_modules/@libp2p/pubsub/node_modules/multiformats": { "version": "12.0.1", "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-12.0.1.tgz", @@ -3590,14 +3656,15 @@ } }, "node_modules/@noble/secp256k1": { - "version": "1.7.1", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@noble/secp256k1/-/secp256k1-2.0.0.tgz", + "integrity": "sha512-rUGBd95e2a45rlmFTqQJYEFA4/gdIARFfuTuTqLglz0PZ6AKyzyXsEZZq7UZn8hZsvaBgpCzKKBJizT2cJERXw==", "funding": [ { "type": "individual", "url": "https://paulmillr.com/funding/" } - ], - "license": "MIT" + ] }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", @@ -15538,6 +15605,17 @@ "uint8arrays": "^4.0.4" } }, + "node_modules/libp2p/node_modules/@noble/secp256k1": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@noble/secp256k1/-/secp256k1-1.7.1.tgz", + "integrity": "sha512-hOUk6AyBFmqVrv7k5WAw/LpszxVbj9gGN4JRkIX52fdFAj1UA61KXmZDvqVEm+pOyec3+fIeZB02LYa/pWOArw==", + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ] + }, "node_modules/libp2p/node_modules/it-filter": { "version": "3.0.2", "license": "Apache-2.0 OR MIT", @@ -30586,7 +30664,7 @@ "@libp2p/crypto": "^1.0.17", "@libp2p/peer-id": "^2.0.4", "@multiformats/multiaddr": "^12.0.0", - "@noble/secp256k1": "^1.7.1", + "@noble/secp256k1": "^2.0.0", "@waku/utils": "0.0.10", "debug": "^4.3.4", "js-sha3": "^0.8.0" @@ -30640,7 +30718,7 @@ "version": "0.0.20", "license": "MIT OR Apache-2.0", "dependencies": { - "@noble/secp256k1": "^1.7.1", + "@noble/secp256k1": "^2.0.0", "@waku/core": "0.0.22", "@waku/interfaces": "0.0.17", "@waku/proto": "0.0.5", @@ -31036,6 +31114,17 @@ "uint8arrays": "^4.0.4" } }, + "packages/tests/node_modules/@noble/secp256k1": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@noble/secp256k1/-/secp256k1-1.7.1.tgz", + "integrity": "sha512-hOUk6AyBFmqVrv7k5WAw/LpszxVbj9gGN4JRkIX52fdFAj1UA61KXmZDvqVEm+pOyec3+fIeZB02LYa/pWOArw==", + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ] + }, "packages/tests/node_modules/delay": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/delay/-/delay-6.0.0.tgz", @@ -32242,6 +32331,11 @@ "uint8arrays": "^4.0.4" } }, + "@noble/secp256k1": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@noble/secp256k1/-/secp256k1-1.7.1.tgz", + "integrity": "sha512-hOUk6AyBFmqVrv7k5WAw/LpszxVbj9gGN4JRkIX52fdFAj1UA61KXmZDvqVEm+pOyec3+fIeZB02LYa/pWOArw==" + }, "multiformats": { "version": "12.0.1", "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-12.0.1.tgz", @@ -32309,6 +32403,11 @@ "uint8arrays": "^4.0.4" } }, + "@noble/secp256k1": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@noble/secp256k1/-/secp256k1-1.7.1.tgz", + "integrity": "sha512-hOUk6AyBFmqVrv7k5WAw/LpszxVbj9gGN4JRkIX52fdFAj1UA61KXmZDvqVEm+pOyec3+fIeZB02LYa/pWOArw==" + }, "it-stream-types": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/it-stream-types/-/it-stream-types-2.0.1.tgz", @@ -33205,6 +33304,13 @@ "protons-runtime": "^5.0.0", "uint8arraylist": "^2.4.3", "uint8arrays": "^4.0.2" + }, + "dependencies": { + "@noble/secp256k1": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@noble/secp256k1/-/secp256k1-1.7.1.tgz", + "integrity": "sha512-hOUk6AyBFmqVrv7k5WAw/LpszxVbj9gGN4JRkIX52fdFAj1UA61KXmZDvqVEm+pOyec3+fIeZB02LYa/pWOArw==" + } } }, "@libp2p/interface": { @@ -33334,6 +33440,11 @@ "uint8arrays": "^4.0.4" } }, + "@noble/secp256k1": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@noble/secp256k1/-/secp256k1-1.7.1.tgz", + "integrity": "sha512-hOUk6AyBFmqVrv7k5WAw/LpszxVbj9gGN4JRkIX52fdFAj1UA61KXmZDvqVEm+pOyec3+fIeZB02LYa/pWOArw==" + }, "multiformats": { "version": "12.0.1", "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-12.0.1.tgz", @@ -33557,6 +33668,11 @@ "uint8arrays": "^4.0.4" } }, + "@noble/secp256k1": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@noble/secp256k1/-/secp256k1-1.7.1.tgz", + "integrity": "sha512-hOUk6AyBFmqVrv7k5WAw/LpszxVbj9gGN4JRkIX52fdFAj1UA61KXmZDvqVEm+pOyec3+fIeZB02LYa/pWOArw==" + }, "multiformats": { "version": "12.0.1", "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-12.0.1.tgz", @@ -33631,6 +33747,11 @@ "uint8arrays": "^4.0.4" } }, + "@noble/secp256k1": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@noble/secp256k1/-/secp256k1-1.7.1.tgz", + "integrity": "sha512-hOUk6AyBFmqVrv7k5WAw/LpszxVbj9gGN4JRkIX52fdFAj1UA61KXmZDvqVEm+pOyec3+fIeZB02LYa/pWOArw==" + }, "multiformats": { "version": "12.0.1", "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-12.0.1.tgz", @@ -33789,7 +33910,9 @@ "integrity": "sha512-EbqwksQwz9xDRGfDST86whPBgM65E0OH/pCgqW0GBVzO22bNE+NuIbeTb714+IfSjU3aRk47EUvXIb5bTsenKA==" }, "@noble/secp256k1": { - "version": "1.7.1" + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@noble/secp256k1/-/secp256k1-2.0.0.tgz", + "integrity": "sha512-rUGBd95e2a45rlmFTqQJYEFA4/gdIARFfuTuTqLglz0PZ6AKyzyXsEZZq7UZn8hZsvaBgpCzKKBJizT2cJERXw==" }, "@nodelib/fs.scandir": { "version": "2.1.5", @@ -35567,7 +35690,7 @@ "@libp2p/peer-id": "^2.0.4", "@libp2p/peer-id-factory": "^2.0.4", "@multiformats/multiaddr": "^12.0.0", - "@noble/secp256k1": "^1.7.1", + "@noble/secp256k1": "^2.0.0", "@rollup/plugin-commonjs": "^24.0.1", "@rollup/plugin-json": "^6.0.0", "@rollup/plugin-node-resolve": "^15.0.2", @@ -35608,7 +35731,7 @@ "@waku/message-encryption": { "version": "file:packages/message-encryption", "requires": { - "@noble/secp256k1": "^1.7.1", + "@noble/secp256k1": "^2.0.0", "@rollup/plugin-commonjs": "^24.0.1", "@rollup/plugin-json": "^6.0.0", "@rollup/plugin-node-resolve": "^15.0.2", @@ -35944,6 +36067,11 @@ } } }, + "@noble/secp256k1": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@noble/secp256k1/-/secp256k1-1.7.1.tgz", + "integrity": "sha512-hOUk6AyBFmqVrv7k5WAw/LpszxVbj9gGN4JRkIX52fdFAj1UA61KXmZDvqVEm+pOyec3+fIeZB02LYa/pWOArw==" + }, "delay": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/delay/-/delay-6.0.0.tgz", @@ -42388,6 +42516,11 @@ "uint8arrays": "^4.0.4" } }, + "@noble/secp256k1": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@noble/secp256k1/-/secp256k1-1.7.1.tgz", + "integrity": "sha512-hOUk6AyBFmqVrv7k5WAw/LpszxVbj9gGN4JRkIX52fdFAj1UA61KXmZDvqVEm+pOyec3+fIeZB02LYa/pWOArw==" + }, "it-filter": { "version": "3.0.2", "requires": { diff --git a/packages/enr/package.json b/packages/enr/package.json index a4baf537a7..7a07335dfb 100644 --- a/packages/enr/package.json +++ b/packages/enr/package.json @@ -55,7 +55,7 @@ "@libp2p/crypto": "^1.0.17", "@libp2p/peer-id": "^2.0.4", "@multiformats/multiaddr": "^12.0.0", - "@noble/secp256k1": "^1.7.1", + "@noble/secp256k1": "^2.0.0", "@waku/utils": "0.0.10", "debug": "^4.3.4", "js-sha3": "^0.8.0" diff --git a/packages/message-encryption/package.json b/packages/message-encryption/package.json index 1c459c1acb..df0ee33e84 100644 --- a/packages/message-encryption/package.json +++ b/packages/message-encryption/package.json @@ -71,7 +71,7 @@ "crypto": false }, "dependencies": { - "@noble/secp256k1": "^1.7.1", + "@noble/secp256k1": "^2.0.0", "@waku/core": "0.0.22", "@waku/interfaces": "0.0.17", "@waku/proto": "0.0.5", From 9e5284bb53adf454741718438b52b5ca16ab5b32 Mon Sep 17 00:00:00 2001 From: danisharora099 Date: Wed, 16 Aug 2023 23:40:55 +0530 Subject: [PATCH 2/6] refactor API --- packages/message-encryption/src/waku_payload.ts | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/packages/message-encryption/src/waku_payload.ts b/packages/message-encryption/src/waku_payload.ts index 8da80da4be..d68ec2a8d2 100644 --- a/packages/message-encryption/src/waku_payload.ts +++ b/packages/message-encryption/src/waku_payload.ts @@ -1,12 +1,12 @@ -import * as secp from "@noble/secp256k1"; +import { sign, Signature } from "@noble/secp256k1"; import { concat, hexToBytes } from "@waku/utils/bytes"; import { Symmetric } from "./constants.js"; import * as ecies from "./crypto/ecies.js"; -import { keccak256, randomBytes, sign } from "./crypto/index.js"; +import { keccak256, randomBytes } from "./crypto/index.js"; import * as symmetric from "./crypto/symmetric.js"; -import { Signature } from "./index.js"; +import { Signature as WakuSignature } from "./index.js"; const FlagsLength = 1; const FlagMask = 3; // 0011 @@ -159,11 +159,8 @@ function ecRecoverPubKey( messageHash: Uint8Array, signature: Uint8Array ): Uint8Array | undefined { - const recoveryDataView = new DataView(signature.slice(64).buffer); - const recovery = recoveryDataView.getUint8(0); - const _signature = secp.Signature.fromCompact(signature.slice(0, 64)); - - return secp.recoverPublicKey(messageHash, _signature, recovery, false); + const _signature = Signature.fromCompact(signature); + return _signature.recoverPublicKey(messageHash).toRawBytes(); } /** @@ -203,7 +200,7 @@ export async function preCipher( if (sigPrivKey) { envelope[0] |= IsSignedMask; const hash = keccak256(envelope); - const bytesSignature = await sign(hash, sigPrivKey); + const bytesSignature = sign(hash, sigPrivKey).toCompactRawBytes(); envelope = concat([envelope, bytesSignature]); } @@ -217,7 +214,7 @@ export async function preCipher( */ export function postCipher( message: Uint8Array -): { payload: Uint8Array; sig?: Signature } | undefined { +): { payload: Uint8Array; sig?: WakuSignature } | undefined { const sizeOfPayloadSizeField = getSizeOfPayloadSizeField(message); if (sizeOfPayloadSizeField === 0) return; From 4e1843e71bf59891d0938cb087dfacdd25a9b5b1 Mon Sep 17 00:00:00 2001 From: danisharora099 Date: Thu, 17 Aug 2023 14:58:25 +0530 Subject: [PATCH 3/6] moar refactoring --- packages/enr/src/crypto.ts | 37 +++---- packages/enr/src/v4.ts | 9 +- .../message-encryption/src/crypto/ecies.ts | 96 ++++++++++--------- .../message-encryption/src/crypto/index.ts | 34 +++---- .../src/crypto/symmetric.ts | 6 +- .../message-encryption/src/waku_payload.ts | 5 +- 6 files changed, 93 insertions(+), 94 deletions(-) diff --git a/packages/enr/src/crypto.ts b/packages/enr/src/crypto.ts index b0846f8401..95cde87dbb 100644 --- a/packages/enr/src/crypto.ts +++ b/packages/enr/src/crypto.ts @@ -1,27 +1,21 @@ -import * as secp from "@noble/secp256k1"; +import { + sign as nobleSign, + ProjectivePoint as Point, + Signature, + verify +} from "@noble/secp256k1"; import { concat } from "@waku/utils/bytes"; import sha3 from "js-sha3"; -/** - * ECDSA Sign a message with the given private key. - * - * @param message The message to sign, usually a hash. - * @param privateKey The ECDSA private key to use to sign the message. - * - * @returns The signature and the recovery id concatenated. - */ export async function sign( message: Uint8Array, privateKey: Uint8Array ): Promise { - const [signature, recoveryId] = await secp.sign(message, privateKey, { - recovered: true, - der: false - }); - return concat( - [signature, new Uint8Array([recoveryId])], - signature.length + 1 - ); + const signature = nobleSign(message, privateKey); + return concat([ + signature.toCompactRawBytes(), + new Uint8Array([signature.recovery || 0]) + ]); } export function keccak256(input: Uint8Array): Uint8Array { @@ -32,21 +26,18 @@ export function compressPublicKey(publicKey: Uint8Array): Uint8Array { if (publicKey.length === 64) { publicKey = concat([new Uint8Array([4]), publicKey], 65); } - const point = secp.Point.fromHex(publicKey); + const point = Point.fromHex(publicKey); return point.toRawBytes(true); } -/** - * Verify an ECDSA signature. - */ export function verifySignature( signature: Uint8Array, message: Uint8Array | string, publicKey: Uint8Array ): boolean { try { - const _signature = secp.Signature.fromCompact(signature.slice(0, 64)); - return secp.verify(_signature, message, publicKey); + const _signature = Signature.fromCompact(signature.slice(0, 64)); + return verify(_signature, message, publicKey); } catch { return false; } diff --git a/packages/enr/src/v4.ts b/packages/enr/src/v4.ts index 4d13bf9b9e..b1d52c7c0b 100644 --- a/packages/enr/src/v4.ts +++ b/packages/enr/src/v4.ts @@ -1,19 +1,18 @@ -import * as secp from "@noble/secp256k1"; +import { sign as nobleSign, ProjectivePoint as Point } from "@noble/secp256k1"; import type { NodeId } from "@waku/interfaces"; import { bytesToHex } from "@waku/utils/bytes"; import { keccak256 } from "./crypto.js"; + export async function sign( privKey: Uint8Array, msg: Uint8Array ): Promise { - return secp.sign(keccak256(msg), privKey, { - der: false - }); + return nobleSign(keccak256(msg), privKey).toCompactRawBytes(); } export function nodeId(pubKey: Uint8Array): NodeId { - const publicKey = secp.Point.fromHex(pubKey); + const publicKey = Point.fromHex(pubKey); const uncompressedPubkey = publicKey.toRawBytes(false); return bytesToHex(keccak256(uncompressedPubkey.slice(1))); diff --git a/packages/message-encryption/src/crypto/ecies.ts b/packages/message-encryption/src/crypto/ecies.ts index d8f16557b2..4da26edb92 100644 --- a/packages/message-encryption/src/crypto/ecies.ts +++ b/packages/message-encryption/src/crypto/ecies.ts @@ -1,7 +1,11 @@ -import * as secp from "@noble/secp256k1"; -import { concat, hexToBytes } from "@waku/utils/bytes"; - -import { getSubtle, randomBytes, sha256 } from "./index.js"; +import { + getPublicKey, + getSharedSecret, + etc as secpUtils +} from "@noble/secp256k1"; +import { concat } from "@waku/utils/bytes"; + +import { getSubtle } from "./index.js"; /** * HKDF as implemented in go-ethereum. */ @@ -15,7 +19,7 @@ function kdf(secret: Uint8Array, outputLength: number): Promise { [counters, secret], counters.length + secret.length ); - const willBeHashResult = sha256(countersSecret); + const willBeHashResult = secpUtils.hmacSha256Async(countersSecret); willBeResult = willBeResult.then((result) => willBeHashResult.then((hashResult) => { const _hashResult = new Uint8Array(hashResult); @@ -31,61 +35,59 @@ function kdf(secret: Uint8Array, outputLength: number): Promise { return willBeResult; } -function aesCtrEncrypt( +async function aesCtrEncrypt( counter: Uint8Array, key: ArrayBufferLike, data: ArrayBufferLike ): Promise { - return getSubtle() - .importKey("raw", key, "AES-CTR", false, ["encrypt"]) - .then((cryptoKey) => - getSubtle().encrypt( - { name: "AES-CTR", counter: counter, length: 128 }, - cryptoKey, - data - ) - ) - .then((bytes) => new Uint8Array(bytes)); + const cryptoKey = await getSubtle().importKey("raw", key, "AES-CTR", false, [ + "encrypt" + ]); + const bytes = await getSubtle().encrypt( + { name: "AES-CTR", counter: counter, length: 128 }, + cryptoKey, + data + ); + return new Uint8Array(bytes); } -function aesCtrDecrypt( +async function aesCtrDecrypt( counter: Uint8Array, key: ArrayBufferLike, data: ArrayBufferLike ): Promise { - return getSubtle() - .importKey("raw", key, "AES-CTR", false, ["decrypt"]) - .then((cryptoKey) => - getSubtle().decrypt( - { name: "AES-CTR", counter: counter, length: 128 }, - cryptoKey, - data - ) - ) - .then((bytes) => new Uint8Array(bytes)); + const cryptoKey = await getSubtle().importKey("raw", key, "AES-CTR", false, [ + "decrypt" + ]); + const bytes = await getSubtle().decrypt( + { name: "AES-CTR", counter: counter, length: 128 }, + cryptoKey, + data + ); + return new Uint8Array(bytes); } -function hmacSha256Sign( +async function hmacSha256Sign( key: ArrayBufferLike, msg: ArrayBufferLike -): PromiseLike { +): Promise { const algorithm = { name: "HMAC", hash: { name: "SHA-256" } }; - return getSubtle() - .importKey("raw", key, algorithm, false, ["sign"]) - .then((cryptoKey) => getSubtle().sign(algorithm, cryptoKey, msg)) - .then((bytes) => new Uint8Array(bytes)); + const cryptoKey = await getSubtle().importKey("raw", key, algorithm, false, [ + "sign" + ]); + const bytes = await getSubtle().sign(algorithm, cryptoKey, msg); + return new Uint8Array(bytes); } -function hmacSha256Verify( +async function hmacSha256Verify( key: ArrayBufferLike, msg: ArrayBufferLike, sig: ArrayBufferLike ): Promise { const algorithm = { name: "HMAC", hash: { name: "SHA-256" } }; const _key = getSubtle().importKey("raw", key, algorithm, false, ["verify"]); - return _key.then((cryptoKey) => - getSubtle().verify(algorithm, cryptoKey, sig, msg) - ); + const cryptoKey = await _key; + return await getSubtle().verify(algorithm, cryptoKey, sig, msg); } /** @@ -108,9 +110,11 @@ function derive(privateKeyA: Uint8Array, publicKeyB: Uint8Array): Uint8Array { } else if (publicKeyB[0] !== 4) { throw new Error("Bad public key, a valid public key would begin with 4"); } else { - const px = secp.getSharedSecret(privateKeyA, publicKeyB, true); + const privateKeyAHex = secpUtils.bytesToHex(privateKeyA); + const publicKeyBHex = secpUtils.bytesToHex(publicKeyB); + const px = getSharedSecret(privateKeyAHex, publicKeyBHex, true); // Remove the compression prefix - return new Uint8Array(hexToBytes(px).slice(1)); + return new Uint8Array(px.slice(1)); } } @@ -125,21 +129,21 @@ export async function encrypt( publicKeyTo: Uint8Array, msg: Uint8Array ): Promise { - const ephemPrivateKey = randomBytes(32); + const ephemPrivateKey = secpUtils.randomBytes(32); const sharedPx = derive(ephemPrivateKey, publicKeyTo); const hash = await kdf(sharedPx, 32); - const iv = randomBytes(16); + const iv = secpUtils.randomBytes(16); const encryptionKey = hash.slice(0, 16); const cipherText = await aesCtrEncrypt(iv, encryptionKey, msg); const ivCipherText = concat([iv, cipherText], iv.length + cipherText.length); - const macKey = await sha256(hash.slice(16)); + const macKey = await secpUtils.hmacSha256Async(hash.slice(16)); const hmac = await hmacSha256Sign(macKey, ivCipherText); - const ephemPublicKey = secp.getPublicKey(ephemPrivateKey, false); + const ephemPublicKey = getPublicKey(ephemPrivateKey, false); return concat( [ephemPublicKey, ivCipherText, hmac], @@ -181,9 +185,9 @@ export async function decrypt( // check HMAC const px = derive(privateKey, ephemPublicKey); const hash = await kdf(px, 32); - const [encryptionKey, macKey] = await sha256(hash.slice(16)).then( - (macKey) => [hash.slice(0, 16), macKey] - ); + const [encryptionKey, macKey] = await secpUtils + .hmacSha256Async(hash.slice(16)) + .then((macKey) => [hash.slice(0, 16), macKey]); if (!(await hmacSha256Verify(macKey, cipherAndIv, msgMac))) { throw new Error("Incorrect MAC"); diff --git a/packages/message-encryption/src/crypto/index.ts b/packages/message-encryption/src/crypto/index.ts index 78e23d7774..e65d62be80 100644 --- a/packages/message-encryption/src/crypto/index.ts +++ b/packages/message-encryption/src/crypto/index.ts @@ -1,7 +1,10 @@ import nodeCrypto from "crypto"; -import * as secp from "@noble/secp256k1"; -import { concat } from "@waku/utils/bytes"; +import { + getPublicKey, + sign as secpSign, + etc as secpUtils +} from "@noble/secp256k1"; import sha3 from "js-sha3"; import { Asymmetric, Symmetric } from "../constants.js"; @@ -24,30 +27,28 @@ export function getSubtle(): SubtleCrypto { } } -export const randomBytes = secp.utils.randomBytes; -export const sha256 = secp.utils.sha256; - /** * Generate a new private key to be used for asymmetric encryption. * * Use {@link getPublicKey} to get the corresponding Public Key. */ export function generatePrivateKey(): Uint8Array { - return randomBytes(Asymmetric.keySize); + return secpUtils.randomBytes(Asymmetric.keySize); } /** * Generate a new symmetric key to be used for symmetric encryption. */ + export function generateSymmetricKey(): Uint8Array { - return randomBytes(Symmetric.keySize); + return secpUtils.randomBytes(Symmetric.keySize); } /** * Return the public key for the given private key, to be used for asymmetric * encryption. */ -export const getPublicKey = secp.getPublicKey; +export { getPublicKey }; /** * ECDSA Sign a message with the given private key. @@ -61,14 +62,15 @@ export async function sign( message: Uint8Array, privateKey: Uint8Array ): Promise { - const [signature, recoveryId] = await secp.sign(message, privateKey, { - recovered: true, - der: false - }); - return concat( - [signature, new Uint8Array([recoveryId])], - signature.length + 1 - ); + const signatureObj = secpSign(message, privateKey); + const signature = signatureObj.toCompactRawBytes(); + const recoveryId = signatureObj.recovery; + + if (recoveryId === undefined) { + throw new Error("Recovery ID is undefined"); + } + + return new Uint8Array([...signature, recoveryId]); } export function keccak256(input: Uint8Array): Uint8Array { diff --git a/packages/message-encryption/src/crypto/symmetric.ts b/packages/message-encryption/src/crypto/symmetric.ts index 35f69f4558..0d7107dec1 100644 --- a/packages/message-encryption/src/crypto/symmetric.ts +++ b/packages/message-encryption/src/crypto/symmetric.ts @@ -1,6 +1,8 @@ +import { etc as secpUtils } from "@noble/secp256k1"; + import { Symmetric } from "../constants.js"; -import { getSubtle, randomBytes } from "./index.js"; +import { getSubtle } from "./index.js"; export async function encrypt( iv: Uint8Array, @@ -29,5 +31,5 @@ export async function decrypt( } export function generateIv(): Uint8Array { - return randomBytes(Symmetric.ivSize); + return secpUtils.randomBytes(Symmetric.ivSize); } diff --git a/packages/message-encryption/src/waku_payload.ts b/packages/message-encryption/src/waku_payload.ts index d68ec2a8d2..d5a0fc247d 100644 --- a/packages/message-encryption/src/waku_payload.ts +++ b/packages/message-encryption/src/waku_payload.ts @@ -1,9 +1,10 @@ import { sign, Signature } from "@noble/secp256k1"; +import { etc as secpUtils } from "@noble/secp256k1"; import { concat, hexToBytes } from "@waku/utils/bytes"; import { Symmetric } from "./constants.js"; import * as ecies from "./crypto/ecies.js"; -import { keccak256, randomBytes } from "./crypto/index.js"; +import { keccak256 } from "./crypto/index.js"; import * as symmetric from "./crypto/symmetric.js"; import { Signature as WakuSignature } from "./index.js"; @@ -190,7 +191,7 @@ export async function preCipher( const remainder = rawSize % PaddingTarget; const paddingSize = PaddingTarget - remainder; - const pad = randomBytes(paddingSize); + const pad = secpUtils.randomBytes(paddingSize); if (!validateDataIntegrity(pad, paddingSize)) { throw new Error("failed to generate random padding of size " + paddingSize); From e6bed26f105df0565b04412b9dc58caeb9973cc3 Mon Sep 17 00:00:00 2001 From: danisharora099 Date: Thu, 17 Aug 2023 22:15:16 +0530 Subject: [PATCH 4/6] readd tsdoc --- packages/enr/src/crypto.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/packages/enr/src/crypto.ts b/packages/enr/src/crypto.ts index 95cde87dbb..8d613ce594 100644 --- a/packages/enr/src/crypto.ts +++ b/packages/enr/src/crypto.ts @@ -7,6 +7,14 @@ import { import { concat } from "@waku/utils/bytes"; import sha3 from "js-sha3"; +/** + * ECDSA Sign a message with the given private key. + * + * @param message The message to sign, usually a hash. + * @param privateKey The ECDSA private key to use to sign the message. + * + * @returns The signature and the recovery id concatenated. + */ export async function sign( message: Uint8Array, privateKey: Uint8Array From 8c00c679795b01ad0138bcfc8c40711f1620bb7c Mon Sep 17 00:00:00 2001 From: danisharora099 Date: Thu, 17 Aug 2023 22:19:58 +0530 Subject: [PATCH 5/6] resolve typedoc --- packages/message-encryption/src/crypto/index.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/message-encryption/src/crypto/index.ts b/packages/message-encryption/src/crypto/index.ts index e65d62be80..b9160bfe4e 100644 --- a/packages/message-encryption/src/crypto/index.ts +++ b/packages/message-encryption/src/crypto/index.ts @@ -1,7 +1,7 @@ import nodeCrypto from "crypto"; import { - getPublicKey, + getPublicKey as secpGetPublicKey, sign as secpSign, etc as secpUtils } from "@noble/secp256k1"; @@ -48,7 +48,7 @@ export function generateSymmetricKey(): Uint8Array { * Return the public key for the given private key, to be used for asymmetric * encryption. */ -export { getPublicKey }; +export const getPublicKey = secpGetPublicKey; /** * ECDSA Sign a message with the given private key. From 0674a15c879cc0da341696eeaf79906fd8c81498 Mon Sep 17 00:00:00 2001 From: danisharora099 Date: Mon, 21 Aug 2023 13:59:46 +0530 Subject: [PATCH 6/6] shim crypto --- packages/message-encryption/src/crypto/index.ts | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/packages/message-encryption/src/crypto/index.ts b/packages/message-encryption/src/crypto/index.ts index b9160bfe4e..5c937901e5 100644 --- a/packages/message-encryption/src/crypto/index.ts +++ b/packages/message-encryption/src/crypto/index.ts @@ -10,16 +10,17 @@ import sha3 from "js-sha3"; import { Asymmetric, Symmetric } from "../constants.js"; declare const self: Record | undefined; -const crypto: { node?: any; web?: any } = { - node: nodeCrypto, - web: typeof self === "object" && "crypto" in self ? self.crypto : undefined -}; + +// Determine the correct crypto object for the environment +if (typeof self === "object" && "crypto" in self) { + globalThis.crypto = self.crypto; // Browser environment +} else { + globalThis.crypto = nodeCrypto.webcrypto as unknown as Crypto; // Node.js environment +} export function getSubtle(): SubtleCrypto { - if (crypto.web) { - return crypto.web.subtle; - } else if (crypto.node) { - return crypto.node.webcrypto.subtle; + if (globalThis.crypto && globalThis.crypto.subtle) { + return globalThis.crypto.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)"