Skip to content

Commit

Permalink
Merge pull request #4910 from BitGo/WP-2617-mpcv2-overriding-sender
Browse files Browse the repository at this point in the history
refactor(sdk-core): decouple request sender from MPCv2 codes
  • Loading branch information
pengyuc-bitgo authored Sep 20, 2024
2 parents fb2f647 + 15ed709 commit 27b3fc3
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 27 deletions.
39 changes: 32 additions & 7 deletions modules/sdk-core/src/bitgo/utils/tss/ecdsa/SMC/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ import {
BitgoToOVC1Round2Response,
BitgoToOVC1Round3Response,
KeyCreationMPCv2StateEnum,
MPCv2KeyGenRound1Response,
MPCv2KeyGenRound2Response,
MPCv2KeyGenRound3Response,
OVC1ToBitgoRound3Payload,
OVC2ToBitgoRound1Payload,
OVC2ToBitgoRound2Payload,
Expand All @@ -13,15 +16,31 @@ import { IBaseCoin } from '../../../../baseCoin';
import { BitGoBase } from '../../../../bitgoBase';
import { EcdsaMPCv2Utils } from '../ecdsaMPCv2';
import { decodeOrElse, Keychain } from '../../../..';
import { EcdsaMPCv2KeyGenSendFn, KeyGenSenderForEnterprise } from '../ecdsaMPCv2KeyGenSender';

export class MPCv2SMCUtils {
private MPCv2Utils: EcdsaMPCv2Utils;

constructor(bitgo: BitGoBase, private baseCoin: IBaseCoin) {
constructor(private bitgo: BitGoBase, private baseCoin: IBaseCoin) {
this.MPCv2Utils = new EcdsaMPCv2Utils(bitgo, baseCoin);
}

public async keyGenRound1(enterprise: string, payload: OVC2ToBitgoRound1Payload): Promise<BitgoToOVC1Round1Response> {
return this.keyGenRound1BySender(KeyGenSenderForEnterprise(this.bitgo, enterprise), payload);
}

public async keyGenRound2(enterprise: string, payload: OVC2ToBitgoRound2Payload): Promise<BitgoToOVC1Round2Response> {
return this.keyGenRound2BySender(KeyGenSenderForEnterprise(this.bitgo, enterprise), payload);
}

public async keyGenRound3(enterprise: string, payload: OVC1ToBitgoRound3Payload): Promise<BitgoToOVC1Round3Response> {
return this.keyGenRound3BySender(KeyGenSenderForEnterprise(this.bitgo, enterprise), payload);
}

public async keyGenRound1BySender(
senderFn: EcdsaMPCv2KeyGenSendFn<MPCv2KeyGenRound1Response>,
payload: OVC2ToBitgoRound1Payload
): Promise<BitgoToOVC1Round1Response> {
assert(
payload.state === KeyCreationMPCv2StateEnum.WaitingForBitgoRound1Data,
`Invalid state for round 1, expected: ${KeyCreationMPCv2StateEnum.WaitingForBitgoRound1Data}, got: ${payload.state}`
Expand All @@ -35,8 +54,8 @@ export class MPCv2SMCUtils {
const userGpgPublicKey = ovc1.gpgPubKey;
const backupGpgPublicKey = ovc2.gpgPubKey;
const messages = { p2pMessages: [], broadcastMessages: [ovc1.ovcMsg1, ovc2.ovcMsg1] };
const result = await this.MPCv2Utils.sendKeyGenerationRound1(
enterprise,
const result = await this.MPCv2Utils.sendKeyGenerationRound1BySender(
senderFn,
userGpgPublicKey,
backupGpgPublicKey,
messages
Expand Down Expand Up @@ -64,7 +83,10 @@ export class MPCv2SMCUtils {
});
}

public async keyGenRound2(enterprise: string, payload: OVC2ToBitgoRound2Payload): Promise<BitgoToOVC1Round2Response> {
public async keyGenRound2BySender(
senderFn: EcdsaMPCv2KeyGenSendFn<MPCv2KeyGenRound2Response>,
payload: OVC2ToBitgoRound2Payload
): Promise<BitgoToOVC1Round2Response> {
assert(
payload.state === KeyCreationMPCv2StateEnum.WaitingForBitgoRound2Data,
`Invalid state for round 2, expected: ${KeyCreationMPCv2StateEnum.WaitingForBitgoRound2Data}, got: ${payload.state}`
Expand All @@ -76,7 +98,7 @@ export class MPCv2SMCUtils {
const ovc2 = payload.ovc[OVCIndexEnum.TWO];
const sessionId = payload.platform.sessionId;
const messages = { p2pMessages: [ovc1.ovcToBitgoMsg2, ovc2.ovcToBitgoMsg2], broadcastMessages: [] };
const result = await this.MPCv2Utils.sendKeyGenerationRound2(enterprise, sessionId, messages);
const result = await this.MPCv2Utils.sendKeyGenerationRound2BySender(senderFn, sessionId, messages);

const response = {
state: KeyCreationMPCv2StateEnum.WaitingForOVC1Round3aData,
Expand Down Expand Up @@ -106,7 +128,10 @@ export class MPCv2SMCUtils {
});
}

public async keyGenRound3(enterprise: string, payload: OVC1ToBitgoRound3Payload): Promise<BitgoToOVC1Round3Response> {
public async keyGenRound3BySender(
senderFn: EcdsaMPCv2KeyGenSendFn<MPCv2KeyGenRound3Response>,
payload: OVC1ToBitgoRound3Payload
): Promise<BitgoToOVC1Round3Response> {
assert(
payload.state === KeyCreationMPCv2StateEnum.WaitingForBitgoRound3Data,
`Invalid state for round 3, expected: ${KeyCreationMPCv2StateEnum.WaitingForBitgoRound3Data}, got: ${payload.state}`
Expand All @@ -121,7 +146,7 @@ export class MPCv2SMCUtils {
p2pMessages: [ovc1.ovcToBitgoMsg3, ovc2.ovcToBitgoMsg3],
broadcastMessages: [ovc1.ovcMsg4, ovc2.ovcMsg4],
};
const result = await this.MPCv2Utils.sendKeyGenerationRound3(enterprise, sessionId, messages);
const result = await this.MPCv2Utils.sendKeyGenerationRound3BySender(senderFn, sessionId, messages);

const keychains = this.baseCoin.keychains();
const bitgoKeychain = await keychains.add({
Expand Down
57 changes: 37 additions & 20 deletions modules/sdk-core/src/bitgo/utils/tss/ecdsa/ecdsaMPCv2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,10 @@ import createKeccakHash from 'keccak';
import * as pgp from 'openpgp';
import { KeychainsTriplet } from '../../../baseCoin';
import {
KeyGenTypeEnum,
MPCv2BroadcastMessage,
MPCv2KeyGenRound1Response,
MPCv2KeyGenRound2Response,
MPCv2KeyGenRound3Response,
MPCv2KeyGenState,
MPCv2KeyGenStateEnum,
MPCv2P2PMessage,
MPCv2PartyFromStringOrNumber,
Expand All @@ -26,7 +24,7 @@ import { AddKeychainOptions, Keychain, KeyType } from '../../../keychain';
import { DecryptedRetrofitPayload } from '../../../keychain/iKeychains';
import { ECDSAMethodTypes, getTxRequest } from '../../../tss';
import { sendSignatureShareV2, sendTxRequest } from '../../../tss/common';
import { GenerateMPCv2KeyRequestBody, GenerateMPCv2KeyRequestResponse, MPCv2PartiesEnum } from './typesMPCv2';
import { MPCv2PartiesEnum } from './typesMPCv2';
import {
getSignatureShareRoundOne,
getSignatureShareRoundThree,
Expand All @@ -49,6 +47,7 @@ import {
TxRequest,
} from '../baseTypes';
import { BaseEcdsaUtils } from './base';
import { EcdsaMPCv2KeyGenSendFn, KeyGenSenderForEnterprise } from './ecdsaMPCv2KeyGenSender';

export class EcdsaMPCv2Utils extends BaseEcdsaUtils {
/** @inheritdoc */
Expand Down Expand Up @@ -546,20 +545,38 @@ export class EcdsaMPCv2Utils extends BaseEcdsaUtils {
}
// #endregion

// #region generate key request utils
private async sendKeyGenerationRequest<T extends GenerateMPCv2KeyRequestResponse>(
async sendKeyGenerationRound1(
enterprise: string,
round: MPCv2KeyGenState,
payload: GenerateMPCv2KeyRequestBody & { walletId?: string }
): Promise<T> {
return this.bitgo
.post(this.bitgo.url('/mpc/generatekey', 2))
.send({ enterprise, type: KeyGenTypeEnum.MPCv2, round, payload })
.result();
userGpgPublicKey: string,
backupGpgPublicKey: string,
payload: DklsTypes.AuthEncMessages & { walletId?: string }
): Promise<MPCv2KeyGenRound1Response> {
return this.sendKeyGenerationRound1BySender(
KeyGenSenderForEnterprise(this.bitgo, enterprise),
userGpgPublicKey,
backupGpgPublicKey,
payload
);
}

async sendKeyGenerationRound1(
async sendKeyGenerationRound2(
enterprise: string,
sessionId: string,
payload: DklsTypes.AuthEncMessages
): Promise<MPCv2KeyGenRound2Response> {
return this.sendKeyGenerationRound2BySender(KeyGenSenderForEnterprise(this.bitgo, enterprise), sessionId, payload);
}

async sendKeyGenerationRound3(
enterprise: string,
sessionId: string,
payload: DklsTypes.AuthEncMessages
): Promise<MPCv2KeyGenRound3Response> {
return this.sendKeyGenerationRound3BySender(KeyGenSenderForEnterprise(this.bitgo, enterprise), sessionId, payload);
}

async sendKeyGenerationRound1BySender(
senderFn: EcdsaMPCv2KeyGenSendFn<MPCv2KeyGenRound1Response>,
userGpgPublicKey: string,
backupGpgPublicKey: string,
payload: DklsTypes.AuthEncMessages & { walletId?: string }
Expand All @@ -571,7 +588,7 @@ export class EcdsaMPCv2Utils extends BaseEcdsaUtils {
const backupMsg1 = payload.broadcastMessages.find((m) => m.from === MPCv2PartiesEnum.BACKUP)?.payload;
assert(backupMsg1, 'Backup message 1 not found in broadcast messages');

return this.sendKeyGenerationRequest<MPCv2KeyGenRound1Response>(enterprise, MPCv2KeyGenStateEnum['MPCv2-R1'], {
return senderFn(MPCv2KeyGenStateEnum['MPCv2-R1'], {
userGpgPublicKey,
backupGpgPublicKey,
userMsg1: { from: 0, ...userMsg1 },
Expand All @@ -580,8 +597,8 @@ export class EcdsaMPCv2Utils extends BaseEcdsaUtils {
});
}

async sendKeyGenerationRound2(
enterprise: string,
async sendKeyGenerationRound2BySender(
senderFn: EcdsaMPCv2KeyGenSendFn<MPCv2KeyGenRound2Response>,
sessionId: string,
payload: DklsTypes.AuthEncMessages
): Promise<MPCv2KeyGenRound2Response> {
Expand All @@ -599,7 +616,7 @@ export class EcdsaMPCv2Utils extends BaseEcdsaUtils {
assert(backupMsg2.commitment, 'Backup to Bitgo commitment not found in P2P messages');
assert(NonEmptyString.is(backupMsg2.commitment), 'Backup to Bitgo commitment is required');

return this.sendKeyGenerationRequest<MPCv2KeyGenRound2Response>(enterprise, MPCv2KeyGenStateEnum['MPCv2-R2'], {
return senderFn(MPCv2KeyGenStateEnum['MPCv2-R2'], {
sessionId,
userMsg2: {
from: MPCv2PartiesEnum.USER,
Expand All @@ -618,8 +635,8 @@ export class EcdsaMPCv2Utils extends BaseEcdsaUtils {
});
}

async sendKeyGenerationRound3(
enterprise: string,
async sendKeyGenerationRound3BySender(
senderFn: EcdsaMPCv2KeyGenSendFn<MPCv2KeyGenRound3Response>,
sessionId: string,
payload: DklsTypes.AuthEncMessages
): Promise<MPCv2KeyGenRound3Response> {
Expand All @@ -637,7 +654,7 @@ export class EcdsaMPCv2Utils extends BaseEcdsaUtils {
const backupMsg4 = payload.broadcastMessages.find((m) => m.from === MPCv2PartiesEnum.BACKUP)?.payload;
assert(backupMsg4, 'Backup message 1 not found in broadcast messages');

return this.sendKeyGenerationRequest<MPCv2KeyGenRound3Response>(enterprise, MPCv2KeyGenStateEnum['MPCv2-R3'], {
return senderFn(MPCv2KeyGenStateEnum['MPCv2-R3'], {
sessionId,
userMsg3: { from: 0, to: 2, ...userMsg3 },
backupMsg3: { from: 1, to: 2, ...backupMsg3 },
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { KeyGenTypeEnum, MPCv2KeyGenState } from '@bitgo/public-types';
import { GenerateMPCv2KeyRequestBody, GenerateMPCv2KeyRequestResponse } from './typesMPCv2';
import { BitGoBase } from '../../../bitgoBase';

export type EcdsaMPCv2KeyGenSendFn<T extends GenerateMPCv2KeyRequestResponse> = (
round: MPCv2KeyGenState,
payload: GenerateMPCv2KeyRequestBody & { walletId?: string }
) => Promise<T>;

export function KeyGenSenderForEnterprise<T extends GenerateMPCv2KeyRequestResponse>(
bitgo: BitGoBase,
enterprise: string
): EcdsaMPCv2KeyGenSendFn<T> {
return (round, payload) => {
return bitgo
.post(bitgo.url('/mpc/generatekey', 2))
.send({ enterprise, type: KeyGenTypeEnum.MPCv2, round, payload })
.result();
};
}
1 change: 1 addition & 0 deletions modules/sdk-core/src/bitgo/utils/tss/ecdsa/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ export * from './ecdsaMPCv2';
export * from './types';
export * from './typesMPCv2';
export * from './SMC/utils';
export * from './ecdsaMPCv2KeyGenSender';

0 comments on commit 27b3fc3

Please sign in to comment.