Skip to content

Commit

Permalink
feat(sdk-core): add tests for new pick mpc gpg pub key function
Browse files Browse the repository at this point in the history
TICKET: HSM-432
  • Loading branch information
islamaminBitGo committed Oct 29, 2024
1 parent f2db18f commit fbcfcbf
Show file tree
Hide file tree
Showing 6 changed files with 196 additions and 10 deletions.
169 changes: 169 additions & 0 deletions modules/bitgo/test/v2/unit/internal/tssUtils/bitgoMpcGpgPubKeys.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
import {
BitgoMpcGpgPubKeys,
common,
ECDSAUtils,
EddsaUtils,
EnvironmentName,
IRequestTracer,
Wallet,
} from '@bitgo/sdk-core';
import { TestBitGo } from '@bitgo/sdk-test';

import { BitGo } from '../../../../../src';
import * as openpgp from 'openpgp';
import nock = require('nock');
import assert = require('assert');

class TestEcdsaMpcv2Utils extends ECDSAUtils.EcdsaMPCv2Utils {
public async testPickBitgoPubGpgKeyForSigning(
isMpcv2: boolean,
reqId?: IRequestTracer,
enterpriseId?: string
): Promise<openpgp.Key> {
return this.pickBitgoPubGpgKeyForSigning(isMpcv2, reqId, enterpriseId);
}
}

class TestEddsaMpcv1Utils extends EddsaUtils {
public async testPickBitgoPubGpgKeyForSigning(
isMpcv2: boolean,
reqId?: IRequestTracer,
enterpriseId?: string
): Promise<openpgp.Key> {
return this.pickBitgoPubGpgKeyForSigning(isMpcv2, reqId, enterpriseId);
}
}

describe('TSS MPC Pick BitGo GPG Pub Key Utils:', function () {
const walletId = '5b34252f1bf349930e34020a00000000';
const enterpriseId = '6449153a6f6bc20006d66771cdbe15d3';
const ecdsaCoinName = 'hteth';
const eddsaCoinName = 'tsol';
const ecdsaWalletData = {
id: walletId,
enterprise: enterpriseId,
coin: ecdsaCoinName,
coinSpecific: {},
multisigType: 'tss',
keys: ['key1', 'key2', 'key3'],
};
const eddsaWalletData = {
id: walletId,
enterprise: enterpriseId,
coin: eddsaCoinName,
coinSpecific: {},
multisigType: 'tss',
keys: ['key1', 'key2', 'key3'],
};
const envs: EnvironmentName[] = ['test', 'staging', 'prod'];
const ecdsaMpcv2Utils: TestEcdsaMpcv2Utils[] = [];
const eddsaMpcv1Utils: TestEddsaMpcv1Utils[] = [];

before(async function () {
nock.cleanAll();
for (const env of envs) {
const bitgoInstance = TestBitGo.decorate(BitGo, { env });
bitgoInstance.initializeTestVars();
let coinInstance = bitgoInstance.coin(ecdsaCoinName);
ecdsaMpcv2Utils.push(
new TestEcdsaMpcv2Utils(bitgoInstance, coinInstance, new Wallet(bitgoInstance, coinInstance, ecdsaWalletData))
);
coinInstance = bitgoInstance.coin(eddsaCoinName);
eddsaMpcv1Utils.push(
new TestEddsaMpcv1Utils(bitgoInstance, coinInstance, new Wallet(bitgoInstance, coinInstance, eddsaWalletData))
);
}
});

beforeEach(async function () {
for (const env of envs) {
const bgUrl = common.Environments[env].uri;
nock(bgUrl).get(`/api/v2/${ecdsaCoinName}/key/key3`).times(envs.length).reply(200, { hsmType: 'onprem' });
nock(bgUrl).get(`/api/v2/${eddsaCoinName}/key/key3`).times(envs.length).reply(200, { hsmType: 'nitro' });
}
});

envs.forEach(async function (env, index) {
it(`should pick correct Mpcv2 BitGo GPG Pub Key for ${env} env`, async function () {
const bitgoGpgPubKey = await ecdsaMpcv2Utils[index].testPickBitgoPubGpgKeyForSigning(true);
bitgoGpgPubKey
.armor()
.should.equal(BitgoMpcGpgPubKeys.bitgoMpcGpgPubKeys['mpcv2']['onprem'][env === 'staging' ? 'test' : env]);
});
});

envs.forEach(async function (env, index) {
it(`should pick correct Mpcv1 BitGo GPG Pub Key for ${env} env`, async function () {
const bitgoGpgPubKey = await eddsaMpcv1Utils[index].testPickBitgoPubGpgKeyForSigning(false);
bitgoGpgPubKey
.armor()
.should.equal(BitgoMpcGpgPubKeys.bitgoMpcGpgPubKeys['mpcv1']['nitro'][env === 'staging' ? 'test' : env]);
});
});

it(`should pick BitGo GPG Pub Key based on enterprise flag for mock env`, async function () {
const bgUrl = common.Environments['mock'].uri;
const testBitgo = TestBitGo.decorate(BitGo, { env: 'mock' });
const testCoin = testBitgo.coin(ecdsaCoinName);
const bitgoGPGKey = await openpgp.generateKey({
userIDs: [
{
name: 'bitgo',
email: '[email protected]',
},
],
});
nock(bgUrl)
.get(`/api/v2/${ecdsaCoinName}/tss/pubkey`)
.query({ enterpriseId })
.reply(200, { mpcv2PublicKey: bitgoGPGKey.publicKey });
const ecdsaMpcv2Util = new TestEcdsaMpcv2Utils(
testBitgo,
testCoin,
new Wallet(testBitgo, testCoin, ecdsaWalletData)
);
const bitgoGpgPubKey = await ecdsaMpcv2Util.testPickBitgoPubGpgKeyForSigning(true, undefined, enterpriseId);
bitgoGpgPubKey.armor().should.equal(bitgoGPGKey.publicKey);
});

it(`should pick BitGo GPG Pub Key based on constants api for mock env if enterprise flag based fetch fails`, async function () {
nock.cleanAll();
const bgUrl = common.Environments['mock'].uri;
const testBitgo = TestBitGo.decorate(BitGo, { env: 'mock' });
const testCoin = testBitgo.coin(ecdsaCoinName);
const bitgoGPGKey = await openpgp.generateKey({
userIDs: [
{
name: 'bitgo',
email: '[email protected]',
},
],
});
const constants = {
mpc: {
bitgoMPCv2PublicKey: bitgoGPGKey.publicKey,
bitgoPublicKey: bitgoGPGKey.publicKey,
},
};
nock(bgUrl).get('/api/v1/client/constants').times(2).reply(200, { ttl: 3600, constants });
const ecdsaMpcv2Util = new TestEcdsaMpcv2Utils(
testBitgo,
testCoin,
new Wallet(testBitgo, testCoin, ecdsaWalletData)
);
const bitgoGpgPubKey = await ecdsaMpcv2Util.testPickBitgoPubGpgKeyForSigning(true, undefined, enterpriseId);
bitgoGpgPubKey.armor().should.equal(bitgoGPGKey.publicKey);
});

it(`should throw an error if config is not available in one of test, staging, or prod`, async function () {
nock.cleanAll();
const testBitgo = TestBitGo.decorate(BitGo, { env: 'test' });
const testCoin = testBitgo.coin(ecdsaCoinName);
const ecdsaMpcv2Util = new TestEcdsaMpcv2Utils(
testBitgo,
testCoin,
new Wallet(testBitgo, testCoin, ecdsaWalletData)
);
await assert.rejects(async () => await ecdsaMpcv2Util.testPickBitgoPubGpgKeyForSigning(true));
});
});
1 change: 1 addition & 0 deletions modules/express/test/unit/clientRoutes/externalSign.ts
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,7 @@ describe('External signer', () => {
const reqCommitment = {
bitgo: bgTest,
body: {
bitgoGpgPubKey: bitgoGpgKey.public,
txRequest: {
apiVersion: 'full',
walletId: walletID,
Expand Down
22 changes: 16 additions & 6 deletions modules/sdk-core/src/bitgo/tss/bitgoPubKeys.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,20 @@ export const bitgoMpcGpgPubKeys = {
},
};

export function getBitgoMpcGpgPubKey(env: EnvironmentName, pubKeyType: 'nitro' | 'onprem', mpcVersion: 'mpcv1' | 'mpcv2'): string {
assert(mpcVersion in bitgoMpcGpgPubKeys, `Invalid mpcVersion in getBitgoMpcGpgPubKey, got: ${mpcVersion}, expected: mpcv1 or mpcv2`);
assert(pubKeyType in bitgoMpcGpgPubKeys[mpcVersion], `Invalid pubKeyType in getBitgoMpcGpgPubKey, got: ${pubKeyType}, expected: nitro or onprem`);
if (env !== 'prod' && env !== 'test' && env !== 'staging' && env !== 'adminProd' && env !== 'adminTest'){
export function getBitgoMpcGpgPubKey(
env: EnvironmentName,
pubKeyType: 'nitro' | 'onprem',
mpcVersion: 'mpcv1' | 'mpcv2'
): string {
assert(
mpcVersion in bitgoMpcGpgPubKeys,
`Invalid mpcVersion in getBitgoMpcGpgPubKey, got: ${mpcVersion}, expected: mpcv1 or mpcv2`
);
assert(
pubKeyType in bitgoMpcGpgPubKeys[mpcVersion],
`Invalid pubKeyType in getBitgoMpcGpgPubKey, got: ${pubKeyType}, expected: nitro or onprem`
);
if (env !== 'prod' && env !== 'test' && env !== 'staging' && env !== 'adminProd' && env !== 'adminTest') {
throw new Error('Invalid environment to get a BitGo MPC GPG public key');
}
if (env !== 'prod' && env !== 'adminProd') {
Expand All @@ -37,7 +47,7 @@ export function getBitgoMpcGpgPubKey(env: EnvironmentName, pubKeyType: 'nitro' |
if (env === 'adminProd') {
env = 'prod';
}
if (pubKeyType === 'nitro' && env === 'prod') {
if (pubKeyType === 'nitro' && env === 'prod' && mpcVersion === 'mpcv2') {
throw new Error('Nitro mpcv2 pub key is not available in production environments yet.');
}
if (pubKeyType !== 'nitro') {
Expand All @@ -52,5 +62,5 @@ export function isBitgoMpcPubKey(key: string, mpcvVersion: 'mpcv1' | 'mpcv2'): b
}

export function envRequiresBitgoPubGpgKeyConfig(env: EnvironmentName): boolean {
return env === 'prod' || env === 'test' || env === 'staging' || env === 'adminProd' || env === 'adminTest';
return env === 'prod' || env === 'test' || env === 'staging' || env === 'adminProd' || env === 'adminTest';
}
1 change: 1 addition & 0 deletions modules/sdk-core/src/bitgo/tss/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import ECDSAMethods, { ECDSAMethodTypes, DKLSMethods } from './ecdsa';

export { EDDSAMethods, EDDSAMethodTypes, ECDSAMethods, ECDSAMethodTypes, DKLSMethods };
export { ShareKeyPosition } from './types';
export * as BitgoMpcGpgPubKeys from './bitgoPubKeys';

// exporting this types for backward compatibility.
/** @deprecated Use EDDSAMethods */
Expand Down
10 changes: 8 additions & 2 deletions modules/sdk-core/src/bitgo/utils/tss/baseTSSUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,14 @@ export default class BaseTssUtils<KeyShare> extends MpcUtils implements ITssUtil

protected async setBitgoGpgPubKey(bitgo) {
const { mpcV1, mpcV2 } = await getBitgoGpgPubKey(bitgo);
this.bitgoPublicGpgKey = mpcV1;
this.bitgoMPCv2PublicGpgKey = mpcV2;
// Do not unset the MPCv1 key if it is already set. This is to avoid unsetting if extra constants api calls fail.
if (mpcV1 !== undefined) {
this.bitgoPublicGpgKey = mpcV1;
}
// Do not unset the MPCv2 key if it is already set
if (mpcV2 !== undefined) {
this.bitgoMPCv2PublicGpgKey = mpcV2;
}
}

protected async pickBitgoPubGpgKeyForSigning(
Expand Down
3 changes: 1 addition & 2 deletions modules/sdk-core/src/bitgo/utils/tss/ecdsa/base.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import * as openpgp from 'openpgp';
import { ec } from 'elliptic';

import { IBaseCoin } from '../../../baseCoin';
import baseTSSUtils from '../baseTSSUtils';
import { KeyShare } from './types';
import { BackupGpgKey } from '../baseTypes';
import { generateGPGKeyPair, getBitgoGpgPubKey, getTrustGpgPubKey } from '../../opengpgUtils';
import { generateGPGKeyPair, getTrustGpgPubKey } from '../../opengpgUtils';
import { BitGoBase } from '../../../bitgoBase';
import { IWallet } from '../../../wallet';

Expand Down

0 comments on commit fbcfcbf

Please sign in to comment.