diff --git a/package.json b/package.json index 2ceae76..71c6c6a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "silent-payments", - "version": "0.3.3", + "version": "0.3.4", "description": "BIP-352", "main": "src/index.ts", "scripts": { diff --git a/src/index.ts b/src/index.ts index c02e830..50e0793 100644 --- a/src/index.ts +++ b/src/index.ts @@ -94,7 +94,7 @@ export class SilentPayment { const Pmk = Buffer.from(ecc.pointAdd(ecc.pointMultiply(G, tk) as Uint8Array, Bm) as Uint8Array); // Encode Pmk as a BIP341 taproot output - const address = Pmk.slice(1).toString("hex"); + const address = SilentPayment.pubkeyToAddress(Pmk.slice(1).toString("hex")); const newTarget: Target = { address }; newTarget.value = amount; ret.push(newTarget); @@ -194,4 +194,13 @@ export class SilentPayment { return true; } + + static pubkeyToAddress(hex: string): string { + const publicKey = Buffer.from("5120" + hex, "hex"); + return bitcoin.address.fromOutputScript(publicKey, bitcoin.networks.bitcoin); + } + + static addressToPubkey(address: string): string { + return bitcoin.address.toOutputScript(address).subarray(2).toString("hex"); + } } diff --git a/tests/silent-payment.test.ts b/tests/silent-payment.test.ts index 57dd5ff..27a0336 100644 --- a/tests/silent-payment.test.ts +++ b/tests/silent-payment.test.ts @@ -69,7 +69,7 @@ tests.forEach((testCase, index) => { }).toThrow("No eligible UTXOs with private keys found"); } else { const generated = sp.createTransaction(utxos, recipients); - const generated_pubkeys: string[] = generated.map((obj) => obj.address).filter(Boolean) as string[]; + const generated_pubkeys: string[] = generated.map((obj) => SilentPayment.addressToPubkey(String(obj.address))).filter(Boolean) as string[]; assert(matchSubset(generated_pubkeys, sending.expected.outputs)); } }); @@ -176,3 +176,15 @@ it("can validate payment code", () => { assert.ok(!SilentPayment.isPaymentCodeValid("qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv")); // no prefix assert.ok(!SilentPayment.isPaymentCodeValid("qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv123")); // no prefix }); + +it("can turn pubkey into taproot address", () => { + assert.strictEqual(SilentPayment.pubkeyToAddress("40ef293a8a0ebaf8b351a27d89ff4b5b3822a635e4afdca77a30170c363bafa3"), "bc1pgrhjjw52p6a03v635f7cnl6ttvuz9f34ujhaefm6xqtscd3m473szkl92g"); + + expect(() => { + SilentPayment.pubkeyToAddress("512040ef293a8a0ebaf8b351a27d89ff4b5b3822a635e4afdca77a30170c363bafa3"); + }).toThrow(/has no matching Address/); +}); + +it("can turn taproot address into pubkey", () => { + assert.strictEqual(SilentPayment.addressToPubkey("bc1pgrhjjw52p6a03v635f7cnl6ttvuz9f34ujhaefm6xqtscd3m473szkl92g"), "40ef293a8a0ebaf8b351a27d89ff4b5b3822a635e4afdca77a30170c363bafa3"); +});