From de0fdf15a59847e98052a84a7e5c3346157985c5 Mon Sep 17 00:00:00 2001 From: Nishant Ghodke <64554492+iamcrazycoder@users.noreply.github.com> Date: Fri, 3 Nov 2023 13:15:21 +0530 Subject: [PATCH] feat(sdk): integrate bip322-js to sign & verify non-legacy address messages (#91) * chore: install bip322-js lib * feat: use bip322 to sign non-legacy addr message also, use the same lib to verify non-legacy addr message * feat: allow non-legacy addresses to sign message * fix: pass missing WIF & network to msg signer also, remove compressed flag * refactor: restore fallback verification also, replace ternary expression w/ if block --- packages/sdk/package.json | 1 + .../browser-wallets/metamask/signatures.ts | 5 ++- packages/sdk/src/signatures/message.ts | 17 +++++---- packages/sdk/src/wallet/Ordit.ts | 7 +++- pnpm-lock.yaml | 37 +++++++++++++++++++ 5 files changed, 56 insertions(+), 11 deletions(-) diff --git a/packages/sdk/package.json b/packages/sdk/package.json index 6c8c74c6..b239a3d7 100644 --- a/packages/sdk/package.json +++ b/packages/sdk/package.json @@ -25,6 +25,7 @@ "dependencies": { "@bitcoinerlab/secp256k1": "1.0.2", "bip32": "4.0.0", + "bip322-js": "^1.1.0", "bip39": "3.1.0", "bitcoinjs-lib": "6.1.3", "bitcoinjs-message": "2.2.0", diff --git a/packages/sdk/src/browser-wallets/metamask/signatures.ts b/packages/sdk/src/browser-wallets/metamask/signatures.ts index c6087675..c8df4700 100644 --- a/packages/sdk/src/browser-wallets/metamask/signatures.ts +++ b/packages/sdk/src/browser-wallets/metamask/signatures.ts @@ -1,3 +1,4 @@ +import { Address, Signer } from "bip322-js" import { Psbt } from "bitcoinjs-lib" import { sign } from "bitcoinjs-message" import { ethers } from "ethers" @@ -86,7 +87,9 @@ export async function signMessage(options: SignMetaMaskMessageOptions) { const node = await getDerivedNodeFromMetaMaskSignature(signature, "", options.network) const { address: addressBtc } = createTransaction(node.parent.publicKey, "p2pkh", options.network) - const signedMessage = sign(options.message, node.parent.privateKey!) + const signedMessage = Address.isP2PKH(address) + ? sign(options.message, node.parent.privateKey!) + : Signer.sign(node.parent.privateKey!.toString(), address, options.message) return { hex: signedMessage.toString("hex"), diff --git a/packages/sdk/src/signatures/message.ts b/packages/sdk/src/signatures/message.ts index b4db0d29..041d27ae 100644 --- a/packages/sdk/src/signatures/message.ts +++ b/packages/sdk/src/signatures/message.ts @@ -1,3 +1,4 @@ +import { Address, Signer, Verifier } from "bip322-js" import { sign, verify } from "bitcoinjs-message" import { Network } from "../config/types" @@ -20,7 +21,9 @@ export async function signMessage(options: SignMessageOptions) { // const keyPair = EcPair.fromWIF(wif); const { address } = createTransaction(parent.publicKey, "p2pkh", network) - const signature = sign(options.message, parent.privateKey!) + const signature = Address.isP2PKH(address!) + ? sign(options.message, parent.privateKey!) + : Signer.sign(parent.privateKey!.toString(), address!, options.message) return { hex: signature.toString("hex"), @@ -34,15 +37,13 @@ export async function signMessage(options: SignMessageOptions) { export function verifyMessage(options: VerifyMessageOptions) { try { - let isValid = verify(options.message, options.address, options.signature) - - if (!isValid) { - isValid = fallbackVerification(options) + if (Address.isP2PKH(options.address)) { + return !verify(options.message, options.address, options.signature) ? fallbackVerification(options) : true } - return isValid - } catch (error) { - return fallbackVerification(options) + return Verifier.verifySignature(options.address, options.message, options.signature) + } catch (_) { + return false } } diff --git a/packages/sdk/src/wallet/Ordit.ts b/packages/sdk/src/wallet/Ordit.ts index 91066ad8..e55bd482 100644 --- a/packages/sdk/src/wallet/Ordit.ts +++ b/packages/sdk/src/wallet/Ordit.ts @@ -1,6 +1,7 @@ import * as ecc from "@bitcoinerlab/secp256k1" import BIP32Factory, { BIP32Interface } from "bip32" import { mnemonicToSeedSync } from "bip39" +import { Address as BIP22Address, Signer } from "bip322-js" import * as bitcoin from "bitcoinjs-lib" import { isTaprootInput } from "bitcoinjs-lib/src/psbt/bip371" import { sign } from "bitcoinjs-message" @@ -231,8 +232,10 @@ export class Ordit { } signMessage(message: string) { - const legacyWallet = this.allAddresses.find((wallet) => wallet.format === "legacy") as Account - const signature = sign(message, legacyWallet.child.privateKey!, false) + const node = this.allAddresses.find((wallet) => wallet.format === this.selectedAddressType) as Account + const signature = BIP22Address.isP2PKH(node.address!) + ? sign(message, node.child.privateKey!) + : Signer.sign(node.child.toWIF(), node.address!, message, getNetwork(this.#network)) return signature.toString("base64") } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 719c5f33..3c6cf319 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -32,6 +32,9 @@ importers: bip32: specifier: 4.0.0 version: 4.0.0 + bip322-js: + specifier: ^1.1.0 + version: 1.1.0 bip39: specifier: 3.1.0 version: 3.1.0 @@ -531,6 +534,17 @@ packages: engines: {node: '>=8.0.0'} dev: false + /bip322-js@1.1.0: + resolution: {integrity: sha512-Nxyw4lnhh4qm/zitfagJYpO7HofkABbt7Cce+Wiy4PGeilJ/hOvtqM0pxmTZxMoOhRnvDPZ55NzkFPrsyq43ew==} + dependencies: + '@bitcoinerlab/secp256k1': 1.0.2 + bitcoinjs-lib: 6.1.3 + bitcoinjs-message: 2.2.0 + ecpair: 2.1.0 + fast-sha256: 1.3.0 + secp256k1: 5.0.0 + dev: false + /bip32@4.0.0: resolution: {integrity: sha512-aOGy88DDlVUhspIXJN+dVEtclhIsfAUppD43V0j40cPTld3pv/0X/MlrZSZ6jowIaQQzFwP8M6rFU2z2mVYjDQ==} engines: {node: '>=6.0.0'} @@ -1207,6 +1221,10 @@ packages: resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} dev: true + /fast-sha256@1.3.0: + resolution: {integrity: sha512-n11RGP/lrWEFI/bWdygLxhI+pVeo1ZYIVwvvPkW7azl/rOy+F3HYRZ2K5zeE9mmkhQppyv9sQFx0JM9UabnpPQ==} + dev: false + /fastq@1.15.0: resolution: {integrity: sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==} dependencies: @@ -1812,6 +1830,10 @@ packages: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} dev: true + /node-addon-api@5.1.0: + resolution: {integrity: sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA==} + dev: false + /node-fetch@2.6.11: resolution: {integrity: sha512-4I6pdBY1EthSqDmJkiNk3JIT8cswwR9nfeW/cPdUagJYEQG7R95WRH74wpz7ma8Gh/9dI9FP+OU+0E4FvtA55w==} engines: {node: 4.x || >=6.0.0} @@ -1824,6 +1846,11 @@ packages: whatwg-url: 5.0.0 dev: false + /node-gyp-build@4.6.1: + resolution: {integrity: sha512-24vnklJmyRS8ViBNI8KbtK/r/DmXQMRiOMXTNz2nrTnAYUwjmEEbnnpB/+kt+yWRv73bPsSPRFddrcIbAxSiMQ==} + hasBin: true + dev: false + /normalize-package-data@3.0.3: resolution: {integrity: sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==} engines: {node: '>=10'} @@ -2100,6 +2127,16 @@ packages: safe-buffer: 5.2.1 dev: false + /secp256k1@5.0.0: + resolution: {integrity: sha512-TKWX8xvoGHrxVdqbYeZM9w+izTF4b9z3NhSaDkdn81btvuh+ivbIMGT/zQvDtTFWhRlThpoz6LEYTr7n8A5GcA==} + engines: {node: '>=14.0.0'} + requiresBuild: true + dependencies: + elliptic: 6.5.4 + node-addon-api: 5.1.0 + node-gyp-build: 4.6.1 + dev: false + /semver@6.3.0: resolution: {integrity: sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==} hasBin: true