feat(sdk-core): add createOfflineKeyGenRound1Share to EddsaMPCv2Utils#9187
feat(sdk-core): add createOfflineKeyGenRound1Share to EddsaMPCv2Utils#9187bitgo-ai-agent-dev[bot] wants to merge 1 commit into
Conversation
6ed644e to
348b90e
Compare
Add createOfflineKeyGenRound1Share to EddsaMPCv2Utils to support the external signer pattern for EdDSA MPCv2 DKG. This method decrypts the caller-provided GPG private key, initializes a DKG session for the given party, produces and signs the round-1 message, then serializes and encrypts the session state so round 2 can resume it later without re-running round 1. Pattern mirrors createOfflineRound1Share (signing) but targets EddsaMPSDkg.DKG instead of EddsaMPSDsg.DSG. The encryptedRound1Session payload includes dkgSession, ownMsgPayload (base64), and ownMsgFrom so that handleIncomingMessages can reconstruct the round-1 DeserializedMessage in round 2. Tests verify: valid signedMsg1 + encrypted session, passphrase binding, session restorability + message verification, and rejection of invalid GPG key material. Ticket: WCI-889 Session-Id: eac7d223-cc21-440f-83a1-6de6cd3cb3b6 Task-Id: 03326a98-89d2-41c6-8fab-6c6040541092
348b90e to
76e2907
Compare
| encryptedUserGpgPrvKey: string; | ||
| bitgoGpgPubKey: string; | ||
| counterPartyGpgPubKey: string; | ||
| partyId?: MPCv2PartiesEnum; |
There was a problem hiding this comment.
you're using the full enum here which also includes BITGO
you can use the narrower type SignerPartyId in modules/sdk-core/src/bitgo/tss/eddsa/eddsaMPCv2?
There was a problem hiding this comment.
Add USER vs BACKUP test, i.e. partyId: BACKUP produces different session state than USER by adding a test that runs both, decrypts both sessions, and asserts they differ
| const encryptedRound1Session = await this.bitgo.encryptAsync({ | ||
| input: sessionPayload, | ||
| password: walletPassphrase, | ||
| adata: EddsaMPCv2Utils.MPS_DKG_KEYGEN_ROUND1_STATE, |
There was a problem hiding this comment.
bind partyId into session adata
adata: ${EddsaMPCv2Utils.MPS_DKG_KEYGEN_ROUND1_STATE}:${partyId}
you can see below these lines (line 666 rn) that signing already binds that extra context into adata so keygen can do they same for party.
|
|
||
| const [, ownSk] = await MPSComms.extractEd25519KeyPair(gpgPrvKey); | ||
|
|
||
| const bitgoKeyObj = await pgp.readKey({ armoredKey: bitgoGpgPubKey }); |
There was a problem hiding this comment.
consider this check
if (envRequiresBitgoPubGpgKeyConfig(this.bitgo.getEnv())) {
assert(isBitgoEddsaMpcv2PubKey(bitgoGpgPubKey), 'Invalid BitGo GPG public key');
}
reading the armored key
What
createOfflineKeyGenRound1Sharemethod toEddsaMPCv2Utilsinmodules/sdk-core/src/bitgo/utils/tss/eddsa/eddsaMPCv2.ts{ signedMsg1: MPSTypes.MPSSignedMessage, encryptedRound1Session: string }, following the same offline signer pattern ascreateOfflineRound1Sharefor signingMPS_DKG_KEYGEN_ROUND1_STATEdomain-separator constant to prevent session ciphertext reuse across signing and key-gen contextsWhy
createKeychainsWithExternalSigner) can be wired up — see WCI-888 for the full scopingTest plan
EddsaMPCv2Utils.createOfflineKeyGenRound1Share— 4 unit tests passeddsaMPCv2.tstest suite (52 tests) passes with no regressionsTicket: WCI-889