Skip to content

refactor: euint256 and code generation #414

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 1, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
384 changes: 122 additions & 262 deletions contracts/codegen/common.ts

Large diffs are not rendered by default.

335 changes: 217 additions & 118 deletions contracts/codegen/generateOverloads.ts

Large diffs are not rendered by default.

64 changes: 49 additions & 15 deletions contracts/codegen/main.ts
Original file line number Diff line number Diff line change
@@ -1,27 +1,61 @@
import { mkdirSync, writeFileSync } from 'fs';
import path from 'path';

import { ALL_OPERATORS, SUPPORTED_BITS, checks } from './common';
import { validateFHETypes, validateOperators } from './common';
import { generateOverloads } from './generateOverloads';
import { ALL_OPERATORS } from './operators';
import operatorsPrices from './operatorsPrices.json';
import { generateFHEGasLimit } from './payments';
import * as t from './templates';
import * as testgen from './testgen';
import { generateSolidityFHEGasLimit } from './payments';
import { generateSolidityFheType, generateSolidityImplLib, generateSolidityTFHELib } from './templates';
import {
generateSolidityOverloadTestFiles,
generateSolidityUnitTestContracts,
generateTypeScriptTestCode,
splitOverloadsToShards,
} from './testgen';
import { ALL_FHE_TYPES } from './types';

/**
* Generates all necessary files including Solidity contracts and TypeScript test files.
*
* This function performs the following steps:
* 1. Generates FHE types from a JSON file.
* 2. Validates and processes the list of operators.
* 3. Generates Solidity source code for TFHE and implementation contracts.
* 4. Splits the generated overloads into multiple shards to avoid exceeding Solidity's contract size limit.
* 5. Writes the generated Solidity contracts and test files to the appropriate directories.
* 6. Generates TypeScript test code for the split overloads and writes them to the test directory.
*
*/
function generateAllFiles() {
const numberOfTestSplits = 12;
if (!ALL_OPERATORS || !Array.isArray(ALL_OPERATORS) || ALL_OPERATORS.length === 0) {
throw new Error('ALL_OPERATORS is not defined or invalid');
}
const operators = checks(ALL_OPERATORS);
const [tfheSolSource, overloads] = t.tfheSol(operators, SUPPORTED_BITS, false);
const overloadShards = testgen.splitOverloadsToShards(overloads);
writeFileSync('lib/Impl.sol', t.implSol(operators));
writeFileSync('lib/TFHE.sol', tfheSolSource);
writeFileSync('contracts/FHEGasLimit.sol', generateFHEGasLimit(operatorsPrices));

// Validate the FHE types
validateFHETypes(ALL_FHE_TYPES);
// Validate the operators
validateOperators(ALL_OPERATORS);

/// Generate core Solidity contract files.
writeFileSync('contracts/FheType.sol', generateSolidityFheType(ALL_FHE_TYPES));
writeFileSync('lib/Impl.sol', generateSolidityImplLib(ALL_OPERATORS));
writeFileSync('lib/TFHE.sol', generateSolidityTFHELib(ALL_OPERATORS, ALL_FHE_TYPES));
writeFileSync('contracts/FHEGasLimit.sol', generateSolidityFHEGasLimit(operatorsPrices));

// TODO: For now, the testgen only supports automatically generated tests for euintXX.
/// Generate overloads, split them into shards, and generate Solidity contracts to be used for TypeScript unit test files.
writeFileSync(
`${path.resolve(__dirname)}/overloads.json`,
JSON.stringify(generateOverloads(ALL_FHE_TYPES), (_key, value) =>
typeof value === 'bigint' ? value.toString() : value,
),
);
const overloadShards = splitOverloadsToShards(generateSolidityOverloadTestFiles(ALL_OPERATORS, ALL_FHE_TYPES));
mkdirSync('contracts/tests', { recursive: true });
overloadShards.forEach((os) => {
writeFileSync(`examples/tests/TFHETestSuite${os.shardNumber}.sol`, testgen.generateSmartContract(os));
writeFileSync(`examples/tests/TFHETestSuite${os.shardNumber}.sol`, generateSolidityUnitTestContracts(os));
});
const tsSplits: string[] = testgen.generateTestCode(overloadShards, numberOfTestSplits);

const tsSplits: string[] = generateTypeScriptTestCode(overloadShards, numberOfTestSplits);
tsSplits.forEach((split, splitIdx) => writeFileSync(`test/tfheOperations/tfheOperations${splitIdx + 1}.ts`, split));
}

Expand Down
211 changes: 211 additions & 0 deletions contracts/codegen/operators.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,211 @@
import { Operator, OperatorArguments, ReturnType } from './common';

/**
* A list of all supported operators with their respective properties.
*
* Each operator object contains the following properties:
* - `name`: The name of the operator.
* - `hasScalar`: A boolean indicating if the operator supports scalar values.
* - `hasEncrypted`: A boolean indicating if the operator supports encrypted values.
* - `arguments`: The type of arguments the operator accepts (binary or unary).
* - `returnType`: The return type of the operator.
* - `fheLibName`: The corresponding function name in the FHE library.
* - `leftScalarEncrypt` (optional): A boolean indicating if the left scalar should be encrypted.
* - `leftScalarDisable` (optional): A boolean indicating if the left scalar is disabled.
* - `shiftOperator` (optional): A boolean indicating if the operator is a shift operator.
* - `rotateOperator` (optional): A boolean indicating if the operator is a rotate operator.
* - `leftScalarInvertOp` (optional): The name of the inverted operator for the left scalar.
*/
export const ALL_OPERATORS: Operator[] = [
{
name: 'add',
hasScalar: true,
hasEncrypted: true,
arguments: OperatorArguments.Binary,
returnType: ReturnType.Euint,
fheLibName: 'fheAdd',
},
{
name: 'sub',
hasScalar: true,
hasEncrypted: true,
arguments: OperatorArguments.Binary,
returnType: ReturnType.Euint,
leftScalarEncrypt: true,
fheLibName: 'fheSub',
},
{
name: 'mul',
hasScalar: true,
hasEncrypted: true,
arguments: OperatorArguments.Binary,
returnType: ReturnType.Euint,
fheLibName: 'fheMul',
},
{
name: 'div',
hasScalar: true,
hasEncrypted: false,
arguments: OperatorArguments.Binary,
returnType: ReturnType.Euint,
leftScalarDisable: true,
fheLibName: 'fheDiv',
},
{
name: 'rem',
hasScalar: true,
hasEncrypted: false,
arguments: OperatorArguments.Binary,
returnType: ReturnType.Euint,
leftScalarDisable: true,
fheLibName: 'fheRem',
},
{
name: 'and',
hasScalar: true,
hasEncrypted: true,
arguments: OperatorArguments.Binary,
returnType: ReturnType.Euint,
fheLibName: 'fheBitAnd',
},
{
name: 'or',
hasScalar: true,
hasEncrypted: true,
arguments: OperatorArguments.Binary,
returnType: ReturnType.Euint,
fheLibName: 'fheBitOr',
},
{
name: 'xor',
hasScalar: true,
hasEncrypted: true,
arguments: OperatorArguments.Binary,
returnType: ReturnType.Euint,
fheLibName: 'fheBitXor',
},
{
name: 'shl',
hasScalar: true,
hasEncrypted: true,
arguments: OperatorArguments.Binary,
returnType: ReturnType.Euint,
leftScalarEncrypt: true,
shiftOperator: true,
fheLibName: 'fheShl',
},
{
name: 'shr',
hasScalar: true,
hasEncrypted: true,
arguments: OperatorArguments.Binary,
returnType: ReturnType.Euint,
leftScalarEncrypt: true,
shiftOperator: true,
fheLibName: 'fheShr',
},
{
name: 'rotl',
hasScalar: true,
hasEncrypted: true,
arguments: OperatorArguments.Binary,
returnType: ReturnType.Euint,
leftScalarEncrypt: true,
rotateOperator: true,
fheLibName: 'fheRotl',
},
{
name: 'rotr',
hasScalar: true,
hasEncrypted: true,
arguments: OperatorArguments.Binary,
returnType: ReturnType.Euint,
leftScalarEncrypt: true,
rotateOperator: true,
fheLibName: 'fheRotr',
},
{
name: 'eq',
hasScalar: true,
hasEncrypted: true,
arguments: OperatorArguments.Binary,
returnType: ReturnType.Ebool,
fheLibName: 'fheEq',
},
{
name: 'ne',
hasScalar: true,
hasEncrypted: true,
arguments: OperatorArguments.Binary,
returnType: ReturnType.Ebool,
fheLibName: 'fheNe',
},
{
name: 'ge',
leftScalarInvertOp: 'le',
hasScalar: true,
hasEncrypted: true,
arguments: OperatorArguments.Binary,
returnType: ReturnType.Ebool,
fheLibName: 'fheGe',
},
{
name: 'gt',
leftScalarInvertOp: 'lt',
hasScalar: true,
hasEncrypted: true,
arguments: OperatorArguments.Binary,
returnType: ReturnType.Ebool,
fheLibName: 'fheGt',
},
{
name: 'le',
leftScalarInvertOp: 'ge',
hasScalar: true,
hasEncrypted: true,
arguments: OperatorArguments.Binary,
returnType: ReturnType.Ebool,
fheLibName: 'fheLe',
},
{
name: 'lt',
leftScalarInvertOp: 'gt',
hasScalar: true,
hasEncrypted: true,
arguments: OperatorArguments.Binary,
returnType: ReturnType.Ebool,
fheLibName: 'fheLt',
},
{
name: 'min',
hasScalar: true,
hasEncrypted: true,
arguments: OperatorArguments.Binary,
returnType: ReturnType.Euint,
fheLibName: 'fheMin',
},
{
name: 'max',
hasScalar: true,
hasEncrypted: true,
arguments: OperatorArguments.Binary,
returnType: ReturnType.Euint,
fheLibName: 'fheMax',
},
{
name: 'neg',
hasScalar: true,
hasEncrypted: true,
arguments: OperatorArguments.Unary,
returnType: ReturnType.Euint,
fheLibName: 'fheNeg',
},
{
name: 'not',
hasScalar: true,
hasEncrypted: true,
arguments: OperatorArguments.Unary,
returnType: ReturnType.Euint,
fheLibName: 'fheNot',
},
];
Loading