From 1b35954901ab005198c80920d2615e800204cbdf Mon Sep 17 00:00:00 2001 From: Vibhav Simha G Date: Fri, 11 Sep 2026 14:59:52 +0530 Subject: [PATCH 1/2] chore: bump wasm-mps to 1.15.0 Ticket: WCI-1614 --- modules/sdk-lib-mpc/package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/modules/sdk-lib-mpc/package.json b/modules/sdk-lib-mpc/package.json index 30a3ea572c..ce273161cc 100644 --- a/modules/sdk-lib-mpc/package.json +++ b/modules/sdk-lib-mpc/package.json @@ -36,7 +36,7 @@ ] }, "dependencies": { - "@bitgo/wasm-mps": "1.14.0", + "@bitgo/wasm-mps": "1.15.0", "@noble/curves": "1.8.1", "@silencelaboratories/dkls-wasm-ll-node": "1.2.0-pre.4", "@silencelaboratories/dkls-wasm-ll-vrf-node": "1.0.0-pre.9", diff --git a/yarn.lock b/yarn.lock index 41c57b723d..5cf44e31f2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1037,10 +1037,10 @@ resolved "https://registry.npmjs.org/@bitgo/wasm-dot/-/wasm-dot-1.7.0.tgz" integrity sha512-KoXavJvyDHlEN+sWcigbgxYJtdFaU7gS0EkYQbNH4npVjNlzo6rL6gwjyWbyOy7oEs65DhpJ9vY5kRbE/bKiTQ== -"@bitgo/wasm-mps@1.14.0": - version "1.14.0" - resolved "https://registry.npmjs.org/@bitgo/wasm-mps/-/wasm-mps-1.14.0.tgz#5a5dece54486006852735651df7a63f7f61fc050" - integrity sha512-PDVU5Yg8HWy6fHH0iHstUXKLNggyXXGMCSAFCfaVSi36bfFuRKa5fd2ljMGKHl6RaAhQOvv4h2njVomYtjADEQ== +"@bitgo/wasm-mps@1.15.0": + version "1.15.0" + resolved "https://registry.npmjs.org/@bitgo/wasm-mps/-/wasm-mps-1.15.0.tgz#734bcb78a18b1b2d76125f86f31cf7d30caeca88" + integrity sha512-/764uy+CBV6XOll2ssyv0dQ1QWk3Hza/SGrk85drjCx1f7I6b5TDIOVTdx3MA6sEszKT+6tZlSQMFTz4KYX3sQ== "@bitgo/wasm-solana@^2.6.0": version "2.6.0" From 753568b9eeaa939e333099ec77a924a25a46d58e Mon Sep 17 00:00:00 2001 From: Vibhav Simha G Date: Fri, 11 Sep 2026 15:19:40 +0530 Subject: [PATCH 2/2] fix(sdk-lib-mpc): adapt RedPallas DKG to wasm-mps 1.15.0 API wasm-mps 1.15.0 changed the RedPallas DKG bindings: - redpallas_dkg_round2_process no longer takes a derivationSeed and returns RedPallasShare directly (MsgDerivationInit removed) - handleIncomingMessages drops the derivationSeed param - generateRedPallasDKGKeyShares drops its derivationSeed param Update dkg.ts, util.ts, and tests accordingly; remove the obsolete 'derivationSeed required for round 2' test. Ticket: WCI-1614 --- .../sdk-lib-mpc/src/tss/redpallas-mps/dkg.ts | 13 ++-- .../sdk-lib-mpc/src/tss/redpallas-mps/util.ts | 11 +--- .../test/unit/tss/redpallas/dkg.ts | 59 ++++--------------- .../unit/tss/redpallas/redpallas-utils.ts | 26 ++------ 4 files changed, 23 insertions(+), 86 deletions(-) diff --git a/modules/sdk-lib-mpc/src/tss/redpallas-mps/dkg.ts b/modules/sdk-lib-mpc/src/tss/redpallas-mps/dkg.ts index f54a0f0cb0..b376ba0779 100644 --- a/modules/sdk-lib-mpc/src/tss/redpallas-mps/dkg.ts +++ b/modules/sdk-lib-mpc/src/tss/redpallas-mps/dkg.ts @@ -1,4 +1,4 @@ -import type { MsgDerivationInit, MsgState } from '@bitgo/wasm-mps'; +import type { MsgState } from '@bitgo/wasm-mps'; import { encode } from 'cbor-x'; import crypto from 'crypto'; import { DeserializedMessage, DeserializedMessages, RedPallasDkgState, RedPallasReducedKeyShare } from './types'; @@ -149,10 +149,8 @@ export class RedPallasDKG { * matching the ordering expected by @bitgo/wasm-mps. * * @param messagesForIthRound - All n messages for this round (including own). - * @param derivationSeed - Required only when advancing WaitMsg2 -> Complete (round2): a - * 32-byte seed consumed by the subsequent, platform-side-only derivation process. */ - handleIncomingMessages(messagesForIthRound: DeserializedMessages, derivationSeed?: Buffer): DeserializedMessages { + handleIncomingMessages(messagesForIthRound: DeserializedMessages): DeserializedMessages { if (this.dkgState === RedPallasDkgState.Complete) { throw Error('DKG session already completed'); } @@ -190,12 +188,9 @@ export class RedPallasDKG { } if (this.dkgState === RedPallasDkgState.WaitMsg2) { - if (!derivationSeed || derivationSeed.length !== 32) { - throw Error('Missing or invalid derivationSeed: must be 32 bytes (required for round2)'); - } - let result: MsgDerivationInit; + let result; try { - result = wasm.redpallas_dkg_round2_process(otherMsgs, this.dkgStateBytes!, derivationSeed); + result = wasm.redpallas_dkg_round2_process(otherMsgs, this.dkgStateBytes!); } catch (err) { throw new Error(`Error while creating messages from party ${this.partyIdx}, round ${this.dkgState}: ${err}`); } diff --git a/modules/sdk-lib-mpc/src/tss/redpallas-mps/util.ts b/modules/sdk-lib-mpc/src/tss/redpallas-mps/util.ts index ae6c68de0d..f3b6f0f3b5 100644 --- a/modules/sdk-lib-mpc/src/tss/redpallas-mps/util.ts +++ b/modules/sdk-lib-mpc/src/tss/redpallas-mps/util.ts @@ -29,12 +29,8 @@ function validateSeed(seed?: RedPallasDKGPartySeed): RedPallasDKGPartySeed { /** * Runs a full 3-party (2-of-3) RedPallas DKG in-process. See `RedPallasDKGPartySeed`. * Mirrors `generateEdDsaDKGKeyShares` in `../eddsa-mps/util.ts`. - * - * @param derivationSeed - 32-byte seed consumed by round2 for the (platform-side-only) - * subsequent derivation process. Must be the same value across all three parties. */ export async function generateRedPallasDKGKeyShares( - derivationSeed: Buffer, seedUser?: RedPallasDKGPartySeed, seedBackup?: RedPallasDKGPartySeed, seedBitgo?: RedPallasDKGPartySeed @@ -67,10 +63,9 @@ export async function generateRedPallasDKGKeyShares( ...bitgo.handleIncomingMessages(r1Messages), ]; - user.handleIncomingMessages(r2Messages, derivationSeed); - backup.handleIncomingMessages(r2Messages, derivationSeed); - bitgo.handleIncomingMessages(r2Messages, derivationSeed); - + user.handleIncomingMessages(r2Messages); + backup.handleIncomingMessages(r2Messages); + bitgo.handleIncomingMessages(r2Messages); return [user, backup, bitgo]; } diff --git a/modules/sdk-lib-mpc/test/unit/tss/redpallas/dkg.ts b/modules/sdk-lib-mpc/test/unit/tss/redpallas/dkg.ts index cc350dd226..9c1fd7b19e 100644 --- a/modules/sdk-lib-mpc/test/unit/tss/redpallas/dkg.ts +++ b/modules/sdk-lib-mpc/test/unit/tss/redpallas/dkg.ts @@ -11,10 +11,6 @@ function makeKeypair(seed?: Buffer) { return { privKey, pubKey }; } -function makeDerivationSeed(): Buffer { - return crypto.randomBytes(32); -} - describe('RedPallas MPS DKG', function () { let user: RedPallasMPSDkg.RedPallasDKG; let backup: RedPallasMPSDkg.RedPallasDKG; @@ -22,17 +18,14 @@ describe('RedPallas MPS DKG', function () { let userKP: { privKey: Buffer; pubKey: Buffer }; let backupKP: { privKey: Buffer; pubKey: Buffer }; let bitgoKP: { privKey: Buffer; pubKey: Buffer }; - let derivationSeed: Buffer; beforeEach(function () { user = new RedPallasMPSDkg.RedPallasDKG(3, 2, 0); backup = new RedPallasMPSDkg.RedPallasDKG(3, 2, 1); bitgo = new RedPallasMPSDkg.RedPallasDKG(3, 2, 2); - userKP = makeKeypair(); backupKP = makeKeypair(); bitgoKP = makeKeypair(); - derivationSeed = makeDerivationSeed(); }); describe('DKG Initialization', function () { @@ -131,9 +124,9 @@ describe('RedPallas MPS DKG', function () { }); const r3Messages = [ - ...user.handleIncomingMessages(r2Messages, derivationSeed), - ...backup.handleIncomingMessages(r2Messages, derivationSeed), - ...bitgo.handleIncomingMessages(r2Messages, derivationSeed), + ...user.handleIncomingMessages(r2Messages), + ...backup.handleIncomingMessages(r2Messages), + ...bitgo.handleIncomingMessages(r2Messages), ]; assert.strictEqual(user.getState(), RedPallasDkgState.Complete); @@ -154,28 +147,6 @@ describe('RedPallas MPS DKG', function () { assert(Buffer.isBuffer(bitgoKeyShare) && bitgoKeyShare.length > 0, 'BitGo key share should be non-empty Buffer'); }); - it('should require a 32-byte derivationSeed for round 2', async function () { - const r1Messages = [user.getFirstMessage(), backup.getFirstMessage(), bitgo.getFirstMessage()]; - const r2Messages = [ - ...user.handleIncomingMessages(r1Messages), - ...backup.handleIncomingMessages(r1Messages), - ...bitgo.handleIncomingMessages(r1Messages), - ]; - - assert.strictEqual(user.getState(), RedPallasDkgState.WaitMsg2); - - assert.throws(() => { - user.handleIncomingMessages(r2Messages); - }, /Missing or invalid derivationSeed/); - - assert.throws(() => { - user.handleIncomingMessages(r2Messages, Buffer.alloc(31)); - }, /Missing or invalid derivationSeed/); - - // Failed round2 must leave the session in WaitMsg2 - assert.strictEqual(user.getState(), RedPallasDkgState.WaitMsg2); - }); - it('should generate consistent public keys across all parties', async function () { const r1Messages = [user.getFirstMessage(), backup.getFirstMessage(), bitgo.getFirstMessage()]; const r2Messages = [ @@ -183,9 +154,9 @@ describe('RedPallas MPS DKG', function () { ...backup.handleIncomingMessages(r1Messages), ...bitgo.handleIncomingMessages(r1Messages), ]; - user.handleIncomingMessages(r2Messages, derivationSeed); - backup.handleIncomingMessages(r2Messages, derivationSeed); - bitgo.handleIncomingMessages(r2Messages, derivationSeed); + user.handleIncomingMessages(r2Messages); + backup.handleIncomingMessages(r2Messages); + bitgo.handleIncomingMessages(r2Messages); const userPk = user.getSharePublicKey().toString('hex'); const backupPk = backup.getSharePublicKey().toString('hex'); @@ -200,19 +171,13 @@ describe('RedPallas MPS DKG', function () { const seedUser = Buffer.from('a304733c16cc821fe171d5c7dbd7276fd90deae808b7553d17a1e55e4a76b270', 'hex'); const seedBackup = Buffer.from('9d91c2e6353202cf61f8f275158b3468e9a00f7872fc2fd310b72cd026e2e2f9', 'hex'); const seedBitgo = Buffer.from('33c749b635cdba7f9fbf51ad0387431cde47e20d8dc13acd1f51a9a0ad06ebfe', 'hex'); - const fixedDerivationSeed = Buffer.from('c526955e37be0a0c8b77a831eb615948772b38df9f04d8c5a2e0e1f1d0c9b8a7', 'hex'); it('should create key shares with deterministic seeds', async function () { const userParty = { encKey: seedUser, dkgSeed: seedUser }; const backupParty = { encKey: seedBackup, dkgSeed: seedBackup }; const bitgoParty = { encKey: seedBitgo, dkgSeed: seedBitgo }; - const [user1, backup1, bitgo1] = await generateRedPallasDKGKeyShares( - fixedDerivationSeed, - userParty, - backupParty, - bitgoParty - ); + const [user1, backup1, bitgo1] = await generateRedPallasDKGKeyShares(userParty, backupParty, bitgoParty); const pk0 = user1.getSharePublicKey().toString('hex'); const pk1 = backup1.getSharePublicKey().toString('hex'); @@ -220,7 +185,7 @@ describe('RedPallas MPS DKG', function () { assert.strictEqual(pk0, pk1, 'User and backup should have same public key'); assert.strictEqual(pk1, pk2, 'Backup and BitGo should have same public key'); - const [user2] = await generateRedPallasDKGKeyShares(fixedDerivationSeed, userParty, backupParty, bitgoParty); + const [user2] = await generateRedPallasDKGKeyShares(userParty, backupParty, bitgoParty); assert.strictEqual( user1.getSharePublicKey().toString('hex'), user2.getSharePublicKey().toString('hex'), @@ -237,13 +202,11 @@ describe('RedPallas MPS DKG', function () { const seedBBitgo = Buffer.from('44d85ab746decb8f0f0c62be0498542ddf58f31d9ed24bd1f62b1b1be17fce0f', 'hex'); const [user1] = await generateRedPallasDKGKeyShares( - fixedDerivationSeed, { encKey: seedAUser, dkgSeed: seedAUser }, { encKey: seedABackup, dkgSeed: seedABackup }, { encKey: seedABitgo, dkgSeed: seedABitgo } ); const [user2] = await generateRedPallasDKGKeyShares( - fixedDerivationSeed, { encKey: seedBUser, dkgSeed: seedBUser }, { encKey: seedBBackup, dkgSeed: seedBBackup }, { encKey: seedBBitgo, dkgSeed: seedBBitgo } @@ -257,7 +220,7 @@ describe('RedPallas MPS DKG', function () { }); it('should create key shares without party seeds (random)', async function () { - const [userDkg, backupDkg, bitgoDkg] = await generateRedPallasDKGKeyShares(derivationSeed); + const [userDkg, backupDkg, bitgoDkg] = await generateRedPallasDKGKeyShares(); const userPk = userDkg.getSharePublicKey().toString('hex'); const backupPk = backupDkg.getSharePublicKey().toString('hex'); @@ -268,7 +231,7 @@ describe('RedPallas MPS DKG', function () { }); it('should generate valid reduced key shares', async function () { - const [userDkg, backupDkg, bitgoDkg] = await generateRedPallasDKGKeyShares(derivationSeed); + const [userDkg, backupDkg, bitgoDkg] = await generateRedPallasDKGKeyShares(); const userReduced = userDkg.getReducedKeyShare(); const backupReduced = backupDkg.getReducedKeyShare(); @@ -361,7 +324,7 @@ describe('RedPallas MPS DKG', function () { }); it('should throw error when trying to export session after completion', async function () { - const [userDkg, backupDkg, bitgoDkg] = await generateRedPallasDKGKeyShares(derivationSeed); + const [userDkg, backupDkg, bitgoDkg] = await generateRedPallasDKGKeyShares(); assert.throws(() => { userDkg.getSession(); diff --git a/modules/sdk-lib-mpc/test/unit/tss/redpallas/redpallas-utils.ts b/modules/sdk-lib-mpc/test/unit/tss/redpallas/redpallas-utils.ts index 9331c06002..99df75ba94 100644 --- a/modules/sdk-lib-mpc/test/unit/tss/redpallas/redpallas-utils.ts +++ b/modules/sdk-lib-mpc/test/unit/tss/redpallas/redpallas-utils.ts @@ -9,7 +9,6 @@ describe('RedPallas Utility Functions', function () { const dkgSeedUser = Buffer.from('b415844d27dd9320f282d6d8ecd8387f0e9fbf9198664e28a2f66e6f5b87c381', 'hex'); const dkgSeedBackup = Buffer.from('ae02d3f7464313d0f72f9f3862694579fa11f8983fc3fe42183cd137e3f3f30a', 'hex'); const dkgSeedBitgo = Buffer.from('44d85ab746decb8f0f0c62be0498542ddf58f31d9ed24bd1f62b1b1be17fce0f', 'hex'); - const derivationSeed = Buffer.from('c526955e37be0a0c8b77a831eb615948772b38df9f04d8c5a2e0e1f1d0c9b8a7', 'hex'); it('should be deterministic with split encKey and dkgSeed', async function () { const split = { @@ -17,13 +16,8 @@ describe('RedPallas Utility Functions', function () { backup: { encKey: seedBackup, dkgSeed: dkgSeedBackup }, bitgo: { encKey: seedBitgo, dkgSeed: dkgSeedBitgo }, }; - const [user, backup, bitgo] = await generateRedPallasDKGKeyShares( - derivationSeed, - split.user, - split.backup, - split.bitgo - ); - const [repeatUser] = await generateRedPallasDKGKeyShares(derivationSeed, split.user, split.backup, split.bitgo); + const [user, backup, bitgo] = await generateRedPallasDKGKeyShares(split.user, split.backup, split.bitgo); + const [repeatUser] = await generateRedPallasDKGKeyShares(split.user, split.backup, split.bitgo); const userPublicKey = user.getSharePublicKey().toString('hex'); assert.strictEqual(userPublicKey, backup.getSharePublicKey().toString('hex')); @@ -35,27 +29,17 @@ describe('RedPallas Utility Functions', function () { const okBackup = { encKey: seedBackup, dkgSeed: dkgSeedBackup }; const okBitgo = { encKey: seedBitgo, dkgSeed: dkgSeedBitgo }; await assert.rejects( - generateRedPallasDKGKeyShares( - derivationSeed, - { encKey: Buffer.alloc(31), dkgSeed: dkgSeedUser }, - okBackup, - okBitgo - ), + generateRedPallasDKGKeyShares({ encKey: Buffer.alloc(31), dkgSeed: dkgSeedUser }, okBackup, okBitgo), /encKey must be at least 32 bytes/ ); await assert.rejects( - generateRedPallasDKGKeyShares( - derivationSeed, - { encKey: seedUser, dkgSeed: Buffer.alloc(31) }, - okBackup, - okBitgo - ), + generateRedPallasDKGKeyShares({ encKey: seedUser, dkgSeed: Buffer.alloc(31) }, okBackup, okBitgo), /dkgSeed must be at least 32 bytes/ ); }); it('should produce distinct key shares per party with a shared public key', async function () { - const [user, backup, bitgo] = await generateRedPallasDKGKeyShares(derivationSeed); + const [user, backup, bitgo] = await generateRedPallasDKGKeyShares(); const userShare = user.getKeyShare(); const backupShare = backup.getKeyShare();