Skip to content

Commit 914a1aa

Browse files
davidkaplanbitgochristopher-fong
authored andcommitted
chore: got tests to work
BTC-2047 TICKET: BTC-2047 feat(utxo-core): cleaned up comments TICKET: BTC-2047 chore(utxo-core): added bitcoinjs-message to deps and fixed import TICKET: BTC-2047
1 parent 795048f commit 914a1aa

File tree

4 files changed

+82
-51
lines changed

4 files changed

+82
-51
lines changed

modules/utxo-core/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,8 @@
5454
"@bitgo/unspents": "^0.47.21",
5555
"@bitgo/utxo-lib": "^11.3.0",
5656
"@bitgo/wasm-miniscript": "2.0.0-beta.7",
57-
"bip174": "npm:@bitgo-forks/[email protected]"
57+
"bip174": "npm:@bitgo-forks/[email protected]",
58+
"bitcoinjs-message": "npm:@bitgo-forks/[email protected]"
5859
},
5960
"gitHead": "18e460ddf02de2dbf13c2aa243478188fb539f0c"
6061
}

modules/utxo-core/src/paygo/psbt/PayGoUtils.ts

Lines changed: 46 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
1+
import * as utxolib from '@bitgo/utxo-lib';
12
import * as bitcoinMessage from 'bitcoinjs-message';
2-
import { crypto } from 'bitcoinjs-lib';
3-
import { networks, bitgo } from '@bitgo/utxo-lib';
4-
import { toBase58Check } from '@bitgo/utxo-lib/src/address';
53

64
import { extractAddressBufferFromPayGoAttestationProof } from '../ExtractAddressPayGoAttestation';
75

@@ -14,11 +12,16 @@ import { extractAddressBufferFromPayGoAttestationProof } from '../ExtractAddress
1412
* @param outputIndex - the index of the address in our output
1513
* @param sig - the signature that we want to encode
1614
*/
17-
export function addPaygoAddressProof(psbt: bitgo.UtxoPsbt, outputIndex: number, sig: Buffer, pub: Buffer): void {
15+
export function addPaygoAddressProof(
16+
psbt: utxolib.bitgo.UtxoPsbt,
17+
outputIndex: number,
18+
sig: Buffer,
19+
pub: Buffer
20+
): void {
1821
psbt.addProprietaryKeyValToOutput(outputIndex, {
1922
key: {
20-
identifier: bitgo.PSBT_PROPRIETARY_IDENTIFIER,
21-
subtype: bitgo.ProprietaryKeySubtype.PAYGO_ADDRESS_ATTESTATION_PROOF,
23+
identifier: utxolib.bitgo.PSBT_PROPRIETARY_IDENTIFIER,
24+
subtype: utxolib.bitgo.ProprietaryKeySubtype.PAYGO_ADDRESS_ATTESTATION_PROOF,
2225
keydata: pub,
2326
},
2427
value: sig,
@@ -33,10 +36,15 @@ export function addPaygoAddressProof(psbt: bitgo.UtxoPsbt, outputIndex: number,
3336
* @param message - The message we want to verify corresponding to sig
3437
* @returns
3538
*/
36-
export function verifyPaygoAddressProof(psbt: bitgo.UtxoPsbt, outputIndex: number, message: Buffer): void {
39+
export function verifyPaygoAddressProof(
40+
psbt: utxolib.bitgo.UtxoPsbt,
41+
outputIndex: number,
42+
message: Buffer,
43+
attestationPubKey: Buffer
44+
): void {
3745
const stored = psbt.getOutputProprietaryKeyVals(outputIndex, {
38-
identifier: bitgo.PSBT_PROPRIETARY_IDENTIFIER,
39-
subtype: bitgo.ProprietaryKeySubtype.PAYGO_ADDRESS_ATTESTATION_PROOF,
46+
identifier: utxolib.bitgo.PSBT_PROPRIETARY_IDENTIFIER,
47+
subtype: utxolib.bitgo.ProprietaryKeySubtype.PAYGO_ADDRESS_ATTESTATION_PROOF,
4048
});
4149
if (!stored) {
4250
throw new Error(`No address proof.`);
@@ -51,21 +59,37 @@ export function verifyPaygoAddressProof(psbt: bitgo.UtxoPsbt, outputIndex: numbe
5159

5260
const signature = stored[0].value;
5361
const pub = stored[0].key.keydata;
62+
63+
// Check that the keydata pubkey is the same as the one we are verifying against
64+
if (Buffer.compare(pub, attestationPubKey) !== 0) {
65+
throw new Error('The public key in the PSBT does not match the provided public key.');
66+
}
67+
5468
// It doesn't matter that this is bitcoin or not, we just need to convert the public key buffer into an address format
5569
// for the verification
56-
const messageToVerify = toBase58Check(crypto.hash160(pub), networks.bitcoin.pubKeyHash, networks.bitcoin);
70+
const messageToVerify = utxolib.address.toBase58Check(
71+
utxolib.crypto.hash160(pub),
72+
utxolib.networks.bitcoin.pubKeyHash,
73+
utxolib.networks.bitcoin
74+
);
5775

58-
if (!bitcoinMessage.verify(message, messageToVerify, signature)) {
76+
if (!bitcoinMessage.verify(message, messageToVerify, signature, utxolib.networks.bitcoin.messagePrefix)) {
5977
throw new Error('Cannot verify the paygo address signature with the provided pubkey.');
6078
}
61-
// We should be verifying the address that was encoded into our message, not from our transaction output.
62-
// We already do this because our message should be signed with our address
63-
// which is the same one we used to verify the authenticity of the message given its signature as well.
64-
const addressFromProof = extractAddressBufferFromPayGoAttestationProof(message);
79+
// We should be verifying the address that was encoded into our message.
80+
const addressFromProof = extractAddressBufferFromPayGoAttestationProof(message).toString();
81+
82+
// Check that the address from the proof matches what is in the PSBT
83+
const txOutputs = psbt.txOutputs;
84+
if (outputIndex >= txOutputs.length) {
85+
throw new Error(`Output index ${outputIndex} is out of bounds for PSBT outputs.`);
86+
}
87+
const output = txOutputs[outputIndex];
88+
const addressFromOutput = utxolib.address.fromOutputScript(output.script, psbt.network);
6589

66-
if (Buffer.compare(addressFromProof, Buffer.from(messageToVerify)) !== 0) {
90+
if (addressFromProof !== addressFromOutput) {
6791
throw new Error(
68-
`The address from the output (${messageToVerify}) does not match the address that is in the proof (${addressFromProof}).`
92+
`The address from the output (${addressFromOutput}) does not match the address that is in the proof (${addressFromProof}).`
6993
);
7094
}
7195
}
@@ -77,11 +101,11 @@ export function verifyPaygoAddressProof(psbt: bitgo.UtxoPsbt, outputIndex: numbe
77101
* @param psbt
78102
* @returns number - the index of the output address
79103
*/
80-
export function getPaygoAddressProofOutputIndex(psbt: bitgo.UtxoPsbt): number | undefined {
104+
export function getPaygoAddressProofOutputIndex(psbt: utxolib.bitgo.UtxoPsbt): number | undefined {
81105
const res = psbt.data.outputs.flatMap((output, outputIndex) => {
82-
const proprietaryKeyVals = bitgo.getPsbtOutputProprietaryKeyVals(output, {
83-
identifier: bitgo.PSBT_PROPRIETARY_IDENTIFIER,
84-
subtype: bitgo.ProprietaryKeySubtype.PAYGO_ADDRESS_ATTESTATION_PROOF,
106+
const proprietaryKeyVals = utxolib.bitgo.getPsbtOutputProprietaryKeyVals(output, {
107+
identifier: utxolib.bitgo.PSBT_PROPRIETARY_IDENTIFIER,
108+
subtype: utxolib.bitgo.ProprietaryKeySubtype.PAYGO_ADDRESS_ATTESTATION_PROOF,
85109
});
86110

87111
if (proprietaryKeyVals.length > 1) {
@@ -94,6 +118,6 @@ export function getPaygoAddressProofOutputIndex(psbt: bitgo.UtxoPsbt): number |
94118
return res.length === 0 ? undefined : res[0];
95119
}
96120

97-
export function psbtOutputIncludesPaygoAddressProof(psbt: bitgo.UtxoPsbt): boolean {
121+
export function psbtOutputIncludesPaygoAddressProof(psbt: utxolib.bitgo.UtxoPsbt): boolean {
98122
return getPaygoAddressProofOutputIndex(psbt) !== undefined;
99123
}

modules/utxo-core/test/paygo/psbt/PayGoUtils.ts

Lines changed: 32 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import assert from 'assert';
22

3+
import * as utxolib from '@bitgo/utxo-lib';
34
import * as bitcoinMessage from 'bitcoinjs-message';
45
import { decodeProprietaryKey } from 'bip174/src/lib/proprietaryKeyVal';
56
import { KeyValue } from 'bip174/src/lib/interfaces';
67
import { checkForOutput } from 'bip174/src/lib/utils';
7-
import { bitgo, networks, testutil, bip32, crypto, address } from '@bitgo/utxo-lib';
88

99
import {
1010
addPaygoAddressProof,
@@ -15,37 +15,42 @@ import {
1515
import { generatePayGoAttestationProof } from '../../../src/testutil/generatePayGoAttestationProof.utils';
1616

1717
// To construct our PSBTs
18-
const network = networks.bitcoin;
19-
const keys = [1, 2, 3].map((v) => bip32.fromSeed(Buffer.alloc(16, `test/2/${v}`), network));
20-
const rootWalletKeys = new bitgo.RootWalletKeys([keys[0], keys[1], keys[2]]);
21-
const psbtInputs = testutil.inputScriptTypes.map((scriptType) => ({ scriptType, value: BigInt(1000) }));
22-
const psbtOutputs = testutil.outputScriptTypes.map((scriptType) => ({ scriptType, value: BigInt(900) }));
23-
const dummyPub1 = rootWalletKeys.deriveForChainAndIndex(50, 200);
18+
const network = utxolib.networks.bitcoin;
19+
const keys = [1, 2, 3].map((v) => utxolib.bip32.fromSeed(Buffer.alloc(16, `test/2/${v}`), network));
20+
const rootWalletKeys = new utxolib.bitgo.RootWalletKeys([keys[0], keys[1], keys[2]]);
21+
22+
// PSBT INPUTS AND OUTPUTS
23+
const psbtInputs = utxolib.testutil.inputScriptTypes.map((scriptType) => ({
24+
scriptType,
25+
value: BigInt(1000),
26+
}));
27+
const psbtOutputs = utxolib.testutil.outputScriptTypes.map((scriptType) => ({
28+
scriptType,
29+
value: BigInt(900),
30+
}));
31+
2432
// wallet pub and priv key for tbtc
33+
const dummyPub1 = rootWalletKeys.deriveForChainAndIndex(50, 200);
2534
const attestationPubKey = dummyPub1.user.publicKey;
2635
const attestationPrvKey = dummyPub1.user.privateKey!;
27-
// const attestationPubKey =
28-
// 'xpub661MyMwAqRbcFU2Qx7pvGmmiQpVj8NcR7dSVpgqNChMkQyobpVWWERcrTb47WicmXwkhAY2VrC3hb29s18FDQWJf5pLm3saN6uLXAXpw1GV';
29-
// const attestationPrvKey = '3FlzrW1WuPbab2GWGyx+k/pHUNefDlw3SV0NQHLrWA+YEzqbvEQmosFGXMslYqtgpeIy6HiEoEvKzbNKM7yGY8GQHv7E++/sQRFDprOyklaW7GVyC2yEZe/LdaEfBvxf2VHBmu2hYubjsdHYF5+RQ3FhnyaNT+0=';
30-
// const keypair = ECPair.fromPrivateKey(Buffer.from(attestationPrvKey));
3136

3237
// UUID structure
3338
const nilUUID = '00000000-0000-0000-0000-000000000000';
3439

3540
// our xpub converted to base58 address
36-
const addressFromPubkey = address.toBase58Check(
37-
crypto.hash160(Buffer.from(attestationPubKey)),
38-
networks.bitcoin.pubKeyHash,
39-
networks.bitcoin
41+
const addressToVerify = utxolib.address.toBase58Check(
42+
utxolib.crypto.hash160(Buffer.from(dummyPub1.backup.publicKey)),
43+
utxolib.networks.bitcoin.pubKeyHash,
44+
utxolib.networks.bitcoin
4045
);
46+
4147
// this should be retuning a Buffer
42-
const addressProofBuffer = generatePayGoAttestationProof(nilUUID, Buffer.from(addressFromPubkey));
48+
const addressProofBuffer = generatePayGoAttestationProof(nilUUID, Buffer.from(addressToVerify));
4349
// signature with the given msg addressProofBuffer
44-
// console.log(attestationPrvKey)
45-
const sig = bitcoinMessage.sign(addressProofBuffer, attestationPrvKey!);
50+
const sig = bitcoinMessage.sign(addressProofBuffer, attestationPrvKey!, true, network.messagePrefix);
4651

4752
function getTestPsbt() {
48-
return testutil.constructPsbt(psbtInputs, psbtOutputs, network, rootWalletKeys, 'unsigned');
53+
return utxolib.testutil.constructPsbt(psbtInputs, psbtOutputs, network, rootWalletKeys, 'unsigned');
4954
}
5055

5156
describe('addPaygoAddressProof and verifyPaygoAddressProof', () => {
@@ -56,8 +61,8 @@ describe('addPaygoAddressProof and verifyPaygoAddressProof', () => {
5661
})
5762
.filter((keyValue) => {
5863
return (
59-
keyValue.key.identifier === bitgo.PSBT_PROPRIETARY_IDENTIFIER &&
60-
keyValue.key.subtype === bitgo.ProprietaryKeySubtype.PAYGO_ADDRESS_ATTESTATION_PROOF
64+
keyValue.key.identifier === utxolib.bitgo.PSBT_PROPRIETARY_IDENTIFIER &&
65+
keyValue.key.subtype === utxolib.bitgo.ProprietaryKeySubtype.PAYGO_ADDRESS_ATTESTATION_PROOF
6166
);
6267
});
6368
}
@@ -70,16 +75,17 @@ describe('addPaygoAddressProof and verifyPaygoAddressProof', () => {
7075
const proofInPsbt = getPaygoProprietaryKey(output.unknownKeyVals!);
7176
assert(proofInPsbt.length === 1);
7277
assert.throws(
73-
() => verifyPaygoAddressProof(psbt, 0, Buffer.from('Random Signed Message')),
78+
() => verifyPaygoAddressProof(psbt, 0, Buffer.from('Random Signed Message'), attestationPubKey),
7479
(e: any) => e.message === 'Cannot verify the paygo address signature with the provided pubkey.'
7580
);
7681
});
7782

7883
it('should add and verify a valid paygo address proof on the PSBT', () => {
79-
const outputIndex = 0;
8084
const psbt = getTestPsbt();
85+
psbt.addOutput({ script: utxolib.address.toOutputScript(addressToVerify, network), value: BigInt(10000) });
86+
const outputIndex = psbt.data.outputs.length - 1;
8187
addPaygoAddressProof(psbt, outputIndex, sig, Buffer.from(attestationPubKey));
82-
verifyPaygoAddressProof(psbt, outputIndex, Buffer.from(addressProofBuffer));
88+
verifyPaygoAddressProof(psbt, outputIndex, Buffer.from(addressProofBuffer), attestationPubKey);
8389
});
8490

8591
it('should throw an error if there are multiple PayGo proprietary keys in the PSBT', () => {
@@ -92,7 +98,7 @@ describe('addPaygoAddressProof and verifyPaygoAddressProof', () => {
9298
assert(proofInPsbt.length !== 0);
9399
assert(proofInPsbt.length > 1);
94100
assert.throws(
95-
() => verifyPaygoAddressProof(psbt, outputIndex, addressProofBuffer),
101+
() => verifyPaygoAddressProof(psbt, outputIndex, addressProofBuffer, attestationPubKey),
96102
(e: any) => e.message === 'There are multiple paygo address proofs encoded in the PSBT. Something went wrong.'
97103
);
98104
});
@@ -102,7 +108,7 @@ describe('verifyPaygoAddressProof', () => {
102108
it('should throw an error if there is no PayGo address in PSBT', () => {
103109
const psbt = getTestPsbt();
104110
assert.throws(
105-
() => verifyPaygoAddressProof(psbt, 0, addressProofBuffer),
111+
() => verifyPaygoAddressProof(psbt, 0, addressProofBuffer, attestationPubKey),
106112
(e: any) => e.message === 'There is no paygo address proof encoded in the PSBT at output 0.'
107113
);
108114
});

modules/utxo-lib/src/bitgo/zcash/address.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ export function toBase58Check(hash: Buffer, version: number): string {
2323
}
2424

2525
export function fromOutputScript(outputScript: Buffer, network: Network): string {
26-
assert(isZcash(network));
26+
assert.ok(isZcash(network));
2727
let o;
2828
let prefix;
2929
try {
@@ -41,7 +41,7 @@ export function fromOutputScript(outputScript: Buffer, network: Network): string
4141
}
4242

4343
export function toOutputScript(address: string, network: Network): Buffer {
44-
assert(isZcash(network));
44+
assert.ok(isZcash(network));
4545
const { version, hash } = fromBase58Check(address);
4646
if (version === network.pubKeyHash) {
4747
return payments.p2pkh({ hash }).output as Buffer;

0 commit comments

Comments
 (0)