diff --git a/package-lock.json b/package-lock.json index c3acb56..b71ef57 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,7 +15,7 @@ "bs58check": "^2.1.1", "create-hmac": "^1.1.7", "ecpair": "^2.0.1", - "tiny-secp256k1": "^2.2.1" + "tiny-secp256k1": "^1.1.6" }, "devDependencies": { "@types/chai": "^4.3.0", @@ -643,6 +643,14 @@ "node": ">=8" } }, + "node_modules/bindings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "dependencies": { + "file-uri-to-path": "1.0.0" + } + }, "node_modules/bip174": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/bip174/-/bip174-2.0.1.tgz", @@ -710,6 +718,11 @@ "safe-buffer": "^5.1.2" } }, + "node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -720,6 +733,11 @@ "concat-map": "0.0.1" } }, + "node_modules/brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==" + }, "node_modules/browser-stdout": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", @@ -1169,6 +1187,20 @@ "integrity": "sha512-3Vftv7cenJtQb+k00McEBZ2vVmZ/x+HEF7pcZONZIkOsESqAqVuACmBxMv0JhzX7u0YltU0vSqRqgBSTAhFUjA==", "dev": true }, + "node_modules/elliptic": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", + "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", + "dependencies": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + } + }, "node_modules/es6-error": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", @@ -1206,6 +1238,11 @@ "node": ">=4" } }, + "node_modules/file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==" + }, "node_modules/find-cache-dir": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", @@ -1535,6 +1572,15 @@ "node": ">=4" } }, + "node_modules/hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "dependencies": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, "node_modules/hasha": { "version": "5.2.2", "resolved": "https://registry.npmjs.org/hasha/-/hasha-5.2.2.tgz", @@ -1572,6 +1618,16 @@ "he": "bin/he" } }, + "node_modules/hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==", + "dependencies": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, "node_modules/html-escaper": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", @@ -1988,6 +2044,16 @@ "safe-buffer": "^5.1.2" } }, + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" + }, + "node_modules/minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==" + }, "node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -2356,6 +2422,11 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, + "node_modules/nan": { + "version": "2.17.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.17.0.tgz", + "integrity": "sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ==" + }, "node_modules/nanoid": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.1.tgz", @@ -3165,14 +3236,19 @@ } }, "node_modules/tiny-secp256k1": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/tiny-secp256k1/-/tiny-secp256k1-2.2.1.tgz", - "integrity": "sha512-/U4xfVqnVxJXN4YVsru0E6t5wVncu2uunB8+RVR40fYUxkKYUPS10f+ePQZgFBoE/Jbf9H1NBveupF2VmB58Ng==", + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/tiny-secp256k1/-/tiny-secp256k1-1.1.6.tgz", + "integrity": "sha512-FmqJZGduTyvsr2cF3375fqGHUovSwDi/QytexX1Se4BPuPZpTE5Ftp5fg+EFSuEf3lhZqgCRjEG3ydUQ/aNiwA==", + "hasInstallScript": true, "dependencies": { - "uint8array-tools": "0.0.7" + "bindings": "^1.3.0", + "bn.js": "^4.11.8", + "create-hmac": "^1.1.7", + "elliptic": "^6.4.0", + "nan": "^2.13.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=6.0.0" } }, "node_modules/to-fast-properties": { @@ -3390,14 +3466,6 @@ "node": ">=4.2.0" } }, - "node_modules/uint8array-tools": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/uint8array-tools/-/uint8array-tools-0.0.7.tgz", - "integrity": "sha512-vrrNZJiusLWoFWBqz5Y5KMCgP9W9hnjZHzZiZRT8oNAkq3d5Z5Oe76jAvVVSRh4U8GGR90N2X1dWtrhvx6L8UQ==", - "engines": { - "node": ">=14.0.0" - } - }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -4006,6 +4074,14 @@ "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", "dev": true }, + "bindings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "requires": { + "file-uri-to-path": "1.0.0" + } + }, "bip174": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/bip174/-/bip174-2.0.1.tgz", @@ -4068,6 +4144,11 @@ } } }, + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -4078,6 +4159,11 @@ "concat-map": "0.0.1" } }, + "brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==" + }, "browser-stdout": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", @@ -4432,6 +4518,20 @@ "integrity": "sha512-3Vftv7cenJtQb+k00McEBZ2vVmZ/x+HEF7pcZONZIkOsESqAqVuACmBxMv0JhzX7u0YltU0vSqRqgBSTAhFUjA==", "dev": true }, + "elliptic": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", + "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", + "requires": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + } + }, "es6-error": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", @@ -4456,6 +4556,11 @@ "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", "dev": true }, + "file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==" + }, "find-cache-dir": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", @@ -4688,6 +4793,15 @@ "safe-buffer": "^5.2.0" } }, + "hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "requires": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, "hasha": { "version": "5.2.2", "resolved": "https://registry.npmjs.org/hasha/-/hasha-5.2.2.tgz", @@ -4712,6 +4826,16 @@ "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", "dev": true }, + "hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==", + "requires": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, "html-escaper": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", @@ -5021,6 +5145,16 @@ "safe-buffer": "^5.1.2" } }, + "minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" + }, + "minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==" + }, "minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -5284,6 +5418,11 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, + "nan": { + "version": "2.17.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.17.0.tgz", + "integrity": "sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ==" + }, "nanoid": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.1.tgz", @@ -5885,11 +6024,15 @@ "dev": true }, "tiny-secp256k1": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/tiny-secp256k1/-/tiny-secp256k1-2.2.1.tgz", - "integrity": "sha512-/U4xfVqnVxJXN4YVsru0E6t5wVncu2uunB8+RVR40fYUxkKYUPS10f+ePQZgFBoE/Jbf9H1NBveupF2VmB58Ng==", + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/tiny-secp256k1/-/tiny-secp256k1-1.1.6.tgz", + "integrity": "sha512-FmqJZGduTyvsr2cF3375fqGHUovSwDi/QytexX1Se4BPuPZpTE5Ftp5fg+EFSuEf3lhZqgCRjEG3ydUQ/aNiwA==", "requires": { - "uint8array-tools": "0.0.7" + "bindings": "^1.3.0", + "bn.js": "^4.11.8", + "create-hmac": "^1.1.7", + "elliptic": "^6.4.0", + "nan": "^2.13.2" } }, "to-fast-properties": { @@ -6040,11 +6183,6 @@ "integrity": "sha512-HM/hFigTBHZhLXshn9sN37H085+hQGeJHJ/X7LpBWLID/fbc2acUMfU+lGD98X81sKP+pFa9f0DZmCwB9GnbAg==", "dev": true }, - "uint8array-tools": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/uint8array-tools/-/uint8array-tools-0.0.7.tgz", - "integrity": "sha512-vrrNZJiusLWoFWBqz5Y5KMCgP9W9hnjZHzZiZRT8oNAkq3d5Z5Oe76jAvVVSRh4U8GGR90N2X1dWtrhvx6L8UQ==" - }, "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", diff --git a/package.json b/package.json index 00d06d0..8b3cdc9 100644 --- a/package.json +++ b/package.json @@ -40,7 +40,7 @@ "bs58check": "^2.1.1", "create-hmac": "^1.1.7", "ecpair": "^2.0.1", - "tiny-secp256k1": "^2.2.1" + "tiny-secp256k1": "^1.1.6" }, "devDependencies": { "@types/chai": "^4.3.0", diff --git a/src/bip47.js b/src/bip47.js index 2daf205..03346fc 100644 --- a/src/bip47.js +++ b/src/bip47.js @@ -12,7 +12,7 @@ function BIP47Factory(ecc) { // TODO: implement a test assertion function for ecc const bip32 = (0, bip32_1.default)(ecc); const G = Buffer.from('0279BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798', 'hex'); - const { getPublicPaymentCodeNodeFromBase58, getRootPaymentCodeNodeFromSeedHex, getRootPaymentCodeNodeFromBIP39Seed, uintArrayToBuffer, getSharedSecret, toInternalByteOrder } = (0, utils_1.default)(ecc, bip32); + const { getPublicPaymentCodeNodeFromBase58, getRootPaymentCodeNodeFromSeedHex, getRootPaymentCodeNodeFromBIP39Seed, uintArrayToBuffer, getSharedSecret, toInternalByteOrder, } = (0, utils_1.default)(ecc, bip32); class BIP47 { constructor(network, RootPaymentCodeNode) { this.network = network; @@ -105,7 +105,7 @@ function BIP47Factory(ecc) { const a = privateKey; const B = bobBIP47.getNotificationNode().publicKey; const S = uintArrayToBuffer(ecc.pointMultiply(B, a)); - const x = uintArrayToBuffer(ecc.xOnlyPointFromPoint(S)); + const x = uintArrayToBuffer(S.slice(1, 33)); const o = outpoint; const s = crypto.hmacSHA512(o, x); const binaryPaymentCode = this.getBinaryPaymentCode(); @@ -144,9 +144,9 @@ function BIP47Factory(ecc) { const A = pubKey; const b = this.getNotificationNode().privateKey; const S = uintArrayToBuffer(ecc.pointMultiply(A, b)); - const x = uintArrayToBuffer(ecc.xOnlyPointFromPoint(S)); + const x = uintArrayToBuffer(S.slice(1, 33)); const s = crypto.hmacSHA512(outpoint, x); - const opReturnOutput = tx.outs.find(o => o.script.toString('hex').startsWith('6a4c50')); + const opReturnOutput = tx.outs.find((o) => o.script.toString('hex').startsWith('6a4c50')); if (!opReturnOutput) throw new Error('No OP_RETURN output in notification'); const binaryPaymentCode = opReturnOutput.script.slice(3); diff --git a/src/utils.js b/src/utils.js index 05aaf5f..abfb353 100644 --- a/src/utils.js +++ b/src/utils.js @@ -26,7 +26,7 @@ function getUtils(ecc, bip32) { return b; }; const getSharedSecret = (B, a) => { - const S = uintArrayToBuffer(ecc.xOnlyPointFromPoint(ecc.pointMultiply(B, a, true))); + const S = uintArrayToBuffer(ecc.pointMultiply(B, a, true).slice(1, 33)); let s = bitcoin.crypto.sha256(S); if (!ecc.isPrivate(s)) throw new Error('Shared secret is not a valid private key'); diff --git a/tests/bip47.test.ts b/tests/bip47.test.ts index a2bcc59..7163887 100644 --- a/tests/bip47.test.ts +++ b/tests/bip47.test.ts @@ -1,8 +1,8 @@ import { BIP32Interface } from 'bip32'; import { expect } from 'chai'; import ECPairFactory from 'ecpair'; -import * as ecc from 'tiny-secp256k1'; import BIP47Factory from '../ts-src'; +const ecc = require('tiny-secp256k1'); const ECPair = ECPairFactory(ecc); @@ -57,7 +57,7 @@ const privateKeysAliceToBobWallets = [ 'f103fe818377ff6040eb9aac10677384bb1ca6ff7f9d33e5a6306c3e402daec9', '5bd0be3fa5ae87ea97301b1e637915478efb45afcfe64133954eae93a29553a0', '0c4d3825253bc7a28a83097cfaf8affd9924d9a9ac921dbb9ce20a684253d349', - '118951327db87b267c2ed385631cda9c2905078cff8e63a053dc586d624c7899' + '118951327db87b267c2ed385631cda9c2905078cff8e63a053dc586d624c7899', ]; describe('Payment codes and notification addresses', () => { @@ -84,15 +84,17 @@ describe('Payment codes and notification addresses', () => { }); describe('Payment Addresses and Private keys', () => { - it('should generate alice to bob payment addresses from Alice\'s node', () => { + it("should generate alice to bob payment addresses from Alice's node", () => { const aliceBip47 = BIP47Factory(ecc).fromBip39Seed(alice.seedPhrase); const bobBip47 = BIP47Factory(ecc).fromPaymentCode(bob.paymentCode); const bobPaymentCodeNode: BIP32Interface = bobBip47.getPaymentCodeNode(); for (let i = 0; i < aliceToBobAddresses.length; i++) - expect(aliceBip47.getPaymentAddress(bobPaymentCodeNode, i)).to.equal(aliceToBobAddresses[i]); + expect(aliceBip47.getPaymentAddress(bobPaymentCodeNode, i)).to.equal( + aliceToBobAddresses[i], + ); }); - it('Should generate alice to bob payment addresses and private keys from Bob\'s node', () => { + it("Should generate alice to bob payment addresses and private keys from Bob's node", () => { const bobBip47 = BIP47Factory(ecc).fromBip39Seed(bob.seedPhrase); const aliceBip47 = BIP47Factory(ecc).fromPaymentCode(alice.paymentCode); const alicePaymentNode: BIP32Interface = aliceBip47.getPaymentCodeNode(); @@ -102,15 +104,19 @@ describe('Payment Addresses and Private keys', () => { alicePaymentNode, i, ); - expect(bobBip47.getAddressFromNode(wallet, bobBip47.network)).to.equal(aliceToBobAddresses[i]) + expect(bobBip47.getAddressFromNode(wallet, bobBip47.network)).to.equal( + aliceToBobAddresses[i], + ); // check private key - expect(wallet.privateKey?.toString('hex')).to.equal(privateKeysAliceToBobWallets[i]); + expect(wallet.privateKey?.toString('hex')).to.equal( + privateKeysAliceToBobWallets[i], + ); } }); }); describe('Notification Transaction and blinded payment code exchange', () => { - it('should generate Alice\'s blinded payment code for Bob', () => { + it("should generate Alice's blinded payment code for Bob", () => { const aliceBip47 = BIP47Factory(ecc).fromBip39Seed(alice.seedPhrase); const bobBip47 = BIP47Factory(ecc).fromPaymentCode(bob.paymentCode); const keyPair = ECPair.fromWIF(alice.privateKeyWIF); @@ -123,13 +129,12 @@ describe('Notification Transaction and blinded payment code exchange', () => { expect(blindedPaymentCode).to.equal(alice.blindedPaymentCode); }); - it('Bob should be able to retrieve Alice\'s payment code, from Alice\'s notification transaction', () => { + it("Bob should be able to retrieve Alice's payment code, from Alice's notification transaction", () => { const bobBip47 = BIP47Factory(ecc).fromBip39Seed(bob.seedPhrase); const p = bobBip47.getPaymentCodeFromRawNotificationTransaction( aliceToBobRawNotificationHex, ); expect(p).to.equal(alice.paymentCode); - }) - + }); }); diff --git a/ts-src/bip47.ts b/ts-src/bip47.ts index 4709afb..0d105ef 100644 --- a/ts-src/bip47.ts +++ b/ts-src/bip47.ts @@ -3,7 +3,13 @@ import * as bitcoin from 'bitcoinjs-lib'; import * as crypto from './crypto'; import { xor } from './xor'; -import { BIP47API, BIP47Interface, NetworkCoin, PublicKeyOutpoint, TinySecp256k1Interface } from './interfaces'; +import { + BIP47API, + BIP47Interface, + NetworkCoin, + PublicKeyOutpoint, + TinySecp256k1Interface, +} from './interfaces'; import { mainnetData } from './networks'; import getUtils from './utils'; const bs58check = require('bs58check'); @@ -23,7 +29,7 @@ export function BIP47Factory(ecc: TinySecp256k1Interface): BIP47API { getRootPaymentCodeNodeFromBIP39Seed, uintArrayToBuffer, getSharedSecret, - toInternalByteOrder + toInternalByteOrder, } = getUtils(ecc, bip32); class BIP47 implements BIP47Interface { @@ -35,27 +41,27 @@ export function BIP47Factory(ecc: TinySecp256k1Interface): BIP47API { this.RootPaymentCodeNode = RootPaymentCodeNode; } - getPaymentWallet( - aliceNode: BIP32Interface, - index: number, - ): BIP32Interface { + getPaymentWallet(aliceNode: BIP32Interface, index: number): BIP32Interface { if (!this.network || !this.RootPaymentCodeNode) throw new Error('Root Payment code node or network not set'); const bobNode: BIP32Interface = this.RootPaymentCodeNode.derive(index); if (bobNode.privateKey === undefined) - throw new Error('Missing private key to generate payment wallets') + throw new Error('Missing private key to generate payment wallets'); const firstAliceNode: BIP32Interface = aliceNode.derive(0); const s: Buffer = getSharedSecret( firstAliceNode.publicKey, bobNode.privateKey, ); - const prvKeyUint8: Uint8Array | null = ecc.privateAdd(bobNode.privateKey, s); + const prvKeyUint8: Uint8Array | null = ecc.privateAdd( + bobNode.privateKey, + s, + ); if (prvKeyUint8 === null) - throw new Error('Could not calculate private key') + throw new Error('Could not calculate private key'); const prvKey: Buffer = uintArrayToBuffer(prvKeyUint8); return bip32.fromPrivateKey( @@ -81,26 +87,23 @@ export function BIP47Factory(ecc: TinySecp256k1Interface): BIP47API { bobsRootPaymentCodeNode.derive(index); if (firstAlicePaymentCodeNode.privateKey === undefined) - throw new Error('Missing private key to generate payment address') + throw new Error('Missing private key to generate payment address'); const a: Buffer = firstAlicePaymentCodeNode.privateKey; const B: Buffer = bobPaymentCodeNode.publicKey; const s = getSharedSecret(B, a); const sGUint: Uint8Array | null = ecc.pointMultiply(G, s, true); - if (sGUint === null) - throw new Error('Could not compute sG') + if (sGUint === null) throw new Error('Could not compute sG'); const sG: Buffer = uintArrayToBuffer(sGUint); const BPrimeUint: Uint8Array | null = ecc.pointAdd(B, sG, true); - if (BPrimeUint === null) - throw new Error('Could not calculate pubkey'); + if (BPrimeUint === null) throw new Error('Could not calculate pubkey'); const BPrime: Buffer = uintArrayToBuffer(BPrimeUint); - if (!ecc.isPoint(BPrime)) - throw new Error('Calculate Pubkey is invalid'); + if (!ecc.isPoint(BPrime)) throw new Error('Calculate Pubkey is invalid'); const node: BIP32Interface = bip32.fromPublicKey( BPrime, @@ -175,7 +178,7 @@ export function BIP47Factory(ecc: TinySecp256k1Interface): BIP47API { const B: Buffer = bobBIP47.getNotificationNode().publicKey; const S: Buffer = uintArrayToBuffer(ecc.pointMultiply(B, a) as Buffer); - const x: Buffer = uintArrayToBuffer(ecc.xOnlyPointFromPoint(S) as Buffer); + const x: Buffer = uintArrayToBuffer(S.slice(1, 33)); const o: Buffer = outpoint; const s = crypto.hmacSHA512(o, x); @@ -238,14 +241,15 @@ export function BIP47Factory(ecc: TinySecp256k1Interface): BIP47API { const A: Buffer = pubKey; const b: Buffer = this.getNotificationNode().privateKey as Buffer; const S: Buffer = uintArrayToBuffer(ecc.pointMultiply(A, b) as Buffer); - const x: Buffer = uintArrayToBuffer(ecc.xOnlyPointFromPoint(S)); + const x: Buffer = uintArrayToBuffer(S.slice(1, 33)); const s = crypto.hmacSHA512(outpoint, x); - const opReturnOutput = tx.outs.find(o => + const opReturnOutput = tx.outs.find((o) => o.script.toString('hex').startsWith('6a4c50'), ); - if (!opReturnOutput) throw new Error('No OP_RETURN output in notification'); + if (!opReturnOutput) + throw new Error('No OP_RETURN output in notification'); const binaryPaymentCode: Buffer = opReturnOutput.script.slice(3); diff --git a/ts-src/index.ts b/ts-src/index.ts index a02ca9d..d3943f6 100644 --- a/ts-src/index.ts +++ b/ts-src/index.ts @@ -1,5 +1,5 @@ export { BIP47Factory as default, BIP47Factory } from './bip47'; -export { +export type { NetworkCoin, TinySecp256k1Interface, BIP47Interface, diff --git a/ts-src/interfaces.ts b/ts-src/interfaces.ts index 2f67ac0..1b66327 100644 --- a/ts-src/interfaces.ts +++ b/ts-src/interfaces.ts @@ -30,8 +30,6 @@ export interface TinySecp256k1Interface extends TinySecp256k1InterfaceBIP32 { pB: Uint8Array, compressed?: boolean, ): Uint8Array | null; - - xOnlyPointFromPoint(p: Uint8Array): Uint8Array; } export interface BIP47Interface { diff --git a/ts-src/utils.ts b/ts-src/utils.ts index 2f9269f..78569ee 100644 --- a/ts-src/utils.ts +++ b/ts-src/utils.ts @@ -47,13 +47,12 @@ export default function getUtils(ecc: TinySecp256k1Interface, bip32: BIP32API) { const getSharedSecret = (B: Buffer, a: Buffer): Buffer => { const S: Buffer = uintArrayToBuffer( - ecc.xOnlyPointFromPoint( - ecc.pointMultiply(B, a, true) as Buffer - )) + (ecc.pointMultiply(B, a, true) as Buffer).slice(1, 33), + ); let s: Buffer = bitcoin.crypto.sha256(S); if (!ecc.isPrivate(s)) - throw new Error('Shared secret is not a valid private key') + throw new Error('Shared secret is not a valid private key'); return s; }; @@ -62,7 +61,7 @@ export default function getUtils(ecc: TinySecp256k1Interface, bip32: BIP32API) { let start = 0; let length = data.length; - while(length - start >= 1) { + while (length - start >= 1) { const tmp = data[start]; const lastIndex = length - 1; data[start] = data[lastIndex]; @@ -71,8 +70,7 @@ export default function getUtils(ecc: TinySecp256k1Interface, bip32: BIP32API) { start++; } return data; - - } + }; return { getPublicPaymentCodeNodeFromBase58, getRootPaymentCodeNodeFromSeedHex, diff --git a/tsconfig.json b/tsconfig.json index 51e3dd5..459d470 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -5,9 +5,7 @@ "declaration": true, "declarationDir": "./types", "esModuleInterop": false, - "lib": [ - "es2017" - ], + "lib": ["es2017"], "module": "commonjs", "noImplicitAny": true, "noImplicitThis": true, @@ -19,16 +17,8 @@ "strictNullChecks": true, "strictPropertyInitialization": true, "target": "es2017", - "types": [ - "@types/mocha", - "node" - ] + "types": ["@types/mocha", "node"] }, - "include": [ - "ts-src/*.ts" - ], - "exclude": [ - "**/*.spec.ts", - "node_modules/**/*" - ] + "include": ["ts-src/*.ts", "types/tiny-secp256k1.d.ts"], + "exclude": ["**/*.spec.ts", "node_modules/**/*"] } diff --git a/types/index.d.ts b/types/index.d.ts index dc78923..243e5b2 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -1,3 +1,3 @@ export { BIP47Factory as default, BIP47Factory } from './bip47'; -export { NetworkCoin, TinySecp256k1Interface, BIP47Interface, BIP47API, PublicKeyOutpoint, } from './interfaces'; +export type { NetworkCoin, TinySecp256k1Interface, BIP47Interface, BIP47API, PublicKeyOutpoint, } from './interfaces'; export { testnetData, mainnetData } from './networks'; diff --git a/types/interfaces.d.ts b/types/interfaces.d.ts index 1232a02..a01e863 100644 --- a/types/interfaces.d.ts +++ b/types/interfaces.d.ts @@ -15,7 +15,6 @@ export interface TinySecp256k1Interface extends TinySecp256k1InterfaceBIP32 { privateAdd(d: Uint8Array, tweak: Uint8Array): Uint8Array | null; pointMultiply(p: Uint8Array, tweak: Uint8Array, compressed?: boolean): Uint8Array | null; pointAdd(pA: Uint8Array, pB: Uint8Array, compressed?: boolean): Uint8Array | null; - xOnlyPointFromPoint(p: Uint8Array): Uint8Array; } export interface BIP47Interface { network: NetworkCoin; diff --git a/types/tiny-secp256k1.d.ts b/types/tiny-secp256k1.d.ts new file mode 100644 index 0000000..6199738 --- /dev/null +++ b/types/tiny-secp256k1.d.ts @@ -0,0 +1 @@ +declare module 'tiny-secp256k1';