Add hasHDKey

This commit is contained in:
junderw 2020-04-29 14:39:50 +09:00
parent 5d19abfb85
commit f87a20caa7
No known key found for this signature in database
GPG key ID: A9273B5AD3E47B45
4 changed files with 105 additions and 0 deletions

View file

@ -305,10 +305,24 @@ class Psbt {
const input = utils_1.checkForInput(this.data.inputs, inputIndex);
return pubkeyInInput(pubkey, input, inputIndex, this.__CACHE);
}
inputHasHDKey(inputIndex, root) {
const input = utils_1.checkForInput(this.data.inputs, inputIndex);
const derivationIsMine = bip32DerivationIsMine(root);
return (
!!input.bip32Derivation && input.bip32Derivation.some(derivationIsMine)
);
}
outputHasPubkey(outputIndex, pubkey) {
const output = utils_1.checkForOutput(this.data.outputs, outputIndex);
return pubkeyInOutput(pubkey, output, outputIndex, this.__CACHE);
}
outputHasHDKey(outputIndex, root) {
const output = utils_1.checkForOutput(this.data.outputs, outputIndex);
const derivationIsMine = bip32DerivationIsMine(root);
return (
!!output.bip32Derivation && output.bip32Derivation.some(derivationIsMine)
);
}
validateSignaturesOfAllInputs() {
utils_1.checkForInput(this.data.inputs, 0); // making sure we have at least one
const results = range(this.data.inputs.length).map(idx =>
@ -696,6 +710,13 @@ const isP2PKH = isPaymentFactory(payments.p2pkh);
const isP2WPKH = isPaymentFactory(payments.p2wpkh);
const isP2WSHScript = isPaymentFactory(payments.p2wsh);
const isP2SHScript = isPaymentFactory(payments.p2sh);
function bip32DerivationIsMine(root) {
return d => {
if (!d.masterFingerprint.equals(root.fingerprint)) return false;
if (!root.derivePath(d.path).publicKey.equals(d.pubkey)) return false;
return true;
};
}
function check32Bit(num) {
if (
typeof num !== 'number' ||

View file

@ -1,4 +1,5 @@
import * as assert from 'assert';
import * as crypto from 'crypto';
import { describe, it } from 'mocha';
import { bip32, ECPair, networks as NETWORKS, payments, Psbt } from '..';
@ -641,6 +642,29 @@ describe(`Psbt`, () => {
].forEach(getInputTypeTest);
});
describe('inputHasHDKey', () => {
it('should return true if HD key is present', () => {
const root = bip32.fromSeed(crypto.randomBytes(32));
const root2 = bip32.fromSeed(crypto.randomBytes(32));
const path = "m/0'/0";
const psbt = new Psbt();
psbt.addInput({
hash:
'0000000000000000000000000000000000000000000000000000000000000000',
index: 0,
bip32Derivation: [
{
masterFingerprint: root.fingerprint,
path,
pubkey: root.derivePath(path).publicKey,
},
],
});
assert.strictEqual(psbt.inputHasHDKey(0, root), true);
assert.strictEqual(psbt.inputHasHDKey(0, root2), false);
});
});
describe('inputHasPubkey', () => {
it('should throw', () => {
const psbt = new Psbt();
@ -712,6 +736,37 @@ describe(`Psbt`, () => {
});
});
describe('outputHasHDKey', () => {
it('should return true if HD key is present', () => {
const root = bip32.fromSeed(crypto.randomBytes(32));
const root2 = bip32.fromSeed(crypto.randomBytes(32));
const path = "m/0'/0";
const psbt = new Psbt();
psbt
.addInput({
hash:
'0000000000000000000000000000000000000000000000000000000000000000',
index: 0,
})
.addOutput({
script: Buffer.from(
'0014000102030405060708090a0b0c0d0e0f00010203',
'hex',
),
value: 2000,
bip32Derivation: [
{
masterFingerprint: root.fingerprint,
path,
pubkey: root.derivePath(path).publicKey,
},
],
});
assert.strictEqual(psbt.outputHasHDKey(0, root), true);
assert.strictEqual(psbt.outputHasHDKey(0, root2), false);
});
});
describe('outputHasPubkey', () => {
it('should throw', () => {
const psbt = new Psbt();

View file

@ -1,6 +1,7 @@
import { Psbt as PsbtBase } from 'bip174';
import * as varuint from 'bip174/src/lib/converter/varint';
import {
Bip32Derivation,
KeyValue,
PartialSig,
PsbtGlobalUpdate,
@ -377,11 +378,27 @@ export class Psbt {
return pubkeyInInput(pubkey, input, inputIndex, this.__CACHE);
}
inputHasHDKey(inputIndex: number, root: HDSigner): boolean {
const input = checkForInput(this.data.inputs, inputIndex);
const derivationIsMine = bip32DerivationIsMine(root);
return (
!!input.bip32Derivation && input.bip32Derivation.some(derivationIsMine)
);
}
outputHasPubkey(outputIndex: number, pubkey: Buffer): boolean {
const output = checkForOutput(this.data.outputs, outputIndex);
return pubkeyInOutput(pubkey, output, outputIndex, this.__CACHE);
}
outputHasHDKey(outputIndex: number, root: HDSigner): boolean {
const output = checkForOutput(this.data.outputs, outputIndex);
const derivationIsMine = bip32DerivationIsMine(root);
return (
!!output.bip32Derivation && output.bip32Derivation.some(derivationIsMine)
);
}
validateSignaturesOfAllInputs(): boolean {
checkForInput(this.data.inputs, 0); // making sure we have at least one
const results = range(this.data.inputs.length).map(idx =>
@ -905,6 +922,16 @@ const isP2WPKH = isPaymentFactory(payments.p2wpkh);
const isP2WSHScript = isPaymentFactory(payments.p2wsh);
const isP2SHScript = isPaymentFactory(payments.p2sh);
function bip32DerivationIsMine(
root: HDSigner,
): (d: Bip32Derivation) => boolean {
return (d: Bip32Derivation): boolean => {
if (!d.masterFingerprint.equals(root.fingerprint)) return false;
if (!root.derivePath(d.path).publicKey.equals(d.pubkey)) return false;
return true;
};
}
function check32Bit(num: number): void {
if (
typeof num !== 'number' ||

2
types/psbt.d.ts vendored
View file

@ -71,7 +71,9 @@ export declare class Psbt {
finalizeInput(inputIndex: number, finalScriptsFunc?: FinalScriptsFunc): this;
getInputType(inputIndex: number): AllScriptType;
inputHasPubkey(inputIndex: number, pubkey: Buffer): boolean;
inputHasHDKey(inputIndex: number, root: HDSigner): boolean;
outputHasPubkey(outputIndex: number, pubkey: Buffer): boolean;
outputHasHDKey(outputIndex: number, root: HDSigner): boolean;
validateSignaturesOfAllInputs(): boolean;
validateSignaturesOfInput(inputIndex: number, pubkey?: Buffer): boolean;
signAllInputsHD(hdKeyPair: HDSigner, sighashTypes?: number[]): this;