Skip to content

Commit

Permalink
Merge pull request #209 from zama-ai/network1
Browse files Browse the repository at this point in the history
Add network1 development support
  • Loading branch information
david-zk authored Oct 24, 2023
2 parents 3133929 + bd58142 commit a9a84cb
Show file tree
Hide file tree
Showing 13 changed files with 108 additions and 82 deletions.
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,15 @@ Ensure the faucet command was succesful.
</details>
<br />

#### Run tests for network1 network

```bash
# codegen for network1 network
TARGET_NETWORK=Network1 npx ts-node codegen/main.ts && npm run prettier
# run tests for network1 network, assumes network1 rpc already running locally
npx hardhat test --network localNetwork1
```

### Adding new operators

Operators can be defined as data inside `codegen/common.ts` file and code automatically generates solidity overloads.
Expand Down
54 changes: 20 additions & 34 deletions codegen/common.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
import { strict as assert } from 'node:assert';

export enum Network {
Evmos,
Network1,
}

export type Operator = {
name: string;
// express left scalar operation as different operation with arguments swapped
Expand All @@ -18,9 +23,8 @@ export type Operator = {
unarySolidityOperator?: string;
};

export type Precompile = {
name: string;
code: number;
export type CodegenContext = {
libFheAddress: string;
};

export enum OperatorArguments {
Expand All @@ -35,37 +39,6 @@ export enum ReturnType {

export const SUPPORTED_BITS: number[] = [8, 16, 32];

export const ALL_PRECOMPILES: Precompile[] = [
{ name: 'Add', code: 65 },
{ name: 'Verify', code: 66 },
{ name: 'Reencrypt', code: 67 },
{ name: 'FhePubKey', code: 68 },
{ name: 'LessThanOrEqual', code: 70 },
{ name: 'Subtract', code: 71 },
{ name: 'Multiply', code: 72 },
{ name: 'LessThan', code: 73 },
{ name: 'Rand', code: 74 },
{ name: 'OptimisticRequire', code: 75 },
{ name: 'Cast', code: 76 },
{ name: 'TrivialEncrypt', code: 77 },
{ name: 'BitwiseAnd', code: 78 },
{ name: 'BitwiseOr', code: 79 },
{ name: 'BitwiseXor', code: 80 },
{ name: 'Equal', code: 81 },
{ name: 'GreaterThanOrEqual', code: 82 },
{ name: 'GreaterThan', code: 83 },
{ name: 'ShiftLeft', code: 84 },
{ name: 'ShiftRight', code: 85 },
{ name: 'NotEqual', code: 86 },
{ name: 'Min', code: 87 },
{ name: 'Max', code: 88 },
{ name: 'Negate', code: 89 },
{ name: 'Not', code: 90 },
{ name: 'Decrypt', code: 91 },
{ name: 'Divide', code: 92 },
{ name: 'Rem', code: 94 },
];

export const ALL_OPERATORS: Operator[] = [
{
name: 'add',
Expand Down Expand Up @@ -263,3 +236,16 @@ export function checks(operators: Operator[]): Operator[] {

return operators;
}

export function networkCodegenContext(network: Network): CodegenContext {
switch (network) {
case Network.Evmos:
return {
libFheAddress: '0x000000000000000000000000000000000000005d',
};
case Network.Network1:
return {
libFheAddress: '0x010000000000000000000000000000000000005D',
};
}
}
14 changes: 11 additions & 3 deletions codegen/main.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,29 @@
import { mkdirSync, writeFileSync } from 'fs';

import { ALL_OPERATORS, ALL_PRECOMPILES, SUPPORTED_BITS, checks } from './common';
import { ALL_OPERATORS, Network, SUPPORTED_BITS, checks, networkCodegenContext } from './common';
import * as t from './templates';
import * as testgen from './testgen';

function generateAllFiles() {
const operators = checks(ALL_OPERATORS);

const [tfheSolSource, overloads] = t.tfheSol(operators, SUPPORTED_BITS);
const network = Network[(process.env.TARGET_NETWORK as keyof typeof Network) || 'Evmos'];
const context = networkCodegenContext(network);
const [tfheSolSource, overloads] = t.tfheSol(context, operators, SUPPORTED_BITS);
const ovShards = testgen.splitOverloadsToShards(overloads);
writeFileSync('lib/Impl.sol', t.implSol(operators));
writeFileSync('lib/Impl.sol', t.implSol(context, operators));
writeFileSync('lib/TFHE.sol', tfheSolSource);
mkdirSync('examples/tests', { recursive: true });
ovShards.forEach((os) => {
writeFileSync(`examples/tests/TFHETestSuite${os.shardNumber}.sol`, testgen.generateSmartContract(os));
});
writeFileSync('test/tfheOperations/tfheOperations.ts', testgen.generateTestCode(ovShards));
writeFileSync(
'test/generated.ts',
`
export const FHE_LIB_ADDRESS = '${context.libFheAddress}';
`,
);
}

generateAllFiles();
40 changes: 12 additions & 28 deletions codegen/templates.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { assert } from 'console';

import { Operator, OperatorArguments, Precompile, ReturnType } from './common';
import { CodegenContext, Operator, OperatorArguments, ReturnType } from './common';
import { ArgumentType, OverloadSignature } from './testgen';

export function commonSolLib(): string {
Expand Down Expand Up @@ -42,7 +42,7 @@ function binaryOperatorImpl(op: Operator, isScalar: boolean, isEncrypted: boolea
);
}

export function implSol(operators: Operator[]): string {
export function implSol(ctx: CodegenContext, operators: Operator[]): string {
const res: string[] = [];

const fheLibInterface = generateImplFhevmLibInterface(operators);
Expand All @@ -54,7 +54,7 @@ pragma solidity 0.8.19;
${fheLibInterface}
address constant EXT_TFHE_LIBRARY = address(93);
address constant EXT_TFHE_LIBRARY = address(${ctx.libFheAddress});
library Impl {
// 32 bytes for the 'byte' type header + 48 bytes for the NaCl anonymous
Expand All @@ -77,7 +77,7 @@ library Impl {
}
});

res.push(implCustomMethods());
res.push(implCustomMethods(ctx));

res.push('}\n');

Expand Down Expand Up @@ -136,7 +136,11 @@ function fheLibCustomInterfaceFunctions(): string {
`;
}

export function tfheSol(operators: Operator[], supportedBits: number[]): [string, OverloadSignature[]] {
export function tfheSol(
ctx: CodegenContext,
operators: Operator[],
supportedBits: number[],
): [string, OverloadSignature[]] {
const signatures: OverloadSignature[] = [];
const res: string[] = [];

Expand Down Expand Up @@ -182,7 +186,7 @@ library TFHE {
supportedBits.forEach((bits) => res.push(tfheUnaryOperators(bits, operators, signatures)));
supportedBits.forEach((bits) => res.push(tfheCustomUnaryOperators(bits, signatures)));

res.push(tfheCustomMethods());
res.push(tfheCustomMethods(ctx));

res.push('}\n');

Expand Down Expand Up @@ -523,26 +527,6 @@ function tfheCustomUnaryOperators(bits: number, signatures: OverloadSignature[])
`;
}

export function precompiles(precompiles: Precompile[]): string {
const res: string[] = [];

res.push(`// SPDX-License-Identifier: BSD-3-Clause-Clear
pragma solidity 0.8.19;
library Precompiles {
`);

precompiles.forEach((op) => {
res.push(` uint256 public constant ${op.name} = ${op.code};
`);
});

res.push('}\n');

return res.join('');
}

function unaryOperatorImpl(op: Operator): string {
let fname = operatorFheLibFunction(op);
return `
Expand All @@ -552,7 +536,7 @@ function unaryOperatorImpl(op: Operator): string {
`;
}

function tfheCustomMethods(): string {
function tfheCustomMethods(ctx: CodegenContext): string {
return `
// Optimistically require that 'b' is true.
//
Expand Down Expand Up @@ -625,7 +609,7 @@ function tfheCustomMethods(): string {
`;
}

function implCustomMethods(): string {
function implCustomMethods(ctx: CodegenContext): string {
return `
// If 'control's value is 'true', the result has the same value as 'ifTrue'.
// If 'control's value is 'false', the result has the same value as 'ifFalse'.
Expand Down
18 changes: 14 additions & 4 deletions docs/client/examples.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,14 @@ const getInstance = async () => {
const chainId = +network.chainId.toString(); // Need to be a number

// Get blockchain public key
const publicKey = await provider.call({
to: "0x0000000000000000000000000000000000000044",
const ret = await provider.call({
// fhe lib address, may need to be changed depending on network
to: "0x000000000000000000000000000000000000005d",
// first four bytes of keccak256('fhePubKey(bytes1)') + 1 byte for library
data: "0xd9d47bb001",
});
const decoded = ethers.AbiCoder.defaultAbiCoder().decode(["bytes"], ret);
const publicKey = decoded[0];

// Create instance
_instance = createInstance({ chainId, publicKey });
Expand Down Expand Up @@ -74,9 +79,14 @@ const getInstance = async () => {
const chainId = +network.chainId.toString();

// Get blockchain public key
const publicKey = await provider.call({
to: "0x0000000000000000000000000000000000000044",
const ret = await provider.call({
// fhe lib address, may need to be changed depending on network
to: "0x000000000000000000000000000000000000005d",
// first four bytes of keccak256('fhePubKey(bytes1)') + 1 byte for library
data: "0xd9d47bb001",
});
const decoded = ethers.AbiCoder.defaultAbiCoder().decode(["bytes"], ret);
const publicKey = decoded[0];

// Create instance
_instance = createInstance({ chainId, publicKey });
Expand Down
9 changes: 7 additions & 2 deletions docs/client/examples/getbalance.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,14 @@ const getInstance = async () => {
const chainId = +network.chainId.toString();

// Get blockchain public key
const publicKey = await provider.call({
to: "0x0000000000000000000000000000000000000044",
const ret = await provider.call({
// fhe lib address, may need to be changed depending on network
to: "0x000000000000000000000000000000000000005d",
// first four bytes of keccak256('fhePubKey(bytes1)') + 1 byte for library
data: "0xd9d47bb001",
});
const decoded = ethers.AbiCoder.defaultAbiCoder().decode(["bytes"], ret);
const publicKey = decoded[0];

// Create instance
_instance = createInstance({ chainId, publicKey });
Expand Down
9 changes: 7 additions & 2 deletions docs/client/examples/transfererc20.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,14 @@ const getInstance = async () => {
const chainId = +network.chainId.toString(); // Need to be a number

// Get blockchain public key
const publicKey = await provider.call({
to: "0x0000000000000000000000000000000000000044",
const ret = await provider.call({
// fhe lib address, may need to be changed depending on network
to: "0x000000000000000000000000000000000000005d",
// first four bytes of keccak256('fhePubKey(bytes1)') + 1 byte for library
data: "0xd9d47bb001",
});
const decoded = ethers.AbiCoder.defaultAbiCoder().decode(["bytes"], ret);
const publicKey = decoded[0];

// Create instance
_instance = createInstance({ chainId, publicKey });
Expand Down
10 changes: 7 additions & 3 deletions docs/client/getting_started/browser.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,14 @@ const createFhevmInstance = async () => {
const provider = new BrowserProvider(window.ethereum);
const network = await provider.getNetwork();
const chainId = +network.chainId.toString();
const publicKey = await provider.call({
from: null,
to: "0x0000000000000000000000000000000000000044",
const ret = await provider.call({
// fhe lib address, may need to be changed depending on network
to: "0x000000000000000000000000000000000000005d",
// first four bytes of keccak256('fhePubKey(bytes1)') + 1 byte for library
data: "0xd9d47bb001",
});
const decoded = ethers.AbiCoder.defaultAbiCoder().decode(["bytes"], ret);
const publicKey = decoded[0];
return createInstance({ chainId, publicKey });
};

Expand Down
10 changes: 7 additions & 3 deletions docs/client/instance.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,14 @@ const initInstance = async () => {
const chainId = parseInt(chainIdHex, 16);

// Get blockchain public key
const publicKey = await window.ethereum.request({
method: "eth_call",
params: [{ from: null, to: "0x0000000000000000000000000000000000000044" }],
const ret = await provider.call({
// fhe lib address, may need to be changed depending on network
to: "0x000000000000000000000000000000000000005d",
// first four bytes of keccak256('fhePubKey(bytes1)') + 1 byte for library
data: "0xd9d47bb001",
});
const decoded = ethers.AbiCoder.defaultAbiCoder().decode(["bytes"], ret);
const publicKey = decoded[0];

// Create instance
return createInstance({ chainId, publicKey, keypairs });
Expand Down
5 changes: 5 additions & 0 deletions hardhat.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ if (!mnemonic) {
const chainIds = {
zama: 8009,
local: 9000,
localNetwork1: 9000,
};

function getChainConfig(chain: keyof typeof chainIds): NetworkUserConfig {
Expand All @@ -30,6 +31,9 @@ function getChainConfig(chain: keyof typeof chainIds): NetworkUserConfig {
case 'local':
jsonRpcUrl = 'http://localhost:8545';
break;
case 'localNetwork1':
jsonRpcUrl = 'http://127.0.0.1:9650/ext/bc/fhevm/rpc';
break;
case 'zama':
jsonRpcUrl = 'https://devnet.zama.ai';
break;
Expand Down Expand Up @@ -63,6 +67,7 @@ const config: HardhatUserConfig = {
zama: getChainConfig('zama'),
localDev: getChainConfig('local'),
local: getChainConfig('local'),
localNetwork1: getChainConfig('localNetwork1'),
},
paths: {
artifacts: './artifacts',
Expand Down
2 changes: 1 addition & 1 deletion lib/Impl.sol
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ interface FhevmLib {
function fheRand(bytes1 inp) external view returns (uint256 result);
}

address constant EXT_TFHE_LIBRARY = address(93);
address constant EXT_TFHE_LIBRARY = address(0x000000000000000000000000000000000000005d);

library Impl {
// 32 bytes for the 'byte' type header + 48 bytes for the NaCl anonymous
Expand Down
1 change: 1 addition & 0 deletions test/generated.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const FHE_LIB_ADDRESS = '0x000000000000000000000000000000000000005d';
9 changes: 7 additions & 2 deletions test/instance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Signer } from 'ethers';
import fhevmjs, { FhevmInstance } from 'fhevmjs';
import { ethers as hethers } from 'hardhat';

import { FHE_LIB_ADDRESS } from './generated';
import type { Signers } from './signers';
import { FhevmInstances } from './types';

Expand All @@ -21,9 +22,13 @@ export const createInstances = async (
chainId = +network.chainId.toString(); // Need to be a number

// Get blockchain public key
publicKey = await provider.call({
to: '0x0000000000000000000000000000000000000044',
const ret = await provider.call({
to: FHE_LIB_ADDRESS,
// first four bytes of keccak256('fhePubKey(bytes1)') + 1 byte for library
data: '0xd9d47bb001',
});
const decoded = ethers.AbiCoder.defaultAbiCoder().decode(['bytes'], ret);
publicKey = decoded[0];
}

// Create instance
Expand Down

0 comments on commit a9a84cb

Please sign in to comment.