From 5ddd3e7bac817419397552adb2cd1174bcaaffa8 Mon Sep 17 00:00:00 2001 From: Anmol Sharma Date: Sun, 3 Mar 2024 11:52:58 +0530 Subject: [PATCH] feat: update scanning to match specification in BIP352 Signed-off-by: Anmol Sharma --- packages/core/src/scanning.ts | 14 +- packages/core/test/fixtures/scanning.ts | 502 +++++++++++++++--------- packages/core/test/scanning.spec.ts | 14 +- 3 files changed, 329 insertions(+), 201 deletions(-) diff --git a/packages/core/src/scanning.ts b/packages/core/src/scanning.ts index 2db0b96..d48c871 100644 --- a/packages/core/src/scanning.ts +++ b/packages/core/src/scanning.ts @@ -1,7 +1,6 @@ -import { serialiseUint32 } from './utility.ts'; +import { createTaggedHash, serialiseUint32 } from './utility.ts'; import { LabelMap } from './interface.ts'; import secp256k1 from 'secp256k1'; -import createHash from 'create-hash'; import { Buffer } from 'buffer'; // Handle additional label-related logic @@ -78,13 +77,13 @@ export const scanOutputs = ( scanPrivateKey: Buffer, spendPublicKey: Buffer, sumOfInputPublicKeys: Buffer, - outpointHash: Buffer, + inputHash: Buffer, outputs: Buffer[], labels?: LabelMap, ): Map => { const ecdhSecret = secp256k1.publicKeyTweakMul( sumOfInputPublicKeys, - secp256k1.privateKeyTweakMul(scanPrivateKey, outpointHash), + secp256k1.privateKeyTweakMul(scanPrivateKey, inputHash), true, ); @@ -94,9 +93,10 @@ export const scanOutputs = ( let counterIncrement = 0; do { - const tweak = createHash('sha256') - .update(Buffer.concat([ecdhSecret, serialiseUint32(n)])) - .digest(); + const tweak = createTaggedHash( + 'BIP0352/SharedSecret', + Buffer.concat([ecdhSecret, serialiseUint32(n)]), + ); counterIncrement = processTweak( spendPublicKey, tweak, diff --git a/packages/core/test/fixtures/scanning.ts b/packages/core/test/fixtures/scanning.ts index 00a778d..8a80c51 100644 --- a/packages/core/test/fixtures/scanning.ts +++ b/packages/core/test/fixtures/scanning.ts @@ -1,416 +1,544 @@ export const testData = [ { + description: 'Simple send: two inputs', scanPrivateKey: '0f694e068028a717f8af6b9411f9a133dd3565258714cc226594b34db90c1f2c', spendPublicKey: '025cc9856d6f8375350e123978daac200c260cb5b5ae83106cab90484dcd8fcf36', sumOfInputPublicKeys: '032562c1ab2d6bd45d7ca4d78f569999e5333dffd3ac5263924fd00d00dedc4bee', - outpointHash: - '210fef5d624db17c965c7597e2c6c9f60ef440c831d149c43567c50158557f12', + inputHash: + '5bfe5321d759e01a2ac9292f0f396ff9c3d8b58d89ccb21a6922e84bb7ad0668', outputs: [ - '0239a1e5ff6206cd316151b9b34cee4f80bb48ce61adee0a12ce7ff05ea436a1d9', + '023e9fce73d4e77a4809908e3c3a2e54ee147b9312dc5044a193d1fc85de46e3c1', ], - matches: { - '0239a1e5ff6206cd316151b9b34cee4f80bb48ce61adee0a12ce7ff05ea436a1d9': - '8e4bbee712779f746337cadf39e8b1eab8e8869dd40f2e3a7281113e858ffc0b', + labels: {}, + expected: { + '023e9fce73d4e77a4809908e3c3a2e54ee147b9312dc5044a193d1fc85de46e3c1': + 'f438b40179a3c4262de12986c0e6cce0634007cdc79c1dcd3e20b9ebc2e7eef6', }, }, { + description: 'Simple send: two inputs, order reversed', scanPrivateKey: '0f694e068028a717f8af6b9411f9a133dd3565258714cc226594b34db90c1f2c', spendPublicKey: '025cc9856d6f8375350e123978daac200c260cb5b5ae83106cab90484dcd8fcf36', sumOfInputPublicKeys: '032562c1ab2d6bd45d7ca4d78f569999e5333dffd3ac5263924fd00d00dedc4bee', - outpointHash: - '210fef5d624db17c965c7597e2c6c9f60ef440c831d149c43567c50158557f12', + inputHash: + '5bfe5321d759e01a2ac9292f0f396ff9c3d8b58d89ccb21a6922e84bb7ad0668', outputs: [ - '0239a1e5ff6206cd316151b9b34cee4f80bb48ce61adee0a12ce7ff05ea436a1d9', + '023e9fce73d4e77a4809908e3c3a2e54ee147b9312dc5044a193d1fc85de46e3c1', ], - matches: { - '0239a1e5ff6206cd316151b9b34cee4f80bb48ce61adee0a12ce7ff05ea436a1d9': - '8e4bbee712779f746337cadf39e8b1eab8e8869dd40f2e3a7281113e858ffc0b', + labels: {}, + expected: { + '023e9fce73d4e77a4809908e3c3a2e54ee147b9312dc5044a193d1fc85de46e3c1': + 'f438b40179a3c4262de12986c0e6cce0634007cdc79c1dcd3e20b9ebc2e7eef6', }, }, { + description: 'Simple send: two inputs from the same transaction', scanPrivateKey: '0f694e068028a717f8af6b9411f9a133dd3565258714cc226594b34db90c1f2c', spendPublicKey: '025cc9856d6f8375350e123978daac200c260cb5b5ae83106cab90484dcd8fcf36', sumOfInputPublicKeys: '032562c1ab2d6bd45d7ca4d78f569999e5333dffd3ac5263924fd00d00dedc4bee', - outpointHash: - 'dd7d2a8678cb65b52119af415b578437f5dfc0d9f5bf2daac5e25c21bf0731ce', + inputHash: + 'ca70029b1ca2b9730f341c5bff0c79987213d2ee49f2285958bc0d2df387e851', outputs: [ - '02162f2298705b3ddca01ce1d214eedff439df3927582938d08e29e464908db00b', + '0279e71baa2ba3fc66396de3a04f168c7bf24d6870ec88ca877754790c1db357b6', ], - matches: { - '02162f2298705b3ddca01ce1d214eedff439df3927582938d08e29e464908db00b': - 'f06d8d90561bdbc3e511c3bec7355ad3c858aaf38a132c772d6cd82ec04102ac', + labels: {}, + expected: { + '0279e71baa2ba3fc66396de3a04f168c7bf24d6870ec88ca877754790c1db357b6': + '4851455bfbe1ab4f80156570aa45063201aa5c9e1b1dcd29f0f8c33d10bf77ae', }, }, { + description: + 'Simple send: two inputs from the same transaction, order reversed', scanPrivateKey: '0f694e068028a717f8af6b9411f9a133dd3565258714cc226594b34db90c1f2c', spendPublicKey: '025cc9856d6f8375350e123978daac200c260cb5b5ae83106cab90484dcd8fcf36', sumOfInputPublicKeys: '032562c1ab2d6bd45d7ca4d78f569999e5333dffd3ac5263924fd00d00dedc4bee', - outpointHash: - '1b85dfe15f0d5e1cedd47bdd70c24ecb0e3401c0a2ace659c422916626b66bce', + inputHash: + '402afc065566490b102de1bf599f2f0e045d1379c31945e69ea55f366664a1b1', outputs: [ - '02d9ede52f7e1e64e36ccf895ca0250daad96b174987079c903519b17852b21a3f', + '02f4c2da807f89cb1501f1a77322a895acfb93c28e08ed2724d2beb8e44539ba38', ], - matches: { - '02d9ede52f7e1e64e36ccf895ca0250daad96b174987079c903519b17852b21a3f': - '44b827516c2128287b1d571add7cfeb42f122e86bc40b4eb2b21ac144607fdb2', + labels: {}, + expected: { + '02f4c2da807f89cb1501f1a77322a895acfb93c28e08ed2724d2beb8e44539ba38': + 'ab0c9b87181bf527879f48db9f14a02233619b986f8e8f2d5d408ce68a709f51', }, }, { + description: + 'Single recipient: multiple UTXOs from the same public key', scanPrivateKey: '0f694e068028a717f8af6b9411f9a133dd3565258714cc226594b34db90c1f2c', spendPublicKey: '025cc9856d6f8375350e123978daac200c260cb5b5ae83106cab90484dcd8fcf36', sumOfInputPublicKeys: '03e40664e222ba71e29b80efc907fa22a3c6c64f45e89dbb8511dc7a3712b0a186', - outpointHash: - '210fef5d624db17c965c7597e2c6c9f60ef440c831d149c43567c50158557f12', + inputHash: + '37245a9f8355f4064f385fefeac00c022952acc75e5caec6321f066e113397b4', outputs: [ - '020aafdcdb5893ae813299b16eea75f34ec16653ac39171da04d7c4e6d2e09ab8e', + '02548ae55c8eec1e736e8d3e520f011f1f42a56d166116ad210b3937599f87f566', ], - matches: { - '020aafdcdb5893ae813299b16eea75f34ec16653ac39171da04d7c4e6d2e09ab8e': - 'bf7336bdc02f624715aab385cc62b71f6f494bf8a7dd0fd621cfd365039c39d1', + labels: {}, + expected: { + '02548ae55c8eec1e736e8d3e520f011f1f42a56d166116ad210b3937599f87f566': + 'f032695e2636619efa523fffaa9ef93c8802299181fd0461913c1b8daf9784cd', }, }, { + description: 'Single recipient: taproot only inputs with even y-values', scanPrivateKey: '0f694e068028a717f8af6b9411f9a133dd3565258714cc226594b34db90c1f2c', spendPublicKey: '025cc9856d6f8375350e123978daac200c260cb5b5ae83106cab90484dcd8fcf36', sumOfInputPublicKeys: '038180a2125f9d6dd116e1a6139be4d72fd5057dab6aaabaa5654817c11baeb3ba', - outpointHash: - '210fef5d624db17c965c7597e2c6c9f60ef440c831d149c43567c50158557f12', + inputHash: + 'd0736c3e1f5b40765a6f6898eb489611fa71229f2fcfbb2a34042d5fca0757d8', outputs: [ - '0215d1dfe4403791509cf47f073be2eb3277decabe90da395e63b1f49a09fe965e', + '02de88bea8e7ffc9ce1af30d1132f910323c505185aec8eae361670421e749a1fb', ], - matches: { - '0215d1dfe4403791509cf47f073be2eb3277decabe90da395e63b1f49a09fe965e': - '0734de077e436e8f6f125e16287cb60dead8ebddc8532be3589ba27156f1add2', + labels: {}, + expected: { + '02de88bea8e7ffc9ce1af30d1132f910323c505185aec8eae361670421e749a1fb': + '3fb9ce5ce1746ced103c8ed254e81f6690764637ddbc876ec1f9b3ddab776b03', }, }, { + description: + 'Single recipient: taproot only with mixed even/odd y-values', scanPrivateKey: '0f694e068028a717f8af6b9411f9a133dd3565258714cc226594b34db90c1f2c', spendPublicKey: '025cc9856d6f8375350e123978daac200c260cb5b5ae83106cab90484dcd8fcf36', sumOfInputPublicKeys: - '038180a2125f9d6dd116e1a6139be4d72fd5057dab6aaabaa5654817c11baeb3ba', - outpointHash: - '210fef5d624db17c965c7597e2c6c9f60ef440c831d149c43567c50158557f12', + '020f0ab50f420ab1249bc2a21659c607f2873400853035aad0ca6d0ded04d62623', + inputHash: + 'c166992ca52854ebb5008ebea00586a08b19aef88d74cb0235ffa4090f52e2ed', outputs: [ - '0215d1dfe4403791509cf47f073be2eb3277decabe90da395e63b1f49a09fe965e', + '0277cab7dd12b10259ee82c6ea4b509774e33e7078e7138f568092241bf26b99f1', ], - matches: { - '0215d1dfe4403791509cf47f073be2eb3277decabe90da395e63b1f49a09fe965e': - '0734de077e436e8f6f125e16287cb60dead8ebddc8532be3589ba27156f1add2', + labels: {}, + expected: { + '0277cab7dd12b10259ee82c6ea4b509774e33e7078e7138f568092241bf26b99f1': + 'f5382508609771068ed079b24e1f72e4a17ee6d1c979066bf1d4e2a5676f09d4', }, }, { + description: + 'Single recipient: taproot input with even y-value and non-taproot input', scanPrivateKey: '0f694e068028a717f8af6b9411f9a133dd3565258714cc226594b34db90c1f2c', spendPublicKey: '025cc9856d6f8375350e123978daac200c260cb5b5ae83106cab90484dcd8fcf36', sumOfInputPublicKeys: '031ecda9c64faaa6cd57c9f3d7c62bcfc0763c2627ed8dc0e2c3018e9ff37a0bf0', - outpointHash: - '210fef5d624db17c965c7597e2c6c9f60ef440c831d149c43567c50158557f12', + inputHash: + '89c79a4bb917f3ba868c6ab3435afd8b9830102358810ad319a0d483accee221', outputs: [ - '022b4ff8e5bc608cbdd12117171e7d265b6882ad597559caf67b5ecfaf15301dd0', + '0230523cca96b2a9ae3c98beb5e60f7d190ec5bc79b2d11a0b2d4d09a608c448f0', ], - matches: { - '022b4ff8e5bc608cbdd12117171e7d265b6882ad597559caf67b5ecfaf15301dd0': - '17d93733d2acd8388279c24dc4413483802378c99f266f5961ac3338c5146861', + labels: {}, + expected: { + '0230523cca96b2a9ae3c98beb5e60f7d190ec5bc79b2d11a0b2d4d09a608c448f0': + 'b40017865c79b1fcbed68896791be93186d08f47e416b289b8c063777e14e8df', }, }, { + description: + 'Single recipient: taproot input with odd y-value and non-taproot input', scanPrivateKey: '0f694e068028a717f8af6b9411f9a133dd3565258714cc226594b34db90c1f2c', spendPublicKey: '025cc9856d6f8375350e123978daac200c260cb5b5ae83106cab90484dcd8fcf36', sumOfInputPublicKeys: - '02ef85ee8dc78102f2fd062d3b321f0b4527f0b954ed14b93b0090c8514c9b6a03', - outpointHash: - '210fef5d624db17c965c7597e2c6c9f60ef440c831d149c43567c50158557f12', + '03bc118b1c8178915b716d6137633722c71adfe721551ec7b3938054691de6a2b9', + inputHash: + '2c648edc10c4f485a825c6cbc12db0966c98c4b05ed13fde156d3647bcd061d9', outputs: [ - '0275f501f319db549aaa613717bd7af44da566d4d859b67fe436946564fafc47a3', + '02359358f59ee9e9eec3f00bdf4882570fd5c182e451aa2650b788544aff012a3a', ], - matches: { - '0275f501f319db549aaa613717bd7af44da566d4d859b67fe436946564fafc47a3': - '619a5a59a16d4a8e857ef48e63ef7c8195c858191d4e826205e8438ab70d059e', + labels: {}, + expected: { + '02359358f59ee9e9eec3f00bdf4882570fd5c182e451aa2650b788544aff012a3a': + 'a2f9dd05d1d398347c885d9c61a64d18a264de6d49cea4326bafc2791d627fa7', }, }, { + description: 'Multiple outputs: multiple outputs, same recipient', scanPrivateKey: '0f694e068028a717f8af6b9411f9a133dd3565258714cc226594b34db90c1f2c', spendPublicKey: '025cc9856d6f8375350e123978daac200c260cb5b5ae83106cab90484dcd8fcf36', sumOfInputPublicKeys: '03853f51bef283502181e93238c8708ae27235dc51ae45a0c4053987c52fc6428b', - outpointHash: - '210fef5d624db17c965c7597e2c6c9f60ef440c831d149c43567c50158557f12', + inputHash: + 'd9a9c2445c8384c1e916faef4a997f00852b877cc959dc69dc1d2bb631eb8f5b', outputs: [ - '0264f1c7e8992352d18cdbca600b9e1c3a6025050d56a3e1cc833222e4f3b59e18', - '020a48c6ccc1d516e8244dc0153dc88db45f8f264357667c2057a29ca3c2445d09', - '02c58e121044b23cba9b4695052229a9fd9e044b579f92864eb886ae7c99b021c9', - '024b15b75f3f184328c4a2f7c79357481ed06cf3b6f95512d5ed946fdc0b60d62b', + '02f207162b1a7abc51c42017bef055e9ec1efc3d3567cb720357e2b84325db33ac', + '02e976a58fbd38aeb4e6093d4df02e9c1de0c4513ae0c588cef68cda5b2f8834ca', + '02841792c33c9dc6193e76744134125d40add8f2f4a96475f28ba150be032d64e8', + '022e847bb01d1b491da512ddd760b8509617ee38057003d6115d00ba562451323a', ], - matches: { - '0264f1c7e8992352d18cdbca600b9e1c3a6025050d56a3e1cc833222e4f3b59e18': - '96439446f13ddaab2c5bc5a59a08992fd9d33bf8563c8a1b362730f4dc022e30', - '020a48c6ccc1d516e8244dc0153dc88db45f8f264357667c2057a29ca3c2445d09': - 'd39df91bd0e7825bfa1d30096febc5bf6fa7da79d7f25b7b4bea9538cc9a9f7f', + labels: {}, + expected: { + '02f207162b1a7abc51c42017bef055e9ec1efc3d3567cb720357e2b84325db33ac': + '33ce085c3c11eaad13694aae3c20301a6c83382ec89a7cde96c6799e2f88805a', + '02e976a58fbd38aeb4e6093d4df02e9c1de0c4513ae0c588cef68cda5b2f8834ca': + 'd97e442d110c0bdd31161a7bb6e7862e038d02a09b1484dfbb463f2e0f7c9230', }, }, { + description: 'Multiple outputs: multiple outputs, multiple recipients', scanPrivateKey: '0f694e068028a717f8af6b9411f9a133dd3565258714cc226594b34db90c1f2c', spendPublicKey: '025cc9856d6f8375350e123978daac200c260cb5b5ae83106cab90484dcd8fcf36', sumOfInputPublicKeys: '03853f51bef283502181e93238c8708ae27235dc51ae45a0c4053987c52fc6428b', - outpointHash: - '210fef5d624db17c965c7597e2c6c9f60ef440c831d149c43567c50158557f12', + inputHash: + 'd9a9c2445c8384c1e916faef4a997f00852b877cc959dc69dc1d2bb631eb8f5b', outputs: [ - '0264f1c7e8992352d18cdbca600b9e1c3a6025050d56a3e1cc833222e4f3b59e18', - '020a48c6ccc1d516e8244dc0153dc88db45f8f264357667c2057a29ca3c2445d09', - '02c58e121044b23cba9b4695052229a9fd9e044b579f92864eb886ae7c99b021c9', - '024b15b75f3f184328c4a2f7c79357481ed06cf3b6f95512d5ed946fdc0b60d62b', + '02f207162b1a7abc51c42017bef055e9ec1efc3d3567cb720357e2b84325db33ac', + '02e976a58fbd38aeb4e6093d4df02e9c1de0c4513ae0c588cef68cda5b2f8834ca', + '02841792c33c9dc6193e76744134125d40add8f2f4a96475f28ba150be032d64e8', + '022e847bb01d1b491da512ddd760b8509617ee38057003d6115d00ba562451323a', ], - matches: { - '0264f1c7e8992352d18cdbca600b9e1c3a6025050d56a3e1cc833222e4f3b59e18': - '96439446f13ddaab2c5bc5a59a08992fd9d33bf8563c8a1b362730f4dc022e30', - '020a48c6ccc1d516e8244dc0153dc88db45f8f264357667c2057a29ca3c2445d09': - 'd39df91bd0e7825bfa1d30096febc5bf6fa7da79d7f25b7b4bea9538cc9a9f7f', + labels: {}, + expected: { + '02f207162b1a7abc51c42017bef055e9ec1efc3d3567cb720357e2b84325db33ac': + '33ce085c3c11eaad13694aae3c20301a6c83382ec89a7cde96c6799e2f88805a', + '02e976a58fbd38aeb4e6093d4df02e9c1de0c4513ae0c588cef68cda5b2f8834ca': + 'd97e442d110c0bdd31161a7bb6e7862e038d02a09b1484dfbb463f2e0f7c9230', }, }, { + description: 'Multiple outputs: multiple outputs, multiple recipients', scanPrivateKey: '060b751d7892149006ed7b98606955a29fe284a1e900070c0971f5fb93dbf422', spendPublicKey: '0381eb9a9a9ec739d527c1631b31b421566f5c2a47b4ab5b1f6a686dfb68eab716', sumOfInputPublicKeys: '03853f51bef283502181e93238c8708ae27235dc51ae45a0c4053987c52fc6428b', - outpointHash: - '210fef5d624db17c965c7597e2c6c9f60ef440c831d149c43567c50158557f12', + inputHash: + 'd9a9c2445c8384c1e916faef4a997f00852b877cc959dc69dc1d2bb631eb8f5b', outputs: [ - '0264f1c7e8992352d18cdbca600b9e1c3a6025050d56a3e1cc833222e4f3b59e18', - '020a48c6ccc1d516e8244dc0153dc88db45f8f264357667c2057a29ca3c2445d09', - '02c58e121044b23cba9b4695052229a9fd9e044b579f92864eb886ae7c99b021c9', - '024b15b75f3f184328c4a2f7c79357481ed06cf3b6f95512d5ed946fdc0b60d62b', + '02f207162b1a7abc51c42017bef055e9ec1efc3d3567cb720357e2b84325db33ac', + '02e976a58fbd38aeb4e6093d4df02e9c1de0c4513ae0c588cef68cda5b2f8834ca', + '02841792c33c9dc6193e76744134125d40add8f2f4a96475f28ba150be032d64e8', + '022e847bb01d1b491da512ddd760b8509617ee38057003d6115d00ba562451323a', ], - matches: { - '02c58e121044b23cba9b4695052229a9fd9e044b579f92864eb886ae7c99b021c9': - '567710d07bdaacc8de3f1cec467bcb162ed7daa6b901b59af257bcd7e39dffcf', - '024b15b75f3f184328c4a2f7c79357481ed06cf3b6f95512d5ed946fdc0b60d62b': - '25dd11163a9a2853709c4c837aafb3347e2eaa875cf4c5170e2a3663879f4c58', + labels: {}, + expected: { + '02841792c33c9dc6193e76744134125d40add8f2f4a96475f28ba150be032d64e8': + '2f17ea873a0047fc01ba8010fef0969e76d0e4283f600d48f735098b1fee6eb9', + '022e847bb01d1b491da512ddd760b8509617ee38057003d6115d00ba562451323a': + '72cd082cccb633bf85240a83494b32dc943a4d05647a6686d23ad4ca59c0ebe4', }, }, { + description: 'Receiving with labels: label with odd parity', scanPrivateKey: '0f694e068028a717f8af6b9411f9a133dd3565258714cc226594b34db90c1f2c', spendPublicKey: '025cc9856d6f8375350e123978daac200c260cb5b5ae83106cab90484dcd8fcf36', sumOfInputPublicKeys: '03853f51bef283502181e93238c8708ae27235dc51ae45a0c4053987c52fc6428b', - outpointHash: - '210fef5d624db17c965c7597e2c6c9f60ef440c831d149c43567c50158557f12', + inputHash: + 'd9a9c2445c8384c1e916faef4a997f00852b877cc959dc69dc1d2bb631eb8f5b', outputs: [ - '0264f1c7e8992352d18cdbca600b9e1c3a6025050d56a3e1cc833222e4f3b59e18', - '020050c52a32566c0dfb517e473c68fedce4bd4543d219348d3bbdceeeb5755e34', + '02d014d4860f67d607d60b1af70e0ee236b99658b61bb769832acbbe87c374439a', ], - matches: { - '0264f1c7e8992352d18cdbca600b9e1c3a6025050d56a3e1cc833222e4f3b59e18': - '96439446f13ddaab2c5bc5a59a08992fd9d33bf8563c8a1b362730f4dc022e30', + labels: { + '0244962c484602f40b7729680ac00e4e118f0a84034bd9445a61234c5e3b5eea54': + '1e06e1749870cac2eda06a04a54fc4edba17cba9377ead25a69b6306711ea9f8', + '03cfda89f13b01fcd27703ab4a1da45ca731bf28efaabbbb5ad11c20a8a3f28b71': + '2c56a5c50c644abe7a282c68ab504d0c0e5e31e1126d614be1a4fb098c455e53', + '03615a94bbe5ad3dca03ff7aa9525b678bfd4d5443873f48b6d47113cda87cfa3e': + 'af68b0c6f4b1458314f3998004f57d78689640e4fff389da7064d0fd183de448', + }, + expected: { + '02d014d4860f67d607d60b1af70e0ee236b99658b61bb769832acbbe87c374439a': + '51d4e9d0d482b5700109b4b2e16ff508269b03d800192a043d61dca4a0a72a52', }, }, { + description: 'Receiving with labels: label with odd parity', scanPrivateKey: '0f694e068028a717f8af6b9411f9a133dd3565258714cc226594b34db90c1f2c', spendPublicKey: '025cc9856d6f8375350e123978daac200c260cb5b5ae83106cab90484dcd8fcf36', sumOfInputPublicKeys: '03853f51bef283502181e93238c8708ae27235dc51ae45a0c4053987c52fc6428b', - outpointHash: - '210fef5d624db17c965c7597e2c6c9f60ef440c831d149c43567c50158557f12', + inputHash: + 'd9a9c2445c8384c1e916faef4a997f00852b877cc959dc69dc1d2bb631eb8f5b', outputs: [ - '022cbceeab2a4982841eb7dc34b8b4f19c04bf3bc083ebf984f5664366778eb50f', + '0267626aebb3c4307cf0f6c39ca23247598fabf675ab783292eb2f81ae75ad1f8c', ], labels: { - '02c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5': - '0000000000000000000000000000000000000000000000000000000000000002', - '02f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9': - '0000000000000000000000000000000000000000000000000000000000000003', - '03348b4f5feb64b557dac8cfa10044bdc2094fca9147163bf514f68687e0d1dba6': - '00000000000000000000000000000000000000000000000000000000000f4779', + '0244962c484602f40b7729680ac00e4e118f0a84034bd9445a61234c5e3b5eea54': + '1e06e1749870cac2eda06a04a54fc4edba17cba9377ead25a69b6306711ea9f8', + '03cfda89f13b01fcd27703ab4a1da45ca731bf28efaabbbb5ad11c20a8a3f28b71': + '2c56a5c50c644abe7a282c68ab504d0c0e5e31e1126d614be1a4fb098c455e53', + '03615a94bbe5ad3dca03ff7aa9525b678bfd4d5443873f48b6d47113cda87cfa3e': + 'af68b0c6f4b1458314f3998004f57d78689640e4fff389da7064d0fd183de448', }, - matches: { - '022cbceeab2a4982841eb7dc34b8b4f19c04bf3bc083ebf984f5664366778eb50f': - '96439446f13ddaab2c5bc5a59a08992fd9d33bf8563c8a1b362730f4dc022e32', + expected: { + '0267626aebb3c4307cf0f6c39ca23247598fabf675ab783292eb2f81ae75ad1f8c': + '6024ae214876356b8d917716e7707d267ae16a0fdb07de2a786b74a7bbcddead', }, }, { + description: 'Receiving with labels: label with odd parity', scanPrivateKey: '0f694e068028a717f8af6b9411f9a133dd3565258714cc226594b34db90c1f2c', spendPublicKey: '025cc9856d6f8375350e123978daac200c260cb5b5ae83106cab90484dcd8fcf36', sumOfInputPublicKeys: '03853f51bef283502181e93238c8708ae27235dc51ae45a0c4053987c52fc6428b', - outpointHash: - '210fef5d624db17c965c7597e2c6c9f60ef440c831d149c43567c50158557f12', + inputHash: + 'd9a9c2445c8384c1e916faef4a997f00852b877cc959dc69dc1d2bb631eb8f5b', outputs: [ - '026b4455de119f51bf4d4a12dea555f14a5dc2c1369af5fba4871c5367264c028d', + '027efa60ce78ac343df8a013a2027c6c5ef29f9502edcbd769d2c21717fecc5951', ], labels: { - '02c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5': - '0000000000000000000000000000000000000000000000000000000000000002', - '02f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9': - '0000000000000000000000000000000000000000000000000000000000000003', - '03348b4f5feb64b557dac8cfa10044bdc2094fca9147163bf514f68687e0d1dba6': - '00000000000000000000000000000000000000000000000000000000000f4779', + '0244962c484602f40b7729680ac00e4e118f0a84034bd9445a61234c5e3b5eea54': + '1e06e1749870cac2eda06a04a54fc4edba17cba9377ead25a69b6306711ea9f8', + '03cfda89f13b01fcd27703ab4a1da45ca731bf28efaabbbb5ad11c20a8a3f28b71': + '2c56a5c50c644abe7a282c68ab504d0c0e5e31e1126d614be1a4fb098c455e53', + '03615a94bbe5ad3dca03ff7aa9525b678bfd4d5443873f48b6d47113cda87cfa3e': + 'af68b0c6f4b1458314f3998004f57d78689640e4fff389da7064d0fd183de448', }, - matches: { - '026b4455de119f51bf4d4a12dea555f14a5dc2c1369af5fba4871c5367264c028d': - '96439446f13ddaab2c5bc5a59a08992fd9d33bf8563c8a1b362730f4dc022e33', + expected: { + '027efa60ce78ac343df8a013a2027c6c5ef29f9502edcbd769d2c21717fecc5951': + 'e336b92330c33030285ce42e4115ad92d5197913c88e06b9072b4a9b47c664a2', }, }, { + description: + 'Multiple outputs with labels: multiple outputs for labeled address; same recipient', scanPrivateKey: '0f694e068028a717f8af6b9411f9a133dd3565258714cc226594b34db90c1f2c', spendPublicKey: '025cc9856d6f8375350e123978daac200c260cb5b5ae83106cab90484dcd8fcf36', sumOfInputPublicKeys: '03853f51bef283502181e93238c8708ae27235dc51ae45a0c4053987c52fc6428b', - outpointHash: - '210fef5d624db17c965c7597e2c6c9f60ef440c831d149c43567c50158557f12', + inputHash: + 'd9a9c2445c8384c1e916faef4a997f00852b877cc959dc69dc1d2bb631eb8f5b', outputs: [ - '02c3473bfcbe5e4d20d0790ae91f1b339bc15b46de64ca068d140118d0e325b849', + '02f207162b1a7abc51c42017bef055e9ec1efc3d3567cb720357e2b84325db33ac', + '0239f42624d5c32a77fda80ff0acee269afec601d3791803e80252ae04e4ffcf4c', ], labels: { - '02c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5': - '0000000000000000000000000000000000000000000000000000000000000002', - '02f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9': - '0000000000000000000000000000000000000000000000000000000000000003', - '03348b4f5feb64b557dac8cfa10044bdc2094fca9147163bf514f68687e0d1dba6': - '00000000000000000000000000000000000000000000000000000000000f4779', + '0298dc9b3e9283cb8cf8c2f2580f0d9c76143195a49f5f5d9136abfd8bf12134ee': + '6991cb5ce09ab332d7067838bd183f4da1e9b633743f8616a03fb6cdd8956825', }, - matches: { - '02c3473bfcbe5e4d20d0790ae91f1b339bc15b46de64ca068d140118d0e325b849': - '96439446f13ddaab2c5bc5a59a08992fd9d33bf8563c8a1b362730f4dc1175a9', + expected: { + '02f207162b1a7abc51c42017bef055e9ec1efc3d3567cb720357e2b84325db33ac': + '33ce085c3c11eaad13694aae3c20301a6c83382ec89a7cde96c6799e2f88805a', + '0239f42624d5c32a77fda80ff0acee269afec601d3791803e80252ae04e4ffcf4c': + '43100f89f1a6bf10081c92b473ffc57ceac7dbed600b6aba9bb3976f17dbb914', }, }, { + description: + 'Multiple outputs with labels: multiple outputs for labeled address; same recipient', scanPrivateKey: '0f694e068028a717f8af6b9411f9a133dd3565258714cc226594b34db90c1f2c', spendPublicKey: '025cc9856d6f8375350e123978daac200c260cb5b5ae83106cab90484dcd8fcf36', sumOfInputPublicKeys: '03853f51bef283502181e93238c8708ae27235dc51ae45a0c4053987c52fc6428b', - outpointHash: - '210fef5d624db17c965c7597e2c6c9f60ef440c831d149c43567c50158557f12', + inputHash: + 'd9a9c2445c8384c1e916faef4a997f00852b877cc959dc69dc1d2bb631eb8f5b', outputs: [ - '0264f1c7e8992352d18cdbca600b9e1c3a6025050d56a3e1cc833222e4f3b59e18', - '027956317130124c32afd07b3f2432a3e92c1447cf58da95491a307ae3d564535e', + '0283dc944e61603137294829aed56c74c9b087d80f2c021b98a7fae5799000696c', + '0239f42624d5c32a77fda80ff0acee269afec601d3791803e80252ae04e4ffcf4c', ], labels: { - '0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798': - '0000000000000000000000000000000000000000000000000000000000000001', + '0298dc9b3e9283cb8cf8c2f2580f0d9c76143195a49f5f5d9136abfd8bf12134ee': + '6991cb5ce09ab332d7067838bd183f4da1e9b633743f8616a03fb6cdd8956825', }, - matches: { - '0264f1c7e8992352d18cdbca600b9e1c3a6025050d56a3e1cc833222e4f3b59e18': - '96439446f13ddaab2c5bc5a59a08992fd9d33bf8563c8a1b362730f4dc022e30', - '027956317130124c32afd07b3f2432a3e92c1447cf58da95491a307ae3d564535e': - 'd39df91bd0e7825bfa1d30096febc5bf6fa7da79d7f25b7b4bea9538cc9a9f80', + expected: { + '0283dc944e61603137294829aed56c74c9b087d80f2c021b98a7fae5799000696c': + '9d5fd3b91cac9ddfea6fc2e6f9386f680e6cee623cda02f53706306c081de87f', + '0239f42624d5c32a77fda80ff0acee269afec601d3791803e80252ae04e4ffcf4c': + '43100f89f1a6bf10081c92b473ffc57ceac7dbed600b6aba9bb3976f17dbb914', }, }, { + description: + 'Multiple outputs with labels: multiple outputs for labeled address; same recipient', scanPrivateKey: '0f694e068028a717f8af6b9411f9a133dd3565258714cc226594b34db90c1f2c', spendPublicKey: '025cc9856d6f8375350e123978daac200c260cb5b5ae83106cab90484dcd8fcf36', sumOfInputPublicKeys: '03853f51bef283502181e93238c8708ae27235dc51ae45a0c4053987c52fc6428b', - outpointHash: - '210fef5d624db17c965c7597e2c6c9f60ef440c831d149c43567c50158557f12', + inputHash: + 'd9a9c2445c8384c1e916faef4a997f00852b877cc959dc69dc1d2bb631eb8f5b', outputs: [ - '028890c19f005d6f6add5fef92d37ac6b161b7fdd5c1aef6eed1d32be3f216ac4c', - '027956317130124c32afd07b3f2432a3e92c1447cf58da95491a307ae3d564535e', + '02f207162b1a7abc51c42017bef055e9ec1efc3d3567cb720357e2b84325db33ac', + '0239f42624d5c32a77fda80ff0acee269afec601d3791803e80252ae04e4ffcf4c', + '02ae1a780c04237bd577283c3ddb2e499767c3214160d5a6b0767e6b8c278bd701', + '02f4569fc5f69c10f0082cfbb8e072e6266ec55f69fba8cffca4cbb4c144b7e59b', ], labels: { - '0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798': - '0000000000000000000000000000000000000000000000000000000000000001', + '0298dc9b3e9283cb8cf8c2f2580f0d9c76143195a49f5f5d9136abfd8bf12134ee': + '6991cb5ce09ab332d7067838bd183f4da1e9b633743f8616a03fb6cdd8956825', }, - matches: { - '028890c19f005d6f6add5fef92d37ac6b161b7fdd5c1aef6eed1d32be3f216ac4c': - '96439446f13ddaab2c5bc5a59a08992fd9d33bf8563c8a1b362730f4dc022e31', - '027956317130124c32afd07b3f2432a3e92c1447cf58da95491a307ae3d564535e': - 'd39df91bd0e7825bfa1d30096febc5bf6fa7da79d7f25b7b4bea9538cc9a9f80', + expected: { + '02f207162b1a7abc51c42017bef055e9ec1efc3d3567cb720357e2b84325db33ac': + '33ce085c3c11eaad13694aae3c20301a6c83382ec89a7cde96c6799e2f88805a', + '0239f42624d5c32a77fda80ff0acee269afec601d3791803e80252ae04e4ffcf4c': + '43100f89f1a6bf10081c92b473ffc57ceac7dbed600b6aba9bb3976f17dbb914', }, }, { + description: 'Single recipient: use silent payments for sender change', scanPrivateKey: - '0f694e068028a717f8af6b9411f9a133dd3565258714cc226594b34db90c1f2c', + '11b7a82e06ca2648d5fded2366478078ec4fc9dc1d8ff487518226f229d768fd', spendPublicKey: - '025cc9856d6f8375350e123978daac200c260cb5b5ae83106cab90484dcd8fcf36', + '03bc95144daf15336db3456825c70ced0a4462f89aca42c4921ee7ccb2b3a44796', sumOfInputPublicKeys: '03853f51bef283502181e93238c8708ae27235dc51ae45a0c4053987c52fc6428b', - outpointHash: - '210fef5d624db17c965c7597e2c6c9f60ef440c831d149c43567c50158557f12', + inputHash: + 'd9a9c2445c8384c1e916faef4a997f00852b877cc959dc69dc1d2bb631eb8f5b', outputs: [ - '0264f1c7e8992352d18cdbca600b9e1c3a6025050d56a3e1cc833222e4f3b59e18', - '027956317130124c32afd07b3f2432a3e92c1447cf58da95491a307ae3d564535e', - '021b90a42136fef9ff2ca192abffc7be4536dc83d4e61cf18ae078f7e92b297cce', - '0287a82600c08a255bc97d172e10816e322967eed6a77c9f37dd926492d7fdc106', + '02f207162b1a7abc51c42017bef055e9ec1efc3d3567cb720357e2b84325db33ac', + '02be368e28979d950245d742891ae6064020ba548c1e2e65a639a8bb0675d95cff', ], labels: { - '0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798': - '0000000000000000000000000000000000000000000000000000000000000001', - '02db0c51cc634a4096374b0b895584a3ca2fb3bea4fd0ee2361f8db63a650fcee6': - '0000000000000000000000000000000000000000000000000000000000000539', + '03792926eb783d9a868b52ad5eef38962112c5c7a1262c4cce17fc1a6b22fb0bf2': + '015d1b458151642ee96c0f534aa795c962dc3ece7eeebe4d0e30820391a53bea', }, - matches: { - '0264f1c7e8992352d18cdbca600b9e1c3a6025050d56a3e1cc833222e4f3b59e18': - '96439446f13ddaab2c5bc5a59a08992fd9d33bf8563c8a1b362730f4dc022e30', - '027956317130124c32afd07b3f2432a3e92c1447cf58da95491a307ae3d564535e': - 'd39df91bd0e7825bfa1d30096febc5bf6fa7da79d7f25b7b4bea9538cc9a9f80', - '021b90a42136fef9ff2ca192abffc7be4536dc83d4e61cf18ae078f7e92b297cce': - '255a912ad6cdebc0842d49fd9f7b2d81ee37d66c62839879371b699010f78ef1', - '0287a82600c08a255bc97d172e10816e322967eed6a77c9f37dd926492d7fdc106': - 'd7535d792cb1388ab0b3bd5ff57337436d62f7719c1796beb5d80ab2fa34f307', + expected: { + '02be368e28979d950245d742891ae6064020ba548c1e2e65a639a8bb0675d95cff': + '80cd767ed20bd0bb7d8ea5e803f8c381293a62e8a073cf46fb0081da46e64e1f', }, }, { + description: 'Single recipient: use silent payments for sender change', scanPrivateKey: - '11b7a82e06ca2648d5fded2366478078ec4fc9dc1d8ff487518226f229d768fd', + '0f694e068028a717f8af6b9411f9a133dd3565258714cc226594b34db90c1f2c', spendPublicKey: - '03bc95144daf15336db3456825c70ced0a4462f89aca42c4921ee7ccb2b3a44796', + '025cc9856d6f8375350e123978daac200c260cb5b5ae83106cab90484dcd8fcf36', sumOfInputPublicKeys: '03853f51bef283502181e93238c8708ae27235dc51ae45a0c4053987c52fc6428b', - outpointHash: - '210fef5d624db17c965c7597e2c6c9f60ef440c831d149c43567c50158557f12', + inputHash: + 'd9a9c2445c8384c1e916faef4a997f00852b877cc959dc69dc1d2bb631eb8f5b', outputs: [ - '0264f1c7e8992352d18cdbca600b9e1c3a6025050d56a3e1cc833222e4f3b59e18', - '020050c52a32566c0dfb517e473c68fedce4bd4543d219348d3bbdceeeb5755e34', + '02f207162b1a7abc51c42017bef055e9ec1efc3d3567cb720357e2b84325db33ac', + '02be368e28979d950245d742891ae6064020ba548c1e2e65a639a8bb0675d95cff', ], - labels: { - '02295dc38e877b754c0d0ed767434f1572cf34a82ccc06ffea1d9e04f1f7878e1a': - '91cb04398a508c9d995ff4a18e5eae24d5e9488309f189120a3fdbb977978c46', + labels: {}, + expected: { + '02f207162b1a7abc51c42017bef055e9ec1efc3d3567cb720357e2b84325db33ac': + '33ce085c3c11eaad13694aae3c20301a6c83382ec89a7cde96c6799e2f88805a', }, - matches: { - '020050c52a32566c0dfb517e473c68fedce4bd4543d219348d3bbdceeeb5755e34': - '2e9c2a37cfa7827907d36357f0632d258dbd14b3a7854937ecf732fb6acefdc8', + }, + { + description: 'Single receipient: taproot input with NUMS point', + scanPrivateKey: + '0f694e068028a717f8af6b9411f9a133dd3565258714cc226594b34db90c1f2c', + spendPublicKey: + '025cc9856d6f8375350e123978daac200c260cb5b5ae83106cab90484dcd8fcf36', + sumOfInputPublicKeys: + '02782eeb913431ca6e9b8c2fd80a5f72ed2024ef72a3c6fb10263c379937323338', + inputHash: + '7488bcb061b294f9936c6011f10e36b1a226fa0de98bdb1781d680dac829d852', + outputs: [ + '0279e79897c52935bfd97fc6e076a6431a0c7543ca8c31e0fc3cf719bb572c842d', + ], + labels: {}, + expected: { + '0279e79897c52935bfd97fc6e076a6431a0c7543ca8c31e0fc3cf719bb572c842d': + '3ddec3232609d348d6b8b53123b4f40f6d4f5398ca586f087b0416ec3b851496', + }, + }, + { + description: 'Pubkey extraction from malleated p2pkh', + scanPrivateKey: + '0f694e068028a717f8af6b9411f9a133dd3565258714cc226594b34db90c1f2c', + spendPublicKey: + '025cc9856d6f8375350e123978daac200c260cb5b5ae83106cab90484dcd8fcf36', + sumOfInputPublicKeys: + '038b0d201fe111bdc0e6953772bd02a41959d25d5b2f66bcbe348af27bbdd42735', + inputHash: + 'aade43188c62354b11952d20585f2cf94aaf3d4451e98c3bd9f71a1d6b0ce5ef', + outputs: [ + '024612cdbf845c66c7511d70aab4d9aed11e49e48cdb8d799d787101cdd0d53e4f', + ], + labels: {}, + expected: { + '024612cdbf845c66c7511d70aab4d9aed11e49e48cdb8d799d787101cdd0d53e4f': + '10bde9781def20d7701e7603ef1b1e5e71c67bae7154818814e3c81ef5b1a3d3', }, }, + { + description: 'P2PKH and P2WPKH Uncompressed Keys are skipped', + scanPrivateKey: + '0f694e068028a717f8af6b9411f9a133dd3565258714cc226594b34db90c1f2c', + spendPublicKey: + '025cc9856d6f8375350e123978daac200c260cb5b5ae83106cab90484dcd8fcf36', + sumOfInputPublicKeys: + '025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5', + inputHash: + '9be481e9efc788e2344fbbacc42db86d5e191a4269cace545bb847bdbb251bfc', + outputs: [ + '0267fee277da9e8542b5d2e6f32d660a9bbd3f0e107c2d53638ab1d869088882d6', + ], + labels: {}, + expected: { + '0267fee277da9e8542b5d2e6f32d660a9bbd3f0e107c2d53638ab1d869088882d6': + '688fa3aeb97d2a46ae87b03591921c2eaf4b505eb0ddca2733c94701e01060cf', + }, + }, + { + description: 'Skip invalid P2SH inputs', + scanPrivateKey: + '0f694e068028a717f8af6b9411f9a133dd3565258714cc226594b34db90c1f2c', + spendPublicKey: + '025cc9856d6f8375350e123978daac200c260cb5b5ae83106cab90484dcd8fcf36', + sumOfInputPublicKeys: + '025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5', + inputHash: + '9be481e9efc788e2344fbbacc42db86d5e191a4269cace545bb847bdbb251bfc', + outputs: [ + '0267fee277da9e8542b5d2e6f32d660a9bbd3f0e107c2d53638ab1d869088882d6', + ], + labels: {}, + expected: { + '0267fee277da9e8542b5d2e6f32d660a9bbd3f0e107c2d53638ab1d869088882d6': + '688fa3aeb97d2a46ae87b03591921c2eaf4b505eb0ddca2733c94701e01060cf', + }, + }, + { + description: 'Recipient ignores unrelated outputs', + scanPrivateKey: + '0f694e068028a717f8af6b9411f9a133dd3565258714cc226594b34db90c1f2c', + spendPublicKey: + '025cc9856d6f8375350e123978daac200c260cb5b5ae83106cab90484dcd8fcf36', + sumOfInputPublicKeys: + '03853f51bef283502181e93238c8708ae27235dc51ae45a0c4053987c52fc6428b', + inputHash: + 'd9a9c2445c8384c1e916faef4a997f00852b877cc959dc69dc1d2bb631eb8f5b', + outputs: [ + '02782eeb913431ca6e9b8c2fd80a5f72ed2024ef72a3c6fb10263c379937323338', + '02841792c33c9dc6193e76744134125d40add8f2f4a96475f28ba150be032d64e8', + ], + labels: {}, + expected: {}, + }, ]; diff --git a/packages/core/test/scanning.spec.ts b/packages/core/test/scanning.spec.ts index 97576a7..39a40e7 100644 --- a/packages/core/test/scanning.spec.ts +++ b/packages/core/test/scanning.spec.ts @@ -1,31 +1,31 @@ -import { scanOutputs, LabelMap } from '../src'; +import { scanOutputs } from '../src'; import { Buffer } from 'buffer'; import { testData } from './fixtures/scanning'; describe('Scanning', () => { it.each(testData)( - 'should pass', + 'should scan outputs and return the expected tweaks: $description', ({ scanPrivateKey, spendPublicKey, sumOfInputPublicKeys, - outpointHash, + inputHash, outputs, labels, - matches, + expected, }) => { const result = scanOutputs( Buffer.from(scanPrivateKey, 'hex'), Buffer.from(spendPublicKey, 'hex'), Buffer.from(sumOfInputPublicKeys, 'hex'), - Buffer.from(outpointHash, 'hex'), + Buffer.from(inputHash, 'hex'), outputs.map((output) => Buffer.from(output, 'hex')), - labels as unknown as LabelMap, + labels, ); expect(result).toStrictEqual( new Map( - Object.entries(matches).map(([output, tweak]) => [ + Object.entries(expected).map(([output, tweak]) => [ output, Buffer.from(tweak as string, 'hex'), ]),