我正在按照我在这里找到的内容尝试从bitcoinjs-lib签署Psbt交易:
我已经检查了账本和bitcoinjsLib的compressedd publicKey返回相同的值。
我可以使用bitcoinjs-lib ECPair对其进行签名,但是当我尝试使用分类帐对其进行签名时,它始终无效。
有人可以帮我指出我在哪里做错了吗?
这是我的代码。
/* tslint:disable */
require('regenerator-runtime');
const { default: Transport } = require('@ledgerhq/hw-transport-node-hid')
const { default: AppBtc } = require('@ledgerhq/hw-app-btc');
import * as bitcoin from 'bitcoinjs-lib'
const mnemonics = 'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about';
// not used, but if someone want to test using their own ledger.
const NETWORK = bitcoin.networks.regtest;
const segwit = true;
const LOCK_TIME = 0;
const SIGHASH_ALL = 1;
const path = `m/12'/0'/55'`
export function toByteArray(hexString: string) {
const Buffer = require('safe-buffer').Buffer;
const result = Buffer.alloc(hexString.length / 2);
let i = 0;
while (hexString.length >= 2) {
result[i] = parseInt(hexString.substring(0, 2), 16);
i += 1;
hexString = hexString.substring(2, hexString.length);
}
return result;
}
function toHexString(buffer: Buffer) {
return Array.prototype.map.call(new Uint8Array(buffer), x => ('00' + x.toString(16)).slice(-2)).join('');
}
function compressPublicKey(pk: string): string {
return toHexString(bitcoin.ECPair.fromPublicKey(toByteArray(pk)).publicKey);
}
async function main(): Promise<void> {
const nonWitnessUtxo = '02000000000105e11d8c7970aff25a8a431c49397316ce80af25dca6ac395f172e2d7326d42e570100000017160014cccb96f2ec1b5a2b7081f96b78077488769e3d8efeffffff77bcf72d69888cc739341107028e1e8a302d507fe9ffb94c5359fb1e82f08f370100000017160014527aef9caa6e0a12ecea8ce255cb36427a2f451afeffffff3cad9140403d6ec68bc0cf0b261daa4a41d92f04bddad98fc05a305127c7145c00000000171600143ea2fa276d3de26e4e220a1e6d343a235edbaff6feffffff250152b93632b8e275aba954c894dcbc2c0124a5c1db10de3edc5a0fd2880cc30100000017160014954f8b16a236e5d76b1f6fb69ea821b370fba749feffffffafd0c8b8eab835303aa213a0390e40e25a152dc62889b32df6887dc147b4e29b000000001716001436c91ffd3fd014ca8955eaa97e14dc9fdbed08f4feffffff0200e1f5050000000017a914f1f02b570afafacde515fcd6862a50822b56973e876c515f000000000017a9141afb048a646910eb09136f1cb311774d6c63e8ed870247304402200bfc0495e92aece0807c4c709fc05df3725794e766f36d372f3b35714d376775022077f01d90848205088374c2d8a9e28aedbc9f46212ce83fad7ab5ba00e33130680121021e3bbec438d71dc4966c817ee8db61970bd2288799d9bad9a5f8dd3795e2b0410247304402202c871ca7260d427f07f0482f939aa6193785de9b6df8742cf48881bd0525c4e0022056d7f2621d17fcacb3abd2dad030618a74abb259e852c98d10c96b541876a8340121033c41c3f65f7dab256d1cb28b195ba27c7fc4b1bf2c75e17935dfe9a3846b8c580247304402206cfb872c56f3cab4fcad77f83fc953d037c091d7714c0e7eca1257b56dff57c2022024540ce39d13d55de9f626aee397bad27ef5434f8e57890a3012886c4a6bc1c80121025dec89fee179c0248b24fa2c88db9890a386b836485784d53d12df639fb1e1d6024730440220239dc8ac1c0692b2a4642318cbef810114818132721ab2ba403f037ac0732b3302207112d7d1592b22958184f311f25b8e7a90ac353316bea8af12eeb731e9b0dd540121021a13c8f4c8767317c3cd9d0f7e4d8d8509822ca6891f7cbcc33ec10139b461040247304402205a407877f002d6dc86a83b3c31880366fc3f82204eb7d61a4c3a34c03439592c02201200f52a858463e6547287b2f2964594c6c3233886e12d7d3b499ef59cca5713012102b05ca0a2dc317d82f64483d4087419122eb27e5646e8190a7bac6c5cbacadbe500000000';
// this is the utxo with txid: 25ba0c45cadf92ded94432101d286975dcdb865df44b68da597910ea783cff74
// ecpairs things.
const ecPrivate = bitcoin.ECPair.fromPrivateKey(Buffer.from('64e897b5fac936a30a7a73e1c2892697c91b0705a8d061ea28e59f41d2876e0d', 'hex'), { network: NETWORK });
const ecPublic = bitcoin.ECPair.fromPublicKey(ecPrivate.publicKey, { network: NETWORK });
const p2wpkh = bitcoin.payments.p2wpkh({ pubkey: ecPublic.publicKey, network: NETWORK });
const p2sh = bitcoin.payments.p2sh({ redeem: p2wpkh, network: NETWORK });
const redeemScript = p2wpkh.output as Buffer;
// psbt things.
const psbt = new bitcoin.Psbt({ network: NETWORK });
psbt.addInput({
hash: '25ba0c45cadf92ded94432101d286975dcdb865df44b68da597910ea783cff74',
index: 0,
nonWitnessUtxo: Buffer.from(nonWitnessUtxo, 'hex'),
redeemScript,
});
psbt.addOutput({
address: '2MuhtGHkdxiL4BjFAAaYjq8Q2mwnCoYSebt',
value: 4000,
});
const transport = await Transport.create();
const btc = new AppBtc(transport);
// fromBitcoinJsLib: p2sh.address,
const fromLedger = await btc.getWalletPublicKey(path, { format: 'p2sh' });
const ledgerPublicKey = compressPublicKey(fromLedger.publicKey);
const bitcoinJsPublicKey = (ecPublic.publicKey as Buffer).toString('hex');
console.log({ ledgerPublicKey, bitcoinJsPublicKey });
// {
// ledgerPublicKey: '02c4ac4c11e08ffe8dce5b9d74d149ebab49949b195f67932be9dac6c810a6e6dc',
// bitcoinJsPublicKey: '02c4ac4c11e08ffe8dce5b9d74d149ebab49949b195f67932be9dac6c810a6e6dc'
// }
// signing with ledger.
const txInput = await btc.splitTransaction(nonWitnessUtxo, segwit);
const inputs = [[txInput, 0, redeemScript.toString('hex'), 0]]
const paths = [path];
const outshex = btc.serializeTransactionOutputs(btc.splitTransaction((psbt as any).__CACHE.__TX.toHex(), true)).toString('hex');
const signatures = await btc.signP2SHTransaction(inputs, paths, outshex, LOCK_TIME, SIGHASH_ALL, segwit, 2);
const signer = {
network: NETWORK,
publicKey: ecPublic.publicKey,
sign: ($hash: Buffer) => {
const signature = ecPrivate.sign($hash); // just for comparison.
const s = signatures[0];
const h = bitcoin.script.signature.decode(toByteArray(s));
console.log({
$hash: $hash.toString('hex'),
signature: signature.toString('hex'),
hsig: h.signature.toString('hex'),
});
// return signature;
return h.signature;
},
} as unknown as bitcoin.ECPairInterface;
psbt.signInput(0, signer);
const validated = psbt.validateSignaturesOfInput(0);
console.log({ validated });
// { validated: false }
// will be true if I used the signature from ecPrivate.sign($hash);
}
main();
我猜是您在传递给toByteArray
函数的字符串中有一个空格。此功能不修剪输入。也不会检查输入的长度是否为偶数。