feat: construct extraData and add context signer fetching#414
feat: construct extraData and add context signer fetching#414zmalatrax wants to merge 12 commits intofeat/kms-contextfrom
Conversation
…and V1 normalization
|
Tests targeting Testnet are expected to fail, as testnet is not updated yet...
|
src/relayer/userDecrypt.ts
Outdated
| ): Promise<UserDecryptResults> => { | ||
| const extraData: BytesHex = '0x00'; | ||
| // Accept caller-provided extraData, default to legacy '0x00' when omitted | ||
| const extraData: BytesHex = options?.extraData ?? '0x00'; |
There was a problem hiding this comment.
nit: not sure if it's accurate to include the extraData in the options type instead of having it as another argument in the userDecryptRequest function. I mean, the RelayerUserDecryptOptionsType seems more specific to a Relayer endpoint configurations/options.
Also, it seems a bit weird not having the publicDecryptRequest function receiving such an extraData argument. Do you know why? @zmalatrax
There was a problem hiding this comment.
not sure if it's accurate to include the extraData in the options type instead of having it as another argument in the userDecryptRequest function. I mean, the RelayerUserDecryptOptionsType seems more specific to a Relayer endpoint configurations/options.
Indeed, it was added to options to avoid adding a new argument to the public api of userDecrypt but it's semantically wrong..
I'll refactor with a new optional param instead
Also, it seems a bit weird not having the publicDecryptRequest function receiving such an extraData argument. Do you know why?
Initially I wanted to avoid exposing extraData to the public API, and fetch it in the internals of the relayer-sdk.
But for user decryption, as the user creates an EIP712 signature, and that the extraData is required I had to expose it to the public api. But for public decryption it's not mandatory, so I didn't add it.
For consistency we could have both userDecrypt and publicDecrypt handle the extraData at the public api level
Closes https://github.com/zama-ai/fhevm-internal/issues/1065
Implements context-aware KMS signer resolution and dynamic
extraDataconstruction for all decryption request types, as specified in issue https://github.com/zama-ai/fhevm-internal/issues/1065 / RFC 003. Part of a coordinated release (https://github.com/zama-ai/planning-blockchain/issues/1097), notably with the updated KMSVerifier contract and relayer.Summary
extraDataparser, builder, and legacy detection (extraData.ts)KmsContextCachefor per-context signer caching with TTL-based current context IDKmsContextCacheintoFhevmHostChain, public decrypt, user decrypt, and delegated user decryptgetExtraData()on the publicFhevmInstanceAPI for user/delegated user decrypt flowsextraDatato relayer response types and V2 guardsMotivation
The SDK previously loaded KMS signers once at initialization and hardcoded
extraDatato'0x00'. After a KMS context switch, the SDK held stale signers and could not verify responses signed by a new signer set. This PR makes both sides context-aware:getCurrentKmsContextId()and buildsextraData = [0x01 | contextId(32B)]before every decryption request.extraData, fetches the matching signer set viagetSignersForKmsContext(contextId), and passes those signers to TKMS verification.Changes by commit
dd3a724kms/extraData.tsisLegacyExtraData,parseExtraData,buildRequestExtraDatawith full test coverage (round-trip, boundary values, version dispatch)bbe62d8kms/KmsContextCache.tsaa7c272fhevmHostChain.tsFhevmHostChaineagerly createsKmsContextCache(no RPC until first use) and exposes it viakmsContextCachegetterf3610eerelayer-provider/extraData: BytesHextoRelayerUserDecryptResultitems andRelayerUserDecryptOptionsType. Updates V2 guards to assertextraData. Test coverage for missing/invalidextraData. V1 routes receive minimal passthrough changes only (deprecated, not the focus)353ba45publicDecrypt.tsextraDatafromkmsContextCache.getCurrentContextId(), reads responseextraDatafor EIP-712 verification, and resolves context-specific signers (legacy fallback to init-time signers)711928euserDecrypt.tsextraData(default'0x00'), resolve context-aware signers viaresolveEffectiveSigners()with mixed-context assertion, and fail closed on RPC errors243f298index.tsgetExtraData()onFhevmInstance, adds optionalextraDataparam tocreateEIP712andcreateDelegatedUserDecryptEIP712, passeskmsContextCacheto all three decrypt closuresDesign decisions
getCurrentContextId()internally before each request.extraDatafrom caller — the EIP-712 signature coversextraData, so the caller must obtain it first viagetExtraData()and pass the same value to bothcreateEIP712()and the decrypt call. Single source of truth:getExtraData() -> createEIP712(extraData) -> userDecrypt(options.extraData).extraDatain responses.isLegacyExtraDataexists only as a defensive code path, not as a compatibility layer for older relayers.Test coverage
extraData construction
extraDatais correctly formatted: version0x01+ 32-byte context ID (extraData.test.ts)parseExtraData(buildRequestExtraData(id)).contextId === idfor boundary values'0x','0x00', and'0x00...'variantsKmsContextCache
getCurrentContextId()returns context ID from contract (KmsContextCache.test.ts)getSignersForContext()cache miss/hit, concurrent dedup, rejection evictioncauseV2 guards
extraDataon response items (RelayerV2ResultUserDecrypt.test.ts)extraDatathrowIntegration (decrypt closures)
publicDecryptanduserDecrypttests pass with mockKmsContextCacheFollow-up notes
Since this is a coordinated release (afaiu the updated relayer always returns v1 context-bearing
extraData), theisLegacyExtraDatabranches inpublicDecrypt.tsandresolveEffectiveSigners()would then be dead code. Removing them would:isLegacyExtraDataand its tests — every response is now context-bearing, so the version-dispatch branches (if (isLegacyExtraData(...)) { use init-time signers }) are never reached.kmsSignersfrom decrypt closures — init-time signers are only used in those legacy branches. Without them, decrypt closures only needkmsContextCache.resolveEffectiveSigners— becomes a straightparseExtraData+getSignersForContextcall, no branching.extraDatarequired increateEIP712/createDelegatedUserDecryptEIP712/RelayerUserDecryptOptionsType— currently defaults to'0x00', which lets callers silently skipgetExtraData()and send legacy requests. Making it required catches integration errors at compile time.Test plan
npx jest --colors --passWithNoTests— all existing and new tests pass