Skip to content

Commit 0d437a8

Browse files
authored
Merge of #2007
2 parents 16d7577 + 9201b26 commit 0d437a8

File tree

13 files changed

+399
-39
lines changed

13 files changed

+399
-39
lines changed

host-contracts/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ npm install
1111
```
1212

1313
To run forge tests:
14+
1415
```
1516
npm run forge:soldeer
1617
npm run test:forge

host-contracts/lib/FHE.sol

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
pragma solidity ^0.8.24;
33

44
import "./Impl.sol";
5-
import "./cryptography/ECDSA.sol";
5+
import {FhevmECDSA} from "./cryptography/FhevmECDSA.sol";
66
import {FheType} from "../contracts/shared/FheType.sol";
77

88
import "encrypted-types/EncryptedTypes.sol";
@@ -9646,7 +9646,7 @@ library FHE {
96469646
address[] memory recoveredSigners = new address[](numSignatures);
96479647
uint256 uniqueValidCount;
96489648
for (uint256 i = 0; i < numSignatures; i++) {
9649-
address signerRecovered = ECDSA.recover(digest, signatures[i]);
9649+
address signerRecovered = FhevmECDSA.recover(digest, signatures[i]);
96509650
if (!_isSigner(signerRecovered, KMSSigners)) {
96519651
revert KMSInvalidSigner(signerRecovered);
96529652
}
@@ -9685,7 +9685,7 @@ library FHE {
96859685
* @return signer The address that supposedly signed the message.
96869686
*/
96879687
function _recoverSigner(bytes32 message, bytes memory signature) private pure returns (address) {
9688-
address signerRecovered = ECDSA.recover(message, signature);
9688+
address signerRecovered = FhevmECDSA.recover(message, signature);
96899689
return signerRecovered;
96909690
}
96919691

host-contracts/lib/cryptography/ECDSA.sol renamed to host-contracts/lib/cryptography/FhevmECDSA.sol

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,11 @@ pragma solidity ^0.8.20;
88
*
99
* These functions can be used to verify that a message was signed by the holder
1010
* of the private keys of a given address.
11+
*
12+
* @dev This library is forked from OpenZeppelin's ECDSA and renamed to FhevmECDSA
13+
* to avoid naming conflicts with the original when both are used in the same project.
1114
*/
12-
library ECDSA {
15+
library FhevmECDSA {
1316
enum RecoverError {
1417
NoError,
1518
InvalidSignature,

host-contracts/test/kmsVerifier/kmsVerifier.t.sol

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -565,7 +565,9 @@ contract KMSVerifierTest is Test {
565565
/**
566566
* @dev Tests that the verifyDecryptionEIP712KMSSignatures function fails if the length of the decryption proof is invalid.
567567
*/
568-
function test_VerifyDecryptionEIP712KMSSignaturesFailsIfDeserializingDecryptionProofFail(uint256 randomValue) public {
568+
function test_VerifyDecryptionEIP712KMSSignaturesFailsIfDeserializingDecryptionProofFail(
569+
uint256 randomValue
570+
) public {
569571
_upgradeProxyWithSigners(3);
570572
bytes32[] memory handlesList = _generateMockHandlesList(3);
571573

library-solidity/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,13 @@ _See full details in the [Key concepts](https://docs.zama.ai/fhevm/smart-contrac
1818
To start writing confidential smart contracts using FHEVM Solidity, follow the Hardhat setup guide here: [Getting Started with Hardhat](https://docs.zama.ai/fhevm/getting-started/overview-1/hardhat).
1919

2020
run
21+
2122
```
2223
npm install
2324
```
2425

2526
To run forge tests:
27+
2628
```
2729
npm run forge:soldeer
2830
npm run test:forge

library-solidity/codegen/src/main.ts

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import { generateSolidityHCULimit } from './hcuLimitGenerator';
2323
import { ALL_OPERATORS } from './operators';
2424
import { ALL_OPERATORS_PRICES } from './operatorsPrices';
2525
import { fromDirToFile, fromFileToFile, isDirectory } from './paths';
26-
import { generateSolidityFHELib } from './templateFHEDotSol';
26+
import { generateFhevmECDSALib, generateSolidityFHELib } from './templateFHEDotSol';
2727
import { generateSolidityFheType } from './templateFheTypeDotSol';
2828
import { generateSolidityImplLib } from './templateImpDotSol';
2929
import {
@@ -147,6 +147,7 @@ export async function commandGenerateAllFiles(options: any) {
147147

148148
const fheTypesDotSol = `${path.join(absConfig.lib.fheTypeDir, 'FheType.sol')}`;
149149
const implDotSol = `${path.join(absConfig.lib.outDir, 'Impl.sol')}`;
150+
const ecdsaDotSol = `${path.join(absConfig.lib.outDir, 'cryptography', 'FhevmECDSA.sol')}`;
150151
const fheDotSol = `${path.join(absConfig.lib.outDir, 'FHE.sol')}`;
151152
const hcuLimitDotSol = `${path.join(absConfig.hostContracts.outDir, 'HCULimit.sol')}`;
152153

@@ -162,6 +163,7 @@ export async function commandGenerateAllFiles(options: any) {
162163
const implRelFheTypesDotSol = fromFileToFile(implDotSol, fheTypesDotSol);
163164
const fheRelFheTypesDotSol = fromFileToFile(fheDotSol, fheTypesDotSol);
164165
const fheRelImplDotSol = fromFileToFile(fheDotSol, implDotSol);
166+
const fheRelEcdsaDotSol = fromFileToFile(fheDotSol, ecdsaDotSol);
165167

166168
debugLog(`============ Config ============`);
167169
debugLog(`basePath: ${absConfig.baseDir}`);
@@ -170,6 +172,7 @@ export async function commandGenerateAllFiles(options: any) {
170172
debugLog(`noTest: ${absConfig.noTest}`);
171173
debugLog(`============= Lib =============`);
172174
debugLog(`libDir: ${absConfig.lib.outDir}`);
175+
debugLog(`FhevmECDSA.sol: ${ecdsaDotSol}`);
173176
debugLog(`Impl.sol: ${implDotSol}`);
174177
debugLog(`FHE.sol: ${fheDotSol}`);
175178
debugLog(`fheTypeDir: ${absConfig.lib.fheTypeDir}`);
@@ -197,15 +200,24 @@ export async function commandGenerateAllFiles(options: any) {
197200
if (config.noLib !== true) {
198201
const fheTypesCode = generateSolidityFheType(ALL_FHE_TYPE_INFOS);
199202
const implCode = generateSolidityImplLib(ALL_OPERATORS, implRelFheTypesDotSol);
200-
const fheCode = generateSolidityFHELib(ALL_OPERATORS, ALL_FHE_TYPE_INFOS, fheRelFheTypesDotSol, fheRelImplDotSol);
203+
const fheCode = generateSolidityFHELib({
204+
operators: ALL_OPERATORS,
205+
fheTypes: ALL_FHE_TYPE_INFOS,
206+
fheTypeDotSol: fheRelFheTypesDotSol,
207+
implDotSol: fheRelImplDotSol,
208+
ecdsaDotSol: fheRelEcdsaDotSol,
209+
});
210+
const ecdsaCode = generateFhevmECDSALib();
201211

202212
mkDir(path.dirname(fheTypesDotSol));
203213
mkDir(path.dirname(implDotSol));
214+
mkDir(path.dirname(ecdsaDotSol));
204215
mkDir(path.dirname(fheDotSol));
205216

206217
// Generate core Solidity contract files.
207218
await formatAndWriteFile(`${fheTypesDotSol}`, fheTypesCode);
208219
await formatAndWriteFile(`${implDotSol}`, implCode);
220+
await formatAndWriteFile(`${ecdsaDotSol}`, ecdsaCode);
209221
await formatAndWriteFile(`${fheDotSol}`, fheCode);
210222
} else {
211223
debugLog(`Skipping lib generation.`);

library-solidity/codegen/src/templateFHEDotSol.ts

Lines changed: 73 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,30 @@ import { OperatorArguments, ReturnType } from './common';
66
import { resolveTemplatePath } from './paths';
77
import { getUint, removeTemplateComments } from './utils';
88

9-
export function generateSolidityFHELib(
10-
operators: Operator[],
11-
fheTypes: FheTypeInfo[],
12-
fheTypeDotSol: string,
13-
implDotSol: string,
14-
): string {
9+
export function generateFhevmECDSALib() {
10+
const file = resolveTemplatePath('FhevmECDSA.sol-template');
11+
const template = readFileSync(file, 'utf8');
12+
let code = removeTemplateComments(template);
13+
return code;
14+
}
15+
16+
export function generateSolidityFHELib({
17+
operators,
18+
fheTypes,
19+
fheTypeDotSol,
20+
implDotSol,
21+
ecdsaDotSol,
22+
}: {
23+
operators: Operator[];
24+
fheTypes: FheTypeInfo[];
25+
fheTypeDotSol: string;
26+
implDotSol: string;
27+
ecdsaDotSol: string;
28+
}): string {
1529
// Placeholders:
1630
// =============
1731
// $${ImplDotSol}$$
32+
// $${EcdsaDotSol}$$
1833
// $${FheTypeDotSol}$$
1934
// $${FHEOperators}$$
2035
// $${ACLFunctions}$$
@@ -25,6 +40,7 @@ export function generateSolidityFHELib(
2540
let code = removeTemplateComments(template);
2641

2742
code = code.replace('$${ImplDotSol}$$', implDotSol);
43+
code = code.replace('$${EcdsaDotSol}$$', ecdsaDotSol);
2844
code = code.replace('$${FheTypeDotSol}$$', fheTypeDotSol);
2945

3046
// Exclude types that do not support any operators.
@@ -191,9 +207,13 @@ function handleSolidityTFHEEncryptedOperatorForTwoEncryptedTypes(
191207

192208
res.push(`
193209
/**
194-
* @dev Evaluates ${operator.name}(e${lhsFheType.type.toLowerCase()} a, e${rhsFheType.type.toLowerCase()} b) and returns the result.
210+
* @dev Evaluates ${
211+
operator.name
212+
}(e${lhsFheType.type.toLowerCase()} a, e${rhsFheType.type.toLowerCase()} b) and returns the result.
195213
*/
196-
function ${operator.name}(e${lhsFheType.type.toLowerCase()} a, e${rhsFheType.type.toLowerCase()} b) internal returns (${returnType}) {
214+
function ${
215+
operator.name
216+
}(e${lhsFheType.type.toLowerCase()} a, e${rhsFheType.type.toLowerCase()} b) internal returns (${returnType}) {
197217
if (!isInitialized(a)) {
198218
a = asE${lhsFheType.type.toLowerCase()}(0);
199219
}
@@ -272,7 +292,9 @@ function generateSolidityTFHEScalarOperator(fheType: AdjustedFheType, operator:
272292
let implExpressionA;
273293

274294
if (fheType.type == 'Bool') {
275-
implExpressionA = `Impl.${operator.name}(e${fheType.type.toLowerCase()}.unwrap(a), bytes32(uint256(b?1:0))${scalarFlag})`;
295+
implExpressionA = `Impl.${
296+
operator.name
297+
}(e${fheType.type.toLowerCase()}.unwrap(a), bytes32(uint256(b?1:0))${scalarFlag})`;
276298
} else if (fheType.type.startsWith('Int')) {
277299
throw new Error('Int types are not supported!');
278300
} else {
@@ -318,9 +340,13 @@ function generateSolidityTFHEScalarOperator(fheType: AdjustedFheType, operator:
318340
res.push(`
319341
320342
/**
321-
* @dev Evaluates ${operator.name}(e${fheType.type.toLowerCase()} a, ${clearMatchingType.toLowerCase()} b) and returns the result.
343+
* @dev Evaluates ${
344+
operator.name
345+
}(e${fheType.type.toLowerCase()} a, ${clearMatchingType.toLowerCase()} b) and returns the result.
322346
*/
323-
function ${operator.name}(e${fheType.type.toLowerCase()} a, ${clearMatchingType.toLowerCase()} b) internal returns (${returnType}) {
347+
function ${
348+
operator.name
349+
}(e${fheType.type.toLowerCase()} a, ${clearMatchingType.toLowerCase()} b) internal returns (${returnType}) {
324350
if (!isInitialized(a)) {
325351
a = asE${fheType.type.toLowerCase()}(${
326352
fheType.type == 'Bool' ? 'false' : fheType.type == 'Address' ? `${clearMatchingType.toLowerCase()}(0)` : 0
@@ -335,9 +361,13 @@ function generateSolidityTFHEScalarOperator(fheType: AdjustedFheType, operator:
335361
res.push(`
336362
337363
/**
338-
* @dev Evaluates ${operator.name}(${clearMatchingType.toLowerCase()} a, e${fheType.type.toLowerCase()} b) and returns the result.
364+
* @dev Evaluates ${
365+
operator.name
366+
}(${clearMatchingType.toLowerCase()} a, e${fheType.type.toLowerCase()} b) and returns the result.
339367
*/
340-
function ${operator.name}(${clearMatchingType.toLowerCase()} a, e${fheType.type.toLowerCase()} b) internal returns (${returnType}) {
368+
function ${
369+
operator.name
370+
}(${clearMatchingType.toLowerCase()} a, e${fheType.type.toLowerCase()} b) internal returns (${returnType}) {
341371
${maybeEncryptLeft}
342372
if (!isInitialized(b)) {
343373
b = asE${fheType.type.toLowerCase()}(${
@@ -379,7 +409,9 @@ function handleSolidityTFHEShiftOperator(fheType: AdjustedFheType, operator: Ope
379409

380410
const leftExpr = 'a';
381411
const rightExpr = castRightToLeft ? `asE${fheType.type.toLowerCase()}(b)` : 'b';
382-
let implExpression: string = `Impl.${operator.name}(e${fheType.type.toLowerCase()}.unwrap(${leftExpr}), e${fheType.type.toLowerCase()}.unwrap(${rightExpr})${scalarFlag})`;
412+
let implExpression: string = `Impl.${
413+
operator.name
414+
}(e${fheType.type.toLowerCase()}.unwrap(${leftExpr}), e${fheType.type.toLowerCase()}.unwrap(${rightExpr})${scalarFlag})`;
383415

384416
res.push(`
385417
/**
@@ -398,13 +430,17 @@ function handleSolidityTFHEShiftOperator(fheType: AdjustedFheType, operator: Ope
398430

399431
// Code and test for shift(euint{inputBits},uint8}
400432
scalarFlag = ', true';
401-
implExpression = `Impl.${operator.name}(e${fheType.type.toLowerCase()}.unwrap(a), bytes32(uint256(b))${scalarFlag})`;
433+
implExpression = `Impl.${
434+
operator.name
435+
}(e${fheType.type.toLowerCase()}.unwrap(a), bytes32(uint256(b))${scalarFlag})`;
402436

403437
res.push(`
404438
/**
405439
* @dev Evaluates ${operator.name}(e${fheType.type.toLowerCase()} a, ${getUint(rhsBits)}) and returns the result.
406440
*/
407-
function ${operator.name}(e${fheType.type.toLowerCase()} a, ${getUint(rhsBits)} b) internal returns (e${fheType.type.toLowerCase()}) {
441+
function ${operator.name}(e${fheType.type.toLowerCase()} a, ${getUint(
442+
rhsBits,
443+
)} b) internal returns (e${fheType.type.toLowerCase()}) {
408444
if (!isInitialized(a)) {
409445
a = asE${fheType.type.toLowerCase()}(0);
410446
}
@@ -466,7 +502,9 @@ function handleSolidityTFHECustomCastBetweenTwoEuint(
466502
*/
467503
function asE${outputFheType.type.toLowerCase()}(e${inputFheType.type.toLowerCase()} value) internal returns (e${outputFheType.type.toLowerCase()}) {
468504
${checkInitialized('value', inputFheType.type)}
469-
return e${outputFheType.type.toLowerCase()}.wrap(Impl.cast(e${inputFheType.type.toLowerCase()}.unwrap(value), FheType.${outputFheType.type}));
505+
return e${outputFheType.type.toLowerCase()}.wrap(Impl.cast(e${inputFheType.type.toLowerCase()}.unwrap(value), FheType.${
506+
outputFheType.type
507+
}));
470508
}
471509
`;
472510
}
@@ -543,7 +581,9 @@ function handleSolidityTFHEConvertPlaintextAndEinputToRespectiveType(fheType: Ad
543581
*/
544582
function fromExternal(externalE${fheType.type.toLowerCase()} inputHandle, bytes memory inputProof) internal returns (e${fheType.type.toLowerCase()}) {
545583
if (inputProof.length!=0) {
546-
return e${fheType.type.toLowerCase()}.wrap(Impl.verify(externalE${fheType.type.toLowerCase()}.unwrap(inputHandle), inputProof, FheType.${fheType.isAlias ? fheType.aliasType : fheType.type}));
584+
return e${fheType.type.toLowerCase()}.wrap(Impl.verify(externalE${fheType.type.toLowerCase()}.unwrap(inputHandle), inputProof, FheType.${
585+
fheType.isAlias ? fheType.aliasType : fheType.type
586+
}));
547587
} else {
548588
bytes32 inputBytes32 = externalE${fheType.type.toLowerCase()}.unwrap(inputHandle);
549589
if(inputBytes32 == 0){
@@ -583,8 +623,12 @@ function handleSolidityTFHEConvertPlaintextAndEinputToRespectiveType(fheType: Ad
583623
/**
584624
* @dev Convert a plaintext value to an encrypted e${fheType.type.toLowerCase()} value.
585625
*/
586-
function asE${fheType.type.toLowerCase()}(${fheType.clearMatchingType} value) internal returns (e${fheType.type.toLowerCase()}) {
587-
return e${fheType.type.toLowerCase()}.wrap(Impl.trivialEncrypt(uint256(${value}), FheType.${fheType.isAlias ? fheType.aliasType : fheType.type}));
626+
function asE${fheType.type.toLowerCase()}(${
627+
fheType.clearMatchingType
628+
} value) internal returns (e${fheType.type.toLowerCase()}) {
629+
return e${fheType.type.toLowerCase()}.wrap(Impl.trivialEncrypt(uint256(${value}), FheType.${
630+
fheType.isAlias ? fheType.aliasType : fheType.type
631+
}));
588632
}
589633
590634
`;
@@ -690,7 +734,9 @@ function handleSolidityTFHERand(fheType: AdjustedFheType): string {
690734
* @dev Generates a random encrypted value.
691735
*/
692736
function randE${fheType.type.toLowerCase()}() internal returns (e${fheType.type.toLowerCase()}) {
693-
return e${fheType.type.toLowerCase()}.wrap(Impl.rand(FheType.${fheType.isAlias ? fheType.aliasType : fheType.type}));
737+
return e${fheType.type.toLowerCase()}.wrap(Impl.rand(FheType.${
738+
fheType.isAlias ? fheType.aliasType : fheType.type
739+
}));
694740
}
695741
696742
`;
@@ -702,8 +748,12 @@ function handleSolidityTFHERand(fheType: AdjustedFheType): string {
702748
* @dev Generates a random encrypted ${fheType.bitLength}-bit unsigned integer in the [0, upperBound) range.
703749
* The upperBound must be a power of 2.
704750
*/
705-
function randE${fheType.type.toLowerCase()}(uint${fheType.bitLength} upperBound) internal returns (e${fheType.type.toLowerCase()}) {
706-
return e${fheType.type.toLowerCase()}.wrap(Impl.randBounded(upperBound, FheType.${fheType.isAlias ? fheType.aliasType : fheType.type}));
751+
function randE${fheType.type.toLowerCase()}(uint${
752+
fheType.bitLength
753+
} upperBound) internal returns (e${fheType.type.toLowerCase()}) {
754+
return e${fheType.type.toLowerCase()}.wrap(Impl.randBounded(upperBound, FheType.${
755+
fheType.isAlias ? fheType.aliasType : fheType.type
756+
}));
707757
}
708758
709759
`;

library-solidity/codegen/src/templates/FHE.sol-template

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ pragma solidity ^0.8.24;
77
//$$ -
88
//$$ -----------------------------------------------------------------------
99
import "$${ImplDotSol}$$";
10-
import "./cryptography/ECDSA.sol";
10+
import {FhevmECDSA} from "$${EcdsaDotSol}$$";
1111
import {FheType} from "$${FheTypeDotSol}$$";
1212
//$$ -----------------------------------------------------------------------
1313

@@ -439,7 +439,7 @@ library FHE {
439439
address[] memory recoveredSigners = new address[](numSignatures);
440440
uint256 uniqueValidCount;
441441
for (uint256 i = 0; i < numSignatures; i++) {
442-
address signerRecovered = ECDSA.recover(digest, signatures[i]);
442+
address signerRecovered = FhevmECDSA.recover(digest, signatures[i]);
443443
if (!_isSigner(signerRecovered, KMSSigners)) {
444444
revert KMSInvalidSigner(signerRecovered);
445445
}
@@ -478,7 +478,7 @@ library FHE {
478478
* @return signer The address that supposedly signed the message.
479479
*/
480480
function _recoverSigner(bytes32 message, bytes memory signature) private pure returns (address) {
481-
address signerRecovered = ECDSA.recover(message, signature);
481+
address signerRecovered = FhevmECDSA.recover(message, signature);
482482
return signerRecovered;
483483
}
484484

library-solidity/lib/cryptography/ECDSA.sol renamed to library-solidity/codegen/src/templates/FhevmECDSA.sol-template

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,11 @@ pragma solidity ^0.8.20;
88
*
99
* These functions can be used to verify that a message was signed by the holder
1010
* of the private keys of a given address.
11+
*
12+
* @dev This library is forked from OpenZeppelin's ECDSA and renamed to FhevmECDSA
13+
* to avoid naming conflicts with the original when both are used in the same project.
1114
*/
12-
library ECDSA {
15+
library FhevmECDSA {
1316
enum RecoverError {
1417
NoError,
1518
InvalidSignature,

library-solidity/lib/FHE.sol

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
pragma solidity ^0.8.24;
33

44
import "./Impl.sol";
5-
import "./cryptography/ECDSA.sol";
5+
import {FhevmECDSA} from "./cryptography/FhevmECDSA.sol";
66
import {FheType} from "./FheType.sol";
77

88
import "encrypted-types/EncryptedTypes.sol";
@@ -9646,7 +9646,7 @@ library FHE {
96469646
address[] memory recoveredSigners = new address[](numSignatures);
96479647
uint256 uniqueValidCount;
96489648
for (uint256 i = 0; i < numSignatures; i++) {
9649-
address signerRecovered = ECDSA.recover(digest, signatures[i]);
9649+
address signerRecovered = FhevmECDSA.recover(digest, signatures[i]);
96509650
if (!_isSigner(signerRecovered, KMSSigners)) {
96519651
revert KMSInvalidSigner(signerRecovered);
96529652
}
@@ -9685,7 +9685,7 @@ library FHE {
96859685
* @return signer The address that supposedly signed the message.
96869686
*/
96879687
function _recoverSigner(bytes32 message, bytes memory signature) private pure returns (address) {
9688-
address signerRecovered = ECDSA.recover(message, signature);
9688+
address signerRecovered = FhevmECDSA.recover(message, signature);
96899689
return signerRecovered;
96909690
}
96919691

0 commit comments

Comments
 (0)