Skip to content
Merged
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
8 changes: 6 additions & 2 deletions modules/sdk-lib-mpc/src/tss/eddsa-mps/dkg.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}
Expand Down
2 changes: 2 additions & 0 deletions modules/sdk-lib-mpc/src/tss/eddsa-mps/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<typeof ReducedKeyShareType>;
Expand Down
32 changes: 29 additions & 3 deletions modules/sdk-lib-mpc/test/unit/tss/eddsa/dkg.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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'
);
});
});

Expand Down
Loading