Skip to content

feat: opt-in v2 Argon2+HKDF encryption for multisig and MPC flows#8592

Draft
pranavjain97 wants to merge 8 commits intopranavjain/wcn-31-phase-1-hkdf-caching-layer-for-multi-call-operationsfrom
pranavjain/wcn-32-v2-encryption-call-sites
Draft

feat: opt-in v2 Argon2+HKDF encryption for multisig and MPC flows#8592
pranavjain97 wants to merge 8 commits intopranavjain/wcn-31-phase-1-hkdf-caching-layer-for-multi-call-operationsfrom
pranavjain/wcn-32-v2-encryption-call-sites

Conversation

@pranavjain97
Copy link
Copy Markdown
Contributor

@pranavjain97 pranavjain97 commented Apr 21, 2026

Summary

Wire v2 encryption (Argon2id + AES-256-GCM + HKDF session caching) into wallet creation and signing call sites across multisig, DKLS MPCv2, and EdDSA flows.

  • Opt-in via encryptionVersion: 2 on wallet/key creation
  • Signing auto-detects v1/v2 from the envelope
  • Default stays v1 -- zero breaking changes
  • decryptKeychainPrivateKey made async to support v1/v2 auto-detection in signing paths

Live Node.JS Testing (testnet)

All flows tested end-to-end on testnet with real transactions:

Operation v1 (SJCL/PBKDF2) v2 (Argon2id+HKDF) Delta
EdDSA wallet creation (tsol) 6.02s 5.53s -8%
ECDSA MPCv2 wallet creation (hteth) 8.57s 7.92s -8%
Multisig wallet creation (tbtc) 2.53s 2.43s -4%
EdDSA signing (tsol) 11.64s 11.06s -5%
ECDSA MPCv2 signing (hteth) 10.23s 11.02s +8%

v2 wallet creation is consistently faster due to HKDF session caching. Signing is roughly equivalent -- network round trips dominate.

Test plan

  • sdk-api unit tests (162 passing)
  • sdk-core unit tests (163 passing)
  • Codec validation tests for Lightning/GoAccount with encryptionVersion
  • E2e tests for DKLS and EdDSA keygen with v2 envelopes
  • Live testnet: EdDSA TSS wallet creation + signing (tsol)
  • Live testnet: ECDSA MPCv2 wallet creation + signing (hteth)
  • Live testnet: Multisig wallet creation + decrypt verification (tbtc)
  • CI

TICKET: WCN-32

pranavjain97 and others added 7 commits April 20, 2026 14:01
…ase/BitGoAPI

WCN-32: Adds async encryption dispatch (v1/v2 based on encryptionVersion param)
and session-based encryption to the BitGoBase interface and BitGoAPI implementation.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
…hain types

WCN-32: Thread encryptionVersion?: 2 through GenerateWalletOptions,
GenerateMpcWalletOptions, CreateMpcOptions, CreateBackupOptions,
and both Lightning/GoAccount codecs.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
…tion

WCN-32: Convert sync encrypt() to async encryptAsync() in wallet generation
and keychain creation paths. Thread encryptionVersion from GenerateWalletOptions
through Lightning, GoAccount, TSS, and onchain multisig flows.

Default remains v1. Only opt-in encryptionVersion: 2 triggers v2 encryption.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
…n and signing

WCN-32: DKLS keygen uses encryption session when encryptionVersion: 2,
signing rounds auto-detect v2 from envelope and use decryptAsync/session.
validateAdata skipped for v2 envelopes. All v1 paths unchanged.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
… signing

WCN-32: EdDSA keygen uses encryption session when encryptionVersion: 2,
signing auto-detects v2 from envelope and uses decryptAsync/session.
All v1 paths unchanged.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
WCN-32: Verify that createKeychains with encryptionVersion: 2 produces
v2 envelopes for encryptedPrv/reducedEncryptedPrv and that they are
decryptable via decryptAsync.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
…etection

WCN-32: Convert decryptKeychainPrivateKey to use decryptAsync internally
so signing flows work with both v1 and v2 encrypted keychains. Make
getUserPrv async and update all callers across sdk-core, abstract-utxo,
abstract-eth, and bitgo.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
@linear
Copy link
Copy Markdown

linear Bot commented Apr 21, 2026

…n destroy

WCN-32: Address PR review feedback:
- Explicitly set tagLength: 128 on AES-GCM encrypt/decrypt calls
- Clear argon2SaltB64 in EncryptionSession.destroy() for consistent cleanup

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
@pranavjain97
Copy link
Copy Markdown
Contributor Author

Wallet sharing to be done as a separate ticket.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant