diff --git a/.circleci/config.yml b/.circleci/config.yml index 0668ebed7cb3..f5364df51cd8 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -232,6 +232,17 @@ jobs: name: "Build and test" command: build noir-contracts + noir-compiler: + machine: + image: ubuntu-2004:202010-01 + resource_class: large + steps: + - *checkout + - *setup_env + - run: + name: "Build and test" + command: build noir-compiler + world-state: machine: image: ubuntu-2004:202010-01 @@ -456,6 +467,7 @@ workflows: - merkle-tree: *yarn_project - p2p: *yarn_project - noir-contracts: *yarn_project + - noir-compiler: *yarn_project - sequencer-client: *yarn_project - types: *yarn_project - circuits-js: *yarn_project diff --git a/build_manifest.json b/build_manifest.json index 6be44f24a6ad..be29f4378819 100644 --- a/build_manifest.json +++ b/build_manifest.json @@ -168,6 +168,17 @@ "rebuildPatterns": ["^yarn-project/noir-contracts/"], "dependencies": ["foundation"] }, + "noir-compiler": { + "buildDir": "yarn-project", + "projectDir": "yarn-project/noir-compiler", + "dockerfile": "noir-compiler/Dockerfile", + "rebuildPatterns": [ + "^yarn-project/noir-compiler/" + ], + "dependencies": [ + "foundation" + ] + }, "p2p": { "buildDir": "yarn-project", "projectDir": "yarn-project/p2p", diff --git a/yarn-project/acir-simulator/src/abi_coder/decoder.ts b/yarn-project/acir-simulator/src/abi_coder/decoder.ts index c3cf56fd411c..9571f63a5aee 100644 --- a/yarn-project/acir-simulator/src/abi_coder/decoder.ts +++ b/yarn-project/acir-simulator/src/abi_coder/decoder.ts @@ -1,5 +1,5 @@ import { Fr } from '@aztec/foundation/fields'; -import { ABIType, FunctionAbi } from '@aztec/noir-contracts'; +import { ABIType, FunctionAbi } from '@aztec/foundation/abi'; /** * Decodes return values from a function call. diff --git a/yarn-project/acir-simulator/src/abi_coder/encoder.ts b/yarn-project/acir-simulator/src/abi_coder/encoder.ts index be186e6e5aa4..3d38a06de68b 100644 --- a/yarn-project/acir-simulator/src/abi_coder/encoder.ts +++ b/yarn-project/acir-simulator/src/abi_coder/encoder.ts @@ -1,7 +1,6 @@ import { ARGS_LENGTH } from '@aztec/circuits.js'; import { Fr } from '@aztec/foundation/fields'; - -import { ABIType, FunctionAbi } from '@aztec/noir-contracts'; +import { ABIType, FunctionAbi } from '@aztec/foundation/abi'; /** * Encodes arguments for a function call. diff --git a/yarn-project/acir-simulator/src/abi_coder/index.ts b/yarn-project/acir-simulator/src/abi_coder/index.ts index da27e3f130e0..560eec125edf 100644 --- a/yarn-project/acir-simulator/src/abi_coder/index.ts +++ b/yarn-project/acir-simulator/src/abi_coder/index.ts @@ -1,8 +1,13 @@ -import { ABIType } from '@aztec/noir-contracts'; +import { ABIType } from '@aztec/foundation/abi'; export * from './encoder.js'; export * from './decoder.js'; +/** + * Get the size of an ABI type in field elements. + * @param type - The ABI type. + * @returns The size of the type in field elements. + */ export function sizeOfType(type: ABIType): number { switch (type.kind) { case 'field': diff --git a/yarn-project/acir-simulator/src/client/db_oracle.ts b/yarn-project/acir-simulator/src/client/db_oracle.ts index 14b895638d04..f245134c91ef 100644 --- a/yarn-project/acir-simulator/src/client/db_oracle.ts +++ b/yarn-project/acir-simulator/src/client/db_oracle.ts @@ -1,7 +1,7 @@ import { AztecAddress } from '@aztec/foundation/aztec-address'; import { EthAddress } from '@aztec/foundation/eth-address'; import { Fr } from '@aztec/foundation/fields'; -import { FunctionAbi } from '@aztec/noir-contracts'; +import { FunctionAbi } from '@aztec/foundation/abi'; /** * The format that noir contracts use to get notes. diff --git a/yarn-project/acir-simulator/src/client/private_execution.ts b/yarn-project/acir-simulator/src/client/private_execution.ts index a8834319aba0..91d2f077229f 100644 --- a/yarn-project/acir-simulator/src/client/private_execution.ts +++ b/yarn-project/acir-simulator/src/client/private_execution.ts @@ -9,7 +9,7 @@ import { } from '../acvm/index.js'; import { CallContext, PrivateCallStackItem, FunctionData } from '@aztec/circuits.js'; import { extractPublicInputs, frToAztecAddress, frToSelector } from '../acvm/deserialize.js'; -import { FunctionAbi } from '@aztec/noir-contracts'; +import { FunctionAbi } from '@aztec/foundation/abi'; import { createDebugLogger } from '@aztec/foundation/log'; import { decodeReturnValues } from '../abi_coder/decoder.js'; import { ClientTxExecutionContext } from './client_execution_context.js'; diff --git a/yarn-project/acir-simulator/src/client/simulator.ts b/yarn-project/acir-simulator/src/client/simulator.ts index ec22e478e1cb..6277a945d641 100644 --- a/yarn-project/acir-simulator/src/client/simulator.ts +++ b/yarn-project/acir-simulator/src/client/simulator.ts @@ -1,5 +1,5 @@ import { CallContext, PrivateHistoricTreeRoots, TxRequest } from '@aztec/circuits.js'; -import { FunctionAbi, FunctionType } from '@aztec/noir-contracts'; +import { FunctionAbi, FunctionType } from '@aztec/foundation/abi'; import { DBOracle } from './db_oracle.js'; import { PrivateFunctionExecution, ExecutionResult } from './private_execution.js'; import { BarretenbergWasm } from '@aztec/barretenberg.js/wasm'; diff --git a/yarn-project/acir-simulator/src/client/unconstrained_execution.ts b/yarn-project/acir-simulator/src/client/unconstrained_execution.ts index 5ad5c60caa75..33439e5ebb44 100644 --- a/yarn-project/acir-simulator/src/client/unconstrained_execution.ts +++ b/yarn-project/acir-simulator/src/client/unconstrained_execution.ts @@ -1,7 +1,7 @@ import { ACVMField, acvm, fromACVMField, toACVMField, toACVMWitness } from '../acvm/index.js'; import { CallContext, FunctionData } from '@aztec/circuits.js'; import { frToAztecAddress, frToNumber } from '../acvm/deserialize.js'; -import { FunctionAbi } from '@aztec/noir-contracts'; +import { FunctionAbi } from '@aztec/foundation/abi'; import { createDebugLogger } from '@aztec/foundation/log'; import { decodeReturnValues } from '../abi_coder/decoder.js'; import { ClientTxExecutionContext } from './client_execution_context.js'; diff --git a/yarn-project/acir-simulator/src/public/index.test.ts b/yarn-project/acir-simulator/src/public/index.test.ts index 0539d23d0a93..c71bfdb500b2 100644 --- a/yarn-project/acir-simulator/src/public/index.test.ts +++ b/yarn-project/acir-simulator/src/public/index.test.ts @@ -4,7 +4,7 @@ import { CallContext, FunctionData } from '@aztec/circuits.js'; import { AztecAddress } from '@aztec/foundation/aztec-address'; import { EthAddress } from '@aztec/foundation/eth-address'; import { Fr } from '@aztec/foundation/fields'; -import { FunctionAbi } from '@aztec/noir-contracts'; +import { FunctionAbi } from '@aztec/foundation/abi'; import { ChildAbi, ParentAbi, PublicTokenContractAbi } from '@aztec/noir-contracts/examples'; import { MockProxy, mock } from 'jest-mock-extended'; import { default as memdown, type MemDown } from 'memdown'; diff --git a/yarn-project/aztec-rpc/src/abi_coder/index.ts b/yarn-project/aztec-rpc/src/abi_coder/index.ts index 0b836f877f0e..910603db3b13 100644 --- a/yarn-project/aztec-rpc/src/abi_coder/index.ts +++ b/yarn-project/aztec-rpc/src/abi_coder/index.ts @@ -1,5 +1,5 @@ import { keccak } from '@aztec/foundation/crypto'; -import { ABIParameter } from '@aztec/noir-contracts'; +import { ABIParameter } from '@aztec/foundation/abi'; /** * Generate a function signature string for a given function name and parameters. diff --git a/yarn-project/aztec-rpc/src/account_state/account_state.ts b/yarn-project/aztec-rpc/src/account_state/account_state.ts index 44af2cfcc40b..59b48c0a7f6c 100644 --- a/yarn-project/aztec-rpc/src/account_state/account_state.ts +++ b/yarn-project/aztec-rpc/src/account_state/account_state.ts @@ -7,7 +7,7 @@ import { AztecAddress } from '@aztec/foundation/aztec-address'; import { Fr, Point } from '@aztec/foundation/fields'; import { createDebugLogger } from '@aztec/foundation/log'; import { ConstantKeyPair, KeyPair } from '@aztec/key-store'; -import { FunctionType } from '@aztec/noir-contracts'; +import { FunctionType } from '@aztec/foundation/abi'; import { EncodedContractFunction, INITIAL_L2_BLOCK_NUM, diff --git a/yarn-project/aztec-rpc/src/aztec_rpc_client/aztec_rpc_client.ts b/yarn-project/aztec-rpc/src/aztec_rpc_client/aztec_rpc_client.ts index b2d8e5b7be3b..aac7b508e32a 100644 --- a/yarn-project/aztec-rpc/src/aztec_rpc_client/aztec_rpc_client.ts +++ b/yarn-project/aztec-rpc/src/aztec_rpc_client/aztec_rpc_client.ts @@ -1,6 +1,6 @@ import { AztecAddress, EthAddress, Fr, TxRequest, EcdsaSignature } from '@aztec/circuits.js'; import { Tx, TxHash } from '@aztec/types'; -import { ContractAbi } from '@aztec/noir-contracts'; +import { ContractAbi } from '@aztec/foundation/abi'; import { TxReceipt } from '../tx/index.js'; import { Point } from '@aztec/foundation/fields'; diff --git a/yarn-project/aztec-rpc/src/aztec_rpc_server/aztec_rpc_server.ts b/yarn-project/aztec-rpc/src/aztec_rpc_server/aztec_rpc_server.ts index 1a757313e8d8..18c3ee05dc1e 100644 --- a/yarn-project/aztec-rpc/src/aztec_rpc_server/aztec_rpc_server.ts +++ b/yarn-project/aztec-rpc/src/aztec_rpc_server/aztec_rpc_server.ts @@ -13,7 +13,7 @@ import { import { Fr, Point } from '@aztec/foundation/fields'; import { createDebugLogger } from '@aztec/foundation/log'; import { KeyStore } from '@aztec/key-store'; -import { ContractAbi, FunctionType } from '@aztec/noir-contracts'; +import { ContractAbi, FunctionType } from '@aztec/foundation/abi'; import { Tx, TxHash } from '@aztec/types'; import { AztecRPCClient, DeployedContract } from '../aztec_rpc_client/index.js'; import { toContractDao } from '../contract_database/index.js'; diff --git a/yarn-project/aztec-rpc/src/contract_database/contract_dao.ts b/yarn-project/aztec-rpc/src/contract_database/contract_dao.ts index 6955e199acbb..907bbe1fbd09 100644 --- a/yarn-project/aztec-rpc/src/contract_database/contract_dao.ts +++ b/yarn-project/aztec-rpc/src/contract_database/contract_dao.ts @@ -1,5 +1,5 @@ -import { ContractAbi, FunctionAbi } from '@aztec/noir-contracts'; import { generateFunctionSelector } from '../abi_coder/index.js'; +import { ContractAbi, FunctionAbi } from '@aztec/foundation/abi'; import { AztecAddress } from '@aztec/foundation/aztec-address'; import { EthAddress } from '@aztec/foundation/eth-address'; diff --git a/yarn-project/aztec-rpc/src/contract_tree/contract_tree.ts b/yarn-project/aztec-rpc/src/contract_tree/contract_tree.ts index e1d816007ff9..6279595827c5 100644 --- a/yarn-project/aztec-rpc/src/contract_tree/contract_tree.ts +++ b/yarn-project/aztec-rpc/src/contract_tree/contract_tree.ts @@ -17,10 +17,10 @@ import { hashVK, } from '@aztec/circuits.js/abis'; import { CircuitsWasm } from '@aztec/circuits.js/wasm'; -import { ContractAbi, FunctionType } from '@aztec/noir-contracts'; import { generateFunctionSelector } from '../abi_coder/index.js'; import { ContractDao, ContractFunctionDao } from '../contract_database/index.js'; import { computeFunctionTreeData } from './function_tree_data.js'; +import { ContractAbi, FunctionType } from '@aztec/foundation/abi'; import { Fr } from '@aztec/foundation/fields'; import { keccak } from '@aztec/foundation/crypto'; import { EthAddress } from '@aztec/foundation/eth-address'; diff --git a/yarn-project/aztec-rpc/src/simulator_oracle/index.ts b/yarn-project/aztec-rpc/src/simulator_oracle/index.ts index 19df22f5b316..796f9c56c1eb 100644 --- a/yarn-project/aztec-rpc/src/simulator_oracle/index.ts +++ b/yarn-project/aztec-rpc/src/simulator_oracle/index.ts @@ -2,7 +2,7 @@ import { DBOracle } from '@aztec/acir-simulator'; import { AztecNode } from '@aztec/aztec-node'; import { AztecAddress, EthAddress, Fr } from '@aztec/circuits.js'; import { KeyPair } from '@aztec/key-store'; -import { FunctionAbi } from '@aztec/noir-contracts'; +import { FunctionAbi } from '@aztec/foundation/abi'; import { ContractDataOracle } from '../contract_data_oracle/index.js'; import { Database } from '../database/index.js'; diff --git a/yarn-project/aztec.js/src/contract/checker.ts b/yarn-project/aztec.js/src/contract/checker.ts index a57064284ed8..cdbd81814387 100644 --- a/yarn-project/aztec.js/src/contract/checker.ts +++ b/yarn-project/aztec.js/src/contract/checker.ts @@ -1,4 +1,4 @@ -import { ABIType, BasicType, ContractAbi, StructType } from '@aztec/noir-contracts'; +import { ABIType, BasicType, ContractAbi, StructType } from '@aztec/foundation/abi'; type TypeWithoutKind = Omit<{ [key in keyof T]: any }, 'kind'>; diff --git a/yarn-project/aztec.js/src/contract/contract.test.ts b/yarn-project/aztec.js/src/contract/contract.test.ts index 15db822f8c87..29c05de60964 100644 --- a/yarn-project/aztec.js/src/contract/contract.test.ts +++ b/yarn-project/aztec.js/src/contract/contract.test.ts @@ -8,11 +8,11 @@ import { TxReceipt, TxRequest, } from '@aztec/aztec-rpc'; -import { ABIParameterVisibility, ContractAbi, FunctionType } from '@aztec/noir-contracts'; import { mock } from 'jest-mock-extended'; import { EcdsaSignature } from '@aztec/circuits.js'; import { Contract } from './contract.js'; +import { ABIParameterVisibility, ContractAbi, FunctionType } from '@aztec/foundation/abi'; import { randomBytes } from '@aztec/foundation/crypto'; describe('Contract Class', () => { diff --git a/yarn-project/aztec.js/src/contract/contract.ts b/yarn-project/aztec.js/src/contract/contract.ts index 03c17520fe8d..174489e17c1c 100644 --- a/yarn-project/aztec.js/src/contract/contract.ts +++ b/yarn-project/aztec.js/src/contract/contract.ts @@ -1,5 +1,5 @@ import { AztecRPCClient, DeployedContract, generateFunctionSelector } from '@aztec/aztec-rpc'; -import { ContractAbi, FunctionAbi } from '@aztec/noir-contracts'; +import { ContractAbi, FunctionAbi } from '@aztec/foundation/abi'; import { ContractFunctionInteraction } from './contract_function_interaction.js'; import { AztecAddress } from '@aztec/foundation/aztec-address'; import { EthAddress } from '@aztec/foundation/eth-address'; diff --git a/yarn-project/aztec.js/src/contract/contract_function_interaction.ts b/yarn-project/aztec.js/src/contract/contract_function_interaction.ts index ac769fbc58b1..8e06eb751cf0 100644 --- a/yarn-project/aztec.js/src/contract/contract_function_interaction.ts +++ b/yarn-project/aztec.js/src/contract/contract_function_interaction.ts @@ -1,6 +1,6 @@ import { AztecRPCClient, Tx, TxHash, TxRequest } from '@aztec/aztec-rpc'; import { AztecAddress, EcdsaSignature, Fr } from '@aztec/circuits.js'; -import { FunctionType } from '@aztec/noir-contracts'; +import { FunctionType } from '@aztec/foundation/abi'; import { SentTx } from './sent_tx.js'; export interface SendMethodOptions { diff --git a/yarn-project/aztec.js/src/contract_deployer/contract_deployer.test.ts b/yarn-project/aztec.js/src/contract_deployer/contract_deployer.test.ts index a24946c2b464..cfff42575923 100644 --- a/yarn-project/aztec.js/src/contract_deployer/contract_deployer.test.ts +++ b/yarn-project/aztec.js/src/contract_deployer/contract_deployer.test.ts @@ -1,6 +1,6 @@ import { AztecRPCClient, Tx, TxHash, TxReceipt, TxRequest } from '@aztec/aztec-rpc'; import { AztecAddress, EcdsaSignature, EthAddress, Fr } from '@aztec/circuits.js'; -import { ContractAbi, FunctionType } from '@aztec/noir-contracts'; +import { ContractAbi, FunctionType } from '@aztec/foundation/abi'; import { randomBytes } from 'crypto'; import { mock } from 'jest-mock-extended'; import { ContractDeployer } from './contract_deployer.js'; diff --git a/yarn-project/aztec.js/src/contract_deployer/contract_deployer.ts b/yarn-project/aztec.js/src/contract_deployer/contract_deployer.ts index 98b807037276..eae96926bfed 100644 --- a/yarn-project/aztec.js/src/contract_deployer/contract_deployer.ts +++ b/yarn-project/aztec.js/src/contract_deployer/contract_deployer.ts @@ -1,5 +1,5 @@ import { AztecRPCClient } from '@aztec/aztec-rpc'; -import { ContractAbi } from '@aztec/noir-contracts'; +import { ContractAbi } from '@aztec/foundation/abi'; import { DeployMethod } from './deploy_method.js'; /** diff --git a/yarn-project/aztec.js/src/contract_deployer/deploy_method.ts b/yarn-project/aztec.js/src/contract_deployer/deploy_method.ts index 95facc4c1d41..0714fe9918ac 100644 --- a/yarn-project/aztec.js/src/contract_deployer/deploy_method.ts +++ b/yarn-project/aztec.js/src/contract_deployer/deploy_method.ts @@ -1,5 +1,5 @@ import { AztecRPCClient } from '@aztec/aztec-rpc'; -import { ContractAbi, FunctionType } from '@aztec/noir-contracts'; +import { ContractAbi, FunctionType } from '@aztec/foundation/abi'; import { ContractFunctionInteraction, SendMethodOptions } from '../contract/index.js'; import { EthAddress } from '@aztec/foundation/eth-address'; import { Fr } from '@aztec/foundation/fields'; diff --git a/yarn-project/end-to-end/src/e2e_block_building.test.ts b/yarn-project/end-to-end/src/e2e_block_building.test.ts index dc2fb842955c..2ce6c727950b 100644 --- a/yarn-project/end-to-end/src/e2e_block_building.test.ts +++ b/yarn-project/end-to-end/src/e2e_block_building.test.ts @@ -3,7 +3,6 @@ import { AztecRPCServer, ContractDeployer, Fr, TxStatus } from '@aztec/aztec.js' import { mnemonicToAccount } from 'viem/accounts'; import { createAztecRpcServer } from './create_aztec_rpc_client.js'; import { deployL1Contracts } from './deploy_l1_contracts.js'; -import { ContractAbi } from '@aztec/noir-contracts'; import { TestContractAbi } from '@aztec/noir-contracts/examples'; import times from 'lodash.times'; import { createDebugLogger } from '@aztec/foundation/log'; @@ -18,7 +17,7 @@ describe('e2e_block_building', () => { let node: AztecNode; let aztecRpcServer: AztecRPCServer; - const abi = TestContractAbi as ContractAbi; + const abi = TestContractAbi; beforeEach(async () => { const account = mnemonicToAccount(MNEMONIC); diff --git a/yarn-project/end-to-end/src/e2e_nested_contract.test.ts b/yarn-project/end-to-end/src/e2e_nested_contract.test.ts index 2f3b2f554948..ef1f59437f82 100644 --- a/yarn-project/end-to-end/src/e2e_nested_contract.test.ts +++ b/yarn-project/end-to-end/src/e2e_nested_contract.test.ts @@ -1,7 +1,7 @@ import { AztecNode, getConfigEnvVars } from '@aztec/aztec-node'; import { AztecAddress, AztecRPCServer, Contract, ContractDeployer, Fr, TxStatus } from '@aztec/aztec.js'; import { createDebugLogger } from '@aztec/foundation/log'; -import { ContractAbi } from '@aztec/noir-contracts'; +import { ContractAbi } from '@aztec/foundation/abi'; import { ChildAbi, ParentAbi } from '@aztec/noir-contracts/examples'; import { mnemonicToAccount } from 'viem/accounts'; diff --git a/yarn-project/foundation/package.json b/yarn-project/foundation/package.json index 3b6d0d4deacb..b9333b84e481 100644 --- a/yarn-project/foundation/package.json +++ b/yarn-project/foundation/package.json @@ -8,6 +8,7 @@ "./eslint": "./.eslintrc.cjs", "./eslint-legacy": "./.eslintrc.legacy.cjs", "./prettier": "./.prettierrc.json", + "./abi": "./dest/abi/index.js", "./async-map": "./dest/async-map/index.js", "./aztec-address": "./dest/aztec-address/index.js", "./collection": "./dest/collection/index.js", diff --git a/yarn-project/noir-contracts/src/abi.ts b/yarn-project/foundation/src/abi/index.ts similarity index 100% rename from yarn-project/noir-contracts/src/abi.ts rename to yarn-project/foundation/src/abi/index.ts diff --git a/yarn-project/noir-compiler/.eslintrc.cjs b/yarn-project/noir-compiler/.eslintrc.cjs new file mode 100644 index 000000000000..e659927475c0 --- /dev/null +++ b/yarn-project/noir-compiler/.eslintrc.cjs @@ -0,0 +1 @@ +module.exports = require('@aztec/foundation/eslint'); diff --git a/yarn-project/noir-compiler/.gitignore b/yarn-project/noir-compiler/.gitignore new file mode 100644 index 000000000000..4e3795cbce5a --- /dev/null +++ b/yarn-project/noir-compiler/.gitignore @@ -0,0 +1,4 @@ +target/ +proofs/ +Prover.toml +Verifier.toml \ No newline at end of file diff --git a/yarn-project/noir-compiler/.prettierignore b/yarn-project/noir-compiler/.prettierignore new file mode 100644 index 000000000000..cf120a369f5c --- /dev/null +++ b/yarn-project/noir-compiler/.prettierignore @@ -0,0 +1 @@ +src/fixtures \ No newline at end of file diff --git a/yarn-project/noir-compiler/Dockerfile b/yarn-project/noir-compiler/Dockerfile new file mode 100644 index 000000000000..b054627ba455 --- /dev/null +++ b/yarn-project/noir-compiler/Dockerfile @@ -0,0 +1,15 @@ +FROM 278380418400.dkr.ecr.eu-west-2.amazonaws.com/yarn-project-base AS builder + +COPY . . + +WORKDIR /usr/src/yarn-project/noir-compiler +RUN yarn build && yarn formatting && yarn test + +# Prune dev dependencies. See comment in base image. +RUN yarn cache clean +RUN yarn workspaces focus --production > /dev/null + +FROM node:18-alpine +COPY --from=builder /usr/src/yarn-project/noir-compiler /usr/src/yarn-project/noir-compiler +WORKDIR /usr/src/yarn-project/noir-compiler +ENTRYPOINT ["yarn"] \ No newline at end of file diff --git a/yarn-project/noir-compiler/README.md b/yarn-project/noir-compiler/README.md new file mode 100644 index 000000000000..a338b2c090ec --- /dev/null +++ b/yarn-project/noir-compiler/README.md @@ -0,0 +1,15 @@ +# Aztec Noir compiler + +The Aztec noir compiler compiles noir contracts using noir_wasm and outputs Aztec formatted contract ABIs. + +## Installation + +To install the package, just run `yarn add @aztec/noir-compiler`. + +## Usage + +To run the compiler as a CLI tool, run `yarn aztec_noir_compiler compile ` + +## Status + +Currently, this noir compiler uses noir master branch. It's not compatible yet with the test contracts for Aztec that are in the `noir-contracts` package, that need to be built following its README.md instructions. diff --git a/yarn-project/noir-compiler/package.json b/yarn-project/noir-compiler/package.json new file mode 100644 index 000000000000..e3b22263d3c4 --- /dev/null +++ b/yarn-project/noir-compiler/package.json @@ -0,0 +1,61 @@ +{ + "name": "@aztec/noir-compiler", + "version": "0.0.0", + "type": "module", + "exports": "./dest/index.js", + "typedoc": { + "entryPoint": "./src/index.ts", + "displayName": "Aztec noir compiler", + "tsconfig": "./tsconfig.json" + }, + "bin": { + "aztec_noir_compiler": "dest/cli.js" + }, + "scripts": { + "prepare": "node ../yarn-project-base/scripts/update_build_manifest.mjs package.json", + "prepare:check": "node ../yarn-project-base/scripts/update_build_manifest.mjs package.json --check", + "build": "yarn clean && tsc -b", + "build:dev": "tsc -b --watch", + "clean": "rm -rf ./dest .tsbuildinfo", + "formatting": "run -T prettier --check ./src && run -T eslint ./src", + "formatting:fix": "run -T prettier -w ./src", + "test": "DEBUG=wasm NODE_NO_WARNINGS=1 node --experimental-vm-modules $(yarn bin jest) --passWithNoTests" + }, + "inherits": [ + "../package.common.json" + ], + "jest": { + "preset": "ts-jest/presets/default-esm", + "moduleNameMapper": { + "^(\\.{1,2}/.*)\\.js$": "$1" + }, + "testRegex": "./src/.*\\.test\\.ts$", + "rootDir": "./src" + }, + "dependencies": { + "@aztec/foundation": "workspace:^", + "@noir-lang/noir-source-resolver": "1.1.1", + "@noir-lang/noir_wasm": "0.5.1-9740f54", + "commander": "^9.0.0", + "fs-extra": "^11.1.1", + "toml": "^3.0.0", + "tslib": "^2.4.0" + }, + "devDependencies": { + "@jest/globals": "^29.5.0", + "@rushstack/eslint-patch": "^1.1.4", + "@types/fs-extra": "^11.0.1", + "@types/jest": "^29.5.0", + "@types/node": "^18.7.23", + "jest": "^29.5.0", + "ts-jest": "^29.1.0", + "ts-node": "^10.9.1", + "typescript": "^5.0.4" + }, + "files": [ + "dest", + "src", + "!*.test.*" + ], + "types": "./dest/index.d.ts" +} diff --git a/yarn-project/noir-compiler/src/__snapshots__/index.test.ts.snap b/yarn-project/noir-compiler/src/__snapshots__/index.test.ts.snap new file mode 100644 index 000000000000..a6956d1bb25e --- /dev/null +++ b/yarn-project/noir-compiler/src/__snapshots__/index.test.ts.snap @@ -0,0 +1,54 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`should compile the test contract 1`] = ` +[ + { + "functions": [ + { + "bytecode": "00000000060000000100000002000000020000000300000005000000020000000105000100000001000000fe00000002000000030000000400000000000000000300000000000000000000000000000000000000000000000000000000000000000000010100000000000000000000000000000000000000000000000000000000000000000000010200000030644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000050000000000000000000000000000000000000000000000000000000000000000000000", + "functionType": "secret", + "name": "constructor", + "parameters": [ + { + "name": "param", + "type": { + "kind": "field", + }, + "visibility": "private", + }, + { + "name": "pub_param", + "type": { + "kind": "field", + }, + "visibility": "public", + }, + ], + "returnTypes": [ + { + "kind": "array", + "length": 2, + "type": { + "kind": "field", + }, + }, + ], + "verificationKey": "0000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f", + }, + { + "bytecode": "00000000020000000000000001000000010000000100000000000000000100000030644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000001000000000000000000000000000000000000000000000000000000000000000000002a", + "functionType": "open", + "name": "openFunction", + "parameters": [], + "returnTypes": [ + { + "kind": "field", + }, + ], + "verificationKey": "0000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f", + }, + ], + "name": "TestContract", + }, +] +`; diff --git a/yarn-project/noir-compiler/src/cli.ts b/yarn-project/noir-compiler/src/cli.ts new file mode 100644 index 000000000000..ed0485ea8fba --- /dev/null +++ b/yarn-project/noir-compiler/src/cli.ts @@ -0,0 +1,37 @@ +#!/usr/bin/env node +import nodePath from 'path'; +import fs from 'fs/promises'; +import fsExtra from 'fs-extra'; +import { Command } from 'commander'; +import { ContractCompiler } from './compile.js'; + +const program = new Command(); + +const main = async () => { + program + .name('aztec_noir_compiler') + .command('compile') + .argument('[path]', 'Path to the contract project', '.') + .action(async (path: string) => { + const projectPath = nodePath.resolve(path); + + const compiler = new ContractCompiler(projectPath); + const contracts = await compiler.compile(); + + const buildFolderPath = nodePath.join(projectPath, 'target'); + + await fsExtra.mkdirp(buildFolderPath); + + for (const contract of contracts) { + const contractPath = nodePath.join(buildFolderPath, `aztec-${contract.name}.json`); + await fs.writeFile(contractPath, JSON.stringify(contract, null, 2)); + } + }); + + await program.parseAsync(process.argv); +}; + +main().catch(err => { + console.log(`Error thrown: ${err}`); + process.exit(1); +}); diff --git a/yarn-project/noir-compiler/src/compile.ts b/yarn-project/noir-compiler/src/compile.ts new file mode 100644 index 000000000000..aa93e6cbe84f --- /dev/null +++ b/yarn-project/noir-compiler/src/compile.ts @@ -0,0 +1,110 @@ +import { compile } from '@noir-lang/noir_wasm'; +import nodePath from 'path'; +import fsSync from 'fs'; +import fs from 'fs/promises'; +import noirResolver from '@noir-lang/noir-source-resolver'; +import toml from 'toml'; +import { NoirCompiledContract } from './noir_artifact.js'; +import { ContractAbi, FunctionType } from '@aztec/foundation/abi'; +import { mockVerificationKey } from './mockedKeys.js'; + +/** + * A dependency entry of Nargo.toml. + */ +export interface Dependency { + /** + * Path to the dependency. + */ + path?: string; + /** + * Git repository of the dependency. + */ + git?: string; +} + +/** + * A class that compiles noir contracts and outputs the Aztec ABI. + */ +export class ContractCompiler { + constructor(private projectPath: string) {} + + /** + * Compiles the contracts in projectPath and returns the Aztec ABI. + * @returns Aztec ABI of the compiled contracts. + */ + public async compile(): Promise { + const noirContracts = await this.compileNoir(); + const abis: ContractAbi[] = noirContracts.map(this.convertToAztecABI); + return abis; + } + + /** + * Converts a compiled noir contract to Aztec ABI. + * @param contract - A compiled noir contract. + * @returns Aztec ABI of the contract. + */ + private convertToAztecABI(contract: NoirCompiledContract): ContractAbi { + return { + ...contract, + functions: contract.functions.map(noirFn => ({ + name: noirFn.name, + functionType: noirFn.function_type.toLowerCase() as FunctionType, + parameters: noirFn.abi.parameters, + returnTypes: [noirFn.abi.return_type], + bytecode: Buffer.from(noirFn.bytecode).toString('hex'), + verificationKey: mockVerificationKey, + })), + }; + } + + /** + * Reads the dependencies of a noir crate. + * @param cratePath - Path to the noir crate. + * @returns A map of dependencies. + */ + private async readDependencies(cratePath: string) { + const { dependencies } = toml.parse( + await fs.readFile(nodePath.join(cratePath, 'Nargo.toml'), { encoding: 'utf8' }), + ); + return (dependencies || {}) as Record; + } + + /** + * Executes the noir compiler. + * @returns A list of compiled noir contracts. + */ + private async compileNoir(): Promise { + const dependenciesMap = await this.readDependencies(this.projectPath); + + /** + * The resolver receives a relative path, and the first part of the path can be a dependency name. + * If the dependency is found in the map, the rest of the path inside that dependency src folder. + * Otherwise, resolve the full relative path requested inside the project path. + */ + noirResolver.initialiseResolver((id: string) => { + const idParts = id.split('/'); + + let path; + if (dependenciesMap[idParts[0]]) { + const [dependencyName, ...dependencySubpathParts] = idParts; + const dependency = dependenciesMap[dependencyName]; + if (!dependency.path) { + throw new Error(`Don't know how to resolve dependency ${dependencyName}`); + } + path = nodePath.resolve(this.projectPath, dependency.path, 'src', dependencySubpathParts.join('/')); + } else { + path = nodePath.join(this.projectPath, 'src', idParts.join('/')); + } + + // The resolver does not support async resolution + // and holding the whole project in memory is not reasonable + const result = fsSync.readFileSync(path, { encoding: 'utf8' }); + return result; + }); + + return compile({ + contracts: true, + optional_dependencies_set: Object.keys(dependenciesMap), // eslint-disable-line camelcase + }); + } +} diff --git a/yarn-project/noir-contracts/src/declarations.d.ts b/yarn-project/noir-compiler/src/declaration.d.ts similarity index 100% rename from yarn-project/noir-contracts/src/declarations.d.ts rename to yarn-project/noir-compiler/src/declaration.d.ts diff --git a/yarn-project/noir-compiler/src/fixtures/test_contract/Nargo.toml b/yarn-project/noir-compiler/src/fixtures/test_contract/Nargo.toml new file mode 100644 index 000000000000..0cb398613b87 --- /dev/null +++ b/yarn-project/noir-compiler/src/fixtures/test_contract/Nargo.toml @@ -0,0 +1,6 @@ +[package] +authors = [""] +compiler_version = "0.1" + +[dependencies] +test = { path = "../test_lib" } diff --git a/yarn-project/noir-compiler/src/fixtures/test_contract/src/main.nr b/yarn-project/noir-compiler/src/fixtures/test_contract/src/main.nr new file mode 100644 index 000000000000..b980af369cf5 --- /dev/null +++ b/yarn-project/noir-compiler/src/fixtures/test_contract/src/main.nr @@ -0,0 +1,12 @@ +contract TestContract { + use dep::test::module::foo; + + fn constructor(param: Field, pub_param: pub Field) -> pub [Field; 2] { + [foo::bar(param), param + pub_param] + } + + open fn openFunction() -> pub Field { + 42 + } + +} diff --git a/yarn-project/noir-compiler/src/fixtures/test_lib/Nargo.toml b/yarn-project/noir-compiler/src/fixtures/test_lib/Nargo.toml new file mode 100644 index 000000000000..e0b467ce5daf --- /dev/null +++ b/yarn-project/noir-compiler/src/fixtures/test_lib/Nargo.toml @@ -0,0 +1,5 @@ +[package] +authors = [""] +compiler_version = "0.1" + +[dependencies] \ No newline at end of file diff --git a/yarn-project/noir-compiler/src/fixtures/test_lib/src/lib.nr b/yarn-project/noir-compiler/src/fixtures/test_lib/src/lib.nr new file mode 100644 index 000000000000..5c0b5a621e04 --- /dev/null +++ b/yarn-project/noir-compiler/src/fixtures/test_lib/src/lib.nr @@ -0,0 +1 @@ +mod module; \ No newline at end of file diff --git a/yarn-project/noir-compiler/src/fixtures/test_lib/src/module.nr b/yarn-project/noir-compiler/src/fixtures/test_lib/src/module.nr new file mode 100644 index 000000000000..2746c97edf0e --- /dev/null +++ b/yarn-project/noir-compiler/src/fixtures/test_lib/src/module.nr @@ -0,0 +1 @@ +mod foo; \ No newline at end of file diff --git a/yarn-project/noir-compiler/src/fixtures/test_lib/src/module/foo.nr b/yarn-project/noir-compiler/src/fixtures/test_lib/src/module/foo.nr new file mode 100644 index 000000000000..61316bc92808 --- /dev/null +++ b/yarn-project/noir-compiler/src/fixtures/test_lib/src/module/foo.nr @@ -0,0 +1,3 @@ +fn bar(param: Field) -> Field { + dep::std::hash::pedersen([param])[0] +} \ No newline at end of file diff --git a/yarn-project/noir-compiler/src/index.test.ts b/yarn-project/noir-compiler/src/index.test.ts new file mode 100644 index 000000000000..3e0706b71f90 --- /dev/null +++ b/yarn-project/noir-compiler/src/index.test.ts @@ -0,0 +1,14 @@ +import path from 'path'; +import { fileURLToPath } from 'url'; +import { ContractCompiler } from './compile.js'; + +const getCurentDirname = () => path.dirname(fileURLToPath(import.meta.url)); + +it('should compile the test contract', async () => { + const testContractPath = path.join(getCurentDirname(), 'fixtures/test_contract'); + const compiler = new ContractCompiler(testContractPath); + + const compilationResult = await compiler.compile(); + + expect(compilationResult).toMatchSnapshot(); +}); diff --git a/yarn-project/noir-compiler/src/index.ts b/yarn-project/noir-compiler/src/index.ts new file mode 100644 index 000000000000..32ac429c3a38 --- /dev/null +++ b/yarn-project/noir-compiler/src/index.ts @@ -0,0 +1 @@ +export * from './compile.js'; diff --git a/yarn-project/noir-compiler/src/mockedKeys.ts b/yarn-project/noir-compiler/src/mockedKeys.ts new file mode 100644 index 000000000000..b8f5c677eade --- /dev/null +++ b/yarn-project/noir-compiler/src/mockedKeys.ts @@ -0,0 +1,2 @@ +export const mockVerificationKey = + '0000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f'; diff --git a/yarn-project/noir-compiler/src/noir_artifact.ts b/yarn-project/noir-compiler/src/noir_artifact.ts new file mode 100644 index 000000000000..bdf786693b64 --- /dev/null +++ b/yarn-project/noir-compiler/src/noir_artifact.ts @@ -0,0 +1,42 @@ +import { ABIParameter, ABIType } from '@aztec/foundation/abi'; + +/** The noir function types. */ +type NoirFunctionType = 'Open' | 'Secret' | 'Unconstrained'; + +/** The ABI of a noir function. */ +interface NoirFunctionAbi { + /** The parameters of the function. */ + parameters: ABIParameter[]; + /** + * The witness indices of the parameters. Indexed by parameter name. + */ + param_witnesses: Record; + /** The return type of the function. */ + return_type: ABIType; + /** The witness indices of the return type. */ + return_witnesses: number[]; +} + +/** + * The compilation result of a noir function. + */ +interface NoirFunctionEntry { + /** The name of the function. */ + name: string; + /** The type of the function. */ + function_type: NoirFunctionType; + /** The ABI of the function. */ + abi: NoirFunctionAbi; + /** The bytecode of the function. */ + bytecode: Uint8Array; +} + +/** + * The compilation result of a noir contract. + */ +export interface NoirCompiledContract { + /** The name of the contract. */ + name: string; + /** The functions of the contract. */ + functions: NoirFunctionEntry[]; +} diff --git a/yarn-project/noir-compiler/tsconfig.json b/yarn-project/noir-compiler/tsconfig.json new file mode 100644 index 000000000000..63f8ab3e9f75 --- /dev/null +++ b/yarn-project/noir-compiler/tsconfig.json @@ -0,0 +1,14 @@ +{ + "extends": "..", + "compilerOptions": { + "outDir": "dest", + "rootDir": "src", + "tsBuildInfoFile": ".tsbuildinfo" + }, + "references": [ + { + "path": "../foundation" + } + ], + "include": ["src"] +} diff --git a/yarn-project/noir-contracts/.eslintrc.cjs b/yarn-project/noir-contracts/.eslintrc.cjs index 97d6f1878135..e659927475c0 100644 --- a/yarn-project/noir-contracts/.eslintrc.cjs +++ b/yarn-project/noir-contracts/.eslintrc.cjs @@ -1 +1 @@ -module.exports = require('@aztec/foundation/eslint-legacy'); +module.exports = require('@aztec/foundation/eslint'); diff --git a/yarn-project/noir-contracts/README.md b/yarn-project/noir-contracts/README.md index ba0935a827ae..27ed37fddf37 100644 --- a/yarn-project/noir-contracts/README.md +++ b/yarn-project/noir-contracts/README.md @@ -1,6 +1,8 @@ # Noir contracts -## Building +This package contains the source code and the Aztec ABIs for the example contracts used in the e2e tests. + +## Building the contracts - Install [noirup](https://github.com/noir-lang/noirup) ``` diff --git a/yarn-project/noir-contracts/package.json b/yarn-project/noir-contracts/package.json index 7ef150be10b2..be8978832dae 100644 --- a/yarn-project/noir-contracts/package.json +++ b/yarn-project/noir-contracts/package.json @@ -40,9 +40,6 @@ }, "dependencies": { "@aztec/foundation": "workspace:^", - "@noir-lang/noir-source-resolver": "^1.1.0", - "@noir-lang/noir_wasm": "0.3.2-29b1f7df", - "toml": "^3.0.0", "tslib": "^2.4.0" }, "devDependencies": { diff --git a/yarn-project/noir-contracts/src/compile.ts b/yarn-project/noir-contracts/src/compile.ts deleted file mode 100644 index 42c20ec7f0f0..000000000000 --- a/yarn-project/noir-contracts/src/compile.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { compile } from '@noir-lang/noir_wasm'; -import { dirname, join as pathJoin } from 'path'; -import { fileURLToPath } from 'url'; -import fs from 'fs'; -import { initialiseResolver } from '@noir-lang/noir-source-resolver'; -import toml from 'toml'; -import { CompiledCircuit, Dependency } from './compiled_circuit.js'; - -const circuitsPath = pathJoin(dirname(fileURLToPath(import.meta.url)), 'circuits'); - -/** - * - * @param circuitPath - Path to the circuit crate. - * @returns The dependencies of the circuit as a map of name to dependency entry. - */ -function readDependencies(circuitPath: string) { - const { dependencies } = toml.parse(fs.readFileSync(pathJoin(circuitPath, 'Nargo.toml'), { encoding: 'utf8' })); - return dependencies as Record; -} - -/** - * Compiles a noir circuit fixture by name. - * @param circuitName - Name of the circuit fixture to compile. - * @returns The compiled circuit. - */ -export function compileCircuit(circuitName: string) { - const circuitPath = pathJoin(circuitsPath, circuitName); - const dependenciesMap = readDependencies(circuitPath); - - initialiseResolver((id: `${string}/lib.nr` | 'main.nr') => { - let path; - if (id === 'main.nr') { - path = pathJoin(circuitPath, 'src/main.nr'); - } else { - const [dependencyName] = id.split('/'); - const dependency = dependenciesMap[dependencyName]; - if (!dependency.path) { - throw new Error(`Don't know how to resolve dependency ${dependencyName}`); - } - path = pathJoin(circuitPath, dependency.path, 'src/lib.nr'); - } - const result = fs.readFileSync(path, { encoding: 'utf8' }); - return result; - }); - - return compile({ - optional_dependencies_set: Object.keys(dependenciesMap), // eslint-disable-line camelcase - }) as CompiledCircuit; -} diff --git a/yarn-project/noir-contracts/src/compiled_circuit.ts b/yarn-project/noir-contracts/src/compiled_circuit.ts deleted file mode 100644 index 22d03c8eccc6..000000000000 --- a/yarn-project/noir-contracts/src/compiled_circuit.ts +++ /dev/null @@ -1,72 +0,0 @@ -/** - * A dependency entry of Nargo.toml. - */ -export interface Dependency { - /** - * Path to the dependency. - */ - path?: string; - /** - * Git repository of the dependency. - */ - git?: string; -} - -/** - * A circuit type. - */ -export interface CircuitType { - /** - * The actual type. - */ - kind: any; -} - -/** - * A parameter to the circuit. - */ -export interface Parameter { - /** - * The name of the parameter. - */ - name: string; - /** - * The type of the parameter. - */ - type: CircuitType; - /** - * The visibility of the parameter. - */ - visibility: 'private' | 'public'; -} - -/** - * The representation of a compiled circuit. - */ -export interface CompiledCircuit { - /** - * The bytecode of the circuit. - */ - circuit: Array; - /** - * The Noir ABI of the circuit. - */ - abi: { - /** - * The circuit parameters. - */ - parameters: Array; - /** - * The witness indices for the parameters. - */ - param_witnesses: Record>; - /** - * The circuit return type. - */ - return_type: CircuitType | null; - /** - * The witness indices for the return value. - */ - return_witnesses: Array; - }; -} diff --git a/yarn-project/noir-contracts/src/examples/index.ts b/yarn-project/noir-contracts/src/examples/index.ts index 1628f1df0a0c..590154368ddf 100644 --- a/yarn-project/noir-contracts/src/examples/index.ts +++ b/yarn-project/noir-contracts/src/examples/index.ts @@ -4,7 +4,7 @@ import ZkTokenContractJson from './zk_token_contract.json'; import ParentJson from './parent_contract.json'; import ChildJson from './child_contract.json'; import PublicTokenContractJson from './public_token_contract.json'; -import { ContractAbi } from '../abi.js'; +import { ContractAbi } from '@aztec/foundation/abi'; export const TestContractAbi = TestContractJson as ContractAbi; export const ZkTokenContractAbi = ZkTokenContractJson as ContractAbi; diff --git a/yarn-project/noir-contracts/src/index.ts b/yarn-project/noir-contracts/src/index.ts index a9cbd49ddb8e..e69de29bb2d1 100644 --- a/yarn-project/noir-contracts/src/index.ts +++ b/yarn-project/noir-contracts/src/index.ts @@ -1,2 +0,0 @@ -export * from './compile.js'; -export * from './abi.js'; diff --git a/yarn-project/noir-contracts/src/scripts/copy_output.ts b/yarn-project/noir-contracts/src/scripts/copy_output.ts index 3f9d68450310..edffd006b975 100644 --- a/yarn-project/noir-contracts/src/scripts/copy_output.ts +++ b/yarn-project/noir-contracts/src/scripts/copy_output.ts @@ -3,10 +3,18 @@ import camelCase from 'lodash.camelcase'; import snakeCase from 'lodash.snakecase'; import upperFirst from 'lodash.upperfirst'; import mockedKeys from './mockedKeys.json' assert { type: 'json' }; -import { ABIParameter, ABIType, FunctionType } from '../abi.js'; +import { ABIParameter, ABIType, FunctionType } from '@aztec/foundation/abi'; const STATEMENT_TYPES = ['type', 'params', 'return'] as const; +/** + * Creates an Aztec function entry. + * @param type - The type of the function. + * @param params - The parameters of the function. + * @param returns - The return types of the function. + * @param fn - The nargo function entry. + * @returns The Aztec function entry. + */ function getFunction(type: FunctionType, params: ABIParameter[], returns: ABIType[], fn: any) { if (!params) throw new Error(`ABI comment not found for function ${fn.name}`); return { @@ -23,6 +31,12 @@ function getFunction(type: FunctionType, params: ABIParameter[], returns: ABITyp }; } +/** + * Creates the Aztec function entries from the source code and the nargo output. + * @param source - The source code of the contract. + * @param output - The nargo output. + * @returns The Aztec function entries. + */ function getFunctions(source: string, output: any) { const abiComments = Array.from(source.matchAll(/\/\/\/ ABI (\w+) (params|return|type) (.+)/g)).map(match => ({ functionName: match[1], @@ -52,7 +66,7 @@ function getFunctions(source: string, output: any) { }); } -function main() { +const main = () => { const name = process.argv[2]; if (!name) throw new Error(`Missing argument contract name`); @@ -70,7 +84,7 @@ function main() { const exampleFile = `${examples}/${snakeCase(name)}_contract.json`; writeFileSync(exampleFile, JSON.stringify(abi, null, 2) + '\n'); console.log(`Written ${exampleFile}`); -} +}; try { main(); diff --git a/yarn-project/package.json b/yarn-project/package.json index dd0d4ef372f3..7ddf182ef01a 100644 --- a/yarn-project/package.json +++ b/yarn-project/package.json @@ -28,6 +28,7 @@ "key-store", "merkle-tree", "noir-contracts", + "noir-compiler", "l1-artifacts", "p2p", "prover-client", diff --git a/yarn-project/tsconfig.json b/yarn-project/tsconfig.json index 13335f85c5f7..be39f6c740a6 100644 --- a/yarn-project/tsconfig.json +++ b/yarn-project/tsconfig.json @@ -31,6 +31,7 @@ { "path": "l1-artifacts/tsconfig.json" }, { "path": "merkle-tree/tsconfig.json" }, { "path": "noir-contracts/tsconfig.json" }, + { "path": "noir-compiler/tsconfig.json" }, { "path": "p2p/tsconfig.json" }, { "path": "prover-client/tsconfig.json" }, { "path": "sequencer-client/tsconfig.json" }, diff --git a/yarn-project/typedoc.json b/yarn-project/typedoc.json index c514de88b08f..70ff58a3a74d 100644 --- a/yarn-project/typedoc.json +++ b/yarn-project/typedoc.json @@ -9,6 +9,7 @@ "aztec.js", "key-store", "noir-contracts", + "noir-compiler", "p2p", "prover-client", "aztec-node", diff --git a/yarn-project/yarn-project-base/Dockerfile b/yarn-project/yarn-project-base/Dockerfile index 5e0824555a11..ed306d3257fe 100644 --- a/yarn-project/yarn-project-base/Dockerfile +++ b/yarn-project/yarn-project-base/Dockerfile @@ -30,6 +30,7 @@ COPY key-store/package.json key-store/package.json COPY merkle-tree/package.json merkle-tree/package.json COPY merkle-tree/package.local.json merkle-tree/package.local.json COPY noir-contracts/package.json noir-contracts/package.json +COPY noir-compiler/package.json noir-compiler/package.json COPY l1-artifacts/package.json l1-artifacts/package.json COPY barretenberg.js/package.json barretenberg.js/package.json COPY circuits.js/package.json circuits.js/package.json diff --git a/yarn-project/yarn.lock b/yarn-project/yarn.lock index 9b01576ae6d5..50c3633871ac 100644 --- a/yarn-project/yarn.lock +++ b/yarn-project/yarn.lock @@ -375,14 +375,37 @@ __metadata: languageName: unknown linkType: soft +"@aztec/noir-compiler@workspace:noir-compiler": + version: 0.0.0-use.local + resolution: "@aztec/noir-compiler@workspace:noir-compiler" + dependencies: + "@aztec/foundation": "workspace:^" + "@jest/globals": ^29.5.0 + "@noir-lang/noir-source-resolver": 1.1.1 + "@noir-lang/noir_wasm": 0.5.1-9740f54 + "@rushstack/eslint-patch": ^1.1.4 + "@types/fs-extra": ^11.0.1 + "@types/jest": ^29.5.0 + "@types/node": ^18.7.23 + commander: ^9.0.0 + fs-extra: ^11.1.1 + jest: ^29.5.0 + toml: ^3.0.0 + ts-jest: ^29.1.0 + ts-node: ^10.9.1 + tslib: ^2.4.0 + typescript: ^5.0.4 + bin: + aztec_noir_compiler: dest/cli.js + languageName: unknown + linkType: soft + "@aztec/noir-contracts@workspace:^, @aztec/noir-contracts@workspace:noir-contracts": version: 0.0.0-use.local resolution: "@aztec/noir-contracts@workspace:noir-contracts" dependencies: "@aztec/foundation": "workspace:^" "@jest/globals": ^29.5.0 - "@noir-lang/noir-source-resolver": ^1.1.0 - "@noir-lang/noir_wasm": 0.3.2-29b1f7df "@rushstack/eslint-patch": ^1.1.4 "@types/jest": ^29.5.0 "@types/lodash.camelcase": ^4.3.7 @@ -393,7 +416,6 @@ __metadata: lodash.camelcase: ^4.3.0 lodash.snakecase: ^4.1.1 lodash.upperfirst: ^4.3.1 - toml: ^3.0.0 ts-jest: ^29.1.0 ts-node: ^10.9.1 tslib: ^2.4.0 @@ -1601,7 +1623,7 @@ __metadata: languageName: node linkType: hard -"@noir-lang/noir-source-resolver@npm:^1.1.0": +"@noir-lang/noir-source-resolver@npm:1.1.1": version: 1.1.1 resolution: "@noir-lang/noir-source-resolver@npm:1.1.1" checksum: 43acc4c1a720ad0837db68bfac59efe58fe2b7467a8508807857aa738e3095d088547692efba5655f3e89e6c4747307c769e582d6ef5b4d454c7787090601a82 @@ -1615,12 +1637,12 @@ __metadata: languageName: node linkType: hard -"@noir-lang/noir_wasm@npm:0.3.2-29b1f7df": - version: 0.3.2-29b1f7df - resolution: "@noir-lang/noir_wasm@npm:0.3.2-29b1f7df" +"@noir-lang/noir_wasm@npm:0.5.1-9740f54": + version: 0.5.1-9740f54 + resolution: "@noir-lang/noir_wasm@npm:0.5.1-9740f54" peerDependencies: - "@noir-lang/noir-source-resolver": 1.1.0 - checksum: f5e61eb256783dca9d35345e77e9137d5fb2a6e3ecc8122b4a10ef0a6871e9e4b3842944f5b9fdbf82fef02bd6c1b27af28a6ed204728718ca89b9b394a09b32 + "@noir-lang/noir-source-resolver": 1.1.2 + checksum: c4b20840cba8bd844153e88c6324aa1f32331c838030734b1cbe6563e6b4f8e24a3ef0cc3d00a68812b457c9d079c0ece2a87adff3c0d8d4bf819e06cbed398e languageName: node linkType: hard @@ -1880,6 +1902,16 @@ __metadata: languageName: node linkType: hard +"@types/fs-extra@npm:^11.0.1": + version: 11.0.1 + resolution: "@types/fs-extra@npm:11.0.1" + dependencies: + "@types/jsonfile": "*" + "@types/node": "*" + checksum: 3e930346e5d84f419deb8ced1c582beef8cb20d0bd8a0eb145a37d75bab0572a1895f0e48a0d681d386b3a58b9a992b2d2acecc464bcaec2548f53ea00718651 + languageName: node + linkType: hard + "@types/graceful-fs@npm:^4.1.3": version: 4.1.6 resolution: "@types/graceful-fs@npm:4.1.6" @@ -1945,6 +1977,15 @@ __metadata: languageName: node linkType: hard +"@types/jsonfile@npm:*": + version: 6.1.1 + resolution: "@types/jsonfile@npm:6.1.1" + dependencies: + "@types/node": "*" + checksum: 0f8fe0a9221a00e8413cffba723dfe16553868724b830237256fb0052ecd5cac96498189d1235a001cfa815f352008261c9ceb373f0aa58227f891e0c7a12c4d + languageName: node + linkType: hard + "@types/keygrip@npm:*": version: 1.0.2 resolution: "@types/keygrip@npm:1.0.2" @@ -4064,6 +4105,17 @@ __metadata: languageName: node linkType: hard +"fs-extra@npm:^11.1.1": + version: 11.1.1 + resolution: "fs-extra@npm:11.1.1" + dependencies: + graceful-fs: ^4.2.0 + jsonfile: ^6.0.1 + universalify: ^2.0.0 + checksum: fb883c68245b2d777fbc1f2082c9efb084eaa2bbf9fddaa366130d196c03608eebef7fb490541276429ee1ca99f317e2d73e96f5ca0999eefedf5a624ae1edfd + languageName: node + linkType: hard + "fs-minipass@npm:^2.0.0, fs-minipass@npm:^2.1.0": version: 2.1.0 resolution: "fs-minipass@npm:2.1.0" @@ -4243,7 +4295,7 @@ __metadata: languageName: node linkType: hard -"graceful-fs@npm:^4.1.15, graceful-fs@npm:^4.2.6, graceful-fs@npm:^4.2.9": +"graceful-fs@npm:^4.1.15, graceful-fs@npm:^4.1.6, graceful-fs@npm:^4.2.0, graceful-fs@npm:^4.2.6, graceful-fs@npm:^4.2.9": version: 4.2.11 resolution: "graceful-fs@npm:4.2.11" checksum: ac85f94da92d8eb6b7f5a8b20ce65e43d66761c55ce85ac96df6865308390da45a8d3f0296dd3a663de65d30ba497bd46c696cc1e248c72b13d6d567138a4fc7 @@ -5261,6 +5313,19 @@ __metadata: languageName: node linkType: hard +"jsonfile@npm:^6.0.1": + version: 6.1.0 + resolution: "jsonfile@npm:6.1.0" + dependencies: + graceful-fs: ^4.1.6 + universalify: ^2.0.0 + dependenciesMeta: + graceful-fs: + optional: true + checksum: 7af3b8e1ac8fe7f1eccc6263c6ca14e1966fcbc74b618d3c78a0a2075579487547b94f72b7a1114e844a1e15bb00d440e5d1720bfc4612d790a6f285d5ea8354 + languageName: node + linkType: hard + "keygrip@npm:~1.1.0": version: 1.1.0 resolution: "keygrip@npm:1.1.0" @@ -7450,6 +7515,13 @@ __metadata: languageName: node linkType: hard +"universalify@npm:^2.0.0": + version: 2.0.0 + resolution: "universalify@npm:2.0.0" + checksum: 2406a4edf4a8830aa6813278bab1f953a8e40f2f63a37873ffa9a3bc8f9745d06cc8e88f3572cb899b7e509013f7f6fcc3e37e8a6d914167a5381d8440518c44 + languageName: node + linkType: hard + "unpipe@npm:1.0.0": version: 1.0.0 resolution: "unpipe@npm:1.0.0"