@exodus/bip322-js
Version:
A Javascript library that provides utility functions related to the BIP-322 signature scheme
69 lines (68 loc) • 2.25 kB
JavaScript
import { hashSync } from '@exodus/crypto/hash';
import * as bitcoin from '@exodus/bitcoinjs';
class BIP322 {
static TAG = Buffer.from('BIP0322-signed-message');
static hashMessage(message) {
const tagHash = hashSync('sha256', this.TAG);
return hashSync('sha256', [tagHash, tagHash, Buffer.from(message)]);
}
static buildToSpendTx(message, scriptPublicKey) {
const psbt = new bitcoin.Psbt();
psbt.setVersion(0);
psbt.setLocktime(0);
const messageHash = this.hashMessage(message);
const scriptSigPartOne = new Uint8Array([0x00, 0x20]);
const scriptSig = new Uint8Array(scriptSigPartOne.length + messageHash.length);
scriptSig.set(scriptSigPartOne);
scriptSig.set(messageHash, scriptSigPartOne.length);
psbt.addInput({
hash: '0'.repeat(64),
index: 0xff_ff_ff_ff,
sequence: 0,
finalScriptSig: Buffer.from(scriptSig),
witnessScript: Buffer.from([]),
});
psbt.addOutput({
value: 0,
script: scriptPublicKey,
});
return psbt.extractTransaction();
}
static buildToSignTx(toSpendTxId, witnessScript, isRedeemScript = false, tapInternalKey) {
const psbt = new bitcoin.Psbt();
psbt.setVersion(0);
psbt.setLocktime(0);
psbt.addInput({
hash: toSpendTxId,
index: 0,
sequence: 0,
witnessUtxo: {
script: witnessScript,
value: 0,
},
});
if (isRedeemScript) {
psbt.updateInput(0, {
redeemScript: witnessScript,
});
}
if (tapInternalKey) {
psbt.updateInput(0, {
tapInternalKey,
});
}
psbt.addOutput({
value: 0,
script: Buffer.from([0x6a]),
});
return psbt;
}
static encodeWitness(signedPsbt) {
const witness = signedPsbt.data.inputs[0]?.finalScriptWitness;
if (witness) {
return witness.toString('base64');
}
throw new Error('Cannot encode empty witness stack.');
}
}
export default BIP322;