Skip to content

Commit e833b38

Browse files
authored
fix: bind external signature verification to request
* chore: release v0.4.0-5 * fix: bind external signature verification to request
1 parent be26a47 commit e833b38

File tree

4 files changed

+52
-16
lines changed

4 files changed

+52
-16
lines changed

package-lock.json

Lines changed: 10 additions & 10 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@zama-fhe/relayer-sdk",
3-
"version": "0.5.0-alpha.1",
3+
"version": "0.5.0-alpha.2",
44
"description": "fhevm Relayer SDK",
55
"main": "lib/node.js",
66
"types": "lib/node.d.ts",
@@ -94,9 +94,9 @@
9494
"fetch-retry": "^6.0.0",
9595
"keccak": "^3.0.4",
9696
"node-tfhe": "1.4.0-alpha.3",
97-
"node-tkms": "0.13.10-rc.0",
97+
"node-tkms": "0.13.10-rc.2",
9898
"tfhe": "1.4.0-alpha.3",
99-
"tkms": "0.13.10-rc.0",
99+
"tkms": "0.13.10-rc.2",
100100
"wasm-feature-detect": "^1.8.0"
101101
},
102102
"devDependencies": {

src/_version.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
// This file is auto-generated
2-
export const version: string = '0.5.0-alpha.1';
2+
export const version: string = '0.5.0-alpha.2';
33
export const sdkName: string = '@zama-fhe/relayer-sdk';

src/relayer/userDecrypt.ts

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,26 @@ interface DelegatedUserDecryptRequest {
3333
defaultOptions?: FhevmInstanceOptions;
3434
}
3535

36+
/**
37+
* Validates that every response item's extraData matches the request's extraData.
38+
* Returns the sanitized (no 0x prefix) request extraData for use in signature verification.
39+
*/
40+
function validateAndSanitizeRequestExtraData(
41+
requestExtraData: BytesHex,
42+
relayerUserDecryptResults: RelayerUserDecryptResult,
43+
): string {
44+
const sanitized = requestExtraData.replace(/^0x/, '');
45+
for (const result of relayerUserDecryptResults) {
46+
const responseExtraData = result.extraData.replace(/^0x/, '');
47+
if (responseExtraData.toLowerCase() !== sanitized.toLowerCase()) {
48+
throw new Error(
49+
`Response extraData does not match request extraData: expected ${requestExtraData}, got ${result.extraData}`,
50+
);
51+
}
52+
}
53+
return sanitized;
54+
}
55+
3656
// Add type checking
3757
const getAddress = (value: string): `0x${string}` =>
3858
ethersGetAddress(value) as `0x${string}`;
@@ -285,6 +305,12 @@ export const userDecryptRequest =
285305
...options,
286306
});
287307

308+
// Validate that response extraData matches request to prevent server tampering
309+
const requestExtraDataSanitized = validateAndSanitizeRequestExtraData(
310+
extraData,
311+
relayerUserDecryptResults,
312+
);
313+
288314
// Response side: resolve context-aware signers
289315
const effectiveSigners = await resolveEffectiveSigners(
290316
relayerUserDecryptResults,
@@ -323,14 +349,16 @@ export const userDecryptRequest =
323349
h.handle.replace(/^0x/, ''),
324350
),
325351
eip712_verifying_contract: verifyingContractAddressDecryption,
352+
extra_data: requestExtraDataSanitized,
326353
};
327354

328355
// Transform response to match node-tkms expected format
356+
// Use request extraData (not response) to bind signature verification to the original request
329357
const tkmsUserDecryptResults = relayerUserDecryptResults.map(
330358
(result) => ({
331359
payload: result.payload,
332360
signature: result.signature,
333-
extra_data: result.extraData.replace(/^0x/, ''),
361+
extra_data: requestExtraDataSanitized,
334362
}),
335363
);
336364

@@ -426,6 +454,12 @@ export const delegatedUserDecryptRequest =
426454
},
427455
);
428456

457+
// Validate that response extraData matches request to prevent server tampering
458+
const requestExtraDataSanitized = validateAndSanitizeRequestExtraData(
459+
extraData,
460+
relayerUserDecryptResults,
461+
);
462+
429463
// Response side: resolve context-aware signers
430464
const effectiveSigners = await resolveEffectiveSigners(
431465
relayerUserDecryptResults,
@@ -464,14 +498,16 @@ export const delegatedUserDecryptRequest =
464498
h.handle.replace(/^0x/, ''),
465499
),
466500
eip712_verifying_contract: verifyingContractAddressDecryption,
501+
extra_data: requestExtraDataSanitized,
467502
};
468503

469504
// Transform response to match node-tkms expected format
505+
// Use request extraData (not response) to bind signature verification to the original request
470506
const tkmsUserDecryptResults = relayerUserDecryptResults.map(
471507
(result) => ({
472508
payload: result.payload,
473509
signature: result.signature,
474-
extra_data: result.extraData.replace(/^0x/, ''),
510+
extra_data: requestExtraDataSanitized,
475511
}),
476512
);
477513

0 commit comments

Comments
 (0)