From 2cdae61da398dd40c357e8af7a3450c00a8a25a6 Mon Sep 17 00:00:00 2001 From: Zahin Mohammad Date: Fri, 10 Apr 2026 18:09:49 +0000 Subject: [PATCH] fix(sdk-lib-mpc): throw in Dsg.endSession() when signature exists Without the throw, endSession() silently reset dsgState to Uninitialized after signing, allowing init() to succeed again and enabling inadvertent session reuse on the same key share. Ticket: WAL-383 --- modules/sdk-lib-mpc/src/tss/ecdsa-dkls/dsg.ts | 2 +- .../test/unit/tss/ecdsa/dklsDsg.ts | 23 +++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/modules/sdk-lib-mpc/src/tss/ecdsa-dkls/dsg.ts b/modules/sdk-lib-mpc/src/tss/ecdsa-dkls/dsg.ts index bffe3e5dca..130778399d 100644 --- a/modules/sdk-lib-mpc/src/tss/ecdsa-dkls/dsg.ts +++ b/modules/sdk-lib-mpc/src/tss/ecdsa-dkls/dsg.ts @@ -164,7 +164,7 @@ export class Dsg { */ endSession(): void { if (this._signature) { - new Error('Session already ended because combined signature was produced.'); + throw new Error('Session already ended because combined signature was produced.'); } if (this.dsgSession) { this.dsgSession.free(); diff --git a/modules/sdk-lib-mpc/test/unit/tss/ecdsa/dklsDsg.ts b/modules/sdk-lib-mpc/test/unit/tss/ecdsa/dklsDsg.ts index 6b1071ef6c..95910cd16b 100644 --- a/modules/sdk-lib-mpc/test/unit/tss/ecdsa/dklsDsg.ts +++ b/modules/sdk-lib-mpc/test/unit/tss/ecdsa/dklsDsg.ts @@ -217,6 +217,29 @@ describe('DKLS Dsg 2x3', function () { await party.init().should.be.rejectedWith(/Invalid messageHash length/); }); + it('should throw in endSession() when signature has already been produced', 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() + ); + const party2 = new DklsDsg.Dsg( + fs.readFileSync(shareFiles[vector.party2]), + vector.party2, + vector.derivationPath, + crypto.createHash('sha256').update(Buffer.from(vector.msgToSign, 'hex')).digest() + ); + const round4Messages = await executeTillRound(4, party1, party2); + party1.handleIncomingMessages({ + p2pMessages: [], + broadcastMessages: round4Messages[1].broadcastMessages, + }); + should.exist(party1.signature); + (() => party1.endSession()).should.throw('Session already ended because combined signature was produced.'); + }); + it(`should fail when signing two different messages`, async function () { const party1 = new DklsDsg.Dsg( fs.readFileSync(`${__dirname}/fixtures/userShare`),