diff --git a/modules/sdk-lib-mpc/src/tss/eddsa-mps/dkg.ts b/modules/sdk-lib-mpc/src/tss/eddsa-mps/dkg.ts index d59e047235..ff16e01be0 100644 --- a/modules/sdk-lib-mpc/src/tss/eddsa-mps/dkg.ts +++ b/modules/sdk-lib-mpc/src/tss/eddsa-mps/dkg.ts @@ -234,14 +234,18 @@ export class DKG { } /** - * Returns a CBOR-encoded reduced representation containing the public key. + * Returns a CBOR-encoded ReducedKeyShare buffer containing the party's opaque + * signing key share in the `keyShare` field. This buffer is private key material. + * The caller encrypts it and stores it as `reducedEncryptedPrv` on the key card QR code. */ getReducedKeyShare(): Buffer { - if (!this.sharePk) { + if (!this.keyShare || !this.sharePk || !this.shareChaincode) { throw Error('DKG session not initialized'); } const reducedKeyShare: EddsaReducedKeyShare = { + keyShare: Array.from(this.keyShare), pub: Array.from(this.sharePk), + rootChainCode: Array.from(this.shareChaincode), }; return Buffer.from(encode(reducedKeyShare)); } diff --git a/modules/sdk-lib-mpc/src/tss/eddsa-mps/types.ts b/modules/sdk-lib-mpc/src/tss/eddsa-mps/types.ts index f026f322f1..02febddce3 100644 --- a/modules/sdk-lib-mpc/src/tss/eddsa-mps/types.ts +++ b/modules/sdk-lib-mpc/src/tss/eddsa-mps/types.ts @@ -3,7 +3,9 @@ import { isLeft } from 'fp-ts/Either'; import * as t from 'io-ts'; export const ReducedKeyShareType = t.type({ + keyShare: t.array(t.number), pub: t.array(t.number), + rootChainCode: t.array(t.number), }); export type EddsaReducedKeyShare = t.TypeOf; diff --git a/modules/sdk-lib-mpc/test/unit/tss/eddsa/dkg.ts b/modules/sdk-lib-mpc/test/unit/tss/eddsa/dkg.ts index 1f458298b8..f826536fec 100644 --- a/modules/sdk-lib-mpc/test/unit/tss/eddsa/dkg.ts +++ b/modules/sdk-lib-mpc/test/unit/tss/eddsa/dkg.ts @@ -205,12 +205,38 @@ describe('EdDSA MPS DKG', function () { ); assert(Buffer.isBuffer(bitgoReduced) && bitgoReduced.length > 0, 'BitGo reduced key share should be non-empty'); - const userPub = Buffer.from(MPSTypes.getDecodedReducedKeyShare(userReduced).pub).toString('hex'); - const backupPub = Buffer.from(MPSTypes.getDecodedReducedKeyShare(backupReduced).pub).toString('hex'); - const bitgoPub = Buffer.from(MPSTypes.getDecodedReducedKeyShare(bitgoReduced).pub).toString('hex'); + const userDecoded = MPSTypes.getDecodedReducedKeyShare(userReduced); + const backupDecoded = MPSTypes.getDecodedReducedKeyShare(backupReduced); + const bitgoDecoded = MPSTypes.getDecodedReducedKeyShare(bitgoReduced); + + const userPub = Buffer.from(userDecoded.pub).toString('hex'); + const backupPub = Buffer.from(backupDecoded.pub).toString('hex'); + const bitgoPub = Buffer.from(bitgoDecoded.pub).toString('hex'); assert.strictEqual(userPub, backupPub, 'User and backup should have same public key in reduced share'); assert.strictEqual(backupPub, bitgoPub, 'Backup and BitGo should have same public key in reduced share'); + + // keyShare must be present and non-empty (opaque WASM bincode needed for DSG) + assert(userDecoded.keyShare.length > 0, 'User reduced share must include keyShare'); + assert(backupDecoded.keyShare.length > 0, 'Backup reduced share must include keyShare'); + assert(bitgoDecoded.keyShare.length > 0, 'BitGo reduced share must include keyShare'); + + // rootChainCode must be 32 bytes + assert.strictEqual(userDecoded.rootChainCode.length, 32, 'User rootChainCode must be 32 bytes'); + assert.strictEqual(backupDecoded.rootChainCode.length, 32, 'Backup rootChainCode must be 32 bytes'); + assert.strictEqual(bitgoDecoded.rootChainCode.length, 32, 'BitGo rootChainCode must be 32 bytes'); + + // All parties derive the same chaincode + assert.strictEqual( + Buffer.from(userDecoded.rootChainCode).toString('hex'), + Buffer.from(backupDecoded.rootChainCode).toString('hex'), + 'User and backup should have same rootChainCode' + ); + assert.strictEqual( + Buffer.from(backupDecoded.rootChainCode).toString('hex'), + Buffer.from(bitgoDecoded.rootChainCode).toString('hex'), + 'Backup and BitGo should have same rootChainCode' + ); }); });