@tomo-inc/ledger-bitcoin-babylon
Version:
Ledger Hardware Wallet Babylon Application Client
211 lines • 20 kB
JavaScript
;
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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