Skip to content

Commit

Permalink
feat(abstract-utxo): update the keySignature verification network
Browse files Browse the repository at this point in the history
  • Loading branch information
rushilbg committed Jun 28, 2023
1 parent e471169 commit a3f1219
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 9 deletions.
8 changes: 6 additions & 2 deletions modules/abstract-utxo/src/abstractUtxoCoin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ const { getExternalChainCode, isChainCode, scriptTypeForChain, outputScripts } =
type Unspent<TNumber extends number | bigint = number> = bitgo.Unspent<TNumber>;

type RootWalletKeys = bitgo.RootWalletKeys;

export interface VerifyAddressOptions extends BaseVerifyAddressOptions {
chain: number;
index: number;
Expand Down Expand Up @@ -677,7 +678,7 @@ export abstract class AbstractUtxoCoin extends BaseCoin {
* @param {VerifyKeySignaturesOptions} params
* @return {{backup: boolean, bitgo: boolean}}
*/
protected verifyKeySignature(params: VerifyKeySignaturesOptions): boolean {
public verifyKeySignature(params: VerifyKeySignaturesOptions): boolean {
// first, let's verify the integrity of the user key, whose public key is used for subsequent verifications
const { userKeychain, keychainToVerify, keySignature } = params;
if (!userKeychain) {
Expand All @@ -695,10 +696,13 @@ export abstract class AbstractUtxoCoin extends BaseCoin {
// verify the signature against the user public key
assert(userKeychain.pub);
const publicKey = bip32.fromBase58(userKeychain.pub).publicKey;
// Due to interface of `bitcoinMessage`, we need to convert the public key to an address.
// Note that this address has no relationship to on-chain transactions. We are
// only interested in the address as a representation of the public key.
const signingAddress = utxolib.address.toBase58Check(
utxolib.crypto.hash160(publicKey),
utxolib.networks.bitcoin.pubKeyHash,
this.network
utxolib.networks.bitcoin
);

// BG-5703: use BTC mainnet prefix for all key signature operations
Expand Down
38 changes: 31 additions & 7 deletions modules/bitgo/test/v2/unit/coins/abstractUtxoCoin.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
/* eslint-disable quote-props */
import * as utxolib from '@bitgo/utxo-lib';
import * as should from 'should';
import * as sinon from 'sinon';
import { UnexpectedAddressError, VerificationOptions } from '@bitgo/sdk-core';
import { Keychain, UnexpectedAddressError, VerificationOptions } from '@bitgo/sdk-core';
import { TestBitGo } from '@bitgo/sdk-test';
import { BitGo } from '../../../../src/bitgo';
import {
Expand Down Expand Up @@ -82,7 +83,10 @@ describe('Abstract UTXO Coin:', () => {

it('should classify outputs which spend change back to a v1 wallet base address as external ' +
'if considerMigratedFromAddressInternal is set and false', async function () {
return runClassifyOutputsTest(wallet.migratedFrom(), { ...verification, considerMigratedFromAddressInternal: false }, true);
return runClassifyOutputsTest(wallet.migratedFrom(), {
...verification,
considerMigratedFromAddressInternal: false,
}, true);
});

it('should classify outputs which spend to addresses not on the wallet as external', async function () {
Expand All @@ -96,7 +100,12 @@ describe('Abstract UTXO Coin:', () => {

it('should classify outputs with external address in recipients as explicit', async function () {
const externalAddress = '2NAuziD75WnPPHJVwnd4ckgY4SuJaDVVbMD';
return runClassifyOutputsTest(externalAddress, verification, true, { recipients: [{ address: externalAddress, amount: outputAmount }] });
return runClassifyOutputsTest(externalAddress, verification, true, {
recipients: [{
address: externalAddress,
amount: outputAmount,
}],
});
});
});

Expand Down Expand Up @@ -239,7 +248,7 @@ describe('Abstract UTXO Coin:', () => {
};

// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const sign = async (key, keychain) => (await coin.signMessage(keychain, key.pub!)).toString('hex');
const sign = async (key, keychain, coinToSignFor = coin) => (await coinToSignFor.signMessage(keychain, key.pub!)).toString('hex');
const signUser = (key) => sign(key, userKeychain);
const signOther = (key) => sign(key, otherKeychain);
const passphrase = 'test_passphrase';
Expand All @@ -252,7 +261,10 @@ describe('Abstract UTXO Coin:', () => {
badKey: {
keychains: {
// user public key swapped out
user: { pub: otherKeychain.pub, encryptedPrv: bitgo.encrypt({ input: userKeychain.prv, password: passphrase }) },
user: {
pub: otherKeychain.pub,
encryptedPrv: bitgo.encrypt({ input: userKeychain.prv, password: passphrase }),
},
},
needsCustomChangeKeySignatureVerification: true,
},
Expand Down Expand Up @@ -423,8 +435,7 @@ describe('Abstract UTXO Coin:', () => {

it('should not allow any implicit external outputs if paygo outputs are disallowed', async () => {
const coinMock = sinon.stub(coin, 'parseTransaction').resolves({
keychains: {
},
keychains: {},
keySignatures: {},
outputs: [],
missingOutputs: [],
Expand Down Expand Up @@ -516,5 +527,18 @@ describe('Abstract UTXO Coin:', () => {
coinMock.restore();
bitcoinMock.restore();
});

it('should verify key signature of ZEC', async () => {
const zecCoin = bitgo.coin('tzec') as AbstractUtxoCoin;
const userKeychain = await zecCoin.keychains().create();
const otherKeychain = await zecCoin.keychains().create();

await zecCoin.verifyKeySignature({
userKeychain: (userKeychain as unknown) as Keychain,
keychainToVerify: (otherKeychain as unknown) as Keychain,
keySignature: await sign(userKeychain, otherKeychain, zecCoin),
}).should.be.true();
});

});
});

0 comments on commit a3f1219

Please sign in to comment.