UNPKG

@tomo-inc/ledger-bitcoin-babylon

Version:

Ledger Hardware Wallet Babylon Application Client

211 lines 20 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.createTaprootBip322Signature = exports.createSegwitBip322Signature = exports.bip0322Hash = void 0; const ecc = __importStar(require("@bitcoinerlab/secp256k1")); const bitcoinjs_lib_1 = require("bitcoinjs-lib"); const bip32_1 = require("bip32"); const varuint_bitcoin_1 = require("varuint-bitcoin"); const __1 = require("../.."); const _1 = require("./"); const types_1 = require("./types"); const BBN_MESSAGE_ADDR_STR_MIN_SIZE = 32; const BBN_MSG_HASH_BYTE_SIZE = 64; const bip32 = (0, bip32_1.BIP32Factory)(ecc); const encodeVarString = (b) => Buffer.concat([(0, varuint_bitcoin_1.encode)(b.byteLength), b]); const DUMMY_INPUT_HASH = Buffer.from('0000000000000000000000000000000000000000000000000000000000000000', 'hex'); const DUMMY_INPUT_INDEX = 0xffffffff; const DUMMY_INPUT_SEQUENCE = 0; function bip0322Hash(message) { const { sha256 } = bitcoinjs_lib_1.crypto; const tag = 'BIP0322-signed-message'; const tagHash = sha256(Buffer.from(tag)); const result = sha256(Buffer.concat([tagHash, tagHash, Buffer.from(message)])); return result.toString('hex'); } exports.bip0322Hash = bip0322Hash; const createMessageSignature = async (app, accountPolicy, message, witnessScript, inputArgs, isSegwit) => { const scriptSig = Buffer.concat([ Buffer.from('0020', 'hex'), Buffer.from(bip0322Hash(message), 'hex'), ]); const txToSpend = new bitcoinjs_lib_1.Transaction(); txToSpend.version = 0; txToSpend.addInput(DUMMY_INPUT_HASH, DUMMY_INPUT_INDEX, DUMMY_INPUT_SEQUENCE, scriptSig); txToSpend.addOutput(witnessScript, 0); const psbtToSign = new bitcoinjs_lib_1.Psbt(); psbtToSign.setVersion(0); psbtToSign.addInput(Object.assign({ hash: txToSpend.getHash(), index: 0, sequence: 0, witnessUtxo: { script: witnessScript, value: 0, } }, inputArgs)); psbtToSign.addOutput({ script: Buffer.from('6a', 'hex'), value: 0 }); const signatures = await app.signPsbt(psbtToSign.toBase64(), accountPolicy, null); for (const signature of signatures) { if (isSegwit) { psbtToSign.updateInput(signature[0], { partialSig: [signature[1]], }); } else { psbtToSign.updateInput(signature[0], { tapKeySig: signature[1].signature, }); } } psbtToSign.finalizeAllInputs(); const txToSign = psbtToSign.extractTransaction(); const len = (0, varuint_bitcoin_1.encode)(txToSign.ins[0].witness.length); const result = Buffer.concat([ len, ...txToSign.ins[0].witness.map((w) => encodeVarString(w)), ]); const signature = result.toString('base64'); return { signature, protocol: types_1.MessageSigningProtocols.BIP322, }; }; function getPublicKeyFromXpubAtIndex(xpub, index, isTestnet) { const btcNetwork = isTestnet ? bitcoinjs_lib_1.networks.testnet : bitcoinjs_lib_1.networks.bitcoin; const { publicKey } = bip32 .fromBase58(xpub, btcNetwork) .derivePath(`0/${index}`); return publicKey; } function getNativeSegwitAccountDataFromXpub(xpub, index, isTestnet = false) { (0, bitcoinjs_lib_1.initEccLib)(ecc); const publicKey = getPublicKeyFromXpubAtIndex(xpub, index, isTestnet); const btcNetwork = isTestnet ? bitcoinjs_lib_1.networks.testnet : bitcoinjs_lib_1.networks.bitcoin; const p2wpkh = bitcoinjs_lib_1.payments.p2wpkh({ pubkey: publicKey, network: btcNetwork }); const address = p2wpkh.address; if (!address) { throw new Error('Address is null'); } if (!p2wpkh.output) { throw new Error('p2wpkh output is null'); } return { publicKey, address, witnessScript: p2wpkh.output, }; } async function createSegwitBip322Signature({ message, app, derivationPath = `m/84'/0'/0'`, isTestnet = false, }) { const masterFingerPrint = await app.getMasterFingerprint(); const extendedPublicKey = await app.getExtendedPubkey(derivationPath); const { publicKey, witnessScript } = getNativeSegwitAccountDataFromXpub(extendedPublicKey, 0, isTestnet); const inputDerivation = { path: `${derivationPath}/0/0`, pubkey: publicKey, masterFingerprint: Buffer.from(masterFingerPrint, 'hex'), }; const accountPolicy = new __1.WalletPolicy('Sign message', 'wpkh(@0/**)', [ `[${derivationPath.replace('m/', `${masterFingerPrint}/`)}]${extendedPublicKey}`, ]); return createMessageSignature(app, accountPolicy, message, witnessScript, { bip32Derivation: [inputDerivation], }, true); } exports.createSegwitBip322Signature = createSegwitBip322Signature; function getTaprootAccountDataFromXpub(xpub, index, isTestnet = false) { (0, bitcoinjs_lib_1.initEccLib)(ecc); const publicKey = getPublicKeyFromXpubAtIndex(xpub, index, isTestnet); const p2tr = bitcoinjs_lib_1.payments.p2tr({ internalPubkey: publicKey.slice(1), network: isTestnet ? bitcoinjs_lib_1.networks.testnet : bitcoinjs_lib_1.networks.bitcoin, }); if (!p2tr.output || !p2tr.address || !p2tr.internalPubkey) { throw new Error('p2tr output, address or internalPubkey is null'); } return { publicKey, address: p2tr.address, internalPubkey: p2tr.internalPubkey, taprootScript: p2tr.output, }; } function _padHexString(hexString, dataLength) { const len = dataLength; const lenHex = len.toString(16).padStart(2, '0'); let result = lenHex + hexString; const padNeeded = 64 - result.length; if (padNeeded > 0) { result += 'fc'.repeat(padNeeded / 2); } return result; } function _formatMessage(data, prefix) { let hexString = ''; for (let i = 0; i < data.length; i++) { const byte = data[i].toString(16).padStart(2, '0'); hexString += byte; } const prefixBuffer = Buffer.from(prefix, 'ascii'); const prefixLenHex = prefixBuffer.length.toString(16).padStart(2, '0'); hexString += prefixLenHex + prefixBuffer.toString('hex'); return _padHexString(hexString, data.length); } async function createTaprootBip322Signature({ message, app, derivationPath = `m/86'/0'/0'`, isTestnet = false, }) { const OriginalMessage = message; let hashHex; let formattedHash; if (message.length > BBN_MESSAGE_ADDR_STR_MIN_SIZE + BBN_MSG_HASH_BYTE_SIZE) { hashHex = message.slice(0, BBN_MSG_HASH_BYTE_SIZE); message = message.slice(BBN_MSG_HASH_BYTE_SIZE); formattedHash = (0, _1.formatKey)(hashHex, isTestnet); } else { hashHex = Buffer.alloc(32, 0xff).toString('hex'); formattedHash = (0, _1.formatKey)(hashHex, isTestnet); } const masterFingerPrint = await app.getMasterFingerprint(); const extendedPublicKey = await app.getExtendedPubkey(derivationPath); const { internalPubkey, taprootScript } = getTaprootAccountDataFromXpub(extendedPublicKey, 0, isTestnet); // Need to update input derivation path so the ledger can recognize the inputs to sign const inputDerivation = { path: `${derivationPath}/0/0`, pubkey: internalPubkey, masterFingerprint: Buffer.from(masterFingerPrint, 'hex'), leafHashes: [], }; const addressResult = (0, _1.validadteAddress)(message); if (!addressResult || !addressResult.data) { throw new Error('The message should be a valid bbn address.'); } const address = addressResult.data; const accountPolicy = new __1.WalletPolicy('Sign message', 'tr(@0/**,and_v(pk_k(@1/**),and_v(pk_k(@2/**),pk_k(@3/**))))', [ `[${derivationPath.replace('m/', `${masterFingerPrint}/`)}]${extendedPublicKey}`, `[${derivationPath.replace('m/', `${types_1.MagicCode.BIP322_MESSAGE_FP}/`)}]${(0, _1.formatKey)(_formatMessage(address, addressResult.prefix), isTestnet)}`, `[${derivationPath.replace('m/', `${types_1.MagicCode.BIP322_TAP_PUBKEY_FP}/`)}]${(0, _1.formatKey)(taprootScript.slice(2), isTestnet)}`, `[${derivationPath.replace('m/', `${types_1.MagicCode.BIP322_HASH_FP}/`)}]${formattedHash}`, ]); return createMessageSignature(app, accountPolicy, OriginalMessage, taprootScript, { tapBip32Derivation: [inputDerivation], tapInternalKey: internalPubkey, }, false); } exports.createTaprootBip322Signature = createTaprootBip322Signature; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYmlwMzIyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL2xpYi9iYWJ5bG9uL2JpcDMyMi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQUFBLDZEQUErQztBQUMvQyxpREFPdUI7QUFDdkIsaUNBQXFDO0FBQ3JDLHFEQUF5QztBQUV6Qyw2QkFBZ0Q7QUFDaEQseUJBQWlEO0FBQ2pELG1DQU1pQjtBQUNqQixNQUFNLDZCQUE2QixHQUFHLEVBQUUsQ0FBQTtBQUN4QyxNQUFNLHNCQUFzQixHQUFHLEVBQUUsQ0FBQTtBQUVqQyxNQUFNLEtBQUssR0FBRyxJQUFBLG9CQUFZLEVBQUMsR0FBRyxDQUFDLENBQUM7QUFDaEMsTUFBTSxlQUFlLEdBQUcsQ0FBQyxDQUFTLEVBQUUsRUFBRSxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsQ0FBQyxJQUFBLHdCQUFNLEVBQUMsQ0FBQyxDQUFDLFVBQVUsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUM7QUFDaEYsTUFBTSxnQkFBZ0IsR0FBRyxNQUFNLENBQUMsSUFBSSxDQUNsQyxrRUFBa0UsRUFDbEUsS0FBSyxDQUNOLENBQUM7QUFDRixNQUFNLGlCQUFpQixHQUFHLFVBQVUsQ0FBQztBQUNyQyxNQUFNLG9CQUFvQixHQUFHLENBQUMsQ0FBQztBQUcvQixTQUFnQixXQUFXLENBQUMsT0FBZTtJQUN6QyxNQUFNLEVBQUUsTUFBTSxFQUFFLEdBQUcsc0JBQU0sQ0FBQztJQUMxQixNQUFNLEdBQUcsR0FBRyx3QkFBd0IsQ0FBQztJQUNyQyxNQUFNLE9BQU8sR0FBRyxNQUFNLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDO0lBQ3pDLE1BQU0sTUFBTSxHQUFHLE1BQU0sQ0FDbkIsTUFBTSxDQUFDLE1BQU0sQ0FBQyxDQUFDLE9BQU8sRUFBRSxPQUFPLEVBQUUsTUFBTSxDQUFDLElBQUksQ0FBQyxPQUFP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