Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 19 additions & 6 deletions modules/sdk-core/src/bitgo/utils/tss/ecdsa/ecdsaMPCv2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1120,7 +1120,12 @@ export class EcdsaMPCv2Utils extends BaseEcdsaUtils {
const userSignerBroadcastMsg1 = await userSigner.init();
const signatureShareRound1 = await getSignatureShareRoundOne(userSignerBroadcastMsg1, userGpgKey);
const session = userSigner.getSession();
const encryptedRound1Session = this.bitgo.encrypt({ input: session, password: walletPassphrase, adata });
const sessionAdata = `${adata}:${DklsTypes.DsgState[DklsTypes.DsgState.Round1]}`;
const encryptedRound1Session = this.bitgo.encrypt({
input: session,
password: walletPassphrase,
adata: sessionAdata,
});

const userGpgPubKey = userGpgKey.publicKey;
const encryptedUserGpgPrvKey = this.bitgo.encrypt({
Expand Down Expand Up @@ -1170,10 +1175,11 @@ export class EcdsaMPCv2Utils extends BaseEcdsaUtils {

const round1Session = this.bitgo.decrypt({ input: encryptedRound1Session, password: walletPassphrase });

this.validateAdata(adata, encryptedRound1Session);
const round1SessionAdata = `${adata}:${DklsTypes.DsgState[DklsTypes.DsgState.Round1]}`;
this.validateAdata(round1SessionAdata, encryptedRound1Session);
const userKeyShare = Buffer.from(prv, 'base64');
const userSigner = new DklsDsg.Dsg(userKeyShare, 0, derivationPath, hashBuffer);
await userSigner.setSession(round1Session);
await userSigner.setSession(round1Session, DklsTypes.DsgState.Round1);

const deserializedMessages = DklsTypes.deserializeMessages(serializedBitGoToUserMessagesRound1);
const userToBitGoMessagesRound2 = userSigner.handleIncomingMessages({
Expand All @@ -1191,7 +1197,13 @@ export class EcdsaMPCv2Utils extends BaseEcdsaUtils {
bitgoGpgKey
);
const session = userSigner.getSession();
const encryptedRound2Session = this.bitgo.encrypt({ input: session, password: walletPassphrase, adata });
// After two rounds of handleIncomingMessages, the session is in DsgState.Round3 (WaitMsg3).
const round3SessionAdata = `${adata}:${DklsTypes.DsgState[DklsTypes.DsgState.Round3]}`;
const encryptedRound2Session = this.bitgo.encrypt({
input: session,
password: walletPassphrase,
adata: round3SessionAdata,
});

return {
signatureShareRound2,
Expand Down Expand Up @@ -1242,10 +1254,11 @@ export class EcdsaMPCv2Utils extends BaseEcdsaUtils {
});

const round2Session = this.bitgo.decrypt({ input: encryptedRound2Session, password: walletPassphrase });
this.validateAdata(adata, encryptedRound2Session);
const round3SessionAdata = `${adata}:${DklsTypes.DsgState[DklsTypes.DsgState.Round3]}`;
this.validateAdata(round3SessionAdata, encryptedRound2Session);
const userKeyShare = Buffer.from(prv, 'base64');
const userSigner = new DklsDsg.Dsg(userKeyShare, 0, derivationPath, hashBuffer);
await userSigner.setSession(round2Session);
await userSigner.setSession(round2Session, DklsTypes.DsgState.Round3);

const userToBitGoMessagesRound4 = userSigner.handleIncomingMessages({
p2pMessages: deserializedBitGoToUserMessagesRound3.p2pMessages,
Expand Down
6 changes: 5 additions & 1 deletion modules/sdk-lib-mpc/src/tss/ecdsa-dkls/dsg.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,9 @@ export class Dsg {
/**
* Sets the DSG session from a base64 string.
* @param {string} session - base64 string of the DSG session
* @param {DsgState} [expectedRound] - if provided, the session's round must match this value
*/
async setSession(session: string): Promise<void> {
async setSession(session: string, expectedRound?: DsgState): Promise<void> {
this.dsgSession = undefined;
if (!this.dklsWasm) {
await this.loadDklsWasm();
Expand All @@ -112,6 +113,9 @@ export class Dsg {
default:
throw Error(`Invalid State: ${round}`);
}
if (expectedRound !== undefined && this.dsgState !== expectedRound) {
throw Error(`Session round mismatch: expected ${DsgState[expectedRound]}, got ${DsgState[this.dsgState]}`);
}
this.dsgSessionBytes = sessionBytes;
}

Expand Down
43 changes: 43 additions & 0 deletions modules/sdk-lib-mpc/test/unit/tss/ecdsa/dklsDsg.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
DeserializedBroadcastMessage,
DeserializedDklsSignature,
DeserializedMessages,
DsgState,
getDecodedReducedKeyShare,
ReducedKeyShare,
RetrofitData,
Expand Down Expand Up @@ -409,4 +410,46 @@ describe('DKLS Dsg 2x3', function () {
should.exist(convertedSignature);
convertedSignature.split(':').length.should.equal(4);
});

it('should succeed when setSession is called with correct expectedRound', async function () {
const vector = vectors[0];
const party1 = new DklsDsg.Dsg(
fs.readFileSync(shareFiles[vector.party1]),
vector.party1,
vector.derivationPath,
crypto.createHash('sha256').update(Buffer.from(vector.msgToSign, 'hex')).digest()
);
await party1.init();
const round1Session = party1.getSession();

const party1Restored = new DklsDsg.Dsg(
fs.readFileSync(shareFiles[vector.party1]),
vector.party1,
vector.derivationPath,
crypto.createHash('sha256').update(Buffer.from(vector.msgToSign, 'hex')).digest()
);
await party1Restored.setSession(round1Session, DsgState.Round1);
});

it('should throw when setSession is called with wrong expectedRound', async function () {
const vector = vectors[0];
const party1 = new DklsDsg.Dsg(
fs.readFileSync(shareFiles[vector.party1]),
vector.party1,
vector.derivationPath,
crypto.createHash('sha256').update(Buffer.from(vector.msgToSign, 'hex')).digest()
);
await party1.init();
const round1Session = party1.getSession();

const party1Restored = new DklsDsg.Dsg(
fs.readFileSync(shareFiles[vector.party1]),
vector.party1,
vector.derivationPath,
crypto.createHash('sha256').update(Buffer.from(vector.msgToSign, 'hex')).digest()
);
await party1Restored
.setSession(round1Session, DsgState.Round2)
.should.be.rejectedWith('Session round mismatch: expected Round2, got Round1');
});
});
Loading