From e022bdc38f7ecbbdd8cbb0403c1ed1cf7e996f7b Mon Sep 17 00:00:00 2001 From: Rafal Czajkowski Date: Wed, 6 Sep 2023 16:01:07 +0200 Subject: [PATCH 1/3] Get rid of `bcrypto` dependency We use `bcrypto` to compute hashes, but since this library is a bit problematic, here we replace it with hashing algorithms from the `ethers` library. `ethers` has no `hash160` algorithm but under the hood `HASH160 = RIPEMD160(SHA256(X))` so it's possible to compute `hash160` using `ethers`. --- typescript/package.json | 1 - typescript/src/bitcoin.ts | 16 ++++++++++------ typescript/src/electrum.ts | 8 +++++--- typescript/typings.d.ts | 2 -- typescript/yarn.lock | 2 +- 5 files changed, 16 insertions(+), 13 deletions(-) diff --git a/typescript/package.json b/typescript/package.json index b1be0c883..936b81f28 100644 --- a/typescript/package.json +++ b/typescript/package.json @@ -28,7 +28,6 @@ "@keep-network/ecdsa": "development", "@keep-network/tbtc-v2": "development", "bcoin": "git+https://github.com/keep-network/bcoin.git#5accd32c63e6025a0d35d67739c4a6e84095a1f8", - "bcrypto": "git+https://github.com/bcoin-org/bcrypto.git#semver:~5.5.0", "bufio": "^1.0.6", "electrum-client-js": "git+https://github.com/keep-network/electrum-client-js.git#v0.1.1", "ethers": "^5.5.2", diff --git a/typescript/src/bitcoin.ts b/typescript/src/bitcoin.ts index a46a4792b..88284dcad 100644 --- a/typescript/src/bitcoin.ts +++ b/typescript/src/bitcoin.ts @@ -1,9 +1,7 @@ import bcoin, { TX, Script } from "bcoin" import wif from "wif" import bufio from "bufio" -import hash160 from "bcrypto/lib/hash160" -import sha256 from "bcrypto/lib/sha256-browser.js" -import { BigNumber } from "ethers" +import { BigNumber, utils } from "ethers" import { Hex } from "./hex" import { BitcoinNetwork, toBcoinNetwork } from "./bitcoin-network" @@ -525,7 +523,12 @@ export function createKeyRing( * @returns Hash as a 20-byte un-prefixed hex string. */ export function computeHash160(text: string): string { - return hash160.digest(Buffer.from(text, "hex")).toString("hex") + const sha256Hash = utils.sha256( + Hex.from(Buffer.from(text, "hex")).toPrefixedString() + ) + const hash160 = utils.ripemd160(sha256Hash) + + return Hex.from(hash160).toString() } /** @@ -534,8 +537,9 @@ export function computeHash160(text: string): string { * @returns Hash as a 32-byte un-prefixed hex string. */ export function computeHash256(text: Hex): Hex { - const firstHash: Buffer = sha256.digest(text.toBuffer()) - const secondHash: Buffer = sha256.digest(firstHash) + const firstHash = utils.sha256(text.toPrefixedString()) + const secondHash = utils.sha256(firstHash) + return Hex.from(secondHash) } diff --git a/typescript/src/electrum.ts b/typescript/src/electrum.ts index 022ccce2a..e942aac3b 100644 --- a/typescript/src/electrum.ts +++ b/typescript/src/electrum.ts @@ -13,8 +13,7 @@ import { } from "./bitcoin" import { BitcoinNetwork } from "./bitcoin-network" import Electrum from "electrum-client-js" -import sha256 from "bcrypto/lib/sha256-browser.js" -import { BigNumber } from "ethers" +import { BigNumber, utils } from "ethers" import { URL } from "url" import { Hex } from "./hex" import { backoffRetrier, RetrierFn } from "./backoff" @@ -557,5 +556,8 @@ export class Client implements BitcoinClient { * @returns Electrum script hash as a hex string. */ function computeScriptHash(script: string): string { - return sha256.digest(Buffer.from(script, "hex")).reverse().toString("hex") + const _script = Hex.from(Buffer.from(script, "hex")).toPrefixedString() + const hash256 = utils.sha256(_script) + + return Hex.from(hash256).reverse().toString() } diff --git a/typescript/typings.d.ts b/typescript/typings.d.ts index 7517bbb08..2558e6a79 100644 --- a/typescript/typings.d.ts +++ b/typescript/typings.d.ts @@ -3,8 +3,6 @@ * don't provide their own typings. */ declare module "bcoin" -declare module "bcrypto/lib/hash160" -declare module "bcrypto/lib/sha256-browser.js" declare module "bufio" declare module "electrum-client-js" declare module "wif" diff --git a/typescript/yarn.lock b/typescript/yarn.lock index 561d0069a..d305c9069 100644 --- a/typescript/yarn.lock +++ b/typescript/yarn.lock @@ -1522,7 +1522,7 @@ "@openzeppelin/upgrades" "^2.7.2" openzeppelin-solidity "2.4.0" -"@keep-network/keep-ecdsa@1.9.0-dev.1", "@keep-network/keep-ecdsa@>1.9.0-dev <1.9.0-ropsten": +"@keep-network/keep-ecdsa@>1.9.0-dev <1.9.0-ropsten": version "1.9.0-dev.1" resolved "https://registry.yarnpkg.com/@keep-network/keep-ecdsa/-/keep-ecdsa-1.9.0-dev.1.tgz#7522b47dd639ddd7479a0e71dc328a9e0bba7cae" integrity sha512-FRIDejTUiQO7c9gBXgjtTp2sXkEQKFBBqVjYoZE20OCGRxbgum9FbgD/B5RWIctBy4GGr5wJHnA1789iaK3X6A== From 85c1a4564c3ffd1113f57c705c012fa08e0b8b8a Mon Sep 17 00:00:00 2001 From: michalsmiarowski Date: Tue, 19 Sep 2023 11:02:52 +0200 Subject: [PATCH 2/3] Add basic tests to compute hashes functions Adds basic tests to `computeHash160`, `computeHash256` and `computeScriptHash` functions so that we are sure they are working exactly the same as when we used `bcrypto` library inside them. --- typescript/src/electrum.ts | 2 +- typescript/test/bitcoin.test.ts | 27 +++++++++++++++++++++++++++ typescript/test/electrum.test.ts | 11 +++++++++++ 3 files changed, 39 insertions(+), 1 deletion(-) diff --git a/typescript/src/electrum.ts b/typescript/src/electrum.ts index e942aac3b..70d47d256 100644 --- a/typescript/src/electrum.ts +++ b/typescript/src/electrum.ts @@ -555,7 +555,7 @@ export class Client implements BitcoinClient { * @param script - Bitcoin script as hex string * @returns Electrum script hash as a hex string. */ -function computeScriptHash(script: string): string { +export function computeScriptHash(script: string): string { const _script = Hex.from(Buffer.from(script, "hex")).toPrefixedString() const hash256 = utils.sha256(_script) diff --git a/typescript/test/bitcoin.test.ts b/typescript/test/bitcoin.test.ts index 748e39004..80eebfda5 100644 --- a/typescript/test/bitcoin.test.ts +++ b/typescript/test/bitcoin.test.ts @@ -14,6 +14,8 @@ import { createOutputScriptFromAddress, createAddressFromOutputScript, readCompactSizeUint, + computeHash160, + computeHash256, } from "../src/bitcoin" import { calculateDepositRefundLocktime } from "../src/deposit" import { BitcoinNetwork } from "../src/bitcoin-network" @@ -66,6 +68,31 @@ describe("Bitcoin", () => { }) }) + describe("computeHash160", () => { + it("should compute hash160 correctly", () => { + const compressedPublicKey = + "03474444cca71c678f5019d16782b6522735717a94602085b4adf707b465c36ca8" + const expectedHash160 = "3e1dfbd72483fb3964ca828ee71cf3270cafdc65" + + expect(computeHash160(compressedPublicKey)).to.be.equal(expectedHash160) + }) + }) + + describe("computeHash256", () => { + it("should compute hash256 correctly", () => { + const hexValue = Hex.from( + "03474444cca71c678f5019d16782b6522735717a94602085b4adf707b465c36ca8" + ) + const expectedHash256 = Hex.from( + "9f0b7447ca6ea11b8badd8a60a4dec1b846451551ef455975b1720f52bc90546" + ) + + expect(computeHash256(hexValue).toString()).to.be.equal( + expectedHash256.toString() + ) + }) + }) + describe("P2PKH <-> public key hash conversion", () => { const publicKeyHash = "3a38d44d6a0c8d0bb84e0232cc632b7e48c72e0e" const P2WPKHAddress = "bc1q8gudgnt2pjxshwzwqgevccet0eyvwtswt03nuy" diff --git a/typescript/test/electrum.test.ts b/typescript/test/electrum.test.ts index 09fca2c2d..e0ad8909b 100644 --- a/typescript/test/electrum.test.ts +++ b/typescript/test/electrum.test.ts @@ -1,6 +1,7 @@ import { Credentials as ElectrumCredentials, Client as ElectrumClient, + computeScriptHash, } from "../src/electrum" import { BitcoinNetwork } from "../src/bitcoin-network" import { @@ -217,6 +218,16 @@ describe("Electrum", () => { expect(result).to.be.eql(testnetTransactionMerkleBranch) }) }) + + describe("computeScriptHash", () => { + it("should convert Bitcoin script to an Electrum script hash correctly", () => { + const script = "00144b47c798d12edd17dfb4ea98e5447926f664731c" + const expectedScriptHash = + "cabdea0bfc10fb3521721dde503487dd1f0e41dd6609da228066757563f292ab" + + expect(computeScriptHash(script)).to.be.equal(expectedScriptHash) + }) + }) }) }) From e019dd104ecc962a765fe7989b7b6c1fb0ff5c42 Mon Sep 17 00:00:00 2001 From: Tomasz Slabon Date: Fri, 15 Sep 2023 16:05:19 +0200 Subject: [PATCH 3/3] Added bitcoinjs-lib in version 6.0.2 --- typescript/package.json | 1 + typescript/yarn.lock | 37 ++++++++++++++++++++++++++++++++++--- 2 files changed, 35 insertions(+), 3 deletions(-) diff --git a/typescript/package.json b/typescript/package.json index 936b81f28..7cecbf2c0 100644 --- a/typescript/package.json +++ b/typescript/package.json @@ -28,6 +28,7 @@ "@keep-network/ecdsa": "development", "@keep-network/tbtc-v2": "development", "bcoin": "git+https://github.com/keep-network/bcoin.git#5accd32c63e6025a0d35d67739c4a6e84095a1f8", + "bitcoinjs-lib": "6.0.2", "bufio": "^1.0.6", "electrum-client-js": "git+https://github.com/keep-network/electrum-client-js.git#v0.1.1", "ethers": "^5.5.2", diff --git a/typescript/yarn.lock b/typescript/yarn.lock index d305c9069..f2778ae49 100644 --- a/typescript/yarn.lock +++ b/typescript/yarn.lock @@ -2575,6 +2575,11 @@ bech32@1.1.4: resolved "https://registry.yarnpkg.com/bech32/-/bech32-1.1.4.tgz#e38c9f37bf179b8eb16ae3a772b40c356d4832e9" integrity sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ== +bech32@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/bech32/-/bech32-2.0.0.tgz#078d3686535075c8c79709f054b1b226a133b355" + integrity sha512-LcknSilhIGatDAsY1ak2I8VtGaHNhgMSYVxFrGLXv+xLHytaKZKcaUJJUE7qmBr7h33o5YQwP55pMI0xmkpJwg== + "bevent@git+https://github.com/bcoin-org/bevent.git#semver:~0.1.5": version "0.1.5" resolved "git+https://github.com/bcoin-org/bevent.git#60fb503de3ea1292d29ce438bfba80f0bc5ccb60" @@ -2639,6 +2644,11 @@ bindings@^1.3.0: bs32 "~0.1.5" bsert "~0.0.10" +bip174@^2.0.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/bip174/-/bip174-2.1.1.tgz#ef3e968cf76de234a546962bcf572cc150982f9f" + integrity sha512-mdFV5+/v0XyNYXjBS6CQPLo9ekCx4gtKZFnJm5PMto7Fs9hTTDpkkzOB7/FtluRI6JbUUAu+snTYfJRgHLZbZQ== + bip32@2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/bip32/-/bip32-2.0.5.tgz#e3808a9e97a880dbafd0f5f09ca4a1e14ee275d2" @@ -2681,6 +2691,20 @@ bip39@3.0.4: pbkdf2 "^3.0.9" randombytes "^2.0.1" +bitcoinjs-lib@6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/bitcoinjs-lib/-/bitcoinjs-lib-6.0.2.tgz#0fdf6c41978d93641b936d66f4afce44bb9b7f35" + integrity sha512-I994pGt9cL5s5OA6mkv1e8IuYcsKN2ORXnWbkqAXLNGvEnOHBhKBSvCjFl7YC2uVoJnfr/iwq7JMrq575SYO5w== + dependencies: + bech32 "^2.0.0" + bip174 "^2.0.1" + bs58check "^2.1.2" + create-hash "^1.1.0" + ripemd160 "^2.0.2" + typeforce "^1.11.3" + varuint-bitcoin "^1.1.2" + wif "^2.0.1" + bl@^1.0.0: version "1.2.3" resolved "https://registry.yarnpkg.com/bl/-/bl-1.2.3.tgz#1e8dd80142eac80d7158c9dccc047fb620e035e7" @@ -6902,7 +6926,7 @@ rimraf@^3.0.2: dependencies: glob "^7.1.3" -ripemd160@^2.0.0, ripemd160@^2.0.1: +ripemd160@^2.0.0, ripemd160@^2.0.1, ripemd160@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c" integrity sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA== @@ -7746,7 +7770,7 @@ typedarray-to-buffer@^3.1.5: dependencies: is-typedarray "^1.0.0" -typeforce@^1.11.5: +typeforce@^1.11.3, typeforce@^1.11.5: version "1.18.0" resolved "https://registry.yarnpkg.com/typeforce/-/typeforce-1.18.0.tgz#d7416a2c5845e085034d70fcc5b6cc4a90edbfdc" integrity sha512-7uc1O8h1M1g0rArakJdf0uLRSSgFcYexrVoKo+bzJd32gd4gDy2L/Z+8/FjPnU9ydY3pEnVPtr9FyscYY60K1g== @@ -7932,6 +7956,13 @@ varint@^5.0.0: resolved "https://registry.yarnpkg.com/varint/-/varint-5.0.2.tgz#5b47f8a947eb668b848e034dcfa87d0ff8a7f7a4" integrity sha512-lKxKYG6H03yCZUpAGOPOsMcGxd1RHCu1iKvEHYDPmTyq2HueGhD73ssNBqqQWfvYs04G9iUFRvmAVLW20Jw6ow== +varuint-bitcoin@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/varuint-bitcoin/-/varuint-bitcoin-1.1.2.tgz#e76c138249d06138b480d4c5b40ef53693e24e92" + integrity sha512-4EVb+w4rx+YfVM32HQX42AbbT7/1f5zwAYhIujKXKk8NQK+JfRVl3pqT3hjNn/L+RstigmGGKVwHA/P0wgITZw== + dependencies: + safe-buffer "^5.1.1" + vary@^1, vary@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" @@ -8770,7 +8801,7 @@ wide-align@1.1.3: dependencies: string-width "^1.0.2 || 2" -wif@2.0.6, wif@^2.0.6: +wif@2.0.6, wif@^2.0.1, wif@^2.0.6: version "2.0.6" resolved "https://registry.yarnpkg.com/wif/-/wif-2.0.6.tgz#08d3f52056c66679299726fade0d432ae74b4704" integrity sha1-CNP1IFbGZnkplyb63g1DKudLRwQ=