Skip to content

feat(sdk-core): add signRecoveryMpcV2 for EdDSA MPCv2 offline signing#9025

Closed
vibhavgo wants to merge 2 commits into
masterfrom
WCI-397/sdk-core
Closed

feat(sdk-core): add signRecoveryMpcV2 for EdDSA MPCv2 offline signing#9025
vibhavgo wants to merge 2 commits into
masterfrom
WCI-397/sdk-core

Conversation

@vibhavgo

Copy link
Copy Markdown
Contributor

Description

Adds signRecoveryMpcV2 to modules/sdk-core/src/bitgo/utils/tss/eddsa/eddsaMPCv2.ts as a standalone export for EdDSA MPCv2 recovery signing flows. The function drives the MPS DSG protocol locally to completion using user and backup key shares (obtained from getEddsaMPCv2RecoveryKeyShares), then verifies the resulting 64-byte Ed25519 signature against the child public key derived via deriveUnhardenedMps. Mirrors the existing ECDSA signRecoveryMpcV2 pattern.

Issue Number

WCI-397

Type of change

  • New feature (non-breaking change which adds functionality)

How Has This Been Tested?

Unit tests added in modules/sdk-core/test/unit/bitgo/utils/tss/eddsa/eddsaMPCv2.ts under describe('signRecoveryMpcV2'):

  • Valid path — runs full 2-party MPS signing with real DKG key shares, asserts the returned Buffer is 64 bytes and verifies with nacl.sign.detached.verify against deriveUnhardenedMps
  • Tampered message — signs one message, verifies against a different message, asserts the nacl verification returns false
  • Wrong commonKeyChain — passes a key chain from a different DKG session, asserts the function throws "EdDSA MPCv2 recovery signature verification failed"

Run with:

yarn run unit-test --scope @bitgo/sdk-core -- -- --grep "signRecoveryMpcV2"

vibhavgo and others added 2 commits June 15, 2026 16:46
Adds a standalone helper to decrypt and validate both EdDSA MPCv2
reduced keycards, returning typed Buffer key shares and the derived
commonKeyChain. Mirrors the ECDSA getMpcV2RecoveryKeyShares pattern
as part of the SJCL-to-Argon2 migration.

- Decrypt both keycards in parallel via Promise.all
- Use bitgo.decryptAsync (v1 + v2) when a BitGoBase instance is
  provided; fall back to sjcl.decrypt (v1 only) otherwise
- Validate pub and rootChainCode separately with distinct error
  messages
- Wrap getDecodedReducedKeyShare in try-catch to surface a descriptive
  error for malformed or public-only keycards
- Add 3 unit tests: v1 happy path, malformed keycard, mismatched keys

Ticket: WCI-396
Ticket: WCI-397

Implements local 2-party MPS signing for EdDSA MPCv2 recovery flows, mirroring
the existing ECDSA signRecoveryMpcV2 pattern. The function runs the MPS DSG
protocol to round 3 using user and backup key shares, then verifies the resulting
64-byte Ed25519 signature against the child public key derived via deriveUnhardenedMps.

- export `signRecoveryMpcV2` from eddsaMPCv2.ts
  - drives `MPSUtil.executeTillRound(3, ...)` locally with user + backup DSG instances
  - derives the child public key via `deriveUnhardenedMps(commonKeyChain, derivationPath)`
  - verifies the signature with `nacl.sign.detached.verify`; throws on mismatch
- add unit tests for `signRecoveryMpcV2`
  - valid path: 64-byte signature verifies against derived public key
  - tampered message: signature does not verify against a different message
  - wrong commonKeyChain: throws "EdDSA MPCv2 recovery signature verification failed"

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@vibhavgo vibhavgo requested review from a team as code owners June 15, 2026 11:40
@linear-code

linear-code Bot commented Jun 15, 2026

Copy link
Copy Markdown

WCI-397

@vibhavgo vibhavgo closed this Jun 15, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant